Python plotting 2d data on to 3d axes - python

I've had a look at matplotlib's examples of 3d plots, but none of these give me what I want to plot, something like:
The plot shows a series of measurements on the y-axis (N) and each measurement has an intensity spectrum (p/2hk_L), i.e. N is fixed for each line you see in the graph. What is the easiest function to use to plot data like this?

Here is a try:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.linspace(-50,50,100)
y = np.arange(25)
X,Y = np.meshgrid(x,y)
Z = np.zeros((len(y),len(x)))
for i in range(len(y)):
damp = (i/float(len(y)))**2
Z[i] = 5*damp*(1 - np.sqrt(np.abs(x/50)))
Z[i] += np.random.uniform(0,.1,len(Z[i]))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1000, color='w', shade=False, lw=.5)
ax.set_zlim(0, 5)
ax.set_xlim(-51, 51)
ax.set_zlabel("Intensity")
ax.view_init(20,-120)
plt.show()

Related

Plot 3d points (x,y,z) in 2d plot with colorbar

I have computed a lot (~5000) of 3d points (x,y,z) in a quite complicated way so I have no function such that z = f(x,y). I can plot the 3d surface using
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
surf = ax.plot_trisurf(X, Y, Z, cmap=cm.coolwarm, vmin=np.nanmin(Z), vmax=np.nanmax(Z))
I would like to plot this also in 2d, with a colorbar indicating the z-value. I know there is a simple solution using ax.contour if my z is a matrix, but here I only have a vector.
Attaching the plot_trisurf result when rotated to xy-plane. This is what I what like to achieve without having to rotate a 3d plot. In this, my variable surface_points is an np.array with size 5024 x 3.
I had the same problems in one of my codes, I solved it this way:
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pylab as plt
from matplotlib import cm
N = 10000
surface_points = np.random.rand(N,3)
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
nx = 10*int(np.sqrt(N))
xg = np.linspace(X.min(), X.max(), nx)
yg = np.linspace(Y.min(), Y.max(), nx)
xgrid, ygrid = np.meshgrid(xg, yg)
ctr_f = griddata((X, Y), Z, (xgrid, ygrid), method='linear')
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.contourf(xgrid, ygrid, ctr_f, cmap=cm.coolwarm)
plt.show()
You could use a scatter plot to display a projection of your z color onto the x-y axis.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
N = 10000
surface_points = np.random.rand(N,3)
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
# fig = plt.figure()
# ax = fig.add_subplot(projection='3d')
# surf = ax.plot_trisurf(X, Y, Z, cmap=cm.coolwarm, vmin=np.nanmin(Z), vmax=np.nanmax(Z))
fig = plt.figure()
cmap = cm.get_cmap('coolwarm')
color = cmap(Z)[..., :3]
plt.scatter(X,Y,c=color)
plt.show()
Since you seem to have a 3D shape that is hollow, you could split the projection into two like if you cur the shape in two pieces.
fig = plt.figure()
plt.subplot(121)
plt.scatter(X[Z<0.5],Y[Z<0.5],c=color[Z<0.5])
plt.title('down part')
plt.subplot(122)
plt.scatter(X[Z>=0.5],Y[Z>=0.5],c=color[Z>+0.5])
plt.title('top part')
plt.show()

matplotlib: Invert y axis on 3d bar graph

I created 3d bar graph with matplotlib with the following code:
fig = plt.figure()
cmap = get_cmap(len(os.listdir(conv1d_kernel_path)))
ax = fig.add_subplot(111, projection='3d')
for f in os.listdir(conv1d_kernel_path):
step = int(re.findall(r'\d+', f)[0])
conv1d_kernel_histo[f]['bins'] = convert_bins(30, min_weight, max_weight, conv1d_kernel_histo[f])
bin_counts = conv1d_kernel_histo[f]['bins'][:, 2]
width = (max_weight-min_weight)/30 #ToDo change 30 to numbins
xs = conv1d_kernel_histo[f]['bins'][:, 0] + width / 2
ax.bar(xs, list(bin_counts), width=width, zs=step, zdir='y', color=cmap(step), ec=cmap(step+20), alpha=0.8)
ax.set_xlabel('weights')
ax.set_ylabel('step')
ax.set_zlabel('count')
plt.show()
The directory and convert bins function isn't so important, just that it gives me the info I can use to define the input data that I iteratively pass to the ax.bar function. Anyways, I receive the following output:
I want to invert the axis titled 'steps', and this question seems to be nearly what I need; however, when I used ax.invert_yaxis() the axis titled 'weights' is inverted. When I alternatively use ax.invert_xaxis() the same axis is inverted. Out of curiosity, I tried ax.invert_zaxis() but that worked as one would think, and flipped the whole graph upside down. Does anybody have a solution to this problem? A different method for inverting the axis? Thanks, all help is appreciated
Well inverting the axis limits like ax.set_ylim(150,0) should work fine. Sample plot:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Invert Y-Axis
ax.set_ylim(4,-4)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Original:
Inverted Y-Axis:

Plotting some third variable against x and y in matplotlib scatter?

I'm fairly new to scatter plots and python in general. I am trying to plot a third variable against an x and a y, however, I'm not quite sure how to about specifying that argument? So I would have X values which are ints, y values which are also ints and then on the graph itself I want the model scores to show. Is there any way to do this sort of thing?
Thank you.
You can use color to plot a third value. Here is a very minimal example :
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
x = np.random.rand(100)
y = np.random.rand(100)
z = np.random.rand(100)
plt.scatter(x,y, c=z, s=5, cmap=cm.hsv)
cbar= plt.colorbar()
plt.show()
Edit
You could also use the size of markers, their transparency, hue or rgb values to depict even more information. Here is an example with marker size, alpha level and color on a perceptually uniform colormap.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as colors
import matplotlib.cm as cmx
x = np.random.rand(100)
y = np.random.rand(100)
z = np.random.rand(100)
t = np.random.rand(100)
w = np.random.rand(100)
fig, ax = plt.subplots(1, 1)
cmap = plt.get_cmap('plasma')
cNorm = colors.Normalize(vmin=0, vmax=max(z))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cmap)
for i in range(100):
ax.scatter(x[i],y[i], c=scalarMap.to_rgba(z[i]), s=t[i]*100, cmap=cmx.plasma, alpha=w[i], edgecolor='none')
scalarMap.set_array([])
fig.colorbar(scalarMap,ax=ax)
for a in [0.1, 0.5, 0.9]:
ax.scatter([], [], c='k', alpha=0.5, s=a*100, label=str(a), edgecolors='none')
l1 = ax.legend(scatterpoints=1, frameon=True, loc='lower left' ,markerscale=1)
for b in [0.25, 0.5, 0.75]:
ax.scatter([], [], c='k', alpha=b, s=50, label=str(b), edgecolors='none')
ax.legend(scatterpoints=1, frameon=True, loc='lower right' ,markerscale=1)
fig.show()
At face value, that question doesn't really make sense because a conventional scatterplot has only two axes, and of course you can't plot points with three dimensions (x, y and accuracy).
However, there are alternative ways to do so.
Use colours
import numpy as np
from matplotlib import pyplot as plt
x = np.random.rand(200)
y = np.random.rand(200)
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(x, y, c=(x + y), cmap='RdPu')
scatter takes a c argument, which can be a numeric value, as well as a cmap argument, which can be a string referencing a colormap.
The colormap object translates the numbers provided in c into points along a colour mapping, which you can think of as a gradient bar.
Use 3D axes
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(5, 5))
ax = Axes3D(fig)
ax.scatter(x, y, (x + y))
This turns your 3rd dimension, accuracy, into an ordinary spatial dimension.
Use size of the markers
Very similar to the color option in the first part, you can change the size of the scatter markers (given you have some idea about the scale of the values). So based on the first example, you can also do;
import numpy as np
from matplotlib import pyplot as plt
x = np.random.rand(200)
y = np.random.rand(200)
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(x, y, c='k', s=5*(x + y), cmap='RdPu')
scatter takes also the s argument, that changes the size of the markers.

Plot NumPy ndarray into a 3D surface

I have a numpy.ndarray of size 200x200. I want to plot it as a 3D surface where x and y are indexes of the array and z is the value of that array element. Is there any easy way to do it or do I have to transform my array into a long list?
For example using matplotlib:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
#your index
x = np.linspace(1, 200, 200);
y = np.linspace(1, 200, 200)
X, Y = np.meshgrid(x, y); #making a grid from it
fig = plt.figure()
ax = fig.gca(projection='3d')
R = np.sqrt(X**2 + Y**2) #make some calculations on the grid
Z = np.sin(R) #some more calculations
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
ax.set_zlim(-5, 5)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
However, as your array is already quite large, you might want to consider a different plotting tool like mayavi. matplotlib usually puts a copy of your complete array into the plot. That's memory demanding when dealing with big data. But I'm not sure, whether mayavi does the same or not.
You can also use mayavi and plot your array as a plane with different colors representing the values. It would look like this:
import numpy
from mayavi import mlab
mlab.imshow(yourarray)
mlab.show()
Alternative you can create points with an elevation from the ground plane and get a fitting plane through the points. See here:http://docs.enthought.com/mayavi/mayavi/auto/example_surface_from_irregular_data.html#example-surface-from-irregular-data
What is best for you depends on the continuity of your data.
If what you want is to plot a 3D surface on top of a 2D grid what you could do is something similar to this:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
# create some fake data
array_distribution3d = np.ones((200, 200))
array_distribution3d[0:25, 0:25] = -1
# create the meshgrid to plot on
x = np.arange(0, array_distribution3d.shape[0])
y = np.arange(0, array_distribution3d.shape[1])
# here are the x,y and respective z values
X, Y = np.meshgrid(x, y)
z = []
for i in range(0, array_distribution3d.shape[0]):
z_y = []
for j in range(0, array_distribution3d.shape[1]):
z_y.append(array_distribution3d[i, j])
z.append(z_y)
Z = np.array(z)
# create the figure, add a 3d axis, set the viewing angle
fig = plt.figure(figsize=(12, 9))
ax = fig.add_subplot(111, projection='3d')
ax.view_init(45, 60)
# here we create the surface plot
ax.plot_surface(X, Y, Z)
However, to the best of my knowledge, this kind of data can be plotted as a colourmap.
This can be plotted as follows:
import numpy as np
import os.path
import matplotlib.pyplot as plt
array_distribution = np.ones((200, 200))
array_distribution[0:25, 0:25] = -1
fig = plt.imshow(array_distribution)
plt.colorbar(fraction=0.035, pad=0.035, ticks=[-1., 0., 1.])
axes = plt.gca()
axes.set_ylim([0, 200])
figure = plt.gcf()
file = os.path.join('demo1.png')
figure.savefig(file, dpi=250)
plt.close('all')
print('done')

Matplotlib 3D scatter plot with color gradient

How can I create a 3D plot with a color gradient for the points? See the example below, which works for a 2D scatter plot.
Edit (thanks to Chris): What I'm expecting to see from the 3D plot is a color gradient of the points ranging from red to green as in the 2D scatter plot.
What I see in the 3D scatter plot are only red points.
Solution: for some reasons (related to the gradient example I copied elsewhere) I set xrange to len-1, which messes everything in the 3D plot.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Create Map
cm = plt.get_cmap("RdYlGn")
x = np.random.rand(30)
y = np.random.rand(30)
z = np.random.rand(30)
#col = [cm(float(i)/(29)) for i in xrange(29)] # BAD!!!
col = [cm(float(i)/(30)) for i in xrange(30)]
# 2D Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(x, y, s=10, c=col, marker='o')
# 3D Plot
fig = plt.figure()
ax3D = fig.add_subplot(111, projection='3d')
ax3D.scatter(x, y, z, s=10, c=col, marker='o')
plt.show()
Here is an example for 3d scatter with gradient colors:
import matplotlib.cm as cmx
from mpl_toolkits.mplot3d import Axes3D
def scatter3d(x,y,z, cs, colorsMap='jet'):
cm = plt.get_cmap(colorsMap)
cNorm = matplotlib.colors.Normalize(vmin=min(cs), vmax=max(cs))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(x, y, z, c=scalarMap.to_rgba(cs))
scalarMap.set_array(cs)
fig.colorbar(scalarMap)
plt.show()
Of course, you can choose the scale to range between different values, like 0 and 1.
Following works: I can't figure out why yours doesn't. You should be able to set color as a sequence of RGBA floats, or just sequence of floats.
# Create Map
cm = plt.get_cmap("RdYlGn")
x = np.random.rand(30)
y = np.random.rand(30)
z = np.random.rand(30)
col = np.arange(30)
# 2D Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(x, y, s=10, c=col, marker='o')
# 3D Plot
fig = plt.figure()
ax3D = fig.add_subplot(111, projection='3d')
p3d = ax3D.scatter(x, y, z, s=30, c=col, marker='o')
plt.show()
However, in help of scatter, I see the following, it may be related.
A :class:`matplotlib.colors.Colormap` instance or registered
name. If *None*, defaults to rc ``image.cmap``. *cmap* is
only used if *c* is an array of floats.

Categories