Plotting histograms on the back planes of 3D plots in matplotlib - python

Using matplotlib, I am attempting to display the histograms of 2 sets of data simultaneously on the side walls of a 3D plot, using this Matlab code and plot from wikipedia as my guide: https://commons.wikimedia.org/wiki/File:MultivariateNormal.png
I am able to plot my raw data on the base plane and have created and plotted my Gaussian fits on the side walls using the 'zdir' kwarg.
This example is able to leverage the 'zdir' kwarg to force where the curves are plotted,
Matplotlib 2d Plot on Faces of 3d Plot
but the matplotlib documentation confirms my AttributeErrors: Unknown property zdir; hist and hist2d don't support this argument.
This example seems to be plotting bars manually on the figure
plotting 3d histogram/barplot in python matplotlib as a way around the problem.
I've tried both .hist and .hist2d with and without zdir=''.
# data is a 2D np.array defined elsewhere
# define plot limits
X = np.linspace(0, np.amax(data), 100)
Y = np.linspace(0, np.amax(data), 100)
# initialize data into x and y sets
x_data = data[:, 0]
y_data = data[:, 1]
# fit a gaussian to both sets
x_mean, x_std = norm.fit(x_data)
x_gauss = norm.pdf(X, x_mean, x_std)
y_mean, y_std = norm.fit(y_data)
y_gauss = norm.pdf(Y, y_mean, y_std)
# initialize plot
figure = plt.figure()
ax = figure.add_subplot(111, projection='3d')
# label axes
ax.set_xlabel('Delta X (um)')
ax.set_ylabel('Delta Y (um)')
ax.set_zlabel('P (X,Y)')
# plot data on base plane
ax.scatter3D(x_data, y_data, zdir='z', zs=0.0, c='k', marker='.')
# plot histograms on walls
ax.hist((x_data, x_gauss), bins=30) #these 2 lines
ax.hist((y_data, y_gauss), bins=30) #are where I'm looking for help
# plot gaussians on walls
ax.plot3D(X, x_gauss, zdir='y', zs=np.amax(data), c='b')
ax.plot3D(Y, y_gauss, zdir='x', zs=np.amax(data), c='g')
# show plot
plt.show()
Is there a direct match in matplotlib for the method Matlab that draws histograms on a specific plane of a 3D plot? Thank you for your help! I am very new to plotting and welcome any other idiomatic or depreciated changes you can see. I always like to see how other coders think.

Related

Adding a 2d histogram to a python cartopy plot causes the extent to be reset

I am writing a program that displays a heat map of lightning strikes over a cartopy plot. Using a scatter plot work; however when I try to implement the 2d histogram, the map becomes zoomed out all the way.
Plot before adding histogram
Plot after adding histogram
Here is the code
lon_small and lat_small are the coordinate arrays.
proj = ccrs.LambertConformal()
fig, ax = plt.subplots(figsize=(10,10),subplot_kw=dict(projection=proj))
#FEATURES
#state_borders = cfeat.NaturalEarthFeature(category='cultural', name="admin_1_states_provinces_lakes", scale = '10m', facecolor = 'none')
extent = ([-99,-92, 27, 31.3])
xynps = ax2.projection.transform_points(ccrs.PlateCarree(), lon_array, lat_array)
ax.set_extent(extent)
ax.set_extent(extent)
ax.add_feature(USCOUNTIES.with_scale('5m'), edgecolor = "gray")
ax.add_feature(state_borders, linestyle='solid', edgecolor='black')
ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False)
#Adding scatter plots
ax.scatter(-95.36, 29.76, transform = ccrs.PlateCarree(), marker='*', s = 400, color = "orange") #Houston
ax.scatter(lon_small, lat_small, transform = ccrs.PlateCarree(), marker='.', s=0.001, c = "red")
#Adding Histogram
h = ax.hist2d(xynps[:,0], xynps[:,1], bins=100, zorder=10, alpha=0.75, cmin=120)
plt.show()
I have checked online for people with a similar problem, but I can't find anything like this problem.
There's a note in the docstring of hist2d stating:
Currently hist2d calculates its own axis limits, and any limits previously set are ignored.
... so i guess the easiest way to maintain initial limits is to do something like this:
...
extent = ax.get_extent(crs=ax.projection)
ax.hist2d(...)
ax.set_extent(extent, crs=ax.projection)
...

PyPlot Scatter Plot - Logarithmic Color Scale - How To Set Color Bar Label Format

I am making a scatter plot in matplotlib with logarithmic color scaling, which is working fine, see attached plot. My problem is, I would like to have the x-tick labels on the r.h.s. of the color bar to be in float format, rather than scientific notation. Interestingly, this works only for some of the labels.
I have my data x, y for the scatter plot and the weights which specify the colors.
This is my code:
fig = plt.figure(dpi=200)
# Plot data, this is the relevant part:
sc = plt.scatter(x, y, c=weights, cmap='rainbow', s=20, alpha=0.5,
norm=mpl.colors.LogNorm(vmin=0.3, vmax=3))
cbar = fig.colorbar(sc, format='%.1f', label='$T_{IDL} / T_{Py}$') # format arg. supposed to do what I want
print(cbar.get_ticks()) # For debugging
# Plot dashed line:
xmin, xmax = plt.gca().get_xlim()
const = np.linspace(xmin, xmax, 500)
plt.plot(const, const, linestyle='--', color='black', alpha=0.3)
# Add titles and axis labels:
fig.suptitle(suptitle)
plt.title(f'{len(amp_py_cmn)} Common Flares -- Duration Ratio: Mean {np.mean(dur_ratio):.2f},'
f' St.Dev. {np.std(dur_ratio):.2f}',
fontsize=7)
plt.xlabel('$A_{Py}$')
plt.ylabel('$A_{IDL}$')
# Save figure and show:
fig.savefig(f'{savePath}/{suptitle}.pdf')
plt.show()
This is the resulting Plot:
Scatter Plot
I added the call of cbar.get_ticks() while debugging, and interestingly the output gives
[1.]
which corresponds to the only label that looks according to my wishes. So the question is, where do the other labels come from, and how can I format them?
Thanks!

continuous Colormap over Surface Plot

I'd like to create a continuous colormap with matplotlib on a 3D Surface Plot, where the color depends on the z-value of the surface. But with the "normal" plt functions the colormap fills the space between the gridpoints with the same color like shown in the picture. So there is no continuous change in color, rather there are just some colored surfaces stitched together:
x = range(0,126)
y = range(0,3)
#z is my data from the experiment
# make a grid of the x/y plane
X,Y= np.meshgrid(x,y)
# get the colormap for the graph
cmap=plt.get_cmap("RdBu")
# cmap = clr.LinearColormap.from_list('custom blue', ['#244162','#DCE6F1'], N=256)
#plot the corresponding z-value at every knot of the grid
surface = ax.plot_surface(X,Y,z, cmap = cmap, antialiased=True, edgecolor='gray' , linewidth=0.2)
m = cm.ScalarMappable(cmap=surface.cmap,norm=surface.norm)
m.set_array(z)
plt.colorbar(m)
ax.set_yticks(y)
ax.set_xticks(x[::25])
plt.show()
which looks like this:
3D-surface Plot
Do I need to interpolate the surface in between with more gridpoints, or is there a more elegant way? I'm a little lost in the documentation and syntax
Thanks in advance,
masterblibla

Change the color of the plot depending on the density (stored in an array) in line plot in matplotlib

I have a file with three columns, lets say, x y z. I need to plot x Vs y but I need to change the color of that (x,y) value depending on its density (stored in z column). I understand that I need to use color map and have to map the values of the color with the z array. I can do that via scatter plot as also shown in this post: How can I make a scatter plot colored by density in matplotlib?
But I do not need the scatter plot, I need the points to be connected, ie I need a line plot. Can it be done in line plot?
It's not possible to connect points from a scatter plot directly. But the same effect can be achieved by plotting a line behind the scatter points.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-3,6)
y = np.sin(x)
z = 0.5+np.random.rand(len(x))
fig, ax = plt.subplots()
ax.plot(x, y, color="k", marker=None, zorder=0)
sc = ax.scatter(x, y, c=z, s=100, edgecolor='',zorder=3)
plt.colorbar(sc, label="Density")
plt.show()

Colormap entire subplot

I'm having some trouble with color maps. Basically, what I would like to produce is similar to the image below.
On the bottom subplot I would like to be able to plot the relevant colour, but spanning the entire background of the subplot.i.e it would just look like a colourmap over the entire plot, with no lines or points plotted. It should still correspond to the colours shown in the scatter plot.
Is it possible to do this? what I would ideally like to do is put this background under the top subplot. ( the y scales are in diferent units)
Thanks for and help.
code for bottom scatter subplot:
x = np.arange(len(wind))
y = wind
t = y
plt.scatter(x, y, c=t)
where wind is a 1D array
You can use imshow to display your wind array. It needs to be reshaped to a 2D array, but the 'height' dimensions can be length 1. Setting the extent to the dimensions of the top axes makes it align with it.
wind = np.random.randn(100) + np.random.randn(100).cumsum() * 0.5
x = np.arange(len(wind))
y = wind
t = y
fig, ax = plt.subplots(2,1,figsize=(10,6))
ax[0].plot(x,y)
ax[1].plot(x, 100- y * 10, lw=2, c='black')
ymin, ymax = ax[1].get_ybound()
xmin, xmax = ax[1].get_xbound()
im = ax[1].imshow(y.reshape(1, y.size), extent=[xmin,xmax,ymin,ymax], interpolation='none', alpha=.5, cmap=plt.cm.RdYlGn_r)
ax[1].set_aspect(ax[0].get_aspect())
cax = fig.add_axes([.95,0.3,0.01,0.4])
cb = plt.colorbar(im, cax=cax)
cb.set_label('Y parameter [-]')
If you want to use it as a 'background' you should first plot whatever you want. Then grab the extent of the bottom plot and set it as an extent to imshow. You can also provide any colormap you want to imshow by using cmap=.

Categories