Colors for loop-generated scatter plot - python-2.7

I have a 3D data cube which I scatter plot using a loop. I want the scatter points to be the cube index, and the color of the scatter points to be the value. Below is code that yields all one color. How do I make the colors based on the value?
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
%matplotlib
# I have a 3D array of numbers of unknown shape containing unknown
# integer values within an unknown range.
# Here, I made this toy 3D array with shape 9,10,11 containing random
# integer values 0-10.
xyz = np.random.rand(9,10,111)*100//10
# Determine the shape of the the array
x_size = np.shape(xyz)[0]
y_size = np.shape(xyz)[1]
z_size = np.shape(xyz)[2]
# Scatter plot the array
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
for xi in range(x_size):
for yi in range(y_size):
for zi in range(z_size):
ax.scatter(xi, yi, zi, c=xyz[xi, yi, zi])

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
# I have a 3D array of numbers of unknown shape containing unknown
# integer values within an unknown range.
# Here, I made this toy 3D array with shape 9,10,11 containing random
# integer values 0-10.
xyz = np.random.rand(9,10,111)*100//10
# Determine the shape of the the array
x_size = np.shape(xyz)[0]
y_size = np.shape(xyz)[1]
z_size = np.shape(xyz)[2]
# Scatter plot the array
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
xi, yi, zi = np.meshgrid(range(x_size), range(y_size), range(z_size))
ax.scatter(xi, yi, zi, c=xyz)
plt.show()

Related

Surface Plotting on Python 2.7 with pyplot

I am new to Python. I have been trying to plot a data file that contains 3 columns and 1024 data points. While running the code the following error arises:
Traceback (most recent call last):
File "plot-data.py", line 27, in <module>
linewidth=0, antialiased=False)
File "/home/ritajit/.local/lib/python2.7/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 1624, in plot_surface
X, Y, Z = np.broadcast_arrays(X, Y, Z)
File "/home/ritajit/.local/lib/python2.7/site-packages/numpy/lib/stride_tricks.py", line 249, in broadcast_arrays
shape = _broadcast_shape(*args)
File "/home/ritajit/.local/lib/python2.7/site-packages/numpy /lib/stride_tricks.py", line 184, in _broadcast_shape
b = np.broadcast(*args[:32])
ValueError: shape mismatch: objects cannot be broadcast to a single shape
My code looks like this
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.mlab import griddata
import matplotlib.cm as cm
from pylab import rcParams
rcParams['figure.figsize'] = 9, 9
## 3D surface_plot
fig = plt.figure()
axes = fig.add_subplot(111, projection='3d') #gca = get current axis
data = np.loadtxt('2D-data.txt')
x = data[:,0]
y = data[:,1]
z = data[:,2]
xi = np.unique(x)
yi = np.unique(y)
xv, yv = np.meshgrid(x,y)
Z = griddata(x, y, z, xi, yi, interp='linear')
# surface_plot with color grading and color bar
p = axes.plot_surface(xv,yv,Z, rstride=4, cstride=4, cmap=cm.RdBu,
linewidth=0, antialiased=False)
fig.colorbar(p, shrink=0.5)
axes.set_xlabel('$x$',fontsize=15)
axes.set_ylabel('$y$',fontsize=15)
axes.set_zlabel('$z$',fontsize=15)
plt.tight_layout()
fig.savefig("surface.pdf")
plt.show()
I am unable to work this through.
What wrong am I doing?
Is there any other way to plot 3d datafile?
A few lines from my data file:
1 2 1.30884
2 2 1.30925
3 2 1.30974
4 2 1.30841
5 2 1.30864
6 2 1.30795
The 1st,2nd,3rd columns are x,y,z respectively
Three main issues here:
You need to meshgrid the unique values, not the original ones
xi = np.unique(x)
yi = np.unique(y)
xv, yv = np.meshgrid(xi,yi)
You need to interpolate on the gridded values
griddata(x, y, z, xv, yv)
You need to plot Z, not z
p = axes.plot_surface(xv,yv,Z)
In total it looks like you could achieve pretty much the same by reshaping the data columns (but the small data excerpt is not enough to judge on this).
Last, matplotlib.mlab.griddata will be deprecated in the next version. As an alternative consider scipy.interpolate.griddata. Also have a look at the Contour plot of irregularly spaced data example.

Equal width plot sizes in pyplot, while keeping aspect ratio equal

I want to have two plots be the same width, however the resulting code shrinks the imshow plot.
xx = np.linspace(0.0,255.5,512)
yy = np.linspace(0.0,255.5,512)
Func = np.random.rand(len(xx),len(yy))
f, axarr = plt.subplots(2,1)
f.tight_layout()
im = axarr[0].imshow(Func, cmap = 'jet', interpolation = 'lanczos',origin = 'lower')
pos = axarr[0].get_position()
colorbarpos = [pos.x0+1.05*pos.width,pos.y0,0.02,pos.height]
cbar_ax = f.add_axes(colorbarpos)
cbar = f.colorbar(im,cax=cbar_ax)
axarr[1].plot(xx,Func[:,255],yy,Func[255,:])
plt.show()
plt.close('all')
EDIT: I would also like to keep imshow's plot from looking stretched (essentially, I need the width and length stretched appropriately so the aspect ratio's are still equal).
Some options:
A. `aspect="auto"
Use `aspect="auto" on the imshow plot
plt.imshow(..., aspect="auto")
B. adjust the figure margings
Adjust the figure margings or the figure size, such that the lower axes will have the same size as the imshow plot, e.g.
plt.subplots_adjust(left=0.35, right=0.65)
C. using a divider
You can use make_axes_locatable functionality from mpl_toolkits.axes_grid1 to divide the image axes to make space for the other axes.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
xx = np.linspace(0.0,255.5,512)
yy = np.linspace(0.0,255.5,512)
Func = np.random.rand(len(xx),len(yy))
fig, ax = plt.subplots(figsize=(4,5))
im = ax.imshow(Func, cmap = 'jet', interpolation = 'lanczos',origin = 'lower')
divider = make_axes_locatable(ax)
ax2 = divider.append_axes("bottom", size=0.8, pad=0.3)
cax = divider.append_axes("right", size=0.08, pad=0.1)
ax2.plot(xx,Func[:,255],yy,Func[255,:])
cbar = fig.colorbar(im,cax=cax)
plt.show()

Tight layout for matplotlib 3d surface plot

I am trying to create a 3d surface plot in matplotlib. the plot surface works fine using ax.plot_surface api. But I couldn't find a way to remove the padding surrounding the subplot. In fact, I don't need the outer axes that go from 0.0 to 1.0 at all. How can i remove the padding? I already tried many suggestions from stackoverflow like "ax.autoscale_view('tight')" and "fig.tight_layout()". autoscale_view don't change anything and fig.tight_layout() is not available in the matplotlib version i am using. For strict compatibility requirements i have to use a very old (Version 0.99) version of matplotlib. Any ideas ?
For completeness I have added a sample source code i am using:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize = (18,12))
rect = fig.add_subplot(2, 3, 2).get_position()
ax = Axes3D(fig, rect)
X = np.arange(-5, 5, 0.025)
Y = np.arange(-5, 5, 0.025)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet)
ax.view_init(azim=-90, elev=90)
ax.axis('off')
plt.show()

How to produce MATLAB plot (interpolation) in Matplotlib (Numpy)?

I am trying to follow a MATLAB example of meshgrid + interpolation. The example code is found HERE. On that site, I am going through the following example: Example – Displaying Nonuniform Data on a Surface.
Now, I would like to produce a similar plot in Python (Numpy + Matplotlib) to what is shown there in MATLAB. This is the plot that MATLAB produces:
I am having trouble with doing this in Python. Here is my code and my output in Python 2.7:
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = np.random.rand(200)*16 - 8
y = np.random.rand(200)*16 - 8
r = np.sqrt(x**2 + y**2)
z = np.sin(r)/r
xi = np.linspace(min(x),max(x), 100)
yi = np.linspace(min(y),max(y), 200)
X,Y = np.meshgrid(xi,yi)
Z = griddata(x, y, z, X, Y, interp='linear')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,cmap=cm.jet)
Here is the result of my attempt at doing this with matplotlib and NumPy..
Could someone please help me recreate the MATLAB plot in matplotlib, as either a mesh or a surface plot?
So it seems that the major differences in the look have to do with the default number of lines plotted by matlab, which can be adjusted by increasing rstride and cstride. In terms of color, in order for the colormap to be scaled properly it is probably best in this case to set your limits, vmin and vmax because when automatically set, it will use the min and max of Z, but in this case, they are both nan, so you could use np.nanmin and np.nanmax.
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = np.random.rand(200)*16 - 8
y = np.random.rand(200)*16 - 8
r = np.sqrt(x**2 + y**2)
z = np.sin(r)/r
xi = np.linspace(min(x),max(x), 100)
yi = np.linspace(min(y),max(y), 200)
X,Y = np.meshgrid(xi,yi)
Z = griddata(x, y, z, X, Y, interp='linear')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=5, cstride=5, cmap=cm.jet, vmin=np.nanmin(Z), vmax=np.nanmax(Z), shade=False)
scat = ax.scatter(x, y, z)
In matplotlib unfortunately I get some annoying overlapping/'clipping' problems, where Axes3d doesn't always properly determine the order in which object should be displayed.

Colouring the surface of a sphere with a set of scalar values in matplotlib

I am rather new to matplotlib (and this is also my first question here). I'm trying to represent the scalp surface potential as recorded by an EEG. So far I have a two-dimensional figure of a sphere projection, which I generated using contourf, and pretty much boils down to an ordinary heat map.
Is there any way this can be done on half a sphere?, i.e. generating a 3D sphere with surface colours given by a list of values? Something like this, http://embal.gforge.inria.fr/img/inverse.jpg, but I have more than enough with just half a sphere.
I have seen a few related questions (for example, Matplotlib 3d colour plot - is it possible?), but they either don't really address my question or remain unanswered to date.
I have also spent the morning looking through countless examples. In most of what I've found, the colour at one particular point of a surface is indicative of its Z value, but I don't want that... I want to draw the surface, then specify the colours with the data I have.
You can use plot_trisurf and assign a custom field to the underlying ScalarMappable through set_array method.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
(n, m) = (250, 250)
# Meshing a unit sphere according to n, m
theta = np.linspace(0, 2 * np.pi, num=n, endpoint=False)
phi = np.linspace(np.pi * (-0.5 + 1./(m+1)), np.pi*0.5, num=m, endpoint=False)
theta, phi = np.meshgrid(theta, phi)
theta, phi = theta.ravel(), phi.ravel()
theta = np.append(theta, [0.]) # Adding the north pole...
phi = np.append(phi, [np.pi*0.5])
mesh_x, mesh_y = ((np.pi*0.5 - phi)*np.cos(theta), (np.pi*0.5 - phi)*np.sin(theta))
triangles = mtri.Triangulation(mesh_x, mesh_y).triangles
x, y, z = np.cos(phi)*np.cos(theta), np.cos(phi)*np.sin(theta), np.sin(phi)
# Defining a custom color scalar field
vals = np.sin(6*phi) * np.sin(3*theta)
colors = np.mean(vals[triangles], axis=1)
# Plotting
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
cmap = plt.get_cmap('Blues')
triang = mtri.Triangulation(x, y, triangles)
collec = ax.plot_trisurf(triang, z, cmap=cmap, shade=False, linewidth=0.)
collec.set_array(colors)
collec.autoscale()
plt.show()