Plotting 3-tuple data points in a surface / contour plot using matplotlib - python

I have some surface data that is generated by an external program as XYZ values. I want to create the following graphs, using matplotlib:
Surface plot
Contour plot
Contour plot overlayed with a surface plot
I have looked at several examples for plotting surfaces and contours in matplotlib - however, the Z values seems to be a function of X and Y i.e. Y ~ f(X,Y).
I assume that I will somehow need to transform my Y variables, but I have not seen any example yet, that shows how to do this.
So, my question is this: given a set of (X,Y,Z) points, how may I generate Surface and contour plots from that data?
BTW, just to clarify, I do NOT want to create scatter plots. Also although I mentioned matplotlib in the title, I am not averse to using rpy(2), if that will allow me to create these charts.

for do a contour plot you need interpolate your data to a regular grid http://www.scipy.org/Cookbook/Matplotlib/Gridding_irregularly_spaced_data
a quick example:
>>> xi = linspace(min(X), max(X))
>>> yi = linspace(min(Y), max(Y))
>>> zi = griddata(X, Y, Z, xi, yi)
>>> contour(xi, yi, zi)
for the surface http://matplotlib.sourceforge.net/examples/mplot3d/surface3d_demo.html
>>> from mpl_toolkits.mplot3d import Axes3D
>>> fig = figure()
>>> ax = Axes3D(fig)
>>> xim, yim = meshgrid(xi, yi)
>>> ax.plot_surface(xim, yim, zi)
>>> show()
>>> help(meshgrid(x, y))
Return coordinate matrices from two coordinate vectors.
[...]
Examples
--------
>>> X, Y = np.meshgrid([1,2,3], [4,5,6,7])
>>> X
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
>>> Y
array([[4, 4, 4],
[5, 5, 5],
[6, 6, 6],
[7, 7, 7]])
contour in 3D http://matplotlib.sourceforge.net/examples/mplot3d/contour3d_demo.html
>>> fig = figure()
>>> ax = Axes3D(fig)
>>> ax.contour(xi, yi, zi) # ax.contourf for filled contours
>>> show()

With pandas and numpy to import and manipulate data, with matplot.pylot.contourf to plot the image
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
PATH='/YOUR/CSV/FILE'
df=pd.read_csv(PATH)
#Get the original data
x=df['COLUMNNE']
y=df['COLUMNTWO']
z=df['COLUMNTHREE']
#Through the unstructured data get the structured data by interpolation
xi = np.linspace(x.min()-1, x.max()+1, 100)
yi = np.linspace(y.min()-1, y.max()+1, 100)
zi = griddata(x, y, z, xi, yi, interp='linear')
#Plot the contour mapping and edit the parameter setting according to your data (http://matplotlib.org/api/pyplot_api.html?highlight=contourf#matplotlib.pyplot.contourf)
CS = plt.contourf(xi, yi, zi, 5, levels=[0,50,100,1000],colors=['b','y','r'],vmax=abs(zi).max(), vmin=-abs(zi).max())
plt.colorbar()
#Save the mapping and save the image
plt.savefig('/PATH/OF/IMAGE.png')
plt.show()
Example Image

Contour plot with rpy2 + ggplot2:
from rpy2.robjects.lib.ggplot2 import ggplot, aes_string, geom_contour
from rpy2.robjects.vectors import DataFrame
# Assume that data are in a .csv file with three columns X,Y,and Z
# read data from the file
dataf = DataFrame.from_csv('mydata.csv')
p = ggplot(dataf) + \
geom_contour(aes_string(x = 'X', y = 'Y', z = 'Z'))
p.plot()
Surface plot with rpy2 + lattice:
from rpy2.robjects.packages import importr
from rpy2.robjects.vectors import DataFrame
from rpy2.robjects import Formula
lattice = importr('lattice')
rprint = robjects.globalenv.get("print")
# Assume that data are in a .csv file with three columns X,Y,and Z
# read data from the file
dataf = DataFrame.from_csv('mydata.csv')
p = lattice.wireframe(Formula('Z ~ X * Y'), shade = True, data = dataf)
rprint(p)

Related

How to convert a matrix to heatmap image in torch [duplicate]

Using Matplotlib, I want to plot a 2D heat map. My data is an n-by-n Numpy array, each with a value between 0 and 1. So for the (i, j) element of this array, I want to plot a square at the (i, j) coordinate in my heat map, whose color is proportional to the element's value in the array.
How can I do this?
The imshow() function with parameters interpolation='nearest' and cmap='hot' should do what you want.
Please review the interpolation parameter details, and see Interpolations for imshow and Image antialiasing.
import matplotlib.pyplot as plt
import numpy as np
a = np.random.random((16, 16))
plt.imshow(a, cmap='hot', interpolation='nearest')
plt.show()
Seaborn is a high-level API for matplotlib, which takes care of a lot of the manual work.
seaborn.heatmap automatically plots a gradient at the side of the chart etc.
import numpy as np
import seaborn as sns
import matplotlib.pylab as plt
uniform_data = np.random.rand(10, 12)
ax = sns.heatmap(uniform_data, linewidth=0.5)
plt.show()
You can even plot upper / lower left / right triangles of square matrices. For example, a correlation matrix, which is square and is symmetric, so plotting all values would be redundant.
corr = np.corrcoef(np.random.randn(10, 200))
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask)] = True
with sns.axes_style("white"):
ax = sns.heatmap(corr, mask=mask, vmax=.3, square=True, cmap="YlGnBu")
plt.show()
I would use matplotlib's pcolor/pcolormesh function since it allows nonuniform spacing of the data.
Example taken from matplotlib:
import matplotlib.pyplot as plt
import numpy as np
# generate 2 2d grids for the x & y bounds
y, x = np.meshgrid(np.linspace(-3, 3, 100), np.linspace(-3, 3, 100))
z = (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2)
# x and y are bounds, so z should be the value *inside* those bounds.
# Therefore, remove the last value from the z array.
z = z[:-1, :-1]
z_min, z_max = -np.abs(z).max(), np.abs(z).max()
fig, ax = plt.subplots()
c = ax.pcolormesh(x, y, z, cmap='RdBu', vmin=z_min, vmax=z_max)
ax.set_title('pcolormesh')
# set the limits of the plot to the limits of the data
ax.axis([x.min(), x.max(), y.min(), y.max()])
fig.colorbar(c, ax=ax)
plt.show()
For a 2d numpy array, simply use imshow() may help you:
import matplotlib.pyplot as plt
import numpy as np
def heatmap2d(arr: np.ndarray):
plt.imshow(arr, cmap='viridis')
plt.colorbar()
plt.show()
test_array = np.arange(100 * 100).reshape(100, 100)
heatmap2d(test_array)
This code produces a continuous heatmap.
You can choose another built-in colormap from here.
Here's how to do it from a csv:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
# Load data from CSV
dat = np.genfromtxt('dat.xyz', delimiter=' ',skip_header=0)
X_dat = dat[:,0]
Y_dat = dat[:,1]
Z_dat = dat[:,2]
# Convert from pandas dataframes to numpy arrays
X, Y, Z, = np.array([]), np.array([]), np.array([])
for i in range(len(X_dat)):
X = np.append(X, X_dat[i])
Y = np.append(Y, Y_dat[i])
Z = np.append(Z, Z_dat[i])
# create x-y points to be used in heatmap
xi = np.linspace(X.min(), X.max(), 1000)
yi = np.linspace(Y.min(), Y.max(), 1000)
# Interpolate for plotting
zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic')
# I control the range of my colorbar by removing data
# outside of my range of interest
zmin = 3
zmax = 12
zi[(zi<zmin) | (zi>zmax)] = None
# Create the contour plot
CS = plt.contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow,
vmax=zmax, vmin=zmin)
plt.colorbar()
plt.show()
where dat.xyz is in the form
x1 y1 z1
x2 y2 z2
...
Use matshow() which is a wrapper around imshow to set useful defaults for displaying a matrix.
a = np.diag(range(15))
plt.matshow(a)
https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.matshow.html
This is just a convenience function wrapping imshow to set useful defaults for displaying a matrix. In particular:
Set origin='upper'.
Set interpolation='nearest'.
Set aspect='equal'.
Ticks are placed to the left and above.
Ticks are formatted to show integer indices.
Here is a new python package to plot complex heatmaps with different kinds of row/columns annotations in Python: https://github.com/DingWB/PyComplexHeatmap

Is there any way to express changing color from Matplotlib, Python?

Before you reading, I apologize about broken English.
I have a data array of moving mass, and want to show them by time area.
Like:
import matplotlib.pyplot as plt
import numpy as np
x = np.array([0, 1, 2, 3])
y = np.array([3, 4, 5, 6])
plt.plot(x,y)
In this code, I just want to see them with different color each rows.
For example,
point (0,3) is white dot,
point (3,5) is black dot,
and (1,4) , (2,5) are gray dot but different brightness.
I just started python, so I searched pyplot lib but didn't find examples.
I tried with Seaborn library, and Pyplot 3d examples. But didn't find solution to express what want to do.
If your aim is to identify the order of your points, you can use a colormap, specifying that the vector that determines the coloring is simply the sequence of the indices of the points.
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(20201222)
x = np.random.randint(5, 20, 20)
y = np.random.randint(5, 20, 20)
r = range(len(x))
plt.scatter(x, y, s=80, c=r, cmap='plasma')
plt.grid()
cb = plt.colorbar()
cb.set_ticks(r)
cb.set_ticklabels(("%d"%(order+1) for order in r))
and eventually the very awaited overworked implementation
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
np.random.seed(20201222)
x = np.random.rand(20)*5+np.arange(20)/3
y = np.random.rand(20)*5+np.arange(20)/3
tck, u = interpolate.splprep([x,y] ,s=0.05)
x1, y1 = interpolate.splev(np.linspace(0, 1, 3333), tck)
r = range(len(x))
plt.plot(x1, y1, color='k', lw=0.4, alpha=0.4)
plt.scatter(x, y, s=60, c=r, cmap='Greys', ec='grey', zorder=4)
plt.xlim((0,12)), plt.ylim((0,12))
plt.grid(1)
plt.gca().set_aspect(1)
cb = plt.colorbar()
cb.set_ticks((0, len(x)-1))
cb.set_ticklabels(('First', 'Last'))
Pass a color argument into a scatter function that displays given points and any defined features.
#array declaration
#...
for x1, y1 in zip(x, y):
if x1 == 0:
color = "white"
elif x1 == 1 or x1 == 2:
color = "gray"
elif x1 == 3:
color = "black"
plt.scatter(x1, y1, c=color)
# plot linear line from arrays
We use the zip class to iterate through both arrays at once, allowing us to plot each point from the given arrays. We use the x-coordinates from the x array to determine what color to label the dot. The scatter function puts this point on the graph, giving us options to change features of the given dot(s).
--
The final code would look something like this:
import matplotlib.pyplot as plt
import numpy as np
x = np.array([0, 1, 2, 3])
y = np.array([3, 4, 5, 6])
for x1, y1 in zip(x, y):
if x1 == 0:
color = "white"
elif x1 == 1 or x1 == 2:
color = "gray"
elif x1 == 3:
color = "black"
plt.scatter(x1, y1, c=color)
plt.plot(x, y)
plt.show()
Documentation on matplotlib's scatter function can be found here
poiboi was on the right track. Here's an example which automatically sets a linear gradient for the colours of the dots.
import matplotlib.pyplot as plt
import numpy as np
x = [0, 1, 2, 3]
y = [3, 4, 5, 6]
plt.scatter(x, y, c=x[:: -1], cmap='gray', vmin=min(x), vmax=max(x))
plt.show()
The c keyword argument tells Matplotlib which colour to use for which point using a grey colourmap. By default, said colourmap goes from black to white, so we pass x reversed. vmin and vmax are the least and greatest values to be assigned colours. Note that the first point is white (hence invisible).

Plotting a heatmap with interpolation in Python using excel file

I need to plot a HEATMAP in python using x, y, z data from the excel file.
All the values of z are 1 except at (x=5,y=5). The plot should be red at point (5,5) and blue elsewhere. But I am getting false alarms which need to be removed. The COLORMAP I have used is 'jet'
X=[0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9]
Y=[0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9]
Z=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
Code I have used is:
import matplotlib.pyplot as plt
import numpy as np
from numpy import ravel
from scipy.interpolate import interp2d
import pandas as pd
import matplotlib as mpl
excel_data_df = pd.read_excel('test.xlsx')
X= excel_data_df['x'].tolist()
Y= excel_data_df['y'].tolist()
Z= excel_data_df['z'].tolist()
x_list = np.array(X)
y_list = np.array(Y)
z_list = np.array(Z)
# f will be a function with two arguments (x and y coordinates),
# but those can be array_like structures too, in which case the
# result will be a matrix representing the values in the grid
# specified by those arguments
f = interp2d(x_list,y_list,z_list,kind="linear")
x_coords = np.arange(min(x_list),max(x_list))
y_coords = np.arange(min(y_list),max(y_list))
z= f(x_coords,y_coords)
fig = plt.imshow(z,
extent=[min(x_list),max(x_list),min(y_list),max(y_list)],
origin="lower", interpolation='bicubic', cmap= 'jet', aspect='auto')
# Show the positions of the sample points, just to have some reference
fig.axes.set_autoscale_on(False)
#plt.scatter(x_list,y_list,400, facecolors='none')
plt.xlabel('X Values', fontsize = 15, va="center")
plt.ylabel('Y Values', fontsize = 15,va="center")
plt.title('Heatmap', fontsize = 20)
plt.tight_layout()
plt.show()
For your ease you can also use the X, Y, Z arrays instead of reading excel file.
The result that I am getting is:
Here you can see dark blue regions at (5,0) and (0,5). These are the FALSE ALARMS I am getting and I need to REMOVE these.
I am probably doing some beginner's mistake. Grateful to anyone who points it out. Regards
There are at least three problems in your example:
x_coords and y_coords are not properly resampled;
the interpolation z does to fill in the whole grid leading to incorrect output;
the output is then forced to be plotted on the original grid (extent) that add to the confusion.
Leading to the following interpolated results:
On what you have applied an extra smoothing with imshow.
Let's create your artificial input:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 11)
y = np.arange(0, 11)
X, Y = np.meshgrid(x, y)
Z = np.ones(X.shape)
Z[5,5] = 9
Depending on how you want to proceed, you can simply let imshow smooth your signal by interpolation:
fig, axe = plt.subplots()
axe.imshow(Z, origin="lower", cmap="jet", interpolation='bicubic')
And you are done, simple and efficient!
If you aim to do it by yourself, then choose the interpolant that suits you best and resample on a grid with a higher resolution:
interpolant = interpolate.interp2d(x, y, Z.ravel(), kind="linear")
xlin = np.linspace(0, 10, 101)
ylin = np.linspace(0, 10, 101)
zhat = interpolant(xlin, ylin)
fig, axe = plt.subplots()
axe.imshow(zhat, origin="lower", cmap="jet")
Have a deeper look on scipy.interpolate module to pick up the best interpolant regarding your needs. Notice that all methods does not expose the same interface for imputing parameters. You may need to reshape your data to use another objects.
MCVE
Here is a complete example using the trial data generated above. Just bind it to your excel columns:
# Flatten trial data to meet your requirement:
x = X.ravel()
y = Y.ravel()
z = Z.ravel()
# Resampling on as square grid with given resolution:
resolution = 11
xlin = np.linspace(x.min(), x.max(), resolution)
ylin = np.linspace(y.min(), y.max(), resolution)
Xlin, Ylin = np.meshgrid(xlin, ylin)
# Linear multi-dimensional interpolation:
interpolant = interpolate.NearestNDInterpolator([r for r in zip(x, y)], z)
Zhat = interpolant(Xlin.ravel(), Ylin.ravel()).reshape(Xlin.shape)
# Render and interpolate again if necessary:
fig, axe = plt.subplots()
axe.imshow(Zhat, origin="lower", cmap="jet", interpolation='bicubic')
Which renders as expected:

Get a 2d contour plot from a 3d surface plot

I use matplotlib plot_surface() function and plot a complex function in 3D. Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
point_num = 200
x = np.linspace(-5, 3, point_num)
y = np.linspace(-5, 5, point_num)
# Real axis and imaginary axis-----------------------------
Re, Im = np.meshgrid(x, y)
#----------------------------------------------------------
# here is the complex function I need evaluate-------------
z = Re + Im * 1j
R3 = 1 + z + 1/2 * z**2 + 1/6 * pow(z, 3)
#----------------------------------------------------------
# my 3d surface plot----------------------------------------
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot_surface(Re, Im, np.abs(R1))
ax.set_xlabel("Im(z)")
ax.set_ylabel("Re(z)")
ax.set_zlabel('R(z)')
plt.show()
#----------------------------------------------------------
I can successfully get the surface plot:
The surface looks like a cone. Now I want to "slice" the cone with plane R(z)=1 and get a 2D contour plot. I can get the contour on the 3D surface like this:
ax.contour(Re, Im, np.abs(R3), [1], colors='r')
Then I get:
I want to plot the red line contour in an independent 2D plot. It should be in the real and imaginary axis. Moreover, can we get the coordinates of the intersection points of the contour line with the axis? Like the figure below:
Thank you very much!
So the issue here is that a plt.Axes() object can't be in the 2D and 3D projections simultaneously. In my version, I have commented out your 3D plots, so that we can focus on the independent 2D plot. It's then only this:
fig = plt.figure()
ax = plt.axes()
ax.contour(Re, Im, np.abs(R3), [1], c='r')
Full version:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
point_num = 200
x = np.linspace(-5, 3, point_num)
y = np.linspace(-5, 5, point_num)
# Real axis and imaginary axis-----------------------------
Re, Im = np.meshgrid(x, y)
#----------------------------------------------------------
# here is the complex function I need evaluate-------------
z = Re + Im * 1j
R3 = 1 + z + 1/2 * z**2 + 1/6 * pow(z, 3)
#----------------------------------------------------------
# my 3d surface plot----------------------------------------
fig = plt.figure()
# ax = plt.axes(projection='3d')
# ax.plot_surface(Re, Im, np.abs(R3))
# ax.set_xlabel("Im(z)")
# ax.set_ylabel("Re(z)")
# ax.set_zlabel('R(z)')
# ax.contour(Re, Im, np.abs(R3), [1], colors='r')
ax = plt.axes()
ax.contour(Re, Im, np.abs(R3), [1], c='r')
plt.show()
#----------------------------------------------------------

3D plot from a data set

I have a data set which looks like this:
Intensity = ( [1, 2, 3, 4], [6, 7, 9, 10] )
Xposition = (0.1, 0.2, 0.3, 0.4)
Yposition = (1E^-9, 1.2E^-9)
So, for each Yposition, we have an 1D array stored in Intensity, corresponding to each Xposition.
Now I want to plot Xposition (X-axis), Yposition (Y-axis) and Intensity along Z to generate a 3D plot. How can I do this using matplotlib?
There are nice tutorials on matplotlib page. Looking at two examples and slightly tweaking the code:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = (0.1,0.2,0.3,0.4)
y = (10**-9, 1.2*10**-9)
x,y = np.meshgrid(x,y)
z = ( [1,2,3,4], [6,7,9,10] )
ax.scatter(x, y, z)
plt.show()

Categories