I just have started with Python and I would translate this example from MATLAB to Python, but I have not found the equivalent in Python.
https://www.mathworks.com/help/matlab/ref/surface.html
load clown
surface(peaks,flipud(X),...
'FaceColor','texturemap',...
'EdgeColor','none',...
'CDataMapping','direct')
colormap(map)
view(-35,45)
Thanks!
Matplotlib offers nearly all plotting options Matlab does. Surface plots can be done as well: http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#surface-plots
To load images scipy has a PIL-wrapper (no clown included, sorry), which loads matplotlib-compatible numpy arrays.
To sum up, you want the following packages: numpy, scipy, matplotlib and PIL. The combination of those four libraries should give you all you need. Also check out the pylab interface of these libraries, as it is very similar to Matlab.
Example that does what I believe you want to do:
from mpl_toolkits.mplot3d import Axes3D
from scipy.misc import imread
from matplotlib.pyplot import figure, show
from numpy import linspace, meshgrid, sqrt, sin, mean, flipud
clown = imread('clown.png')
fig = figure()
ax = fig.gca(projection='3d')
X = linspace(-5, 5, clown.shape[0])
Y = linspace(-5, 5, clown.shape[1])
X, Y = meshgrid(X, Y)
R = sqrt(X**2 + Y**2)
Z = sin(R)
clown = clown.swapaxes(0,1) / 255. # meshgrid orients axes the other way around, scaling of rgb to [0-1]
ax.plot_surface(X, Y, Z, facecolors=flipud(clown))
ax.view_init(45,-35) # swapped wrt matlab
show()
Related
I have an image that I would like to rotate. Namely, exchange the x and y axes. It is of a spectrogram. The basic code is
import matplotlib.pyplot as plt
Sxx, f, t, im = plt.specgram(dataArray, NFFT=2**8, Fs = 100, noverlap = 128)
plt.show()
This is what gets produced:
Does Python have a function that rotates the image 90 degrees as easily as the View function does in Matlab?
UPDATE
I've learned that plt.specgram can take all kwargs that imshow does. I still couldn't find any that would rotate the image, though. Anyone know?
UPDATE 2
I found here and confirmed here that Matlab has an argument option freqloc that can be used to exchange where the axes are drawn, but I can't locate the Python equivalent.
You can use scipy rotate to rotate your data (from the array point of view). The following example:
import matplotlib.pyplot as plt
import numpy as np
from scipy import ndimage
X, Y = np.meshgrid(range(100), range(100))
im = X**2 + Y**2
imrot45 = ndimage.rotate(im, 45)
imrot90 = ndimage.rotate(im, 90)
f, (ax1, ax2, ax3) = plt.subplots(1, 3)
ax1.imshow(im, origin='lower', interpolation='nearest')
ax2.imshow(imrot45, origin='lower', interpolation='nearest')
ax3.imshow(imrot90, origin='lower', interpolation='nearest')
plt.show()
, results in this:
Depending on your data you may also want to try im.T (transpose) or numpy rot90.
I also recently, in another question, gave a recipe to rotate the figure if you prefer to do this. Check the following question:
Rotate a figure but not the legend
Consider this MWE:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import cm
n = 15
m = 12
x = np.linspace(-5, 5, n)
y = np.linspace(-5, 5, m)
Z = np.zeros((m, n))
for i in xrange(m):
for j in xrange(n):
Z[i, j] = x[j]**2 + y[i]**2
### Plot surface ###
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y = np.meshgrid(x, y)
ax.plot_surface(X, Y, Z)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('Z')
plt.show()
Note in particular that the dimensions n and m are not equal. The resulting plot has some weird lines hanging down, as well as strange coloring:
What's going on here, and how can I prevent this?
Unlike 2D, 3D plots in matplotlib have a lot of shortcomings. Let me quote one of the answers in matplotlib FAQ:
This is probably the most commonly reported issue with mplot3d. The
problem is that – from some viewing angles – a 3D object would appear
in front of another object, even though it is physically behind it.
This can result in plots that do not look “physically correct.”
Unfortunately, while some work is being done to reduce the occurance
of this artifact, it is currently an intractable problem, and can not
be fully solved until matplotlib supports 3D graphics rendering at its
core.
The problem occurs due to the reduction of 3D data down to 2D +
z-order scalar. A single value represents the 3rd dimension for all
parts of 3D objects in a collection. Therefore, when the bounding
boxes of two collections intersect, it becomes possible for this
artifact to occur. Furthermore, the intersection of two 3D objects
(such as polygons or patches) can not be rendered properly in
matplotlib’s 2D rendering engine.
This problem will likely not be solved until OpenGL support is added
to all of the backends (patches are greatly welcomed). Until then, if
you need complex 3D scenes, we recommend using MayaVi.
For your particular problem (and notice that I don't think this has anything to do with different sizes in each direction) I would advise you to increase your surface shape (even if artificially) and play around with the number of strides until you obtain something that is satisfactory:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import cm
n = 150
m = 120
x = np.linspace(-5, 5, n)
y = np.linspace(-5, 5, m)
Z = np.zeros((m, n))
for i in range(m):
for j in range(n):
Z[i, j] = x[j]**2 + y[i]**2
### Plot surface ###
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y = np.meshgrid(x, y)
ax.plot_surface(X, Y, Z,rstride=1, cstride=1)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('Z')
plt.show()
,which results in this:
The example above give rstrides and cstrides a value of 10. Should you increase it too much (let's say 80) and the problem becomes obvious:
Other option is for you to follow the recommendation of matplotlib FAQ itself and check Mayavi. Notice, however, that mayavi still does not support Python 3. Personally, if you need something quick to work with, I would recommend PyQtGraph.
I try to render the classic rice.png image for an image processing class but I cannot get the result I want.
import matplotlib.pyplot as plt
import numpy as np
from scipy import misc
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
# rice.png is the image one can find on the internet
rice = misc.imread('rice.png')
height, width = rice.shape
fig = plt.figure(2)
ax = fig.gca(projection='3d')
X = np.arange(0, height, 1)
Y = np.arange(0, width, 1)
X, Y = np.meshgrid(X, Y)
surf = ax.plot_surface(X, Y, rice, cmap=cm.coolwarm, linewidth=0)
plt.title('3D representation of image')
plt.show()
But that gives me this :
I tried using set_zticks but the ticks overflow as in the image above, I tried also the solutions one can see here but it overflows also and/or give poor result.
My goal is to have something like what can be seen in the paragraph how can I do so ?
[edit] I have already seen this question that gives a less complete answer that what can be found in the other link I gave earlier (idea of overriding the proj fonction).
However, I am not happy with the results. First because it means I have to change a functions in the matplotlib library (if I follow the SO solution) and as I will share my code with other students from my class, I do not want to do so. Then because it does not give me the same result (see later) it does not center the image, it just change the scale then cut the above part.
[edit2] update of the code
I am using this code to visualise my data using griddata. The code looks like this:
import math
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
**THE LIST C=DATA IS IN THE LINK ABOVE**
cx=np.asarray([row[0] for row in C])
cy=np.asarray([row[1] for row in C])
cz=np.asarray([row[2] for row in C])
xi = np.linspace(22.4,22.5,10)
yi = np.linspace(37,37.1,10)
# grid the data.
zi = griddata((cx, cy), cz, (xi[None,:], yi[:,None]), method='nearest')
plt.contourf(xi,yi,zi,300,cmap=plt.cm.jet)
# draw colorbar
plt.colorbar()
plt.xlim(xmin=22.4,xmax=22.5)
plt.ylim(ymin=37,ymax=37.1)
plt.title('no diamonds please')
plt.show()
As you can see there are some diamond shaped shapes which in fact should have been like the contours of a gaussian like for example shown here
Am i doing something wrong? Should i use some other tool instead of griddata? I had problems using sagemath for this and now switched to ""pure" python. Noob level keep in mind :)
Silly as it is, the answer is just to increase the value of "stepsize" in linspace like i.e:
xi = np.linspace(22.4,22.5,100)
I've got a numpy array in Python and I'd like to display it on-screen as a raster image. What is the simplest way to do this? It doesn't need to be particularly fancy or have a nice interface, all I need to do is to display the contents of the array as a greyscale raster image.
I'm trying to transition some of my IDL code to Python with NumPy and am basically looking for a replacement for the tv and tvscl commands in IDL.
Depending on your needs, either matplotlib's imshow or glumpy are probably the best options.
Matplotlib is infinitely more flexible, but slower (animations in matplotlib can be suprisingly resource intensive even when you do everything right.). However, you'll have a really wonderful, full-featured plotting library at your disposal.
Glumpy is perfectly suited for the quick, openGL based display and animation of a 2D numpy array, but is much more limited in what it does. If you need to animate a series of images or display data in realtime, it's a far better option than matplotlib, though.
Using matplotlib (using the pyplot API instead of pylab):
import matplotlib.pyplot as plt
import numpy as np
# Generate some data...
x, y = np.meshgrid(np.linspace(-2,2,200), np.linspace(-2,2,200))
x, y = x - x.mean(), y - y.mean()
z = x * np.exp(-x**2 - y**2)
# Plot the grid
plt.imshow(z)
plt.gray()
plt.show()
Using glumpy:
import glumpy
import numpy as np
# Generate some data...
x, y = np.meshgrid(np.linspace(-2,2,200), np.linspace(-2,2,200))
x, y = x - x.mean(), y - y.mean()
z = x * np.exp(-x**2 - y**2)
window = glumpy.Window(512, 512)
im = glumpy.Image(z.astype(np.float32), cmap=glumpy.colormap.Grey)
#window.event
def on_draw():
im.blit(0, 0, window.width, window.height)
window.mainloop()
Using ipython in the pylab interactive mode, you could do:
$ ipython pylab
In [1]: imshow(your_array)
or not in pylab mode:
$ ipython
In [1]: from pylab import *
In [2]: imshow(your_array)
In [3]: pylab.show()
or without the pylab namespace thing:
$ ipython
In [1]: import matplotlib.pyplot as pyplot
In [2]: pyplot.imshow(your_array)
In [3]: pyplot.show()
Quick addition: for displaying with matplotlib, if you want the image to appear "raster", i.e., pixelized without smoothing, then you should include the option interpolation='nearest' in the call to imshow.