3d plotting of data analysis from a file - python

I need to compute 2 functions, mutualinfo2d and mutualinfo3d on data from files and get a 3d plots of these analysis.
I have to run over all the files that are indexed with 3 numbers:
The first and the third are parameters, these values change among the file names into two arrays, mu krat known and given.
The second number say the kind of file (is an input of my code)
So for each file I got back a number that has to be the value that I have to 3d plot referred to the parameters mu krat that characterized the file name.
So looping over the parameter I compute these functions put in a list and at the end I want a 3d plot where x, y are mu krat and z the values computed using my functions mutualinfo2d and mutualinfo3d.
I wrote a simple script that run on these files and analyze them correctly, I am able to make the 2d plot of my functions fixing one of the two parameter but I am not able to vary together and get back the 3d plot.
This is the code that I wrote to get 3d plot:
n= 0 # selected the folder to analyze
path="/storage1/monti/Desktop/info_topology/VaryingK_mu_GRN"
path= path + "%d/"%(n)
krat=[1,3,5,7,9,10,30,50,70,90,100,300,500,700,900,1000,3000,5000,7000,9000]
mu=[1,3,5,7,9,10,30,50,70,90,100,300,500,700,900]
mu = array(mu)
krat=array(krat)
inf0=[]
inf1=[]
inf2=[]
for j in mu:
for k in krat:
filename="InfoDati_"+"%lf_"%(j)+"%d_"%(n) +"%lf.txt"%(k) # InfoDati_mu_GRN_krat
fil = path + filename
data=loadtxt(fil)
t=data[:,0]
x=data[:,1]
y=data[:,2] # y, z should be the simulation, x the sin
z=data[:,3]
x=array(x)
y=array(y)
z=array(z)
t=tran(t,T=24,dx=0.05)
dx1=[0.05, 1]
dx2=[0.05,1,1]
inf0.append(mutualinfo2d(t,x, dx=dx1[0],dy=dx1[1]))
inf1.append(mutualinfo2d(t,y, dx=dx1[0],dy=dx2[1]))
inf2.append(mutualinfo3d(t,y,z, dx2))
fig = plt.figure()
ax = fig.gca(projection='3d')
Y = krat
X = mu
X, Y = meshgrid(X, Y)
Gx, Gy = gradient(inf0) # gradients with respect to x and y
G = (Gx**2+Gy**2)**.5 # gradient magnitude
N = G/G.max()
Gx1, Gy1 = gradient(inf1) # gradients with respect to x and y
G1 = (Gx1**2+Gy1**2)**.5 # gradient magnitude
N1 = G1/G1.max()
Gx2, Gy2 = gradient(inf2) # gradients with respect to x and y
G2 = (Gx2**2+Gy2**2)**.5 # gradient magnitude
N2 = G2/G2.max()
surf = ax.plot_surface(X, Y, inf0, rstride=1, cstride=1,facecolors=cm.jet(N),linewidth=0, antialiased=False, shade=False)
surf1 = ax.plot_surface(X, Y, inf1, rstride=1, cstride=1,facecolors=cm.jet(N1),linewidth=0, antialiased=False, shade=False)
surf2 = ax.plot_surface(X, Y, inf2, rstride=1, cstride=1,facecolors=cm.jet(N2),linewidth=0, antialiased=False, shade=False)
m = cm.ScalarMappable(cmap=cm.jet)
m.set_array(G)
m1 = cm.ScalarMappable(cmap=cm.jet)
m1.set_array(G1)
m2 = cm.ScalarMappable(cmap=cm.jet)
m2.set_array(G2)
plt.colorbar(m)
plt.colorbar(m1)
plt.colorbar(m2)
plt.show()
I got back different 3d plot empty... and I would like to have just one 3d plot but with the three different surfaces!

The problem in the code is probably before the plot_surface commands.
An example:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# create some surfaces
X, Y = np.meshgrid(np.arange(10, dtype='float'), np.arange(8, dtype='float'))
z1 = X+Y
z2 = X-Y
z3 = np.sin(Y / 8. * 2* np.pi)
N1 = z1 / z1.max()
N2 = z2 / z2.max()
N3 = z3 / z3.max()
# create the figure
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, z1, cstride=1, rstride=1, facecolors=plt.cm.jet(N1), linewidth=0, shade=False)
ax.plot_surface(X, Y, z2, cstride=1, rstride=1, facecolors=plt.cm.jet(N2), linewidth=0, shade=False)
ax.plot_surface(X, Y, z3, cstride=1, rstride=1, facecolors=plt.cm.jet(N3), linewidth=0, shade=False)
This gives what it should:
Check that your inf0 and N (etc) are valid. If you have even a single nan in your gradient, the normalization (calculation of N) will give an array full of nans, and then nothing is drawn.

Related

How to plot multiple three-dimensional surface plots with matplotlib in the same plane

My goal is to plot the probability distribution functions (pdfs) of two classes. Each class has Gaussian likelihood and equivalent covariance matrices, but different mean vectors. I want both pdfs on the same plane in the z-axis, with the x and y axes containing the projections of the pdfs.
The following code (mostly borrowed from here) plots one of the pdfs:
# Our 2-dimensional distribution will be over variables X and Y
N = 100
X = np.linspace(-10, 15, N)
Y = np.linspace(-10, 15, N)
X, Y = np.meshgrid(X, Y)
# Mean vector and covariance matrix
mu1 = np.array([8, 2])
mu2 = np.array([2,8])
Sigma1 = Sigma2 = np.array([[4.1,0],[0,2.8]])
# Pack X and Y into a single 3-dimensional array
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y
F1 = multivariate_normal(mu1, Sigma1)
F2 = multivariate_normal(mu2, Sigma2)
Z1 = F1.pdf(pos)
Z2 = F2.pdf(pos)
# Create a surface plot and projected filled contour plot under it.
fig1 = plt.figure(figsize=[10,10])
ax1 = fig1.gca(projection='3d')
ax1.plot_surface(X, Y, Z1, rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno)
cset = ax1.contourf(X, Y, Z1, zdir='z', offset=-0.15, cmap=cm.inferno)
# Adjust the limits, ticks and view angle
ax1.set_zlim(-0.15,0.2)
ax1.set_zticks(np.linspace(0,0.2,5))
ax1.view_init(27, -21)
plt.show()
This is the plot that results from the above code: plot_surfaces for plotting bivariate pdf. However, I need to plot both Z1 and Z2 on the same plane. If I try creating two plots, they overlap and the Z2 pdf cannot be seen. Tweaking the code slightly, I get roughly what I want:
ax1 = fig1.gca(projection='3d')
ax2 = fig1.gca(projection='3d')
ax1.plot_wireframe(X, Y, Z1, rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno)
ax2.plot_wireframe(X,Y,Z2,rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno)
the resulting plot of which can be found here: wireframe method to plot 2 bivariate pdfs. But these plots are still overlapping. How can I get around this issue? I want the result to be styled as the first plot, with the surface_plot method and projections on the x-y plane.
You can play with alpha:
ax1.plot_surface(X, Y, Z1, rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno, alpha = 0.5)
ax1.plot_surface(X, Y, Z2, rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno, alpha = 1)
cset = ax1.contourf(X, Y, Z1, zdir='z', offset=-0.15, cmap=cm.inferno, alpha=1)
cset = ax1.contourf(X, Y, Z2, zdir='z', offset=-0.15, cmap=cm.inferno, alpha=0.5)
But in some cases you can get the same results by just summing your pdf's
ax1.plot_surface(X, Y, Z1 + Z2, rstride=3, cstride=3, linewidth=1, antialiased=True,cmap=cm.inferno)
cset = ax1.contourf(X, Y, Z1 + Z2, zdir='z', offset=-0.15, cmap=cm.inferno)

Plot a 3D cone with vertex, height and angle information, along a given vector, matplotlib

How do I plot a cone in 3 dimensions when I know the coordinates of the vertex, the vector along which the cone lies (as a line segment whose end point coordinates are known), and the height of the cone, in matplotlib or any other python plotting module?
I guess what would be most helpful, would be some instruction on plotting implicit functions in matplotlib.
What I have tried, is to create a grid of points (x,y, and z), define an equation of the cone, and check whether each of those grid points satisfies the equation of the cone (since grid resolution may mean that it won't exactly satisfy the equation, I check whether it satisfies the equation upto some accuracy). However, I am not sure now how to plot this implicit data set in matplotlib. I have tried writing out the equation (which involves quadratic and linear terms in x,y and z) as a quadratic in z, solving for z and performing a surface plot with z in terms of x and y, but that gave me a plane instead of a cone.
Here is the code I used:
x = np.linspace(0,100,100)
y = np.linspace(0,100,100)
z = (-4823.7 + np.sqrt(abs((4823.7**2) - (4*(-240.185)*((-5692*y) - (240.185*np.multiply(x,x)) - (240.185*np.multiply(y,y)) - 57607.26 )) ))/np.float(2*(-240.185)))
#print z
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.arange(-50.0, 50, 1)
y = np.arange(-50.0, 50, 1)
X, Y = np.meshgrid(x, y)
ax.plot_surface(X, Y, z)
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()
try with it:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.arange(-50.0, 50, 1)
y = np.arange(-50.0, 50, 1)
X, Y = np.meshgrid(x, y)
Z = (-4823.7 + np.sqrt(abs((4823.7 ** 2) - (4 * (-240.185) * ((-5692 * Y) - (240.185 * np.multiply(X, X))
- (240.185 * np.multiply(Y, Y)) - 57607.26)))) / np.float(
2 * (-240.185)))
ax.plot_surface(X, Y, Z)
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()

Draw seamless distribution of tweets

I've collected tweets from twitter now I'm trying to draw the distribution of tweets geographically. To do that, I divide the entire square area into small square and count number of tweets in each square. Finally, I use matplotlib to draw the following figure:
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.3, cmap='Accent')
The problem is that the elevation map is not smooth. I'd like a way to draw smooth curve from the data. One example for that in 2D is when we have a histogram of image, we can draw smooth curve over the distribution as follows:
So my question is that is there a way to draw a smooth surface from the discrete data?
Expanding on my answer, here's what you can get with resampling and smoothing (gaussian_filter())/spline interpolation (RectBivariateSpline). Note that it would be nice of you to provide a template code that plots your graph, but since you haven't, I had to improvise.
import numpy
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def plot(name, method):
numpy.random.seed(123)
x = numpy.linspace(0, 50, 51)
X, Y = numpy.meshgrid(x, x)
Z = numpy.zeros((x.size, x.size))
for n in range(50):
i = numpy.random.randint(0, x.size)
j = numpy.random.randint(0, x.size)
Z[i, j] = numpy.abs(numpy.random.normal()) * 1000
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
if method == 0:
# regular plot
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.3, cmap='Accent')
else:
# create a finer grid
resample_coeff = 2
Z2 = numpy.repeat(Z, resample_coeff, 0).repeat(resample_coeff, 1)
x2 = numpy.linspace(x[0], x[-1], x.size * resample_coeff)
X2, Y2 = numpy.meshgrid(x2, x2)
if method == 1:
# smoothing
from scipy.ndimage.filters import gaussian_filter
Z2 = gaussian_filter(Z2, 1)
elif method == 2:
# interpolation
from scipy.interpolate import RectBivariateSpline
spline = RectBivariateSpline(
x, x, Z, bbox=[x[0], x[-1], x[0], x[-1]])
Z2 = spline.ev(X2, Y2)
ax.plot_surface(X2, Y2, Z2, rstride=1, cstride=1, alpha=0.3, cmap='Accent')
fig.savefig(name)
if __name__ == '__main__':
plot('t0.png', 0)
plot('t1.png', 1)
plot('t2.png', 2)
Initial graph:
Smoothing:
Interpolation (notice the negative regions; that's polynomial interpolation for you):

Plot 4th dimension with Python

I would to know if there is the possibility to plot in four dimensions using python. In particular I would to have a tridimensional mesh X, Y, Z and f(X,Y,Z) = 1 or f(X,Y,Z) = 0.
So I need to a symbol (for example "o" or "x") for some specific point (X,Y,Z).
I don't need to a color scale.
Note that I have 100 matrices (512*512) composed by 1 or 0: so my mesh should be 512*512*100.
I hope I have been clear! Thanks.
EDIT:
This is my code:
X = np.arange(W.shape[2])
Y = np.arange(W.shape[1])
Z = np.arange(W.shape[0])
X, Y, Z = np.meshgrid(X, Y, Z)
fig = plt.figure()
ax = fig.gca(projection='3d')
for z in range(W.shape[0]):
indexes = np.where(W[z])
ax.scatter(X[indexes], Y[indexes], ???, marker='.')
ax.set_xlabel('X = columns')
ax.set_ylabel('Y = rows')
ax.set_zlabel('Z')
plt.show()
W is my tridimensional matrix, so: W[0], W[1], etc are 512x512 matrices.
My question is: what have I to write insted of ??? in my code. I know I shouldn't ask this, but I can't understand the idea.
You could create inspect the value of f(x,y,z) for layers of z to see if they are non-zero or not, and then scatterplot the function based on this.
e.g. for nz layers of (n,n) matrices, each a slice of a sphere:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
n, nz = 48, 24
x, y = np.linspace(-n//2,n//2-1,n), np.linspace(-n//2,n//2-1,n)
X, Y = np.meshgrid(x, y)
def f(x,y,z):
return (X**2 + Y**2 + (z-nz//2)**2) < (n*0.2)**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for z in range(nz):
layer = f(X, Y, z)
indexes = np.where(layer)
ax.scatter(X[indexes], Y[indexes], layer[indexes]*(z-nz//2), marker='.')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
For random non-zero elements of f(x,y,z):
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
n, nz = 12, 10
x, y, z = np.linspace(0,n-1,n), np.linspace(0,n-1,n), np.linspace(0,nz-1,nz)
X, Y, Z = np.meshgrid(x, y, z)
f = np.random.randint(2, size=(n,n,nz))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for z in range(nz):
indexes = np.where(f[...,z])
ax.scatter(X[indexes], Y[indexes], f[indexes]+z, marker='.')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
But with your large arrays, you may run into problems (a) with memory and the speed of the plotting and (b) being able to resolve detail in the "central" block of the plot.

How do you create a 3D surface plot with missing values matplotlib?

I am trying to create a 3D surface energy diagram where an x,y position on a grid contains an associated z level. The issue is that the grid is not uniform (ie, there is not a z component for every x,y position). Is there a way to refrain from plotting those values by calling them NaN in the corresponding position in the array?
Here is what I have tried so far:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pylab
from matplotlib import cm
#Z levels
energ = np.array([0,3.5,1,-0.3,-1.5,-2,-3.4,-4.8])
#function for getting x,y associated z values?
def fun(x,y,array):
return array[x]
#arrays for grid
x = np.arange(0,7,0.5)
y = np.arange(0,7,0.5)
#create grid
X, Y = np.meshgrid(x,y)
zs = np.array([fun(x,y,energ) for x in zip(np.ravel(X))])
Z = zs.reshape(X.shape)
plt3d = plt.figure().gca(projection='3d')
#gradients now with respect to x and y, but ideally with respect to z only
Gx, Gz = np.gradient(X * Y)
G = (Gx ** 2 + Gz ** 2) ** .5 # gradient magnitude
N = G / G.max() # normalize 0..1
plt3d.plot_surface(X, Y, Z, rstride=1, cstride=1,
facecolors=cm.jet(N), edgecolor='k', linewidth=0, antialiased=False, shade=False)
plt.show()
I cannot post image here of this plot but if you run the code you will see it
But I would like to not plot certain x,y pairs, so the figure should triangle downward to the minimum. Can this be accomplished by using nan values? Also would like spacing between each level, to be connected by lines.
n = np.NAN
#energ represents the z levels, so the overall figure should look like a triangle.
energ = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,2.6,n,2.97,n,2.6,n,2.97,n,2.6,n,3.58,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,1.09,n,1.23,n,1.09,n,1.23,n,1.7,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,-0.65,n,-0.28,n,-0.65,n,0.33,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,-2.16,n,-2.02,n,-1.55,n,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,-3.9,n,-2.92,n,n,n,n,n,],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,n,-4.8,n,n,n,n,n,n,]])
plt3d = plt.figure().gca(projection='3d')
Gx, Gz = np.gradient(X * energ) # gradients with respect to x and z
G = (Gx ** 2 + Gz ** 2) ** .5 # gradient magnitude
N = G / G.max() # normalize 0..1
x = np.arange(0,13,1)
y = np.arange(0,13,1)
X, Y = np.meshgrid(x,y)
#but the shapes don't seem to match up
plt3d.plot_surface(X, Y, energ, rstride=1, cstride=1,
facecolors=cm.jet(N), edgecolor='k',
linewidth=0, antialiased=False, shade=False
)
Using masked arrays generates the following error: local Python[7155] : void CGPathCloseSubpath(CGMutablePathRef): no current point.
n = np.NAN
energ = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,2.6,n,2.97,n,2.6,n,2.97,n,2.6,n,3.58,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,1.09,n,1.23,n,1.09,n,1.23,n,1.7,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,-0.65,n,-0.28,n,-0.65,n,0.33,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,-2.16,n,-2.02,n,-1.55,n,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,-3.9,n,-2.92,n,n,n,n,n,],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,n,-4.8,n,n,n,n,n,n,]])
x = np.arange(0,13,1)
y = np.arange(0,13,1)
X, Y = np.meshgrid(x,y)
#create masked arrays
mX = ma.masked_array(X, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]])
mY = ma.masked_array(Y, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]])
m_energ = ma.masked_array(energ, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]])
plt3d = plt.figure().gca(projection='3d')
plt3d.plot_surface(mX, mY, m_energ, rstride=1, cstride=1, edgecolor='k', linewidth=0, antialiased=False, shade=False)
plt.show()
I was playing around with the code from this forum post, and I was able to make the graph have missing values. You can try the code yourself! I got it to work using float("nan") for the missing values.
import plotly.graph_objects as go
import numpy as np
x = np.arange(0.1,1.1,0.1)
y = np.linspace(-np.pi,np.pi,10)
#print(x)
#print(y)
X,Y = np.meshgrid(x,y)
#print(X)
#print(Y)
result = []
for i,j in zip(X,Y):
result.append(np.log(i)+np.sin(j))
result[0][0] = float("nan")
upper_bound = np.array(result)+1
lower_bound = np.array(result)-1
fig = go.Figure(data=[
go.Surface(z=result),
go.Surface(z=upper_bound, showscale=False, opacity=0.3,colorscale='purp'),
go.Surface(z=lower_bound, showscale=False, opacity=0.3,colorscale='purp')])
fig.show()

Categories

Resources