Matplotlib - using imshow for transformed coordinates within meshgrid arrays - python

I am using a python script to calculate the stress fields (Z meshgrid array) for a defects within a metal. In order to do this, I have to transform the X and Y meshgrids (xtrans and ytrans). I am then using imshow to plot colour along with the contour lines. The problem I am having is that imshow assumes that the Z array contains values at points running linearly between two ranges. E.g it assumes Z[0,:] are the values in the Y direction that go from -5, -4,-3, -2...3, 4, 5 say. After the coordinates are transformed Y isn't spaced linearly between -5 and 5.
Is there a way to use imshow or a function like it, that has Xtrans, and ytrans meshgrids as input parameters?
import numpy as np
import scipy
import matcompat
from scipy.integrate import quad, nquad
from CalcQSB import CalcQSB
from dislstress import dislstress
import matplotlib.pyplot as plt
from matplotlib import cm
import scipy.interpolate
...
# evaluate over a grid
num = 50
npts =200
xi, yi = np.linspace(-num, num, npts), np.linspace(-num, num, npts)
X, Y = np.meshgrid(xi, yi)
Z = np.zeros(matcompat.size(X))
xtrans, ytrans = np.meshgrid(xi, yi)
... more code for determining correct values in the Z array.
v = np.linspace(np.amin(Z), np.amax(Z), 15, endpoint=True)
plt.imshow(Z, vmin=np.amin(Z), vmax=np.amax(Z), origin='lower',
extent=[np.amin(xtrans), np.amax(xtrans), np.amin(ytrans), np.amax(ytrans)])
plt.colorbar(ticks=v)
CS = plt.contour(xtrans, ytrans, Z,20,colors='k')
plt.show()
If someone can help, I would be most grateful.
Thanks
Luke

Related

colormap from a matrix in python

I have a 2D output matrix (say, Z) which was calculated as a function of two variables x,y.
x varies in a non-uniform manner like [1e-5,5e-5,1e-4,5e-4,1e-3,5e-3,1e-2]
y varies in a uniform manner like [300,400,500,600,700,800]
[ say, Z = np.random.rand(7,6) ]
I was trying to plot a colormap of the matrix Z by first creating a meshgrid for x,y and then using the pcolormesh. Since, my x values are non-uniform, I do not kn ow how to proceed. Any inputs would be greatly appreciated.
No need for meshgrids; regarding the non-uniform axes: In your case a log-scale works fine:
import numpy as np
from matplotlib import pyplot as plt
x = [1e-5,5e-5,1e-4,5e-4,1e-3,5e-3,1e-2]
y = [300,400,500,600,700,800]
# either enlarge x and y by one number (right-most
# endpoint for those bins), or make Z smaller as I did
Z = np.random.rand(6,5)
fig = plt.figure()
ax = fig.gca()
ax.pcolormesh(x,y,Z.T)
ax.set_xscale("log")
fig.show()

Generating a 3D sine curve using python

I want to generate a 3D sine curve in python. Does lumpy support it or is there another library I can use for it?
Generating a 2D curve is straightforward something like this --
x = numpy.linspace(0, 20, 0.1)
y = numpy.sin(x)
I now have x and y I can save to disk.
Now I want to do something similar but for a 3D sine curve over x, y and z axes. I am hoping someone might have done it before and help me.
EDIT: I have realized that for my use case I want a 2D curve in 3D space. So the other axes can be constant. So I am simply generating a 2D curve and adding a constant third parameter value to get the x,y,z values.
You can try something like:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
x = np.arange(0, 20, 0.1)
y = np.sin(x)
z = y*np.sin(x)
fig = plt.figure()
ax = plt.axes(projection='3d')
c = x + y
ax.scatter(x, y, z, c=c)
or maybe you want z = x*np.sin(x) or even z = np.sin(y)
Edit: maybe this is the best solution z = np.sin(np.sqrt(x**2+y**2)) from here
Have a play and to find what you want. Pretty funky stuff and depends on exactly what output you are looking for.

How to do 4D plot in matplotlib without np.meshgrid?

I know that I can do a 4D plot in matplotlib with the following code, with the fourth dimension shown as a colormap:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.add_subplot(111,projection= '3d' )
x = np.arange(100)/ 101
y = np.sin(x) + np.cos(x)
X,Y = np.meshgrid(x,y)
Z = (X**2) / (Y**2)
A = np.sin(Z)
ax.plot_surface(X,Y, Z, facecolors=cm.Oranges(A))
plt.show()
But what if my data is not a function of the other data? How do I do this without np.meshgrid? (In other words, my Z series cannot be a function of the output of the X,Y which is the output of np.meshgrid(x,y), because Z is not a function of X and Y.)
A surface plot is a mapping of 2D points to a 1D value, i.e. for each pair of (x,y) coordinates you need exactly one z coordinate. So while it isn't strictly necessary to have Z being a function of X and Y, those arrays to plot need to have the same number of elements.
For a plot_surface the restriction is to have X and Y as gridded 2D data. Z does not have to be 2D but needs to have the same number of elements.
This requirement can be weakened using a plot_trisurf where the only requirement is that there is a strict mapping of x,y,z, i.e. the ith value in X and Y corresponds to the ith value in Z.
In any case, even if there is no analytic function to map X and Y to Z, Z still needs to be some kind of mapping. Otherwise it is even questionable what information the resulting plot would convey.

Basic scatter plot with reference data on diagonal (identity line)

I have two arrays x,y obtained from a machine learning calculations and I wish to make a scatter plot with the reference data x on the diagonal in a way to visualize better the predicted values y against the true ones x. Please can you suggest me how to do it in python or gnuplot?
import numpy as np
import matplotlib.pyplot as plt
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
plt.scatter(x, y, c=colors)
plt.plot( [0,1],[0,1] )
plt.savefig('a.png')
This will produce:
Check this page for more information.
a simple example:
import matplotlib.pyplot as plt
import numpy as np
x=np.linspace(0,100,101)
y=np.random.normal(x) # add some noise
plt.plot(x,y,'r.') # x vs y
plt.plot(x,x,'k-') # identity line
plt.xlim(0,100)
plt.ylim(0,100)
plt.show()
In matplotlib, you can also draw an "infinite" line in order to avoid having to define the exact coordinates. For example, if you have an axes ax, you can do:
pt = (0, 0)
ax.axline(pt, slope=1, color='black')
where pt is an intersection point. Note if pt isn't included in the limits of the plot, the limits will be modified to include it.

how do you radially 'sweep out' a 1D array to plot 3d figure in python? (to represent a wavefunction)

effectively I have a large 1D array of heights. As a small example consider:
u=array([0,1,2,1,0,2,4,6,4,2,1])
and a 1D array, the same size as u, of radial values which the heights correspond to, e.g.:
r=array([0,1,2,3,4,5,6,7,8,9,10])
Obviously plotting these with:
pylab.plot(r,u)
gives a nice 2D plot.
How can one sweep this out around 360 degrees, to give a 3D contour/surface plot?
If you can imagine it should look like a series of concentric, circular ridges, like for the wavefunction of an atom.
any help would be much appreciated!
You're better off with something more 3D oriented than matplotlib, in this case...
Here's a quick example using mayavi:
from enthought.mayavi import mlab
import numpy as np
# Generate some random data along a straight line in the x-direction
num = 100
x = np.arange(num)
y, z = np.ones(num), np.ones(num)
s = np.cumsum(np.random.random(num) - 0.5)
# Plot using mayavi's mlab api
fig = mlab.figure()
# First we need to make a line source from our data
line = mlab.pipeline.line_source(x,y,z,s)
# Then we apply the "tube" filter to it, and vary the radius by "s"
tube = mlab.pipeline.tube(line, tube_sides=20, tube_radius=1.0)
tube.filter.vary_radius = 'vary_radius_by_scalar'
# Now we display the tube as a surface
mlab.pipeline.surface(tube)
# And finally visualize the result
mlab.show()
#!/usr/bin/python
from mpl_toolkits.mplot3d import Axes3D
import matplotlib
import numpy as np
from scipy.interpolate import interp1d
from matplotlib import cm
from matplotlib import pyplot as plt
step = 0.04
maxval = 1.0
fig = plt.figure()
ax = Axes3D(fig)
u=np.array([0,1,2,1,0,2,4,6,4,2,1])
r=np.array([0,1,2,3,4,5,6,7,8,9,10])
f=interp1d(r,u)
# walk along the circle
p = np.linspace(0,2*np.pi,50)
R,P = np.meshgrid(r,p)
# transform them to cartesian system
X,Y = R*np.cos(P),R*np.sin(P)
Z=f(R)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet)
ax.set_xticks([])
plt.show()

Categories