This is related to (or rather a follow-up) to new pythonic style for shared axes square subplots in matplotlib?.
I want to have subplots sharing one axis just like in the question linked above. However, I also want no space between the plots. This is the relevant part of my code:
f, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True)
plt.setp(ax1, aspect=1.0, adjustable='box-forced')
plt.setp(ax2, aspect=1.0, adjustable='box-forced')
# Plot 1
ax1.matshow(pixels1, interpolation="bicubic", cmap="jet")
ax1.set_xlim((0,500))
ax1.set_ylim((0,500))
# Plot 2
ax2.matshow(pixels2, interpolation="bicubic", cmap="jet")
ax2.set_xlim((0,500))
ax2.set_ylim((0,500))
f.subplots_adjust(wspace=0)
And this is the result:
If i comment out the two plt.setp() commands, I get some added white borders:
How can I make the figure look like my first result, but with axes touching like in the second result?
EDIT: The fastest way to get your result is the one described by #Benjamin Bannier, simply use
fig.subplots_adjust(wspace=0)
The alternative is to make a figure that has a width/height ratio equal to 2 (as you have two plots). This may be advisable only if you plan including the figure in a document, and you already know the columnwidth of the final document.
You can set width and height in the call to Figure(figsize=(width,height)), or as a parameter to plt.subplots(), in inches. Example:
fig, axes = plt.subplots(ncols=2, sharex=True, sharey=True,figsize=(8,4))
fig.subplots_adjust(0,0,1,1,0,0)
Screenshot:
As #Benjamin Bannier points out, as a drawback you have zero margins. Then you can play with subplot_adjust(), but you must be careful with making space in a symmetric way if you want to keep the solution simple. An example could be fig.subplots_adjust(.1,.1,.9,.9,0,0).
Related
In a previous answer it was recommended to me to use add_subplot instead of add_axes to show axes correctly, but searching the documentation I couldn't understand when and why I should use either one of these functions.
Can anyone explain the differences?
Common grounds
Both, add_axes and add_subplot add an axes to a figure. They both return a (subclass of a) matplotlib.axes.Axes object.
However, the mechanism which is used to add the axes differs substantially.
add_axes
The calling signature of add_axes is add_axes(rect), where rect is a list [x0, y0, width, height] denoting the lower left point of the new axes in figure coodinates (x0,y0) and its width and height. So the axes is positionned in absolute coordinates on the canvas. E.g.
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
places a figure in the canvas that is exactly as large as the canvas itself.
add_subplot
The calling signature of add_subplot does not directly provide the option to place the axes at a predefined position. It rather allows to specify where the axes should be situated according to a subplot grid. The usual and easiest way to specify this position is the 3 integer notation,
fig = plt.figure()
ax = fig.add_subplot(231)
In this example a new axes is created at the first position (1) on a grid of 2 rows and 3 columns. To produce only a single axes, add_subplot(111) would be used (First plot on a 1 by 1 subplot grid). (In newer matplotlib versions, add_subplot() without any arguments is possible as well.)
The advantage of this method is that matplotlib takes care of the exact positioning. By default add_subplot(111) would produce an axes positioned at [0.125,0.11,0.775,0.77] or similar, which already leaves enough space around the axes for the title and the (tick)labels. However, this position may also change depending on other elements in the plot, titles set, etc.
It can also be adjusted using pyplot.subplots_adjust(...) or pyplot.tight_layout().
In most cases, add_subplot would be the prefered method to create axes for plots on a canvas. Only in cases where exact positioning matters, add_axes might be useful.
Example
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (5,3)
fig = plt.figure()
fig.add_subplot(241)
fig.add_subplot(242)
ax = fig.add_subplot(223)
ax.set_title("subplots")
fig.add_axes([0.77,.3,.2,.6])
ax2 =fig.add_axes([0.67,.5,.2,.3])
fig.add_axes([0.6,.1,.35,.3])
ax2.set_title("random axes")
plt.tight_layout()
plt.show()
Alternative
The easiest way to obtain one or more subplots together with their handles is plt.subplots(). For one axes, use
fig, ax = plt.subplots()
or, if more subplots are needed,
fig, axes = plt.subplots(nrows=3, ncols=4)
The initial question
In the initial question an axes was placed using fig.add_axes([0,0,1,1]), such that it sits tight to the figure boundaries. The disadvantage of this is of course that ticks, ticklabels, axes labels and titles are cut off. Therefore I suggested in one of the comments to the answer to use fig.add_subplot as this will automatically allow for enough space for those elements, and, if this is not enough, can be adjusted using pyplot.subplots_adjust(...) or pyplot.tight_layout().
The answer by #ImportanceOfBeingErnest is great.
Yet in that context usually one want to generate an axes for a plot and add_axes() has too much overhead.
So one trick is, as in the answer of #ImportanceOfBeingErnest, is to use add_subplot(111).
Yet more elegant alternative and simple would be:
hAx = plt.figure(figsize = (10, 10)).gca()
If you want 3D projection you can pass any axes property. For instance the projection:
hAx = plt.figure(figsize = (16, 10)).gca(projection = '3d')
I'm trying to change the x axis for my graphs but it's only going through for one of them. My other graph has not changed at all. Here is the code:
fig, (gr0, gr1) = plt.subplots(ncols=2, constrained_layout=True, figsize = (17,7))
#gr0
gr0.plot(data['g1'])
gr0.set_title('text 1')
#gr1
gr1.plot(data['g2'])
gr1.set_title('text 2')
plt.xticks(fontsize=8, rotation=45)
plt.show()
Graphs when the code is ran:
As you can tell by the picture, only the graph on the right has the x-axis updated to where the text is rotated and clearly visible. The other one is still the same :(
The
plt.xticks(..., rotation=45)
call might feel like it applies to the whole figure,
when it's phrased that way.
But behind the scenes it's really making a gca() call
and manipulating that, which of course is gr1 at that point.
You could make a pair of xticks calls,
much as you're already doing for title.
But the fact that you asked about this plot's behavior on SO
indicates that the way it's phrased is not a good match
for clearly communicating the intent.
So let's re-phrase it slightly, avoiding that global.
labels = [
'2022-05-21',
'2022-05-25',
'2022-05-29',
]
gr0.set_xticks(labels=labels, rotation=45)
gr1.set_xticks(labels=labels, rotation=45)
Or consider moving to import seaborn.
In which case the idiom would be the somewhat simpler
gr0.grid.set_xticklabels(rotation=45)
gr1.grid.set_xticklabels(rotation=45)
You can set it per axis using ax.tick_params(labelsize=8, labelrotation=45).
ig, (gr0,gr1) = plt.subplots(ncols=2, constrained_layout=True, figsize = (17,7))
#gr0
gr0.plot(data['g1'])
gr0.set_title('text 1')
gr0.tick_params(labelsize=8, labelrotation=45)
#gr1
gr1.plot(data['g2'])
gr1.set_title('text 2')
gr1.tick_params(labelsize=8, labelrotation=45)
plt.show()
I have a couple of subplots and the data are probabilities, so should (and do) range between 0 and 1. When I plot them with a violinplot the y-axis of ax[0] extends above 1 (see pic). I know this is just because of the distribution kernel that the violinplot makes, but still it looks bad and I want the y-axes of these 2 plots to be the same. I have tried set_ylim on the left plot, but then I can't get the values (or look) to be the same as the plot on the right. Any ideas?
When creating your subplots, set the sharey parameter to True so that both plots share the same limits for the vertical axis.
[EDIT]
Since you have already tried setting sharey to True, I suggest getting the lower and upper limits ymin and ymax from the left hand side figure and passing them as arguments in set_ylim() for the right hand side figure.
1) Create your subplots:
fig, ax1 = plt.subplots(1,2, figsize = (5, 5), dpi=100)
2) Create left hand side figure here: ax[0].plot(...)
3) Get the axes limits using the get_ylim() method as detailed here: ymin, ymax = ax[0].get_ylim()
4) Create right hand side figure: ax[1].plot(...)
5) Set the axes limits of this new figure: ax[1].set_ylim(bottom=ymin, top=ymax)
I don't have subplots, but I do have probabilities, and this visual extension beyond 1.0 was frustrating to me.
If you add 'cut=0' to the sns.violinplot() call, it will truncate the kernel at the range of your data exactly.
I found the answer here:
How to better fit seaborn violinplots?
I'm kind of new in coding and thus in python so this may sound quite dumb, but what are the main differences between .subplot() and .subplots() methods from matplotlib in python?
I didn't find this explanation anywhere else and after reading the documentation from https://matplotlib.org/ I inferred that with both methods you can create as many figures and plots as you want...so for me both of them seem to be quite the same thing and they just differ the way you can handle plots, axes, etc...or am I wrong?
Btw, I am using python3 in jupyter notebook if it makes any difference.
1. matplotlib.pyplot.subplots()
From the documentation page on matplotlib.pyplot.subplots():
This utility wrapper makes it convenient to create common layouts of subplots, including the enclosing figure object, in a single call.
That means you can use this single function to create a figure with several subplots with only one line of code. For example, the code below will return both fig which is the figure object, and axes which is a 2x3 array of axes objects which allows you to easily access each subplot:
fig, axes = plt.subplots(nrows=2, ncols=3)
2. matplotlib.pyplot.subplot()
In contrast, matplotlib.pyplot.subplot() creates only a single subplot axes at a specified grid position. This means it will require several lines of code to achieve the same result as matplot.pyplot.subplots() did in a single line of code above:
# first you have to make the figure
fig = plt.figure(1)
# now you have to create each subplot individually
ax1 = plt.subplot(231)
ax2 = plt.subplot(232)
ax3 = plt.subplot(233)
ax4 = plt.subplot(234)
ax5 = plt.subplot(235)
ax6 = plt.subplot(236)
or you can also use built-in method of fig:
ax1 = fig.add_subplot(231)
ax2 = fig.add_subplot(232)
ax3 = fig.add_subplot(233)
ax4 = fig.add_subplot(234)
ax5 = fig.add_subplot(235)
ax6 = fig.add_subplot(236)
Conclusion
The code above can be condensed with a loop, but it is still considerably more tedious to use. I'd therefore recommend you use matplotlib.pyplot.subplots() since it is more concise and easy to use.
I'm making some EDA using pandas and seaborn, this is the code I have to plot the histograms of a group of features:
skewed_data = pd.DataFrame.skew(data)
skewed_features =skewed_data.index
fig, axs = plt.subplots(ncols=len(skewed_features))
plt.ticklabel_format(style='sci', axis='both', scilimits=(0,0))
for i,skewed_feature in enumerate(skewed_features):
g = sns.distplot(data[column])
sns.distplot(data[skewed_feature], ax=axs[i])
This is the result I'm getting:
Is not readable, how can I avoid that issue?
I know you are concerning about the layout of the figures. However, you need to first decide how to represent your data. Here are two choices for your case
(1) Multiple lines in one figure and
(2) Multiple subplots 2x2, each subplot draws one line.
I am not quite familiar with searborn, but the plotting of searborn is based on matplotlib. I could give you some basic ideas.
To archive (1), you can first declare the figure and ax, then add all line to this ax. Example codes:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
# YOUR LOOP, use the ax parameter
for i in range(3)
sns.distplot(data[i], ax=ax)
To archive (2), same as above, but with different number subplots, and put your line in the different subplot.
# Four subplots, 2x2
fig, axarr = plt.subplots(2,2)
# YOUR LOOP, use different cell
You may check matplotlib subplots demo. To do a good visualization is a very tough work. There are so many documents to read. Check the gallery of matplotlib or seaborn is a good and quick way to understand how some kinds of visualization are implemented.
Thanks.