Stacked 2D plots with interconnections in Matplotlib - python
I need to visualize some complex multivariate datasets and the preferrable choice is to use a modification of parallel axis visualization, using stacked 2D plots, where each plot maps a degree of freedom/model parameter and data points belonging to the same data sets should be interconnected across different plots. I am attaching a conceptual sketch. How could I implement it in matplotlib?
To have a rough idea, this could be a possible solution in matplotlib using Axes3D
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, PathPatch
import mpl_toolkits.mplot3d.art3d as art3d
x = np.array([1,2,3])
y = np.array([2,3,1])
z = np.array([1,1,1])
fig = plt.figure(figsize=(6,6))
ax = fig.add_axes([0,0,1,1], projection='3d')
#plot the points
ax.scatter(x,y,z*0.4, c="r", facecolor="r", s=60)
ax.scatter(y,x,z*0.9, c="b", facecolor="b", s=60)
ax.scatter(x,y,z*1.6, c="g", facecolor="g", s=60)
#plot connection lines
ax.plot([x[0],y[0],x[0]],[y[0],x[0],y[0]],[0.4,0.9,1.6], color="k")
ax.plot([x[2],y[2],x[2]],[y[2],x[2],y[2]],[0.4,0.9,1.6], color="k")
#plot planes
p = Rectangle((0,0), 4,4, color="r", alpha=0.2)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0.4, zdir="z")
p = Rectangle((0,0), 4,4, color="b", alpha=0.2)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0.9, zdir="z")
p = Rectangle((0,0), 4,4, color="g", alpha=0.2)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=1.6, zdir="z")
ax.set_aspect('equal')
ax.view_init(13,-63)
ax.set_xlim3d([0,4])
ax.set_ylim3d([0,4])
ax.set_zlim3d([0,2])
plt.savefig(__file__+".png")
plt.show()
Update
Creating three different axes is possible. One has to add the axes and make the upper ones transparent (ax2.patch.set_alpha(0.)). Then the grid has to be turned off (ax.grid(False)) and the panes and lines that we don't need set invisible.
However, I have no clue how to draw a connection with between the axes. The 2D approach of matplotlib.patches.ConnectionPatch does not work for 3D axes.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import mpl_toolkits.mplot3d.art3d as art3d
x = np.array([1,2,3])
y = np.array([2,3,1])
z = np.array([0,0,0])
fig = plt.figure(figsize=(6,6))
ax = fig.add_axes([0,0,1,1], projection='3d')
ax2 = fig.add_axes([0.0,0.24,1,1], projection='3d')
ax2.patch.set_alpha(0.)
ax3 = fig.add_axes([0.0,0.48,1,1], projection='3d')
ax3.patch.set_alpha(0.)
#plot the points
ax.scatter(x,y,z, c="r", facecolor="r", s=60)
ax2.scatter(y*4,x*4,z, c="b", facecolor="b", s=60)
ax3.scatter(x*100,y*100,z, c="g", facecolor="g", s=60)
#plot connection lines
#ax.plot([x[0],y[0],x[0]],[y[0],x[0],y[0]],[0.4,0.9,1.6], color="k")
#ax.plot([x[2],y[2],x[2]],[y[2],x[2],y[2]],[0.4,0.9,1.6], color="k")
#plot planes
p = Rectangle((0,0), 4,4, color="r", alpha=0.2)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
p = Rectangle((0,0), 16,16, color="b", alpha=0.2)
ax2.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
p = Rectangle((0,0), 400,400, color="g", alpha=0.2)
ax3.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
ax.set_aspect('equal')
ax2.set_aspect('equal')
ax3.set_aspect('equal')
ax.view_init(13,-63)
ax2.view_init(10,-63)
ax3.view_init(8,-63)
ax.set_xlim3d([0,4])
ax.set_ylim3d([0,4])
ax.set_zlim3d([0,2])
ax2.set_xlim3d([0,16])
ax2.set_ylim3d([0,16])
ax2.set_zlim3d([0,2])
ax3.set_xlim3d([0,400])
ax3.set_ylim3d([0,400])
ax3.set_zlim3d([0,2])
ax.grid(False)
ax2.grid(False)
ax3.grid(False)
def axinvisible(ax):
for zax in (ax.w_zaxis, ax.w_xaxis, ax.w_yaxis):
zax.pane.set_visible(False)
if zax == ax.w_zaxis:
zax.line.set_visible(False)
for ll in zax.get_ticklines()+zax.get_ticklabels():
ll.set_visible(False)
axinvisible(ax)
axinvisible(ax2)
axinvisible(ax3)
# setting a ConnectionPatch does NOT work
from matplotlib.patches import ConnectionPatch
con = ConnectionPatch(xyA=(2,2), xyB=(2,2),
coordsA='data', coordsB='data',
axesA=ax, axesB=ax2,
arrowstyle='->', clip_on=True)
ax2.add_artist(con) # artist is not shown :-(
plt.show()
A solution could be based on matplotlib's 3D capabilities. You can use Axes3D.plot_surface to plot the axes, and user scatter and line plots for the rest.
Related
How can I plot a heat map contour with x, y coordinates and intensity?
I am trying to plot a heat map contour graph like the following: https://i.stack.imgur.com/XrCOe.png It uses a 6x5 grid for the x and y coordinates. I then have probability values to plot at each of the 30 points. How can I do this? edit: import matplotlib.pyplot as plt import numpy as np grid = np.zeros((5,5)) grid[0,0]=0.9189 grid[1,0]=0.0767 grid[2,0]=0.01459 grid[3,0]=0.1157 grid[4,0]=0.207 heatmap = plt.imshow(grid, cmap='jet', interpolation='lanczos') plt.grid(which='major', axis='both', linestyle='-', color='k', linewidth=1) x=[1,2,3,4,5] y=[1,2,3,4,5] plt.xticks(range(0,5),x) plt.yticks(range(0,5),y) plt.colorbar(heatmap) plt.show() https://i.stack.imgur.com/kzl0b.png
Tell Matplotlib to interpret your grid as an image with interpolation other than the default nearest: import matplotlib.pyplot as plt import numpy as np grid = np.random.uniform(0, 1, (5, 6)) heatmap = plt.imshow(grid, cmap='jet', interpolation='lanczos') plt.grid(which='major', axis='both', linestyle='-', color='k', linewidth=1) plt.colorbar(heatmap) plt.show() The output is e.g.
python - how do I fix interpolate grid origin issues in matplotlib?
I have a data set with a small sample size of data. For example: My code looks something like this: import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy.interpolate import Rbf df=pd.read_csv('test.csv') df.head() extent = x_extent = x_min, x_max, y_min, y_max = [df["X"].min()-1000, df["X"].max()+1000, df["Y"].min()-1000, df["Y"].min()+1000] grid_x, grid_y = np.mgrid[x_min:x_max:100, y_min:y_max:100] rbfi=Rbf(df["X"], df["Y"], df["Total"]) di=rbfi(grid_x, grid_y) plt.scatter(grid_x, grid_y, s=10) plt.figure(figsize=(15,15)) plt.imshow(di.T, origin="lower", extent=extent) c2 = plt.scatter(df["X"], df["Y"], s=60, c=df["Total"], edgecolor='#ffffff66') plt.colorbar(c2, shrink=0.6) plt.show() the result: The result is a scatter plot of my points that appear to be in the correct place, but the interpolated grid is not covering the scatter points. So I think this has something to do with my origin not being correct, but I don't know how to fix this.
Two approaches here, one with a Delaunay triangulation, the other using the Radial Basis Function. Snippet and figure below. import numpy as np import matplotlib.pyplot as plt from matplotlib.tri import Triangulation from scipy.interpolate import Rbf rng = np.random.default_rng() X = rng.random(size=(15)) Y = rng.random(size=(15)) Total = rng.random(size=(15)) fig, (ax, bx) = plt.subplots(nrows=1, ncols=2, num=0, figsize=(16, 8)) tri = Triangulation(X, Y) tctrf = ax.tricontourf(tri, Total) gridY, gridX = np.mgrid[np.amin(Y):np.amax(Y):100 * 1j, np.amin(X):np.amax(X):100 * 1j] rbfi = Rbf(X, Y, Total, function='linear') iTotal = rbfi(gridX, gridY) bx.contourf(gridX, gridY, iTotal) scat = ax.scatter(X, Y, s=60, c=Total, edgecolor='black') fig.colorbar(scat, ax=ax) scat = bx.scatter(X, Y, s=60, c=Total, edgecolor='black') fig.colorbar(scat, ax=bx) ax.set_aspect('equal') bx.set_aspect('equal') fig.tight_layout() fig.savefig('so.png') plt.show()
plotting single 3D point on top of plot_surface in python matplotlib
I have some code to plot 3D surfaces in Python using matplotlib: import math import numpy as np import matplotlib.pyplot as plt from pylab import meshgrid,cm,imshow,contour,clabel,colorbar,axis from mpl_toolkits.mplot3d import Axes3D from matplotlib.ticker import LinearLocator, FormatStrFormatter import seaborn as sns sns.set(style="white") def surface_map(func, xmin=0, xmax=1, ymin=0, ymax=1, step_size=0.05, maxz=25000): X, Y = meshgrid( np.arange(xmin, xmax, step_size), np.arange(ymin, ymax, step_size)) Z = np.zeros(X.shape) for i in range(X.shape[0]): for j in range(X.shape[1]): Z[i, j] = min(func(X[i, j], Y[i, j]), maxz) return X, Y, Z def plot_surface(X, Y, Z, xlabel, ylabel, zlabel, title, point=None, size=25): fig = plt.figure() ax = fig.gca(projection='3d') surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, vmin=0, vmax=20*1000, cmap=cm.RdBu, linewidth=0, antialiased=True) ax.zaxis.set_major_locator(LinearLocator(10)) ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f')) ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) ax.set_zlabel(zlabel) ax.set_title(title) fig.colorbar(surf, shrink=0.5, aspect=5) if point: ax.hold(True) func, fpr, recall = point ax.scatter([fpr], [recall], [ func(fpr, recall) ], s=size, c='b', marker='.', zorder=10) plt.show() And then I call it like so: # create mesh R, FPR, FuncValue = surface_map(my_function, xmin=0, xmax=1, ymin=0, ymax=1, step_size=0.05, maxz=20*1000) # plot it plot_surface(R, FPR, FuncValue, xlabel="Recall", ylabel="FPR", zlabel="Function Value", title="Recall Settings Payout Function", point=(my_function, 0.5, 0.5)) I'm setting ax.scatter to use large marker sizes and a high zorder, but no point gets drawn on the surface when the plot gets rendered. What am I missing?
The point you are looking for is there, but hidden "inside" the surface. This is a common problem in matplotlib. I see two options here: Make the surface plot semitransparent, i.e. use alpha=.8 or similar. Use plot instead of scatter.
matplotlib 3D surface - gaps / holes in surface
A grid is interpolated with scipy's griddata() and contains values and NaNs. However, when the grid is plotted with mplot3d's plot_surface() there are gaps in the surface (see upper plot). The lower the view height, the more of such gaps are rendered. When the grid is plotted in 2D with imshow() there are no gaps (see lower plot). Comparison plot_surface and imshow Here is a close-up: I couldn't find an answer to this problem and I am wondering whether this is a known issue. This small example reproduces the problem: (data.txt) import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D Z = np.loadtxt('data.txt') X = np.linspace(0,3,301) Y = np.linspace(0,3,301) X = np.array([X,]*(301)).transpose() Y = np.array([Y,]*(301)) fig = plt.figure(figsize=(15,15), dpi=100) ax = fig.add_subplot(2, 1, 1, projection='3d') plt.hold(True) ax.view_init(40,300) surf = ax.plot_surface(X, Y, Z, cmap='jet', rstride=1, cstride=1, antialiased=False, shade=False, alpha=1.0, linewidth=0, vmin=0.25, vmax=0.35); ax.invert_yaxis() ax.dist = 11 ax = fig.add_subplot(2, 1, 2) plt.hold(True) plt.imshow(Z, cmap='jet', vmin=0.25, vmax=0.35, origin='lower'); plt.show()
With MatPlotLib, how do I apply autoscaled axes from one graph to a separate graph?
So I have a dataset I want to plot. In this case, I want to plot all the data on the same graph, and then graph each point in the set on its own graph, but keep the axis scale/limits the same for each graph. So what I need to do is find the values of the autoscaled axis limits that were set for the full set of data, and apply those limits to the graph for each individual points. I am and have been reading the mpl docs to see if theres any kind of function I can use that will return the axis limits values, but I haven't found anything so far. Im using Python 3.4 with matplotlib Thanks, evamvid
Although it is possible to find the limits with xmin, xmax = ax.get_xlim() ymin, ymax = ax.get_ylim() and set them on another axes with ax2.set_xlim(xmin, xmax) ax2.set_ylim(ymin, ymax) it might be easier to use plt.subplots with sharex=True and sharey=True: import numpy as np import matplotlib.pyplot as plt np.random.seed(2015) N = 5 x, y = np.random.randint(100, size=(2,N)) fig, axs = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) colors = np.linspace(0, 1, N) axs[0,0].scatter(x,y, s=200, c=colors) for i, ax in enumerate(axs.ravel()[1:]): ax.scatter(x[i], y[i], s=200, c=colors[i], vmin=0, vmax=1) plt.show() Another option is to pass an axes to sharex and sharey: ax3 = subplot(313, sharex=ax1, sharey=ax1) For example, import numpy as np import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec import itertools as IT np.random.seed(2015) N = 6 x, y = np.random.randint(100, size=(2,N)) colors = np.linspace(0, 1, N) gs = gridspec.GridSpec(4, 2) ax = plt.subplot(gs[0, :]) ax.scatter(x, y, s=200, c=colors) for k, coord in enumerate(IT.product(range(1,4), range(2))): i, j = coord ax = plt.subplot(gs[i, j], sharex=ax, sharey=ax) ax.scatter(x[k], y[k], s=200, c=colors[k], vmin=0, vmax=1) plt.tight_layout() plt.show()