Difference between revisions of "Python:Plotting Surfaces"

From PrattWiki
Jump to navigation Jump to search
Line 170: Line 170:
 
You can also use a finer grid to make a better-looking plot:
 
You can also use a finer grid to make a better-looking plot:
 
<syntaxhighlight lang=python>
 
<syntaxhighlight lang=python>
[x, y] = meshgrid(linspace(-1.2, 1.2, 20));
+
fig = plt.figure(num=1)
r = sqrt( (x-(-1)).^2 + (y-(-0.5)).^2 );
+
fig.clf()
meshc(x, y, r);
+
ax = fig.add_subplot(111, projection='3d')
xlabel('x');
+
 
ylabel('y');
+
(x, y) = np.meshgrid(np.linspace(-1.2, 1.2, 20),
zlabel('r');
+
                    np.linspace(-1.2, 1.2, 20))
title('r = Distance from (-1,-0.5)');
+
z = np.sqrt((x-(1))**2 + (y-(-0.5))**2)
 +
 
 +
ax.plot_surface(x, y, z, cmap=cm.magma)
 +
ax.set(xlabel='x', ylabel='y', zlabel='z',
 +
      title='Distance from (1, -0.5)')
 
</syntaxhighlight>
 
</syntaxhighlight>
 
and the plot is:
 
and the plot is:
 
<center>
 
<center>
[[Image:SurfExp03.png|400px]]
+
[[Image:SurfExp03c_py.png|400px]]
 
</center>
 
</center>
 
Note that the <code>meshgrid</code> command was given only one
 
argument - in that case, the range of <code>x</code> and <code>y</code> will be the same.
 
  
 
== Finding Minima and Maxima in 2-D ==
 
== Finding Minima and Maxima in 2-D ==

Revision as of 23:16, 5 November 2018

There are many problems in engineering that require examining a 2-D domain. For example, if you want to determine the distance from a specific point on a flat surface to any other flat surface, you need to think about both the x and y coordinate. There are various other functions that need x and y coordinates.


Introductory Links

To better understand how plotting works in Python, start with reading the following pages from the Tutorials page:

Individual Patches

One way to create a surface is to generate lists of the x, y, and z coordinates for each location of a patch. Python can make a surface from the points specified by the matrices and will then connect those points by linking the values next to each other in the matrix. For example, if x, y, and z are 2x2 matrices, the surface will generate group of four lines connecting the four points and then fill in the space among the four lines:

import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt

fig = plt.figure(num=1)
fig.clf()
ax = fig.add_subplot(111, projection='3d')

x = np.array([[1, 3], [2, 4]])
y = np.array([[5, 6], [7, 8]])
z = np.array([[9, 12], [10, 11]])

ax.plot_surface(x, y, z)
ax.set(xlabel='x', ylabel='y', zlabel='z')

fig.savefig('PatchExOrig_py.png')

PatchExOrig py.png

Note that the four "corners" above are not all co-planar; Python will thus create the patch using two triangles - to show this more clearly, you can tell Python to change the view by specifying the elevation (angle up from the xy plane) and azimuth (angle around the xy plane):

ax.view_init(elev=30, azim=45)
plt.draw()

which yields the following image:

PatchExRot py.png

You can add more patches to the surface by increasing the size of the matrices. For example, adding another column will add two more intersections to the surface:

fig = plt.figure(num=1)
fig.clf()
ax = fig.add_subplot(111, projection='3d')

x = np.array([[1, 3, 5], [2, 4, 6]])
y = np.array([[5, 6, 5], [7, 8, 9]])
z = np.array([[9, 12, 12], [10, 11, 12]])

ax.plot_surface(x, y, z)
ax.set(xlabel='x', ylabel='y', zlabel='z')
ax.view_init(elev=30, azim=220)

PatchExTwoRot py.png

Note the rotation to better see the two different patches.

The meshgrid Command

Much of the time, rather than specifying individual patches, you will have functions of two parameters to plot. Numpy's meshgrid command is specifically used to create matrices that will represent two parameters. For example, note the output to the following Python commands:

In [1]: (x, y) = np.meshgrid(np.arange(-2, 2.1, 1), np.arange(-1, 1.1, .25))
In [2]: x
Out[2]: 
array([[-2., -1.,  0.,  1.,  2.],
       [-2., -1.,  0.,  1.,  2.],
       [-2., -1.,  0.,  1.,  2.],
       [-2., -1.,  0.,  1.,  2.],
       [-2., -1.,  0.,  1.,  2.],
       [-2., -1.,  0.,  1.,  2.],
       [-2., -1.,  0.,  1.,  2.],
       [-2., -1.,  0.,  1.,  2.],
       [-2., -1.,  0.,  1.,  2.]])
In [3]: y
Out[3]: 
array([[-1.  , -1.  , -1.  , -1.  , -1.  ],
       [-0.75, -0.75, -0.75, -0.75, -0.75],
       [-0.5 , -0.5 , -0.5 , -0.5 , -0.5 ],
       [-0.25, -0.25, -0.25, -0.25, -0.25],
       [ 0.  ,  0.  ,  0.  ,  0.  ,  0.  ],
       [ 0.25,  0.25,  0.25,  0.25,  0.25],
       [ 0.5 ,  0.5 ,  0.5 ,  0.5 ,  0.5 ],
       [ 0.75,  0.75,  0.75,  0.75,  0.75],
       [ 1.  ,  1.  ,  1.  ,  1.  ,  1.  ]])

The first argument gives the values that the first output variable should include, and the second argument gives the values that the second output variable should include. Note that the first output variable x basically gives an x coordinate and the second output variable y gives a y coordinate. This is useful if you want to plot a function in 2-D. Note that the stopping values for the arange commands are just past where we wanted to end.

Examples Using 2 Independent Variables

For example, to plot z=x+y over the ranges of x and y specified above - the code would be:

fig = plt.figure(num=1)
fig.clf()
ax = fig.add_subplot(111, projection='3d')

(x, y) = np.meshgrid(np.arange(-2, 2.1, 1), np.arange(-1, 1.1, .25))
z = x + y

ax.plot_surface(x, y, z)
ax.set(xlabel='x', ylabel='y', zlabel='z', title='z = x + y')

and the graph is:

SurfExp01 py.png

If you want to make it more colorful, you can import colormaps and then use one; here is the complete code:

import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm

fig = plt.figure(num=1)
fig.clf()
ax = fig.add_subplot(111, projection='3d')

(x, y) = np.meshgrid(np.arange(-2, 2.1, 1), np.arange(-1, 1.1, .25))
z = x + y

ax.plot_surface(x, y, z, cmap=cm.copper)
ax.set(xlabel='x', ylabel='y', zlabel='z', title='z = x + y')

To see all the colormaps, after importing the cm group just type

help(cm)

to see the names or go to Colormap Reference to see the colors.


To find the distance r from a particular point, say (1,-0.5), you just need to change the function. Since the distance between two points \((x, y)\) and \((x_0, y_0)\) is given by \( r=\sqrt{(x-x_0)^2+(y-y_0)^2} \) the code could be:

fig = plt.figure(num=1)
fig.clf()
ax = fig.add_subplot(111, projection='3d')

(x, y) = np.meshgrid(np.arange(-2, 2.1, 1), np.arange(-1, 1.1, .25))
z = np.sqrt((x-(1))**2 + (y-(-0.5))**2)

ax.plot_surface(x, y, z, cmap=cm.Purples)
ax.set(xlabel='x', ylabel='y', zlabel='z', 
       title='Distance from (1, -0.5)')

and the plot is

SurfExp02c py.png

Examples Using Refined Grids

You can also use a finer grid to make a better-looking plot:

fig = plt.figure(num=1)
fig.clf()
ax = fig.add_subplot(111, projection='3d')

(x, y) = np.meshgrid(np.linspace(-1.2, 1.2, 20), 
                     np.linspace(-1.2, 1.2, 20))
z = np.sqrt((x-(1))**2 + (y-(-0.5))**2)

ax.plot_surface(x, y, z, cmap=cm.magma)
ax.set(xlabel='x', ylabel='y', zlabel='z', 
       title='Distance from (1, -0.5)')

and the plot is:

SurfExp03c py.png

Finding Minima and Maxima in 2-D

You can also use these 2-D structures to find minima and maxima. For example, given the grid in the code directly above, you can find the minimum and maximum distances and where they occur:

MinDistance = min(r(:)) 
MaxDistance = max(r(:))
XatMin = x(find(r == MinDistance))
YatMin = y(find(r == MinDistance))
XatMax = x(find(r == MaxDistance))
YatMax = y(find(r == MaxDistance))
MinDistance =
    0.0782
MaxDistance =
    2.7803
XatMin =
   -0.9474
YatMin =
   -0.4421
XatMax =
    1.2000
YatMax =
    1.2000

You can also use the two-output version of the max and min commands:

[MinDistance, MinIndex] = min(r(:)) 
[MaxDistance, MaxIndex] = max(r(:))
XatMin = x(MinIndex)
YatMin = y(MinIndex)
XatMax = x(MaxIndex)
YatMax = y(MaxIndex)

Fortunately, because of the way MATLAB pulls the elements from a matrix to a single column, the element numbers for the relevant x and y values will be the same.

If there are multiple maxima or minima, the find command will report them all. For example, with the following code,

    [x, y] = meshgrid(linspace(-1, 1, 31));
z2 = exp(-sqrt(x.^2+y.^2)).*cos(4*x).*cos(4*y);
meshc(x, y, z2);
xlabel('x');
ylabel('y');
zlabel('z');
title('z = e^{-(x^2+y^2)^{0.5}} cos(4x) cos(4y)');
MinVal = min(min(z2))
MaxVal = max(max(z2))
XatMin = x(find(z2 == MinVal))
YatMin = y(find(z2 == MinVal))
XatMax = x(find(z2 == MaxVal))
YatMax = y(find(z2 == MaxVal))

which gives a graph of:

SurfExp04.png

the matrix z2 has four entries with the same minimum value and one with the maximum value:

MinVal =
   -0.4699

MaxVal =
     1

XatMin =
   -0.7333
         0
         0
    0.7333

YatMin =
         0
   -0.7333
    0.7333
         0

XatMax =
     0

YatMax =
     0
</syntaxhighlight>

== Higher Refinement ==
As seen in creating line plots [[MATLAB:Plotting#Using_Different_Scales| using different scales]], you may want to use a more highly-refined
grid to locate maxima and minima with greater precision.  This may
include reducing the overall domain of the function as well as
including more points.  For example, the changing the grid to have 1001 points in either direction  makes for a more refined grid.  The code below demonstrates how to increase the
refinement: 
<syntaxhighlight lang=python>
[xp, yp] = meshgrid(linspace(-1.2, 1.2, 1001));
z2p = exp(-sqrt(xp.^2+yp.^2)).*cos(4*xp).*cos(4*yp);
MinValp = min(min(z2p))
MaxValp = max(max(z2p))
XatMinp = xp(find(z2p == MinValp))
YatMinp = yp(find(z2p == MinValp))
XatMaxp = xp(find(z2p == MaxValp))
YatMaxp = yp(find(z2p == MaxValp))
</syntaxhighlight>
The results obtained are:
<source lang="text">
MinValp =
   -0.4703

MaxValp =
     1

XatMinp =
   -0.7248
         0
         0
    0.7248

YatMinp =
         0
   -0.7248
    0.7248
         0

XatMaxp =
     0

YatMaxp =
     0

Note that graphing the more refined points would be a bad idea - there are now over one million nodes and MATLAB will have a hard time rendering such a surface.

Using Other Coordinate Systems

The plotting commands such as meshc and surfc generate surfaces based on matrices of x, y, and z coordinates, respectively, but you can also use other coordinate systems to calculate where the points go. As an example, the surface above could be plotted on a circular domain using polar coordinates. To do that, r and \(\theta\) coordinates could be generated using meshgrid and the appropriate x, y, and z values could be obtained by noting that \(x=r\cos(\theta)\) and \(y=r\sin(\theta)\). z can then be calculated from any combination of x, y, r, and \(\theta\):

 [r, theta] = meshgrid(...
        linspace(0, 1.7, 60), ...
        linspace(0, 2*pi, 73));
x = r.*cos(theta);
y = r.*sin(theta);
z = exp(-r).*cos(4*x).*cos(4*y);
meshc(x, y, z);
x('x');
y('y');
z('z');

produces:

SurfExp06a.png

though in this case, an interpolated surface plot might look better:

surfc(x, y, z);
shading interp
xlabel('x');
ylabel('y');
zlabel('z');

SurfExp06b.png

Color Maps and Color Bars

When printing to a black-and-white printer, it might make sense to change the color scheme to grayscale or something other than the default case. The colormap command does this. The different color maps are listed in the help file for color map, as are instructions for how to make your own colormap if you need to. Along with using a different color map, you may want to add a color bar to indicate the values assigned to particular colors. This may be done using the colorbar command. Continuing on with the examples above:

 [r, theta] = meshgrid(...
        linspace(0, 1.7, 60), ...
        linspace(0, 2*pi, 73));
x = r.*cos(theta);
y = r.*sin(theta);
z = exp(-r).*cos(4*x).*cos(4*y);
meshc(x, y, z);
colormap(gray)
colorbar
x('x');
y('y');
z('z');

produces:

SurfExp07a.png

and for the interpolated surface plot:

surfc(x, y, z);
shading interp
colormap(gray)
colorbar
xlabel('x');
ylabel('y');
zlabel('z');

SurfExp07b.png

Contour Plots

Information on making contour plots is at MATLAB:Contour Plots.

Questions

Post your questions by editing the discussion page of this article. Edit the page, then scroll to the bottom and add a question by putting in the characters *{{Q}}, followed by your question and finally your signature (with four tildes, i.e. ~~~~). Using the {{Q}} will automatically put the page in the category of pages with questions - other editors hoping to help out can then go to that category page to see where the questions are. See the page for Template:Q for details and examples.

External Links

References