Python & Matplotlib: How to create a meshgrid to plot surf? - python

I want to plot the a probability density function z=f(x,y).
I find the code to plot surf in Color matplotlib plot_surface command with surface gradient
But I don't know how to conver the z value into grid so I can plot it
The example code and my modification is below.
import numpy as np
import matplotlib.pyplot as plt
from sklearn import mixture
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
%matplotlib inline
n_samples = 1000
# generate random sample, two components
np.random.seed(0)
shifted_gaussian = np.random.randn(n_samples, 2) + np.array([20, 5])
sample = shifted_gaussian
# fit a Gaussian Mixture Model with two components
clf = mixture.GMM(n_components=3, covariance_type='full')
clf.fit(sample)
# Plot it
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, .25)
Y = np.arange(-5, 5, .25)
X, Y = np.meshgrid(X, Y)
## In example Code, the z is generate by grid
# R = np.sqrt(X**2 + Y**2)
# Z = np.sin(R)
# In my case,
# for each point [x,y], the probability value is
# z = clf.score([x,y])
# but How can I generate a grid Z?
Gx, Gy = np.gradient(Z) # gradients with respect to x and y
G = (Gx**2+Gy**2)**.5 # gradient magnitude
N = G/G.max() # normalize 0..1
surf = ax.plot_surface(
X, Y, Z, rstride=1, cstride=1,
facecolors=cm.jet(N),
linewidth=0, antialiased=False, shade=False)
plt.show()
The original approach to plot z is to generate through mesh. But in my case, the fitted model cannot return result in grid-like style, so the problem is how can I generete the grid-style z value, and plot it?

If I understand correctly, you basically have a function z that takes a two scalar values x,y in a list and returns another scalar z_val. In other words z_val = z([x,y]), right?
If that's the case, the you could do the following (note that this is not written with efficiency in mind, but with focus on readability):
from itertools import product
X = np.arange(15) # or whatever values for x
Y = np.arange(5) # or whatever values for y
N, M = len(X), len(Y)
Z = np.zeros((N, M))
for i, (x,y) in enumerate(product(X,Y)):
Z[np.unravel_index(i, (N,M))] = z([x,y])
If you want to use plot_surface, then follow that with this:
X, Y = np.meshgrid(X, Y)
ax.plot_surface(X, Y, Z.T)

Related

How to plot a one to many function on matplotlib in python

Very simple, if I plot x^2+y^2=z it makes this shape on python it will make this shape:
When I would like to plot it this way:
Below is my code, I am new so I copied it from the internet and have changed the line with the function to plot.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-4*np.pi,4*np.pi,50)
y = np.linspace(-4*np.pi,4*np.pi,50)
z = x**2+y**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(x,y,z)
plt.show()
Also, how do I make it more high definition and smooth, this is a graph of z=sin(x)
You need to define a 2D mathematical domain with numpy.meshgrid, then you can compute the surface on that domain:
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
In order to increase the smoothness of the surface, you have in increase the number of point N you use to compute x and y arrays:
Complete code
import matplotlib.pyplot as plt
import numpy as np
N = 50
x = np.linspace(-4*np.pi, 4*np.pi, N)
y = np.linspace(-4*np.pi, 4*np.pi, N)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z)
plt.show()

Plot 4D Contour in Python (X,Y,Z + Data)

I have a large set of measurements that I want to visualize in 4D using matplotlib in Python.
Currently, my variables are arranged in this way:
x = np.array(range(0, v1))
y = np.array(range(0, v2))
z = np.array(range(0, v3))
I have C which is a 3D array containing measurement values for each combination of the previous variables. So it has a dimension of v1*v2*v3.
Currently, I visualize my measurements using contourf function and I plot that for each z value. This results in 3D contour plot i.e. 2D + color map for the values. Now, I want to combine all the variables and look at the measurements in 4D dimensions (x, y, z, and color corresponding to the measurement value). What is the most efficient way to do this in python?
Regarding to #Sameeresque answer, I think the question was about a 4D graph like this (three coordinates x, y, z and a color as the fourth coordinate):
import numpy as np
import matplotlib.pyplot as plt
# only for example, use your grid
z = np.linspace(0, 1, 15)
x = np.linspace(0, 1, 15)
y = np.linspace(0, 1, 15)
X, Y, Z = np.meshgrid(x, y, z)
# Your 4dimension, only for example (use yours)
U = np.exp(-(X/2) ** 2 - (Y/3) ** 2 - Z ** 2)
# Creating figure
fig = plt.figure()
ax = plt.axes(projection="3d")
# Creating plot
ax.scatter3D(X, Y, Z, c=U, alpha=0.7, marker='.')
plt.show()
A 4D plot with (x,y,z) on the axis and the fourth being color can be obtained like so:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.array(range(0, 50))
y = np.array(range(0, 50))
z = np.array(range(0, 50))
colors = np.random.standard_normal(len(x))
img = ax.scatter(x, y, z, c=colors, cmap=plt.hot())
fig.colorbar(img)
plt.show()
A simple way to visualize your 4D function, call it W(x, y, z), could be producing a gif of the cross-section contour plots along the z-axis.
Package plot4d could help you do it. An example plotting an isotropic 4D function:
from plot4d import plotter
import numpy as np
plotter.plot4d(lambda x,y,z:x**2+y**2+z**2, np.linspace(0,1,20), wbounds=(0,3), fps=5)
The code above generates this gif:

scikit-learn: How to use the fitted probability model?

So I have used scikit-learn's Gaussian mixture models(http://scikit-learn.org/stable/modules/mixture.html) to fit my data, now I want to use the model, How can I do it? Specifically:
How can I plot the probability density distribution?
How can I calculate the mean square error of the fitting model?
Here is the code you may need:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
from sklearn import mixture
import matplotlib as mpl
from matplotlib.patches import Ellipse
%matplotlib inline
n_samples = 300
# generate random sample, two components
np.random.seed(0)
shifted_gaussian = np.random.randn(n_samples, 2) + np.array([20, 5])
sample= shifted_gaussian
# fit a Gaussian Mixture Model with two components
clf = mixture.GMM(n_components=2, covariance_type='full')
clf.fit(sample)
# plot sample scatter
plt.scatter(sample[:, 0], sample[:, 1])
# 1. Plot the probobility density distribution
# 2. Calculate the mean square error of the fitting model
UPDATE:
I can plot the distribution by:
x = np.linspace(-20.0, 30.0)
y = np.linspace(-20.0, 40.0)
X, Y = np.meshgrid(x, y)
XX = np.array([X.ravel(), Y.ravel()]).T
Z = -clf.score_samples(XX)[0]
Z = Z.reshape(X.shape)
CS = plt.contour(X, Y, Z, norm=LogNorm(vmin=1.0, vmax=1000.0),
levels=np.logspace(0, 3, 10))
CB = plt.colorbar(CS, shrink=0.8, extend='both')
But isn't it quite strange? Is there better way do to it? Can I plot something like this?
I think the result is reasonable, if you adjust the xlim and ylim a little bit:
# plot sample scatter
plt.scatter(sample[:, 0], sample[:, 1], marker='+', alpha=0.5)
# 1. Plot the probobility density distribution
# 2. Calculate the mean square error of the fitting model
x = np.linspace(-20.0, 30.0, 100)
y = np.linspace(-20.0, 40.0, 100)
X, Y = np.meshgrid(x, y)
XX = np.array([X.ravel(), Y.ravel()]).T
Z = -clf.score_samples(XX)[0]
Z = Z.reshape(X.shape)
CS = plt.contour(X, Y, Z, norm=LogNorm(vmin=1.0, vmax=10.0),
levels=np.logspace(0, 1, 10))
CB = plt.colorbar(CS, shrink=0.8, extend='both')
plt.xlim((10,30))
plt.ylim((-5, 15))

Distance dependent coloring in matplotlib

I want to create some plots of the farfield of electromagnetic scattering processes.
To do this, I calculated values θ, φ and r. The coordinates θ and φ create a regular grid on the unitsphere so I can use plot_Surface (found here) with conversion to cartesian coordinates.
My problem is now, that I need a way to color the surface with respect to the radius r and not height z, which seems to be the default.
Is there a way, to change this dependency?
I don't know how you're getting on, so maybe you've solved it. But, based on the link from Paul's comment, you could do something like this. We pass the color values we want using the facecolor argument of plot_surface.
(I've modified the surface3d demo from the matplotlib docs)
EDIT: As Stefan noted in his comment, my answer can be simplified to:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
xlen = len(X)
Y = np.arange(-5, 5, 0.25)
ylen = len(Y)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
maxR = np.amax(R)
Z = np.sin(R)
# Note that the R values must still be normalized.
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=cm.jet(R/maxR),
linewidth=0)
plt.show()
And (the end of) my needlessly complicated original version, using the same code as above though omitting the matplotlib.cm import,
# We will store (R, G, B, alpha)
colorshape = R.shape + (4,)
colors = np.empty( colorshape )
for y in range(ylen):
for x in range(xlen):
# Normalize the radial value.
# 'jet' could be any of the built-in colormaps (or your own).
colors[x, y] = plt.cm.jet(R[x, y] / maxR )
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=colors,
linewidth=0)
plt.show()

Scattered x,y,z via python's matplotlib.pyplot.contourf

Most pyplot examples out there use linear data, but what if data is scattered?
x = 3,7,9
y = 1,4,5
z = 20,3,7
better meshgrid for contourf
xi = np.linspace(min(x)-1, max(x)+1, 9)
yi = np.linspace(min(y)-1, max(y)+1, 9)
X, Y = np.meshgrid(xi, yi)
Now "z" data got to be interpolated onto the meshgrid.
numpy.interp does little help here, while both linear and nn interpolaton of
zi = matplotlib.mlab.griddata(x,y,z,xi,yi,interp="linear")
returns rather strange results
scipy.interpolate.griddata cubic from second answer below needs something else to return data rather than nils
With custom levels data expected be looking something like this
This is what happens:
Although contour requires grid data, we can caste scatter data to a grid and then using masked arrays mask out the blank regions. I simulate this in the code below, by creating a random array, then using this to mask a test dataset (shown at bottom). The bulk of the code is taken from this matplotlib demo page.
import matplotlib
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
# difference of Gaussians
Z = 10.0 * (Z2 - Z1)
from numpy.random import *
import numpy.ma as ma
J = random_sample(X.shape)
mask = J > 0.7
X = ma.masked_array(X, mask=mask)
Y = ma.masked_array(Y, mask=mask)
Z = ma.masked_array(Z, mask=mask)
plt.figure()
CS = plt.contour(X, Y, Z, 20)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')
plt.savefig('cat.png')
plt.show()
countourf will only work with a grid of data. If you're data is scattered, then you'll need to create an interpolated grid matching your data, like this: (note you'll need scipy to perform the interpolation)
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
import numpy.ma as ma
from numpy.random import uniform, seed
# your data
x = [3,7,9]
y = [1,4,5]
z = [20,3,7]
# define grid.
xi = np.linspace(0,10,300)
yi = np.linspace(0,6,300)
# grid the data.
zi = griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
# contour the gridded data, plotting dots at the randomly spaced data points.
CS = plt.contour(xi,yi,zi,15,linewidths=0.5,colors='k')
CS = plt.contourf(xi,yi,zi,15,cmap=plt.cm.jet)
plt.colorbar() # draw colorbar
# plot data points.
plt.scatter(x,y,marker='o',c='b',s=5)
plt.xlim(min(x),max(x))
plt.ylim(min(y),max(y))
plt.title('griddata test (%d points)' % len(x))
plt.show()
See here for the origin of that code.

Categories