import matplotlib.pyplot as plt
plt.figure()
plt.xlabel('x')
plt.ylabel('y')
plt.plot([0,1],[1,0])
plt.show()
I would like to be able to resize just the plot itself, NOT the entire window, without having to physically resize it. For example, I would like to have the x axis be only 0.75 times as long as it currently is and the y-axis be only 0.5 times long. Remember, I'm just talking about the plotted part itself, not the entire window. But how?
If I understand your question correctly, what you are looking for is the GridSpec function in the matplotlib module.
you can use :
import matplotlib.pyplot as plt
def make_ticklabels_invisible(fig):
for i, ax in enumerate(fig.axes):
ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center")
for tl in ax.get_xticklabels() + ax.get_yticklabels():
tl.set_visible(False)
plt.figure(0)
ax1 = plt.subplot2grid((3,3), (0,0), colspan=3)
ax2 = plt.subplot2grid((3,3), (1,0), colspan=2)
ax3 = plt.subplot2grid((3,3), (1, 2), rowspan=2)
ax4 = plt.subplot2grid((3,3), (2, 0))
ax5 = plt.subplot2grid((3,3), (2, 1))
plt.suptitle("subplot2grid")
make_ticklabels_invisible(plt.gcf())
plt.show()
which will return us the following example :
for further information you can visit this link
Related
Just wandering - how can one obtain the size of a subplot (axes?) in Matplotlib?
If I do Ctrl-F "size" in https://matplotlib.org/3.1.1/api/axes_api.html - there is only one match, in context: "... with varying marker size and/or ...", so it does not really tell me how to find the size of the axes.
Say, I have the same code as in Interactively resize figure and toggle plot visibility in Matplotlib?
#!/usr/bin/env python3
import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt
import numpy as np
default_size_inch = (9, 6)
showThird = False
def onpress(event):
global fig, ax1, ax2, ax3, showThird
if event.key == 'x':
showThird = not showThird
if showThird:
fig.set_size_inches(default_size_inch[0]+3, default_size_inch[1], forward=True)
plt.subplots_adjust(right=0.85) # leave a bit of space on the right
ax3.set_visible(True)
ax3.set_axis_on()
else:
fig.set_size_inches(default_size_inch[0], default_size_inch[1], forward=True)
plt.subplots_adjust(right=0.9) # default
ax3.set_visible(False)
ax3.set_axis_off()
fig.canvas.draw()
def main():
global fig, ax1, ax2, ax3
xdata = np.arange(0, 101, 1) # 0 to 100, both included
ydata1 = np.sin(0.01*xdata*np.pi/2)
ydata2 = 10*np.sin(0.01*xdata*np.pi/4)
fig = plt.figure(figsize=default_size_inch, dpi=120)
ax1 = plt.subplot2grid((3,3), (0,0), colspan=2, rowspan=2)
ax2 = plt.subplot2grid((3,3), (2,0), colspan=2, sharex=ax1)
ax3 = plt.subplot2grid((3,3), (0,2), rowspan=3)
ax3.set_visible(False)
ax3.set_axis_off()
ax1.plot(xdata, ydata1, color="Red")
ax2.plot(xdata, ydata2, color="Khaki")
fig.canvas.mpl_connect('key_press_event', lambda event: onpress(event))
plt.show()
# ENTRY POINT
if __name__ == '__main__':
main()
How do I find the size of the subplots represented by ax1 and ax2 axes?
For the full explanation of how bbox works refer to here. Each of your axes object fits in a bounding box. All you need to do is to get the height and width of your axis bounding box.
ax_h, ax_w = ax.bbox.height, ax.bbox.width
You can transform to figure coordinates by using bbox.transformed method. For example:
ax_h = ax.bbox.transformed(fig.gca().transAxes).height
I have the following code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
arr = np.random.randint(0, 100, (2, 3, 4))
fig, ax = plt.subplots(1, 1)
pax = ax.imshow(arr, vmin=0, vmax=100)
cbar_kws=dict(ticks=(0, 100))
cbar_txt='arb. units'
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
cbar = ax.figure.colorbar(pax, cax=cax, **dict(cbar_kws))
# cbar = ax.figure.colorbar(plot, ax=ax, **dict(cbar_kws))
if cbar_txt is not None:
only_extremes = 'ticks' in cbar_kws and len(cbar_kws['ticks']) == 2
if only_extremes:
cbar.ax.text(
2.0, 0.5, cbar_txt, fontsize='medium', rotation=90,
va='center', ha='left')
else:
cbar.set_label(cbar_txt)
plt.tight_layout()
plt.show()
This works fine for Matplotlib 2.2.3 where I get a text in the middle of the colorbar (on the right):
But does not work the same way for Matplotlib 3.0.1, where the text gets rendered at the bottom of the colorbar:
Why? Any suggestion for obtaining the same behavior with both versions?
How
Using cbar.ax.text seems to be a workaround for some other problem. The recommended way to set a label to the colorbar is either via the colorbar call itself, or via cbar.set_label("label").
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
arr = np.random.randint(0, 100, (2, 3))
fig, ax = plt.subplots(1, 1)
pax = ax.imshow(arr, vmin=0, vmax=100)
cbar_kws=dict(ticks=(0, 100))
cbar_txt='arb. units'
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
cbar = ax.figure.colorbar(pax, cax=cax, **dict(cbar_kws))
cbar.set_label(cbar_txt, labelpad=-12)
plt.tight_layout()
plt.show()
The result is the same in matplotlib 2.2.3 and 3.0.1:
To have the label distance independent of the length of the colorbar labels you may label the left side of the colorbar and shift the label even more.
cbar.set_label(cbar_txt, labelpad=-36)
cbar.ax.yaxis.set_label_position("left")
Finally, you may indeed use a text on the axes, but position it in axes coordinates instead of data coordinates,
cbar.ax.text(2, 0.5, cbar_txt, fontsize='medium', rotation=90,
va='center', ha='left', transform=cbar.ax.transAxes)
Why
As to why cbar.ax.text works differently between the versions: The internal units of the colorbar have changed. This shouldn't affect any external application, but makes it easier to apply different locators to colorbars. In fact it has become more consistent. E.g. if the colorbar range is 0 to 100, and you place a text at y=0.5, it'll appear very close to 0.
Why not use the label directly? Edit: didn't see answer below. See for better explanation.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
arr = np.random.randint(0, 100, (2, 3, 4))
fig, ax = plt.subplots(1, 1)
pax = ax.imshow(arr, vmin=0, vmax=100)
cbar_txt='arb. units'
cbar_kws=dict(ticks=(0, 100))
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
cbar = ax.figure.colorbar(pax, cax=cax, **dict(cbar_kws))
cbar.set_label(cbar_txt, size = 20)
cbar.ax.tick_params(labelsize = 10)
plt.tight_layout()
plt.show()
I'm trying to create a figure with a number of non-uniform subplots. I would like to be able to create the plots using an iterable index so that I do not have to create each plot individually.
I can create a series of uniform subplots using fig, ax = plt.subplots(5) where I can plot to the various axes using ax[i].
fig, ax = plt.subplots(5)
Going forward I can plot to each plot using ax[i] using ax[0].plt etc.
However I would like to be able to create a series of plots that looks like:
gridsize = (10,3)
fig = plt.figure(figsize=(5,3))
ax0 = plt.subplot2grid(gridsize, (0, 0), colspan=3, rowspan=1)
for i in range(1,5):
ax1 = plt.subplot2grid(gridsize, (i, 0), colspan=2, rowspan=1)
ax2 = plt.subplot2grid(gridsize, (i, 2), colspan=2, rowspan=1)
where I can call each plot using ax[i] as above.
Does anyone have any ideas? Thanks.
You may append the axes to a list from which to index the respective item or over which to iterate.
import numpy as np
import matplotlib.pyplot as plt
gridsize = (10,3)
fig = plt.figure(figsize=(5,3))
ax0 = plt.subplot2grid(gridsize, (0, 0), colspan=3, rowspan=1)
ax = [ax0]
for i in range(1,5):
ax.append(plt.subplot2grid(gridsize, (i, 0), colspan=2, rowspan=1))
ax.append(plt.subplot2grid(gridsize, (i, 2), colspan=2, rowspan=1))
## Now plot to those axes:
for i in range(2*4+1):
ax[i].plot(np.arange(14),np.random.randn(14))
for axi in ax:
axi.plot(np.arange(14),np.random.randn(14))
plt.show()
I am new to python and having some difficulties with plotting using pyplot. My goal is to plot a grid of plots in-line (%pylab inline) in Juypter Notebook.
I programmed a function plot_CV which plots cross-validation erorr over the degree of polynomial of some x where across plots the degree of penalization (lambda) is supposed to vary. Ultimately there are 10 elements in lambda and they are controlled by the first argument in plot_CV. So
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1 = plot_CV(1,CV_ve=CV_ve)
Gives
Now I think I have to use add_subplot to create a grid of plots as in
fig = plt.figure()
ax1 = fig.add_subplot(2,2,1)
ax1 = plot_CV(1,CV_ve=CV_ve)
ax2 = fig.add_subplot(2,2,2)
ax2 = plot_CV(2,CV_ve=CV_ve)
ax3 = fig.add_subplot(2,2,3)
ax3 = plot_CV(3,CV_ve=CV_ve)
ax4 = fig.add_subplot(2,2,4)
ax4 = plot_CV(4,CV_ve=CV_ve)
plt.show()
If I continue this, however, then the plots get smaller and smaller and start to overlap on the x and y labels. Here a picture with a 3 by 3 plot.
Is there a way to space the plots evenly, so that they do not overlap and make better use of the horizontal and vertical in-line space in Jupyter Notebook? To illustrate this point here a screenshot from jupyter:
Final note: I still need to add a title or annotation with the current level of lambda used in plot_CV.
Edit: Using the tight layout as suggested, gives:
Edit 2: Using the fig.set_figheight and fig.set_figwidth I could finally use the full length and heigth available.
The first suggestion to your problem would be taking a look at the "Tight Layout guide" for matplotlib.
They have an example that looks visually very similar to your situation. As well they have examples and suggestions for taking into consideration axis labels and plot titles.
Furthermore you can control the overall figure size by using Figure from the matplotlib.figure class.
Figure(figsize = (x,y))
figsize: x,y (inches)
EDIT:
Here is an example that I pulled from the matplotlib website and added in the:
fig.set_figheight(15)
fig.set_figwidth(15)
example:
import matplotlib.pyplot as plt
plt.rcParams['savefig.facecolor'] = "0.8"
def example_plot(ax, fontsize=12):
ax.plot([1, 2])
ax.locator_params(nbins=3)
ax.set_xlabel('x-label', fontsize=fontsize)
ax.set_ylabel('y-label', fontsize=fontsize)
ax.set_title('Title', fontsize=fontsize)
plt.close('all')
fig = plt.figure()
fig.set_figheight(15)
fig.set_figwidth(15)
ax1 = plt.subplot2grid((3, 3), (0, 0))
ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
plt.tight_layout()
You can achieve padding of your subplots by using tight_layout this way:
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
That way you can keep your subplots from crowding each other even further.
Have a good one!
Having an example code for a scatter plot along with their histograms
x = np.random.rand(5000,1)
y = np.random.rand(5000,1)
fig = plt.figure(figsize=(7,7))
ax = fig.add_subplot(111)
ax.scatter(x, y, facecolors='none')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
fig1 = plt.figure(figsize=(7,7))
ax1 = fig1.add_subplot(111)
ax1.hist(x, bins=25, fill = None, facecolor='none',
edgecolor='black', linewidth = 1)
fig2 = plt.figure(figsize=(7,7))
ax2 = fig2.add_subplot(111)
ax2.hist(y, bins=25 , fill = None, facecolor='none',
edgecolor='black', linewidth = 1)
What I'm wanting to do is to create this graph with the histograms attached to their respected axis almost like this example
I'm familiar with stacking and merging the x-axis
f, (ax1, ax2, ax3) = plt.subplots(3)
ax1.scatter(x, y)
ax2.hist(x, bins=25, fill = None, facecolor='none',
edgecolor='black', linewidth = 1)
ax3.hist(y, bins=25 , fill = None, facecolor='none',
edgecolor='black', linewidth = 1)
f.subplots_adjust(hspace=0)
plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False)
But I have no idea how to attach the histograms to the y axis and x axis like in the picture I posted above, and on top of that, how to vary the size of the graphs (ie make the scatter plot larger and the histograms smaller in comparison)
Seaborn is the way to go for quick statistical plots. But if you want to avoid another dependency you can use subplot2grid to place the subplots and the keywords sharex and sharey to make sure the axes are synchronized.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.randn(100)
y = np.random.randn(100)
scatter_axes = plt.subplot2grid((3, 3), (1, 0), rowspan=2, colspan=2)
x_hist_axes = plt.subplot2grid((3, 3), (0, 0), colspan=2,
sharex=scatter_axes)
y_hist_axes = plt.subplot2grid((3, 3), (1, 2), rowspan=2,
sharey=scatter_axes)
scatter_axes.plot(x, y, '.')
x_hist_axes.hist(x)
y_hist_axes.hist(y, orientation='horizontal')
You should always look at the matplotlib gallery before asking how to plot something, chances are that it will save you a few keystrokes -- I mean you won't have to ask. There are actually two plots like this in the gallery. Unfortunately the code is old and does not take advantage of subplot2grid, the first one uses rectangles and the second one uses axes_grid, which is a somewhat weird beast. That's why I posted this answer.
I think it's hard to do this solely with matplotlib but you can use seaborn which has jointplot function.
import numpy as np
import pandas as pd
import seaborn as sns
sns.set(color_codes=True)
x = np.random.rand(1000,1)
y = np.random.rand(1000,1)
data = np.column_stack((x,y))
df = pd.DataFrame(data, columns=["x", "y"])
sns.jointplot(x="x", y="y", data=df);