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.
Related
I am trying to visualize a 3D graph using Mayavi.
During the program run, some nodes or edges in the graph become unavailable and I want to visualize dynamically that they become inaccessible in the visualization scene. How can I achieve this?
I'm still a newbie in python but it seems that the Mayavi scene can't be changed through the program once it is displayed.
It can be changed in many ways. You can add and remove elements, change background and foreground colors, and animate stuff. For example (from this link):
from __future__ import absolute_import, division, print_function
from mayavi import mlab
import numpy as np
import math
alpha = np.linspace(0, 2*math.pi, 100)
xs = np.cos(alpha)
ys = np.sin(alpha)
zs = np.zeros_like(xs)
mlab.points3d(0,0,0)
plt = mlab.points3d(xs[:1], ys[:1], zs[:1])
#mlab.animate(delay=100)
def anim():
f = mlab.gcf()
while True:
for (x, y, z) in zip(xs, ys, zs):
print('Updating scene...')
plt.mlab_source.set(x=x, y=y, z=z)
yield
anim()
mlab.show()
, will return you an animation where two sphere exist and one is having it's position changed every step of time:
The Mayavi documentation isn't exactly brilliant from my point of view but you can get some information both from the examples and chapters. For example remove an object from Mayavi pipeline.
I am trying to reproduce the left plot of this animation in python using matplotlib.
I am able to generate the vector arrows using the 3D quiver function, but as I read here, it does not seem possible to set the lengths of the arrows. So, my plot does not look quite right:
So, the question is: how do I generate a number of 3D arrows with different lengths? Importantly, can I generate them in such a way so that I can easily modify for each frame of the animation?
Here's my code so far, with the not-so-promising 3D quiver approach:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d
ax1 = plt.subplot(111,projection='3d')
t = np.linspace(0,10,40)
y = np.sin(t)
z = np.sin(t)
line, = ax1.plot(t,y,z,color='r',lw=2)
ax1.quiver(t,y,z, t*0,y,z)
plt.show()
As Azad suggests, an inelegant, but effective, solution is to simply edit the mpl_toolkits/mplot3d/axes3d.py to remove the normalization. Since I didn't want to mess with my actual matplotlib installation, I simply copied the axes3d.py file to the same directory as my other script and modified the line
norm = math.sqrt(u ** 2 + v ** 2 + w ** 2)
to
norm = 1
(Be sure to change the correct line. There is another use of "norm" a few lines higher.) Also, to get axes3d.py to function correctly when it's outside of the mpl directory, I changed
from . import art3d
from . import proj3d
from . import axis3d
to
from mpl_toolkits.mplot3d import art3d
from mpl_toolkits.mplot3d import proj3d
from mpl_toolkits.mplot3d import axis3d
And here is the nice animation that I was able to generate (not sure what's going wrong with the colors, it looks fine before I uploaded to SO).
And the code to generate the animation:
import numpy as np
import matplotlib.pyplot as plt
import axes3d_hacked
ax1 = plt.subplot(111,projection='3d')
plt.ion()
plt.show()
t = np.linspace(0,10,40)
for index,delay in enumerate(np.linspace(0,1,20)):
y = np.sin(t+delay)
z = np.sin(t+delay)
if delay > 0:
line.remove()
ax1.collections.remove(linecol)
line, = ax1.plot(t,y,z,color='r',lw=2)
linecol = ax1.quiver(t,y,z, t*0,y,z)
plt.savefig('images/Frame%03i.gif'%index)
plt.draw()
plt.ioff()
plt.show()
Now, if I could only get those arrows to look prettier, with nice filled heads. But that's a separate question...
EDIT: In the future, matplotlib will not automatically normalize the arrow lengths in the 3D quiver per this pull request.
Another solution is to call ax.quiever on each arrow, individually - with each call having an own length attribute. This is not very efficient but it will get you going.
And there's no need to change MPL-code
I have a code in python to render a few spheres in python that looks like this:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import random
import mayavi
from mayavi import mlab
N = 4;
diams = .4*np.ones([N]);
xvals = np.arange(N);
yvals = np.zeros(N);
zvals = np.zeros(N);
pts = mlab.points3d(xvals, yvals, zvals, diams, scale_factor=1,transparent=True)
mlab.show()
The default view of the figure adds distortion based on the camera position (farther spheres smaller). I'd like to set the to parallel projection (farther spheres same size) by some command so it renders like this automatically.
I didn't find a straightforward solution with google or the documentation. Thanks!
Try setting fig.scene.parallel_projection = True or mlab.gcf().scene.parallel_projection = True in your case.
As a quick example, compare (zoomed in to magnify differences):
import numpy as np
from mayavi import mlab
np.random.seed(1977)
x, y, z = np.random.random((3, 10))
mlab.points3d(x, y, z)
mlab.show()
And when we set an orthogonal projection:
import numpy as np
from mayavi import mlab
np.random.seed(1977)
x, y, z = np.random.random((3, 10))
mlab.points3d(x, y, z)
mlab.gcf().scene.parallel_projection = True
mlab.show()
In addition to the accepted answer, I discovered that when we use the figure.scene.parallel_projection = True mode, the parameters returned by mlab.view() are no longer sufficient to describe the camera view completely. There is another parameter that comes into play:
figure.scene.camera.parallel_scale
So, if one wishes to set the view to be the same every time, then they have to (1) set mlab.view(..) and also (2) set figure.scene.camera.parallel_scale = 5.0 for example.
(Background story: my script plots a surface, then I had set the camera using only mlab.view(..), and saw that the rendered images had inconsistent scaling. The reason is: as I plot, TVTK updates the camera's parameters, so they might be different if the plots are not identical. These parameters include parallel_scale, which affects the projection — it's basically a zoom — but is independent of mlab.view().)
I just wanted to get started on using the matplotlib library for the first time.
So I type the following commands:
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
data = sp.genfromtxt("web_traffic.tsv", delimiter = "\t");
x = data[:, 0];
y = data[:, 1];
x = x[~sp.isnan(y)];
y = y[~sp.isnan(y)];
plt.scatter(x, y);
And I have received the following error :
<matplotlib.collections.PathCollection object at 0x246abd0>
I have no idea what is causing this, I have just installed the required packages, scipy, matplotlib and it returned to me that particular error. I tried to google it but with no results.
I am using openSuse as OS and python came by default. My main purpose is to start learning using the scykit learn package.
Can you give me any advice on how to get over this error?
It's not an error message. It's a string representation of an object.
If you ran the code above in an interactive shell, then what you see is a string representation of the value returned by the plt.scatter function.
To actually open the window, you usually need to call plt.show() at the end.
Or if you want it to be interactive, it is suggested to set interactive: True in your .matplotlibrc.
On an unrelated note, semicolons are not needed at the end of the line in Python.
As shown in the matplotlib example for plt.scatter():
"""
Simple demo of a scatter plot.
"""
import numpy as np
import matplotlib.pyplot as plt
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radiuses
plt.scatter(x, y, s=area, alpha=0.5)
plt.show()
As the previous answer stated, you will have to call plt.show() to actually render the plot.
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()