Pcolor data plot in Python - python

I'm trying to plot a matrix in python using pcolor. This is my code but it's not working. can you show me how to plot the matrix?!
Matrix = np.zeros((NumX, NumY))
for i in range(NumX):
for j in range(NumY):
Matrix[i][j] = Data[i*NumY+j+1]
# Set up a regular grid of interpolation points
xi = np.arange(0, NumX*1.5, 1.5)
yi = np.arange(0, NumY*1.5, 1.5)
X, Y = np.meshgrid(xi, yi)
intensity = np.array(Matrix)
plt.pcolormesh(X, Y, Matrix)
plt.colorbar()
plt.show()
this is the error :
TypeError: Dimensions of C (22, 30) are incompatible with X (22)
and/or Y (30); see help(pcolormesh)

You need to mind the indexing rules for arrays. X is the second dimension, Y is the first dimension.
import numpy as np; np.random.seed(1)
import matplotlib.pyplot as plt
NumX, NumY = 5,7
Data = np.random.randint(1,9,size=NumX*NumY+1)
Matrix = np.zeros((NumY, NumX))
for i in range(NumY):
for j in range(NumX):
Matrix[i,j] = Data[i*NumX+j+1]
print(Matrix)
xi = np.arange(0, NumX)
yi = np.arange(0, NumY)
X, Y = np.meshgrid(xi, yi)
plt.pcolormesh(X, Y, Matrix)
for i in range(NumY-1):
for j in range(NumX-1):
plt.text(j,i, Matrix[i,j], color="w")
plt.colorbar()
plt.show()

Related

3D plot using delauney triangulation using four 1dimensional arrays. First three determine the coordinates while fourth determines the color

I am trying to achieve a plot like the one shown bellow:
The code I am using is the following:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.tri as tri
from matplotlib.colors import Normalize
# Example usage
x = np.linspace(0, 10, 500)
f1 = lambda x: x**2
f2 = lambda x: 3*x**1.4
f3 = lambda x: 2*x**1.2
f4 = lambda x: 2*x**1
X = f1(x)
Y = f2(x)
Z = f3(x)
Z1 = f4(x)
# Find the indices of the non-nan values
valid_indices = np.logical_not(np.logical_or(np.isnan(X), np.logical_or(np.isnan(Y), np.isnan(Z))))
# Use the non-nan indices to index into the arrays
x = X[valid_indices]
y = Y[valid_indices]
z = Z[valid_indices]
z1 = Z1[valid_indices]
# Create grid values first.
ngridx = 300
ngridy = 300
xi = np.linspace(x.min(), x.max(), ngridx)
yi = np.linspace(y.min(), y.max(), ngridy)
# Perform linear interpolation of the data (x,y)
# on a grid defined by (xi,yi)
triang = tri.Triangulation(x, y)
interpolator_z = tri.LinearTriInterpolator(triang, z)
interpolator_z1 = tri.LinearTriInterpolator(triang, z1)
Xi, Yi = np.meshgrid(xi, yi)
zi = interpolator_z(Xi, Yi)
z1i = interpolator_z1(Xi, Yi)
X, Y, Z, Z1 = xi, yi, zi, z1i
fig = plt.gcf()
ax1 = fig.add_subplot(111, projection='3d')
minn, maxx = z1.min(), z1.max()
norm = Normalize()
surf = ax1.plot_surface(X,Y,Z, rstride=1, cstride=1, facecolors=cm.jet(norm(Z1)), vmin=minn, vmax=maxx, shade=False)
#surf =ax.plot_trisurf(X,Y,Z, triangles=tri.triangles, cmap=plt.cm.Spectral)
m = cm.ScalarMappable(cmap=cm.jet)
m.set_array(Z1)
The result I am getting is close but not quite what I want:
I am looking to get something that looks closer to this:
Any ideas on how I could improve my result?

How to convert arrays of x,y,z coordinates to 3D path in numpy

Given three 1D arrays of X, Y and Z coordinates, how to convert into a 3D mesh path using numpy?
I managed to do this for 2D using numpy (ie no for loops):
import numpy
def path_2d_numpy(x, y):
m1, m2 = numpy.meshgrid(x, y)
m1[1::2] = m1[1::2,::-1]
r = numpy.append(m1, m2)
r.shape = 2,-1
return r.T
from matplotlib import lines
from matplotlib import pyplot
def plot_path_2d(path):
x, y = path.T
pyplot.plot(x, y, '-ro', lw=3)
pyplot.show()
x = numpy.linspace(4, 1, 4)
y = numpy.linspace(1, 5, 5)
path = path_2d_numpy(x, y)
plot_path_2d(path)
which outputs:
...but was unable to do it for 3D. Showing pure python solution (ie without numpy):
import numpy
def path_3d(x, y, z):
nb_points =len(x)*len(y)*len(z)
path = numpy.empty((nb_points, 3))
xord, yord, i = True, True, 0
for zi in z:
for yi in y[::1 if yord else -1]:
for xi in x[::1 if xord else -1]:
path[i] = xi, yi, zi
i += 1
xord = not xord
yord = not yord
return path
from matplotlib import pyplot
from mpl_toolkits.mplot3d import Axes3D
def plot_path_3d(path):
fig = pyplot.figure()
ax = fig.gca(projection='3d')
xx, yy, zz = path.T
ax.plot(xx, yy, zz, '-bo', lw=3)
pyplot.show()
x = numpy.linspace(4, 1, 4)
y = numpy.linspace(1, 5, 5)
z = numpy.linspace(-3, 0, 3)
path = path_3d(x, y, z)
plot_path_3d(path)
which outputs:
Essencialy, what I am looking for is for a numpy implementation of path_3d as I did for path_2d_numpy.
I need this because the actual arrays I am dealing with are quite big. Doing it without numpy is just too slow.
How's this look?
import numpy as np
def path_3d_numpy(x, y, z):
coords = np.stack(np.meshgrid(x, y, z), axis=-1) # shape = (nx, ny, nz, 3)
coords[1::2,:,:] = coords[1::2,::-1,:]
coords[:,1::2,:] = coords[:,1::2,::-1]
return coords.reshape(-1, 3) # flatten out the other axes
Doesn't iterate the points in quite the same order as yours, but you could fix that simply by swapping some indices around
Similarly, your 2d case could be written as
def path_2d_numpy(x, y):
coords = np.stack(np.meshgrid(x, y), axis=-1)
coords[1::2] = coords[1::2,::-1]
return coords.reshape(-1, 2)
For some real overkill, you can extend this to N dimensions:
def path_nd(*args):
coords = np.stack(np.meshgrid(*args), axis=-1)
N = len(args)
axes = np.arange(N)
for i in range(N-1):
# the last axis isn't part of our mesh, so don't roll it
rolled_axes = tuple(np.roll(axes, -i)) + (N,)
rolled_view = np.transpose(coords, rolled_axes)
rolled_view[1::2,:] = rolled_view[1::2,::-1]
return coords.reshape(-1, N)

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()

Trying to plot multivariate Gaussian dist. in a 3D plot matplotlib returns an empty figure

I am trying to plot a Gaussian distribution via matplotlib, but all I get back is an empty figure:
When I searched the internet, I understood that three arguments are required for the ax.plot_surface() function, the X values, Y values, and Z (a function that calculates Z from X, Y). Is this correct?
I post the code below in hope you can help me figuring out what I am doing wrong here. Thanks!
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
###############################################
### The multivariate Gaussian density function
###############################################
def pdf_multivariate_gauss(x, mu, cov):
'''
Caculate the multivariate normal density (pdf)
Keyword arguments:
x = numpy array of a "d x 1" sample vector
mu = numpy array of a "d x 1" mean vector
cov = "numpy array of a d x d" covariance matrix
'''
assert(mu.shape[0] > mu.shape[1]), 'mu must be a row vector'
assert(x.shape[0] > x.shape[1]), 'x must be a row vector'
assert(cov.shape[0] == cov.shape[1]), 'covariance matrix must be square'
assert(mu.shape[0] == cov.shape[0]), 'cov_mat and mu_vec must have the same dimensions'
assert(mu.shape[0] == x.shape[0]), 'mu and x must have the same dimensions'
part1 = 1 / ( ((2* np.pi)**(len(mu)/2)) * (np.linalg.det(cov)**(1/2)) )
part2 = (-1/2) * ((x-mu).T.dot(np.linalg.inv(cov))).dot((x-mu))
return float(part1 * np.exp(part2))
# Test
x = np.array([[0],[0]])
mu = np.array([[0],[0]])
cov = np.eye(2)
print(pdf_multivariate_gauss(x, mu, cov))
#prints 0.15915494309189535
###############################################
### The plot
###############################################
mu = np.array([[0],[0]])
cov = np.eye(2)
def construct_Z(X, Y, mu, cov):
Z = []
for i,j in zip(X,Y):
x = np.array([i,j]).reshape(2,1)
Z.append(pdf_multivariate_gauss(x, mu, cov))
return Z
X = linspace(-5, 5, 200)
Y = linspace(-5, 5, 200)
Z = construct_Z(X, Y, mu, cov)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color='0.8',
alpha=0.85, linewidth=1)
plt.show()
I'm no expert with 3D-plots in matplotlib, but I believe your data wrong.
As you can see in the sourcecode in this tutorial, your X,Y and Z data have to be 2-dimensional arrays. Your X and Y are one-dimensional, and your Z is a simple list.
Try reshaping your data to a grid, maybe using X, Y = np.meshgrid(X, Y)

Matplotlib contour from xyz data: griddata invalid index

I'm trying to do a contour plot using matplotlib of a file with the following format:
x1 y1 z1
x2 y2 z2
etc
I can load it with numpy.loadtxt to get the vectors. So far, no trouble.
I read this to learn how to plot, and can reproduce it by copy paste, so i'm sure nothin is wrong with my installation:
http://matplotlib.org/examples/pylab_examples/griddata_demo.html
I understand I have to input x and y as vector and z as an array ,which can be done with griddata. This is also what i find on this site.
The documentation says:
zi = griddata(x,y,z,xi,yi) fits a surface of the form z = f*(*x, y) to the data in the (usually) nonuniformly spaced vectors (x, y, z). griddata() interpolates this surface at the points specified by (xi, yi) to produce zi. xi and yi must describe a regular grid, can be either 1D or 2D, but must be monotonically increasing.
For the sake of the example, I have written this code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as ml
x=np.linspace(1.,10.,20)
y=np.linspace(1.,10.,20)
z=np.linspace(1.,2.,20)
xi=np.linspace(1.,10.,10)
yi=np.linspace(1.,10.,10)
zi = ml.griddata(x,y,z,xi,yi)
However, I get the following error when it comes to the griddata:
IndexError: invalid index
So, I tried to modify a bit the exemple of the doc like following:
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2.1,2.1,300)
y = np.linspace(-2.1,2.1,300)
z = x*np.exp(-x**2-y**2)
# define grid.
xi = np.linspace(-2.1,2.1,100)
yi = np.linspace(-2.1,2.1,200)
# grid the data.
zi = griddata(x,y,z,xi,yi,interp='linear')
And I get the same error. I don't understand what's going wrong.
Thanks for your help.
Consider:
x = np.linspace(1., 10., 20)
y = np.linspace(1., 10., 20)
z = np.linspace(1., 2., 20)
This means we know the z-values at certain points along the line x=y.
From there,
zi = ml.griddata(x,y,z,xi,yi)
is asking mlab.griddata to extrapolate the values of z for all points in a rectangular grid.
We've given a lot of information about how z varies along this line, but no information about how z varies in the perpendicular direction (away from the x = y line). An error is being raised because mlab.griddata refuses to guess.
You'll get better results if your initial x, y data are distributed more randomly:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as ml
ndata = 10
ny, nx = 100, 200
xmin, xmax = 1, 10
ymin, ymax = 1, 10
# x = np.linspace(1, 10, ndata)
# y = np.linspace(1, 10, ndata)
x = np.random.randint(xmin, xmax, ndata)
y = np.random.randint(ymin, ymax, ndata)
z = np.random.random(ndata)
xi = np.linspace(xmin, xmax, nx)
yi = np.linspace(ymin, ymax, ny)
zi = ml.griddata(x, y, z, xi, yi)
plt.contour(xi, yi, zi, 15, linewidths = 0.5, colors = 'k')
plt.pcolormesh(xi, yi, zi, cmap = plt.get_cmap('rainbow'))
plt.colorbar()
plt.scatter(x, y, marker = 'o', c = 'b', s = 5, zorder = 10)
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
plt.show()
If you want mlab.griddata to extrapolate data along the line x=y to the entire grid in an arbitrary way, you could add two extra boundary points (xmin, ymax, z[0]) and (xmax,ymin,z[-1]):
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as ml
np.random.seed(8)
ndata = 10
ny, nx = 100, 200
xmin, xmax = 1, 10
ymin, ymax = 1, 10
x = np.linspace(1, 10, ndata)
y = np.linspace(1, 10, ndata)
z = np.random.random(ndata)
x = np.r_[x,xmin,xmax]
y = np.r_[y,ymax,ymin]
z = np.r_[z,z[0],z[-1]]
xi = np.linspace(xmin, xmax, nx)
yi = np.linspace(ymin, ymax, ny)
# Requires installation of natgrid
# http://sourceforge.net/projects/matplotlib/files/matplotlib-toolkits/
zi = ml.griddata(x, y, z, xi, yi, interp='nn')
# Or, without natgrid:
# zi = ml.griddata(x, y, z, xi, yi, interp='linear')
plt.contour(xi, yi, zi, 15, linewidths = 0.5, colors = 'k')
plt.pcolormesh(xi, yi, zi, cmap = plt.get_cmap('rainbow'))
plt.colorbar()
plt.scatter(x, y, marker = 'o', c = 'b', s = 10, zorder = 10)
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
plt.show()
ok, I finally found the solution to plot it. For those interested, here is the trick: use the griddata from Scipy with the 'nearest' method.
from scipy.interpolate import griddata
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(1.,10.,20)
y=np.linspace(1.,10.,20)
z=z = np.random.random(20)
xi=np.linspace(1.,10.,10)
yi=np.linspace(1.,10.,10)
X,Y= np.meshgrid(xi,yi)
Z = griddata((x, y), z, (X, Y),method='nearest')
plt.contourf(X,Y,Z)

Categories

Resources