Can someone share an example to create 4 scatter hist plots as a subplot?
To clarify. I am planning to create a pdf of plots. Each page will have 4 subplots. Each subplot being the scatter histogram.
The example of creating scatter histogram seems to be this
Would there be any alternate functions to do this in fewer lines than using this scatter plot example and sub-plotting each of them ?
Using the linked example, all you need to do is increase the number of subplots.
Then for each subplot, you go through the example code to make each one a scatter histogram.
I've pasted a toy example below:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig, axes = plt.subplots(figsize=(10,10),nrows=2, ncols=2)
print(axes)
colors = ['r','b','g','m']
for row in axes:
for axScatter in row:
print()
x = np.random.randn(1000)
y = np.random.randn(1000)
# the scatter plot:
# gets color from the end ('m' will be first)
color = colors.pop()
axScatter.scatter(x, y,color = color)
axScatter.set_aspect(1.)
# create new axes on the right and on the top of the current axes
# The first argument of the new_vertical(new_horizontal) method is
# the height (width) of the axes to be created in inches.
divider = make_axes_locatable(axScatter)
axHistx = divider.append_axes("top", 1.2, pad=0.1, sharex=axScatter)
axHisty = divider.append_axes("right", 1.2, pad=0.1, sharey=axScatter)
# make some labels invisible
axHistx.xaxis.set_tick_params(labelbottom=False)
axHisty.yaxis.set_tick_params(labelleft=False)
# now determine nice limits by hand:
binwidth = 0.25
xymax = max(np.max(np.abs(x)), np.max(np.abs(y)))
lim = (int(xymax/binwidth) + 1)*binwidth
bins = np.arange(-lim, lim + binwidth, binwidth)
axHistx.hist(x, bins=bins,color=color)
axHisty.hist(y, bins=bins, orientation='horizontal',color=color)
# the xaxis of axHistx and yaxis of axHisty are shared with axScatter,
# thus there is no need to manually adjust the xlim and ylim of these
# axis.
axHistx.set_yticks([0, 50, 100])
axHisty.set_xticks([0, 50, 100])
plt.show()
Related
I'm trying to generate a linear regression plot with additional distribution curves on the X and Y axes in Python that indicate the distribution of values in each of these dimensions. See attached figure.
I know how to create the linear plot, but have not been able to find a method to generate the distribution curves to appear on the axes themselves in Python.
There is a good section of this on the matplotlib documentation, and with some modifications you can get something close-ish:
https://matplotlib.org/stable/gallery/lines_bars_and_markers/scatter_hist.html#sphx-glr-gallery-lines-bars-and-markers-scatter-hist-py
The main component that I personally think is a great learning point is matplotlib's gridspec. It allows control of where the graphs are located which allows for stronger customization.
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
# some random data
x = np.random.randn(1000)
y = np.random.randn(1000)
def scatter_hist(x, y, ax, ax_histx, ax_histy):
# no labels
ax_histx.tick_params(axis="x", labelbottom=False)
ax_histy.tick_params(axis="y", labelleft=False)
# the scatter plot:
ax.scatter(x, y)
# now determine nice limits by hand:
binwidth = 0.25
xymax = max(np.max(np.abs(x)), np.max(np.abs(y)))
lim = (int(xymax/binwidth) + 1) * binwidth
bins = np.arange(-lim, lim + binwidth, binwidth)
ax_histx.hist(x, bins=bins)
ax_histy.hist(y, bins=bins, orientation='horizontal')
# Start with a square Figure.
fig = plt.figure(figsize=(6, 6))
# Add a gridspec with two rows and two columns and a ratio of 1 to 4 between
# the size of the marginal axes and the main axes in both directions.
# Also adjust the subplot parameters for a square plot.
gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4),
left=0.1, right=0.9, bottom=0.1, top=0.9,
wspace=0.00, hspace=0.00)
# Create the Axes.
ax = fig.add_subplot(gs[1, 0])
ax_histx = fig.add_subplot(gs[0, 0], sharex=ax)
ax_histy = fig.add_subplot(gs[1, 1], sharey=ax)
# Remove Axis Lines
ax_histy.spines[['right', 'top', 'bottom']].set_visible(False)
ax_histx.spines[['right', 'top', 'left']].set_visible(False)
# Remove Ticks
ax_histy.set_xticks([])
ax_histx.set_yticks([])
# Draw the scatter plot and marginals.
scatter_hist(x, y, ax, ax_histx, ax_histy)
I am trying to create a figure with several subplots that have a common colorbar. The subplots have to have an equal aspect ratio and the colorbar has to have the same height as the subplots. However, I don't manage to get a narrow colorbar with the same height as the other subplots.
I am using this recipe to generate a colorbar with a range suitable for all subplots; hence this issue is not addressed in the MWE.
When using the axes divider recipe to attach the colorbar, the height of the subplot changes due to the aspect ratio.
Here's the MWE
from matplotlib import pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import itertools as it
import numpy as np
mean = [0, 0]
cov = [[1, 0.5],
[0.5, 4]]
n_samples = 10000
hrange = [[-5,5],[-5,5]]
bins = 20
# RANDOM DATA
Z_random = np.random.multivariate_normal(mean, cov, size=n_samples)
Z, xedges, yedges = np.histogram2d(Z_random[:,0], Z_random[:,1], bins=bins, range=hrange, normed=True)
X, Y = np.meshgrid(xedges, yedges)
# PLOT PCOLORMESHS
fig, axes = plt.subplots(2,3, subplot_kw=dict(aspect="equal"))
axes = dict(enumerate(fig.get_axes(),1))
for i,ax in axes.items():
if i==6:
break
pcm = ax.pcolormesh(X,Y,Z)
# PLOT COLORBAR
divider = make_axes_locatable(axes[6])
cax = divider.append_axes("left", size="15%", pad=0.0)
fig.colorbar(pcm, cax=cax, label=r"Colorbar label")
I can plot the colorbar over the complete subplot, in which case the height is correct, but it's much to wide to be appealing.
Does anybody have a "robust" solution, i.e. without manually fiddling around with the dimension of the subplots holding the colorbar?
Thanks in advance!
EDIT: Increased width of colorbar to emphasize that it becomes smaller in height.
If the only aim is to get the height of the colorbar correctly aligned with its horizontal neighbor, the last solution from this answer would help.
If however you also want the colorbar to be left-aligned with the plot on top of it, the solution is probably more complicated.
You may use a callback to set the position of the colorbar explicitely as follows:
from matplotlib import pyplot as plt
from matplotlib.transforms import Bbox
import numpy as np
mean = [0, 0]
cov = [[1, 0.5],
[0.5, 4]]
n_samples = 10000
hrange = [[-5,5],[-5,5]]
bins = 20
# RANDOM DATA
Z_random = np.random.multivariate_normal(mean, cov, size=n_samples)
Z, xedges, yedges = np.histogram2d(Z_random[:,0], Z_random[:,1], bins=bins, range=hrange, normed=True)
X, Y = np.meshgrid(xedges, yedges)
# PLOT PCOLORMESHS
fig, axes = plt.subplots(2,3, subplot_kw=dict(aspect="equal"))
for i,ax in enumerate(axes.flat):
if i==5:
break
pcm = ax.pcolormesh(X,Y,Z)
# PLOT COLORBAR
cax = fig.add_axes([0.6,0.01,0.1,0.4])
fig.colorbar(pcm, cax=cax, label=r"Colorbar label")
def align_cbar(cax, hax, vax):
hpos = hax.get_position()
vpos = vax.get_position()
bb = Bbox.from_extents(vpos.x0, hpos.y0, vpos.x0+vpos.width*.05,hpos.y1)
if cax.get_position() != bb:
cax.set_position(bb)
fig.canvas.draw_idle()
align_cbar(cax, axes[1,1], axes[0,2])
fig.canvas.mpl_connect("draw_event", lambda x: align_cbar(cax, axes[1,1], axes[0,2]))
plt.show()
I have a matplotlib bar chart, which bars are colored according to some rules through a colormap. I need a colorbar on the right of the main axes, so I added a new axes with
fig, (ax, ax_cbar) = plt.subplots(1,2)
and managed to draw my color bar in the ax_bar axes, while I have my data displayed in the ax axes. Now I need to reduce the width of the ax_bar, because it looks like this:
How can I do?
Using subplots will always divide your figure equally. You can manually divide up your figure in a number of ways. My preferred method is using subplot2grid.
In this example, we are setting the figure to have 1 row and 10 columns. We then set ax to be the start at row,column = (0,0) and have a width of 9 columns. Then set ax_cbar to start at (0,9) and has by default a width of 1 column.
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,6))
num_columns = 10
ax = plt.subplot2grid((1,num_columns), (0,0), colspan=num_columns-1)
ax_cbar = plt.subplot2grid((1,num_columns), (0,num_columns-1))
The ususal way to add a colorbar is by simply putting it next to the axes:
fig.colorbar(sm)
where fig is the figure and sm is the scalar mappable to which the colormap refers. In the case of the bars, you need to create this ScalarMappable yourself. Apart from that there is no need for complex creation of multiple axes.
import matplotlib.pyplot as plt
import matplotlib.colors
import numpy as np
fig , ax = plt.subplots()
x = [0,1,2,3]
y = np.array([34,40,38,50])*1e3
norm = matplotlib.colors.Normalize(30e3, 60e3)
ax.bar(x,y, color=plt.cm.plasma_r(norm(y)) )
ax.axhline(4.2e4, color="gray")
ax.text(0.02, 4.2e4, "42000", va='center', ha="left", bbox=dict(facecolor="w",alpha=1),
transform=ax.get_yaxis_transform())
sm = plt.cm.ScalarMappable(cmap=plt.cm.plasma_r, norm=norm)
sm.set_array([])
fig.colorbar(sm)
plt.show()
If you do want to create a special axes for the colorbar yourself, the easiest method would be to set the width already inside the call to subplots:
fig , (ax, cax) = plt.subplots(ncols=2, gridspec_kw={"width_ratios" : [10,1]})
and later put the colorbar to the cax axes,
fig.colorbar(sm, cax=cax)
Note that the following questions have been asked for this homework assignment already:
Point picker event_handler drawing line and displaying coordinates in matplotlib
Matplotlib's widget to select y-axis value and change barplot
Display y axis value horizontal line drawn In bar chart
How to change colors automatically once a parameter is changed
Interactively Re-color Bars in Matplotlib Bar Chart using Confidence Intervals
I want to create a plot that looks like the image below. There are two unique plots in the figure. img1 was generated using plt.imshow(), while img2 was generated using plt.plot(). The code I used to generate each of the plots is provided below
plt.clf()
plt.imshow(my_matrix)
plt.savefig("mymatrix.png")
plt.clf()
plt.plot(x,y,'o-')
plt.savefig("myplot.png")
The matrix used in img1 is 64x64. The same range for img2's x-axis (x=range(64)). Ideally, the x-axes of the two img2's align with the axes of img1.
It is important to note that the final image is reminiscent of seaborn's jointplot(), but the marginal subplots (img2) in the image below do not show distribution plots.
You can use the make_axes_locatable functionality of the mpl_toolkits.axes_grid1 to create shared axes along both directions of the central imshow plot.
Here is an example:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np; np.random.seed(0)
Z = np.random.poisson(lam=6, size=(64,64))
x = np.mean(Z, axis=0)
y = np.mean(Z, axis=1)
fig, ax = plt.subplots()
ax.imshow(Z)
# create new axes on the right and on the top of the current axes.
divider = make_axes_locatable(ax)
axtop = divider.append_axes("top", size=1.2, pad=0.3, sharex=ax)
axright = divider.append_axes("right", size=1.2, pad=0.4, sharey=ax)
#plot to the new axes
axtop.plot(np.arange(len(x)), x, marker="o", ms=1, mfc="k", mec="k")
axright.plot(y, np.arange(len(y)), marker="o", ms=1, mfc="k", mec="k")
#adjust margins
axright.margins(y=0)
axtop.margins(x=0)
plt.tight_layout()
plt.show()
The figure above is an illustration of my purpose.
It's easy to plot pie chart in MatPlotLib.
But how to draw several pie in one figure and the size of each figure depend on the value I set.
Any advices or recommandation is appreciate!
You can use subplots to place the pies into the figure. You can then use the radius argument to determine their size. As usual it helps to consult the manual.
Here is an example:
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
t = "Plot a pie chart with different sized pies all in one figure"
X = np.random.rand(12,4)*30
r = np.random.rand(12)*0.8+0.6
fig, axes= plt.subplots(3, 4)
for i, ax in enumerate(axes.flatten()):
x = X[i,:]/np.sum(X[i,:])
ax.pie(x, radius = r[i], autopct="%.1f%%", pctdistance=0.9)
ax.set_title(t.split()[i])
plt.show()
You can use add_axes to adjust the size of the axes for your plot. Also,
there is a radius parameter in the pie function which you can use to specify the radius of the pie plot. Check the code below:
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
fracs = [15, 30, 45, 10]
fig = plt.figure()
ax1 = fig.add_axes([.1, .1, .8, .8], aspect=1)
ax1.pie(fracs, labels=labels)
ax2 = fig.add_axes([.65, .65, .3, .3], aspect=1) # You can adjust the position and size of the axes for the pie plot
ax2.pie(fracs, labels=labels, radius=.8) # The radius argument can also be used to adjust the size of the pie plot
plt.show()