Density map (heatmaps) in matplotlib - python

I have a list of coordinates:
y,x
445.92,483.156
78.273,321.512
417.311,204.304
62.047,235.216
87.24,532.1
150.863,378.184
79.981,474.14
258.894,87.74
56.496,222.336
85.105,454.176
80.408,411.672
90.656,433.568
378.027,441.296
433.964,290.6
453.606,317.648
383.578,115.432
128.232,312.496
116.276,93.536
94.072,222.336
52.226,327.308
321.663,187.56
392.972,279.008
I would like to plot a density map (or heat map) based on these points, using matplotlib. I am using pcolormesh and contourf.
My problem is that pcolormesh is not having same size of the pitch:
This is the code:
x, y = np.genfromtxt('pogba_t1314.csv', delimiter=',', unpack=True)
#print(x[1], y[1])
y = y[np.logical_not(np.isnan(y))]
x = x[np.logical_not(np.isnan(x))]
k = gaussian_kde(np.vstack([x, y]))
xi, yi = np.mgrid[x.min():x.max():x.size**0.5*1j,y.min():y.max():y.size**0.5*1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
fig = plt.figure(figsize=(9,10))
ax1 = fig.add_subplot(211)
ax1.pcolormesh(xi, yi, zi.reshape(xi.shape), alpha=0.5)
ax1.plot(y,x, "o")
ax1.set_xlim(0, 740)
ax1.set_ylim(515, 0)
#overlay soccer field
im = plt.imread('statszone_football_pitch.png')
ax1.imshow(im, extent=[0, 740, 0, 515], aspect='auto')
fig.savefig('pogba1516.png')
Here it is a link for the csv file: https://dl.dropboxusercontent.com/u/12348226/pogba_t1314.csv

This will hopefully get you started on the right track, but I would definitely recommend reading the docs for pcolor and pcolormesh.
You have commented # Plot the density map using nearest-neighbor interpolation, but since Z is a 1D array, you don't have any 2D density data for a density map. Density maps are most easily created through the use of np.histogram2d as I'll show below using your data.
Z, xedges, yedges = np.histogram2d(x, y)
Z is now a 2D array that has information about the distribution of your x, y coordinates. This distribution can be plotted with pcolormesh like so
plt.pcolormesh(xedges, yedges, Z.T)
Sort of a ways to go before you obtain an image like the one you posted, but it should explain your error and help get you on the right track.
Update: For nicer, smoother density maps
Assuming you have two 1D arrays, x and y you can use a kernel density estimate to obtain much nicer heatmaps in the following way [reference],
from scipy.stats.kde import gaussian_kde
k = gaussian_kde(np.vstack([x, y]))
xi, yi = np.mgrid[x.min():x.max():x.size**0.5*1j,y.min():y.max():y.size**0.5*1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
Now you can plot the Gaussian KDE with either pcolormesh or contourf depending on what kind of effect/aesthetics you're after
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(7,8))
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
# alpha=0.5 will make the plots semitransparent
ax1.pcolormesh(xi, yi, zi.reshape(xi.shape), alpha=0.5)
ax2.contourf(xi, yi, zi.reshape(xi.shape), alpha=0.5)
ax1.set_xlim(x.min(), x.max())
ax1.set_ylim(y.min(), y.max())
ax2.set_xlim(x.min(), x.max())
ax2.set_ylim(y.min(), y.max())
# you can also overlay your soccer field
im = plt.imread('soccerPitch.jpg')
ax1.imshow(im, extent=[x.min(), x.max(), y.min(), y.max()], aspect='auto')
ax2.imshow(im, extent=[x.min(), x.max(), y.min(), y.max()], aspect='auto')
I get this image:

Related

Interpolation of measured values with Python

I want to create an efficiency map from measured data in Python. For this purpose I have already tested different interpolation methods. Unfortunately I am not satisfied with the result and would like to ask you for your advice.
I have shown here an example of RBF interpolation, which illustrates my problem well. Between the measured values, the interpolation always falls into a kind of "valley", which is not correct, however. I think that it is difficult for the interpolation to interpolate down to zero on two sides of the plateau.
Here you can find the measuring values (x,y,z) in a matrix:
Link
And here follows the minimal example:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.interpolate import RBFInterpolator, RegularGridInterpolator, LinearNDInterpolator, NearestNDInterpolator
df = pd.read_csv("Data.csv")
mat = df.to_numpy()
x = mat[:,0]
y = mat[:,1]
z = mat[:,2]
# 3D-Plot
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.set_title('Data points')
ax.scatter(x, y, np.transpose(z), marker='o', c='black', s=2)
ax.view_init(30, -115)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
num_points = 500
xi = np.linspace(min(x),max(x),num_points)
yi = np.linspace(min(y),max(y),num_points)
XI, YI = np.meshgrid(xi, yi)
# RBFInterpolator
measured_points = np.stack([x.ravel(), y.ravel()], -1)
interpolated_points = np.stack([XI.ravel(), YI.ravel()], -1)
interpolation_rbf = RBFInterpolator(measured_points, z.ravel(), smoothing=0, kernel='linear')
z_rbf = interpolation_rbf(interpolated_points).reshape(num_points, num_points)
# 3D-Plot
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.set_title('RBFInterpolator')
surf = ax.plot_surface(XI, YI, z_rbf, cmap='jet')
ax.scatter(x, y, np.transpose(z), marker='o', c='black', s=2)
ax.view_init(30, -115)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
# LinearNDInterpolator
interp = LinearNDInterpolator(list(zip(x, y)), z)
ZI = interp(XI, YI)
# 3D-Plot
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.set_title('LinearNDInterpolator')
surf = ax.plot_surface(XI, YI, ZI, cmap='jet')
ax.scatter(x, y, np.transpose(z), marker='o', c='black', s=2)
ax.view_init(30, -115)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
# NearestNDInterpolator
interp = NearestNDInterpolator(list(zip(x, y)), z)
ZI = interp(XI, YI)
# 3D-Plot
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.set_title('NearestNDInterpolator')
surf = ax.plot_surface(XI, YI, ZI, cmap='jet')
ax.scatter(x, y, np.transpose(z), marker='o', c='black', s=2)
ax.view_init(30, -115)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
The measured values and the interpolation can be seen in the following figures.
Measured Values
RBF Interpolation of Measured Values
Edit:
Now I have added the LinearNDInterpolator and the NearestNDInterpolator. The LinearNDInterpolator comes closer to my ideas, but it also creates some valleys.
LinearNDInterpolator
On the following picture you can see how the map should normally look like.
Efficiency Map
The radial basis functions used by RBFInterpolator() assumes the value depends only on distance from a given point - either the origin or the center of the sample matrix. For your source data, you've got a bunch of samples with zero on the x and y axes. RBFInterpolator is thus trying to go close to zero for distances corresponding to axes' samples, even when the same distance shows up in the middle of a bunch of values with non-zero distance. That is, by choosing RBFInterpolator, you've declared the result should look like ripples on a pond moving out from a single point.
In general, choice of interpolation algorithm reflects assumptions about the underlying structure of the data. The choice of basis (axes) is also potentially important. If you want something that "should just be smooth and continuous in the coordinates you're using to make the plot" without additional constraints or structure, then linear interpolation or one of the spline options is usually the way to go. If you have domain knowledge of what the shape should be, independent of measurement, you can build kernels for that - but you haven't stated any such constraints.
Just use linear interpolation unless you have need of specific features for some other interpolation scheme. In your case, with a regular grid of samples, the scipy RegularGridInterpolator should be fine.
If you want smoother curves than what linear interpolation provides, set method to "cubic". If you also need continuous third-order derivatives in the interpolation, set the method to "quintic".

plotting countour profiles in matplotlib

I have a data composed by three 1d-arrays (X,Y,Z) and I want to create a graph like the origin contour profile (https://www.originlab.com/doc/Origin-Help/Contour-Profile), where I have a 3d data plotted in a 2d contour, where the z value is represented by the graphic colors, and two other graphs representing profiles (or slices) of my surface for specific x and y-values. My problem is how to create the profiles.
I started by creating new x and y arrays and a grid surface for z by interpolating the data I had with scipy.interpolate.griddata
and now I can create the contour plot but I don't know how to create the profiles in xz and yz planes. I found out how to this in a 3d plot by using zdir=x and zdir=y (https://matplotlib.org/3.3.1/gallery/mplot3d/contour3d_3.html) but this works only for 3d graphs. I also know that I can trace the profile in the 'xy' plane for a specific z-value with ax.contour(x, y, z, [zvalue]). I want to do something similar to the 'xz' and 'yz' planes.
The code I have is this:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from scipy.interpolate import griddata
# reading the data
path = 'data/2019_12_11_15h17m29s_TZO_1Nd_3Hz_ref_900nm_900mW.txt_output.dat'
df = pd.read_csv(path)
X = df.position
Y = df.time
Z = df.signal
# interpolating data to create a surface
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='linear')
zi = np.nan_to_num(zi)
# if I want to plot a 2D contour plot
fig = plt.figure()
ax = plt.axes()
ax.contourf(xi, yi, zi, levels=300, cmap="RdBu_r")
plt.show()
# if I want to plot a 3d surface with profiles
xi2, yi2 = np.meshgrid(xi, yi)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(xi2, yi2, zi, rstride=3, cstride=3, alpha=0.5)
cset = ax.contour(xi2, yi2, zi, zdir='x', offset=X.min()-30, cmap=cm.coolwarm, levels=10)
cset = ax.contour(xi2, yi2, zi, zdir='y', offset=Y.max()+30, cmap=cm.coolwarm, levels=10)
ax.set_xlim(X.min()-30, X.max()+30)
ax.set_ylim(Y.min()-30, Y.max()+30)
ax.set_zlim(Z.min(), Z.max())
plt.show()
# if I want to make a profile in xy plane:
fig = plt.figure()
ax = plt.axes()
ax.contour(xi, yi, zi, [1])
plt.show()
but I don't know how to create the profiles in 'xz' and 'yz' planes
I found myself a way of doing it that is not exactly what I was looking for but works perfectly. The idea is to fix a column/row of zi and plot against xi/yi to do a profile of the xz/yz plane. Varying the column/row in a for loop I got a result similar to levels of contour plot:
for i in range(0,len(zi),step):
z_xz = zi[i,:]
plt.plot(xi,z_xz)
and
for i in range(0,len(zi[0]),step):
z_xz = zi[:,i]
plt.plot(yi,z_xz)
please, let me know if you find a better solution

3D wireframe plot with 2D projections: Spatial organiszation & frequency of projection

I'm working on a 3D plot displayed by a wireframe, where 2D plots are projected on the x, y, and z surface, respectively. Below you can find a minimum example.
I have 2 questions:
With contourf, the 2D plots for every x=10, x=20,... or y=10, y=20,... are displayed on the plot walls. Is there a possibility to define for which x or y, respectively, the contour plots are displayed? For example, in case I only want to have the xz contour plot for y = 0.5 mirrored on the wall?
ADDITION: To display what I mean with "2D plots", I changed "contourf" in the code to "contour" and added the resulting plot to this question. Here you can see now the xz lines for different y values, all offset to y=90. What if I do not want to have all the lines, but only two of them for defined y values?
3D_plot_with_2D_contours
As you can see in the minimum example, the 2D contour plot optically covers the wireframe 3D plot. With increasing the transparency with alpha=0.5 I can increase the transparency of the 2D contours to at least see the wireframe, but it is still optically wrong. Is it possible to sort the objects correctly?
import matplotlib.pyplot as plt,numpy as np
import pylab as pl
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
plt.clf()
fig = plt.figure(1,figsize=(35,17),dpi=600,facecolor='w',edgecolor='k')
fig.set_size_inches(10.5,8)
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
Xnew = X + 50
Ynew = Y + 50
cset = ax.contourf(Xnew, Ynew, Z, zdir='z', offset=-100, cmap=plt.cm.coolwarm, alpha=0.5)
cset = ax.contourf(Xnew, Ynew, Z, zdir='x', offset=10, cmap=plt.cm.coolwarm, alpha=0.5)
cset = ax.contourf(Xnew, Ynew, Z, zdir='y', offset=90, cmap=plt.cm.coolwarm, alpha = 0.5)
ax.plot_wireframe(Xnew, Ynew, Z, rstride=5, cstride=5, color='black')
Z=Z-Z.min()
Z=Z/Z.max()
from scipy.ndimage.interpolation import zoom
Xall=zoom(Xnew,5)
Yall=zoom(Ynew,5)
Z=zoom(Z,5)
ax.set_xlim(10, 90)
ax.set_ylim(10, 90)
ax.set_zlim(-100, 100)
ax.tick_params(axis='z', which='major', pad=10)
ax.set_xlabel('X',labelpad=10)
ax.set_ylabel('Y',labelpad=10)
ax.set_zlabel('Z',labelpad=17)
ax.view_init(elev=35., azim=-70)
fig.tight_layout()
plt.show()
ADDITION 2: Here is the actual code I'm working with. However, the original data are hidden in the csv files which are too big to be included in the minimal example. That's why was initially replacing them by the test data. However, maybe the actual code helps nevertheless.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
import pylab as pl
from matplotlib.markers import MarkerStyle
import csv
with open("X.csv", 'r') as f:
X = list(csv.reader(f, delimiter=";"))
import numpy as np
X = np.array(X[1:], dtype=np.float)
import csv
with open("Z.csv", 'r') as f:
Z = list(csv.reader(f, delimiter=";"))
import numpy as np
Z = np.array(Z[1:], dtype=np.float)
Y = [[7,7.1,7.2,7.3,7.4,7.5,7.6,7.7,7.8,7.9,8,8.1,8.2,8.3,8.4,8.5,8.6,8.7,8.8,8.9,9]]
Xall = np.repeat(X[:],21,axis=1)
Yall = np.repeat(Y[:],30,axis=0)
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
plt.clf()
fig = plt.figure(1,figsize=(35,17),dpi=600,facecolor='w',edgecolor='k')
fig.set_size_inches(10.5,8)
ax = fig.gca(projection='3d')
cset = ax.contourf(Xall, Yall, Z, 2, zdir='x', offset=0, cmap=plt.cm.coolwarm, shade = False, edgecolor='none', alpha=0.5)
cset = ax.contourf(Xall, Yall, Z, 2, zdir='y', offset=9, cmap=plt.cm.coolwarm, shade = False, edgecolor='none', alpha=0.5)
ax.plot_wireframe(Xall, Yall, Z, rstride=1, cstride=1, color='black')
Z=Z-Z.min()
Z=Z/Z.max()
from scipy.ndimage.interpolation import zoom
Xall=zoom(Xall,5)
Yall=zoom(Yall,5)
Z=zoom(Z,5)
cset = ax.plot_surface(Xall, Yall, np.zeros_like(Z)-0,facecolors=plt.cm.coolwarm(Z),shade=False,alpha=0.5,linewidth=False)
ax.set_xlim(-0.5, 31)
ax.set_ylim(6.9, 9.1)
ax.set_zlim(0, 500)
labelsx = [item.get_text() for item in ax.get_xticklabels()]
empty_string_labelsx = ['']*len(labelsx)
ax.set_xticklabels(empty_string_labelsx)
labelsy = [item.get_text() for item in ax.get_yticklabels()]
empty_string_labelsy = ['']*len(labelsy)
ax.set_yticklabels(empty_string_labelsy)
labelsz = [item.get_text() for item in ax.get_zticklabels()]
empty_string_labelsz = ['']*len(labelsz)
ax.set_zticklabels(empty_string_labelsz)
import matplotlib.ticker as ticker
ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))
ax.yaxis.set_major_locator(ticker.MultipleLocator(0.5))
ax.yaxis.set_minor_locator(ticker.MultipleLocator(0.25))
ax.zaxis.set_major_locator(ticker.MultipleLocator(100))
ax.zaxis.set_minor_locator(ticker.MultipleLocator(50))
ax.tick_params(axis='z', which='major', pad=10)
ax.set_xlabel('X',labelpad=5,fontsize=15)
ax.set_ylabel('Y',labelpad=5,fontsize=15)
ax.set_zlabel('Z',labelpad=5,fontsize=15)
ax.view_init(elev=35., azim=-70)
fig.tight_layout()
plt.show()
Alternate possible answer.
This code demonstrates
A plot of a surface and its correponding wireframe
The creation of data and its plot of 3d lines (draped on the surface in 1) at specified values of x and y
Projections of the 3d lines (in 2) on to the frame walls
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from scipy import interpolate
import numpy as np
# use the test data for plotting
fig = plt.figure(1, figsize=(6,6), facecolor='w', edgecolor='gray')
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.1) #get 3d data at appropriate density
# create an interpolating function
# can take a long time if data is too large
f1 = interpolate.interp2d(X, Y, Z, kind='linear')
# in general, one can use a set of other X,Y,Z that cover a surface
# preferably, (X,Y) are in grid arrangement
# make up a new set of 3d data to plot
# ranges of x1, and y1 will be inside (X,Y) of the data obtained above
# related grid, x1g,y1g,z1g will be obtained from meshgrid and the interpolated function
x1 = np.linspace(-15,15,10)
y1 = np.linspace(-15,15,10)
x1g, y1g = np.meshgrid(x1, y1)
z1g = f1(x1, y1) #dont use (x1g, y1g)
# prep data for 3d line on the surface (X,Y,Z) at x=7.5
n = 12
x_pf = 7.5
x5 = x_pf*np.ones(n)
y5 = np.linspace(-15, 15, n)
z5 = f1(x_pf, y5)
# x5,y5,z5 can be used to plot 3d line on the surface (X,Y,Z)
# prep data for 3d line on the surface (X,Y,Z) at y=6
y_pf = 6
x6 = np.linspace(-15, 15, n)
y6 = x_pf*np.ones(n)
z6 = f1(x6, y_pf)
# x6,y6,z6 can be used to plot 3d line on the surface (X,Y,Z)
ax = fig.gca(projection='3d')
ax.plot_surface(x1g, y1g, z1g, alpha=0.25)
ax.plot_wireframe(x1g, y1g, z1g, rstride=2, cstride=2, color='black', zorder=10, alpha=1, lw=0.8)
# 3D lines that follow the surface
ax.plot(x5,y5,z5.flatten(), color='red', lw=4)
ax.plot(x6,y6,z6.flatten(), color='green', lw=4)
# projections of 3d curves
# project red and green lines to the walls
ax.plot(-15*np.ones(len(y5)), y5, z5.flatten(), color='red', lw=4, linestyle=':', alpha=0.6)
ax.plot(x6, 15*np.ones(len(x6)), z6.flatten(), color='green', lw=4, linestyle=':', alpha=0.6)
# projections on other sides (become vertical lines)
# change to if True, to plot these
if False:
ax.plot(x5, 15*np.ones(len(x5)), z5.flatten(), color='red', lw=4, alpha=0.3)
ax.plot(-15*np.ones(len(x6)), y6, z6.flatten(), color='green', lw=4, alpha=0.3)
ax.set_title("Projections of 3D lines")
# set limits
ax.set_xlim(-15, 15.5)
ax.set_ylim(-15.5, 15)
plt.show();
(Answer to question 1) To plot the intersections between the surface and the specified planes (y=-20, and y=20), one need to find what Y[?]=-20 and 20. By inspection, I found that Y[100]=20, Y[20]=-20.
The relevant code to plot the lines of intersection:
# By inspection, Y[100]=20, Y[20]=-20
ax.plot3D(X[100], Y[100], Z[100], color='red', lw=6) # line-1 at y=20
ax.plot3D(X[20], Y[20], Z[20], color='green', lw=6) # line-2 at y=-20
# Project them on Z=-100 plane
ax.plot3D(X[100], Y[100], -100, color='red', lw=3) # projection of Line-1
ax.plot3D(X[20], Y[20], -100, color='green', lw=3) # projection of Line-2
The output plot:
(Answer to question 2) To get better plot with the wireframe standout from the surface plot. The surface plot must be partially transparent, which is achieved by setting option alpha=0.6. The relevant code follows.
Z1 = Z-Z.min()
Z1 = Z1/Z.max()
Xall = zoom(X,3)
Yall = zoom(Y,3)
Zz = zoom(Z1, 3)
surf = ax.plot_surface(Xall, Yall, Zz, rstride=10, cstride=10,
facecolors = cm.jet(Zz/np.amax(Zz)),
linewidth=0, antialiased=True,
alpha= 0.6)
# Wireframe
ax.plot_wireframe(X, Y, Z, rstride=5, cstride=5, color='black', alpha=1, lw=0.8)
The plot is:

Matplotlib 2d Plot on Faces of 3d Plot

I am producing plots of a spacecraft's trajectory at a specific point in its orbit.
I have a piece of code which produces a 3d line plot in 3dMatplotlib (a part of mycode and figure is shown here (I have drastically reduced the number of points within X,Y,Z to ~20 per array to make it easier to simply copy and paste as the principle is the same):
#
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
from numpy import *
XdS=[14.54156005, 14.53922242, 14.53688586, 14.53454823, 14.5322106 , 14.52987297, 14.52753426, 14.52519555, 14.52285792, 14.52051922, 14.51818051, 14.51584073, 14.51350095, 14.51116117, 14.5088214 , 14.50648162, 14.50414076, 14.50179991, 14.49945906, 14.49711821]
YdS=[31.13035144, 31.12920087, 31.12805245, 31.12690188, 31.12575131, 31.12460073, 31.12345016, 31.12229745, 31.12114473, 31.11999201, 31.1188393 , 31.11768443, 31.11652957, 31.11537471, 31.11421984, 31.11306283, 31.11190582, 31.11074882, 31.10959181, 31.1084348]
ZdS=[3.94109446, 3.94060316, 3.94011186, 3.93962083, 3.93912926, 3.93863796, 3.93814639, 3.93765482, 3.93716325, 3.93667169, 3.93617985, 3.93568828, 3.93519618, 3.93470434, 3.9342125 , 3.9337204 , 3.93322829, 3.93273592, 3.93224382, 3.93175144]
fig=plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(XdS,YdS,ZdS,c='black',linewidth=2)
ax.set_xlabel('XKSM (Saturn Radii)')
ax.set_ylabel('YKSM (Saturn Radii)')
ax.set_zlabel('ZKSM (Saturn Radii)')
plt.show()
#
What I want to do is be able to plot the 2d plots X vs Y, X vs Z, and Y vs Z on the edges/planes of this plot i.e. show what the 3d trajectory looks like looking at it in the 3 2d planes and display them at each axis of the current plot. (It isn’t actually as complicated as it might sound, as I already have the X,Y,Z, values for the trajectory). Here I found a similar example which achieves this, however utilising all 3d plot functions, available at: http://matplotlib.org/1.3.1/examples/mplot3d/contour3d_demo3.html : If you check out check out the link it will show the type of image i am trying to achieve.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)
plt.show()
This is in theory exactly what I need, in the way it takes sort of a planar view of the 3d situation. However I cannot implement a 2d line plot on a 3d axis nor can I use the offset command in a 2d plot (getting the error: TypeError: There is no line property "offset").
Is there a 2d equivalent to the 3d “offset” command and Is it possible to plot the 2d values on the planes of the 3d plot as I desire? Also is there a way to plot 2d lines having initialised a 3d projection? Can anyone offer any ideas/point me in any direction in general to help me achieve this?
My sincere thanks in advance and apologies if any part of this post is out of order, this is my first one!
Try this:
xmin = min(XdS)
ymax = max(YdS)
zmin = min(ZdS)
length_of_array = len(XdS)
xmin_array = [xmin] * length_of_array
ymax_array = [ymax] * length_of_array
zmin_array = [zmin] * length_of_array
fig=plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(XdS,YdS,ZdS,zdir='z', c='r')
ax.plot(XdS,YdS,zmin_array, zdir='z', c='g')
ax.plot(xmin_array, YdS, ZdS, 'y')
ax.plot(XdS,ymax_array,ZdS,'b')
ax.set_xlabel('XKSM (Saturn Radii)')
ax.set_ylabel('YKSM (Saturn Radii)')
ax.set_zlabel('ZKSM (Saturn Radii)')
plt.show()

Adding y=x to a matplotlib scatter plot if I haven't kept track of all the data points that went in

Here's some code that does scatter plot of a number of different series using matplotlib and then adds the line y=x:
import numpy as np, matplotlib.pyplot as plt, matplotlib.cm as cm, pylab
nseries = 10
colors = cm.rainbow(np.linspace(0, 1, nseries))
all_x = []
all_y = []
for i in range(nseries):
x = np.random.random(12)+i/10.0
y = np.random.random(12)+i/5.0
plt.scatter(x, y, color=colors[i])
all_x.extend(x)
all_y.extend(y)
# Could I somehow do the next part (add identity_line) if I haven't been keeping track of all the x and y values I've seen?
identity_line = np.linspace(max(min(all_x), min(all_y)),
min(max(all_x), max(all_y)))
plt.plot(identity_line, identity_line, color="black", linestyle="dashed", linewidth=3.0)
plt.show()
In order to achieve this I've had to keep track of all the x and y values that went into the scatter plot so that I know where identity_line should start and end. Is there a way I can get y=x to show up even if I don't have a list of all the points that I plotted? I would think that something in matplotlib can give me a list of all the points after the fact, but I haven't been able to figure out how to get that list.
You don't need to know anything about your data per se. You can get away with what your matplotlib Axes object will tell you about the data.
See below:
import numpy as np
import matplotlib.pyplot as plt
# random data
N = 37
x = np.random.normal(loc=3.5, scale=1.25, size=N)
y = np.random.normal(loc=3.4, scale=1.5, size=N)
c = x**2 + y**2
# now sort it just to make it look like it's related
x.sort()
y.sort()
fig, ax = plt.subplots()
ax.scatter(x, y, s=25, c=c, cmap=plt.cm.coolwarm, zorder=10)
Here's the good part:
lims = [
np.min([ax.get_xlim(), ax.get_ylim()]), # min of both axes
np.max([ax.get_xlim(), ax.get_ylim()]), # max of both axes
]
# now plot both limits against eachother
ax.plot(lims, lims, 'k-', alpha=0.75, zorder=0)
ax.set_aspect('equal')
ax.set_xlim(lims)
ax.set_ylim(lims)
fig.savefig('/Users/paul/Desktop/so.png', dpi=300)
Et voilà
In one line:
ax.plot([0,1],[0,1], transform=ax.transAxes)
No need to modify the xlim or ylim.
Starting with matplotlib 3.3 this has been made very simple with the axline method which only needs a point and a slope. To plot x=y:
ax.axline((0, 0), slope=1)
You don't need to look at your data to use this because the point you specify (i.e. here (0,0)) doesn't actually need to be in your data or plotting range.
If you set scalex and scaley to False, it saves a bit of bookkeeping. This is what I have been using lately to overlay y=x:
xpoints = ypoints = plt.xlim()
plt.plot(xpoints, ypoints, linestyle='--', color='k', lw=3, scalex=False, scaley=False)
or if you've got an axis:
xpoints = ypoints = ax.get_xlim()
ax.plot(xpoints, ypoints, linestyle='--', color='k', lw=3, scalex=False, scaley=False)
Of course, this won't give you a square aspect ratio. If you care about that, go with Paul H's solution.

Categories