Converting a 2D figure into a cylinder in Python - python

At the moment I have a figure that looks like this,
Generated by the code:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.rand(20,5)
rows,cols = data.shape
plt.imshow(data, interpolation='nearest', extent=[0.5, 0.5+cols, 0.5, 0.5+cols], cmap='bwr')
plt.show()
However I would like to 'fold' this up into a 3D cylinder, joining the left and right edges (as one would do with a sheet of paper). In other words the left edge and the right edges are actually the same edge and so I would like to join them together to form a cylinder.
How would I go about doing this?

The Poly3DCollection is the method of choice for arbitrary 3D polygons in mplot3d.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
nphi,nz=12,20
r=1 # radius of cylinder
phi = np.linspace(0,360, nphi)/180.0*np.pi
z= np.linspace(0,1.0,nz)
print z
facecolors=['r','g','b','y']
cols=[]
verts2 = []
for i in range(len(phi)-1):
cp0= r*np.cos(phi[i])
cp1= r*np.cos(phi[i+1])
sp0= r*np.sin(phi[i])
sp1= r*np.sin(phi[i+1])
for j in range(len(z)-1):
z0=z[j]
z1=z[j+1]
verts=[]
verts.append((cp0, sp0, z0))
verts.append((cp1, sp1, z0))
verts.append((cp1, sp1, z1))
verts.append((cp0, sp0, z1))
verts2.append(verts)
value=np.random.rand()
print value
col=plt.cm.bwr(value)
print col
cols.append(col)
poly3= Poly3DCollection(verts2, facecolor=cols )
poly3.set_alpha(0.8)
ax.add_collection3d(poly3)
ax.set_xlabel('X')
ax.set_xlim3d(-1, 1)
ax.set_ylabel('Y')
ax.set_ylim3d(-1, 1)
ax.set_zlabel('Z')
ax.set_zlim3d(0, 1)
plt.show()

You could use plot_surface:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as axes3d
np.random.seed(2016)
data = np.random.rand(12, 20)
h, w = data.shape
theta, z = np.linspace(0, 2 * np.pi, w), np.linspace(0, 1, h)
THETA, Z = np.meshgrid(theta, z)
X = np.cos(THETA)
Y = np.sin(THETA)
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
cmap = plt.get_cmap('bwr')
plot = ax.plot_surface(
X, Y, Z, rstride=1, cstride=1, facecolors=cmap(data),
linewidth=0, antialiased=False, alpha=0.75)
plt.show()
yields

Related

Paraboiloid from an array elements python

Please help with the problem of paraboloid 3d plotting using from the elements in an array.
Below code gives a nice parabolid:
from matplotlib import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
a=2
t = np.arange(0, 1, 0.01)
th = np.arange(0, 2*pi, 0.01)
t,th = np.meshgrid(r, T)
#Parametrise it
X = r*cos(T)
Y = r*sin(T)
Z = a*r**2
ax.plot_surface(X, Y, Z, alpha=0.9, rstride=10, cstride=10, linewidth=0.5, cmap=cm.summer)
plt.show()
But I want something like this:
th,t,a = symbols('th t a')
rotz=np.matrix([[cos(th),-sin(th),0,0],
[sin(th),cos(th),0,0],
[0,0,1,0],
[0,0,0,1]])
g=np.matrix([t,0,a*(t**2),1])
g=np.transpose(g)
M = rotz*g
print(M)
Now M is a 4x1 matrix with the 1st three elements to parametrize the paraboloid code
[[t*cos(th)]
[t*sin(th)]
[a*t**2]
[1]]
Now I want to use the x=M[0,:],y=M[1,:],z=M[2,:] and replace it in the parabolid code and plot the paraboloid.
I want this way so that I could do some transformation to the matrix as needed.

How to make my surface plot appear using Axes3D?

I'm trying to create a surface plot using Python Matplotlib. I've read the documentation in an attempt to figure out where my code was wrong or if I've left anything out, but was having trouble.
The code that I've written is
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def computeCost(X, y, theta):
m = len(y)
predictions = np.dot(X, theta)
squareErros = (predictions - y) ** 2
J = (1 / (2 * m)) * sum(squareErrors)
return J
data = np.loadtxt("./data1.txt", delimiter=',')
X = data[:, 0].reshape(-1, 1)
y = data[:, 1].reshape(-1, 1)
m = len(y)
X = np.concatenate((np.ones((m, 1)), X), axis=1)
theta0_vals = np.linspace(-10, 10, 100) # size (100,)
theta1_vals = np.linspace(-1, 4, 100) # size (100,)
J_vals = np.zeros((len(theta0_vals), len(theta1_vals)))
for i in range(len(x_values)):
for j in range(len(y_values)):
t = np.array([theta0_vals[i], theta1_vals[j]]).reshape(-1, 1)
J_vals[i][j] = computeCost(X, y, t) # size (100, 100)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(theta0_vals, theta1_vals, J_vals)
plt.show()
When I invoke plt.show() I get no output. The surface plot that I'm expecting to see is similar to this:
Would anybody be kind enough to let me know where my usage of the surface plot library went wrong? Thank you.
EDIT
I've tried to run the demo code provided here and it works fine. Here's the code for that:
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)
# 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()
I think I've figured out the issue by changing a couple of the last lines of code from
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(theta0_vals, theta1_vals, J_vals)
to
ax = plt.axes(projection='3d')
surf = ax.plot_surface(theta0_vals, theta1_vals, J_vals, rstride=1, cstride=1, cmap='viridis', edgecolor='none')
Making this change gives me a surface plot such that:
The link that gave me reference to this was this.

Spherical coordinates plot in matplotlib

R(teta, phi) = cos(phi^2), teta[0, 2*pi], phi[0,pi]
How to draw a graph of this function (R(teta, phi)) in spherical coordinates with the help of matplotlib?
The documentation I have not found Spherical coordinates.
The code below is very much like the 3D polar plot from the Matplotlib gallery. The only difference is that you use np.meshgrid to make 2D arrays for PHI and THETA instead of R and THETA (or what the 3D polar plot example calls P).
The moral of the story is that as long as X, Y, and Z can be expressed as (smooth) functions of two parameters, plot_surface can plot it.
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as axes3d
theta, phi = np.linspace(0, 2 * np.pi, 40), np.linspace(0, np.pi, 40)
THETA, PHI = np.meshgrid(theta, phi)
R = np.cos(PHI**2)
X = R * np.sin(PHI) * np.cos(THETA)
Y = R * np.sin(PHI) * np.sin(THETA)
Z = R * np.cos(PHI)
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
plot = ax.plot_surface(
X, Y, Z, rstride=1, cstride=1, cmap=plt.get_cmap('jet'),
linewidth=0, antialiased=False, alpha=0.5)
plt.show()
yields
Typically R, the radius, should be positive, so you might want
R = np.abs(np.cos(PHI**2))
In that case,
import matplotlib.colors as mcolors
cmap = plt.get_cmap('jet')
norm = mcolors.Normalize(vmin=Z.min(), vmax=Z.max())
plot = ax.plot_surface(
X, Y, Z, rstride=1, cstride=1,
facecolors=cmap(norm(Z)),
linewidth=0, antialiased=False, alpha=0.5)
yields
Who knew R = np.abs(np.cos(PHI**2)) is a little girl in a dress? :)
If you want a lot of control you can use Poly3Dcollection directly and roll your own (allows you to have portions of the surface, that you don't plot.
Note that I changed the variables to the more common definition of phi in the azimuth and theta for the z-direction.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
from __future__ import division
fig = plt.figure()
ax = fig.gca(projection='3d')
nphi,nth=48,12
phi = np.linspace(0,360, nphi)/180.0*np.pi
th = np.linspace(-90,90, nth)/180.0*np.pi
verts2 = []
for i in range(len(phi)-1):
for j in range(len(th)-1):
r= np.cos(phi[i])**2 # <----- your function is here
r1= np.cos(phi[i+1])**2
cp0= r*np.cos(phi[i])
cp1= r1*np.cos(phi[i+1])
sp0= r*np.sin(phi[i])
sp1= r1*np.sin(phi[i+1])
ct0= np.cos(th[j])
ct1= np.cos(th[j+1])
st0= np.sin(th[j])
st1= np.sin(th[j+1])
verts=[]
verts.append((cp0*ct0, sp0*ct0, st0))
verts.append((cp1*ct0, sp1*ct0, st0))
verts.append((cp1*ct1, sp1*ct1, st1))
verts.append((cp0*ct1, sp0*ct1, st1))
verts2.append(verts )
poly3= Poly3DCollection(verts2, facecolor='g')
poly3.set_alpha(0.2)
ax.add_collection3d(poly3)
ax.set_xlabel('X')
ax.set_xlim3d(-1, 1)
ax.set_ylabel('Y')
ax.set_ylim3d(-1, 1)
ax.set_zlabel('Z')
ax.set_zlim3d(-1, 1)
plt.show()

matplotlib correct colors/colorbar for plot with multiple surfaces each of a different color

Is it possible to plot multiple surfaces in one pyplot figure? Here is my attempt. The ax.plot_surface command seems to reset the figure, as I only get a single plane in the resulting plot. I am hoping to produce "stacked" planes, each with distinctive colors, and a color bar showing the numeric value of each color. Currently my colors show up wrong.
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import pylab
from scipy.interpolate import griddata
dat = open('ex.csv', 'w')
dat.write('x,y,z,c\n')
for x in range(20):
for y in range(20):
for c in range(0,7):
dat.write(','.join([str(s) for s in [x,y,x+y+c,c/10.0,'\n']]))
dat.close()
fig = matplotlib.pyplot.gcf()
dat = np.genfromtxt('ex.csv', delimiter=',',skip_header=1)
X_dat = dat[:,0]
Y_dat = dat[:,1]
Z_dat = dat[:,2]
C_dat = dat[:,3]
ax1 = fig.add_subplot(111, projection='3d')
for color in np.unique(C_dat):
X, Y, Z, C = np.array([]), np.array([]), np.array([]), np.array([])
for i in range(len(X_dat)):
if C_dat[i]==color:
X = np.append(X,X_dat[i])
Y = np.append(Y,Y_dat[i])
Z = np.append(Z,Z_dat[i])
C = np.append(C,C_dat[i])
xi = np.linspace(X.min(),X.max(),100)
yi = np.linspace(Y.min(),Y.max(),100)
zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic')
ci = griddata((X, Y), C, (xi[None,:], yi[:,None]), method='cubic')
xig, yig = np.meshgrid(xi, yi)
surf = ax1.plot_surface(xig, yig, zi,facecolors=cm.rainbow(ci), alpha = 0.7)
xi = np.linspace(X_dat.min(),X_dat.max(),100)
yi = np.linspace(Y_dat.min(),Y_dat.max(),100)
ci = griddata((X_dat, Y_dat), C_dat, (xi[None,:], yi[:,None]), method='cubic')
m = cm.ScalarMappable(cmap=cm.rainbow)
m.set_array(ci)
col = plt.colorbar(m)
plt.show()
(there should be a red plane)
Move the line
ax1 = fig.add_subplot(111, projection='3d')
outside of the for color in... loop. By recreating the axes each iteration, you hide the previously created surfaces
EDIT (to answer second question about colormaps)
You need to normalise your data. Currently, you have facecolors in the range 0 to 0.6, so when you feed the maximum (0.6) to cm.rainbow, you get green, not red (since it expects a range of 0 to 1).
Here's a modified script, which I think works as it should. We use Normalise from matplotlib.colors with a vmin and vmax determined from your C_dat data. Then, use facecolors=cm.rainbow(norm(ci)) to set the colors of your surfaces.
You also then want to set the array of your ScalarMappable using the values in C_dat, so we don't need to use griddata again here.
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib.colors as colors
from mpl_toolkits.mplot3d import Axes3D
import pylab
from scipy.interpolate import griddata
dat = open('ex.csv', 'w')
dat.write('x,y,z,c\n')
for x in range(20):
for y in range(20):
for c in range(0,7):
dat.write(','.join([str(s) for s in [x,y,x+y+c,c/10.0,'\n']]))
dat.close()
fig = matplotlib.pyplot.gcf()
dat = np.genfromtxt('ex.csv', delimiter=',',skip_header=1)
X_dat = dat[:,0]
Y_dat = dat[:,1]
Z_dat = dat[:,2]
C_dat = dat[:,3]
# Create a Normalize instance.
norm = colors.Normalize(vmin=C_dat.min(),vmax=C_dat.max())
ax1 = fig.add_subplot(111, projection='3d')
for color in np.unique(C_dat):
X, Y, Z, C = np.array([]), np.array([]), np.array([]), np.array([])
for i in range(len(X_dat)):
if C_dat[i]==color:
X = np.append(X,X_dat[i])
Y = np.append(Y,Y_dat[i])
Z = np.append(Z,Z_dat[i])
C = np.append(C,C_dat[i])
xi = np.linspace(X.min(),X.max(),100)
yi = np.linspace(Y.min(),Y.max(),100)
zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic')
ci = griddata((X, Y), C, (xi[None,:], yi[:,None]), method='cubic')
xig, yig = np.meshgrid(xi, yi)
# Note the use of norm in the facecolors option
surf = ax1.plot_surface(xig, yig, zi,facecolors=cm.rainbow(norm(ci)), alpha = 0.7)
m = cm.ScalarMappable(cmap=cm.rainbow)
m.set_array(np.unique(C_dat))
col = plt.colorbar(m)
plt.show()

Fixing jagged edges of 3D plot, selecting an appropriate mask

So I have some 3D data that I am able to plot just fine except the edges look jagged.
The relevant code:
import numpy as np
from matplotlib import cm
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
x = np.arange(-1, 1, 0.01)
y = np.arange(-1, 1, 0.01)
x, y = np.meshgrid(x, y)
rho = np.sqrt(x**2 + y**2)
# Attempts at masking shown here
# My Mask
row=0
while row<np.shape(x)[0]:
col=0
while col<np.shape(x)[1]:
if rho[row][col] > 1:
rho[row][col] = None
col=col+1
row=row+1
# Calculate & Plot
z = rho**2
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(x, y, z, rstride=8, cstride=8, cmap=cm.bone, alpha=0.15, linewidth=0.25)
plt.show()
Produces:
This is so close to what I want except the edges are jagged.
If I disable my mask in the code above & replace it with rho = np.ma.masked_where(rho > 1, rho) it gives:
It isn't jagged but not want I want in the corners.
Any suggestions on different masking or plotting methods to get rid of this jaggedness?
Did you consider using polar coordinates (like in this example) ?
Something like:
import numpy as np
from matplotlib import cm
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# create supporting points in polar coordinates
r = np.linspace(0,1.25,50)
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)
rho = np.sqrt(x**2 + y**2)
# Calculate & Plot
z = rho**2
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.bone, alpha=0.15, linewidth=0.25)
plt.show()

Categories