Overlapping subplot-title since update of Matplotlib - python

I recently had to re-install my OS and decided to switch to Python3. With it came updates of my IDE PyCharm and presumably also an update of Matplotlib.
Running a script that worked perfectly fine before, now gives me ugly results with overlapping titles of my subplots.
This is an example code:
import numpy as np
import matplotlib.pyplot as plt
z = np.random.uniform(low=0, high=100, size=(20,4))
fig, axes = plt.subplots(2, 2, constrained_layout=True, sharey=True, sharex=True)
axes[-1, 0].set_xlabel('.\n', color=(0, 0, 0, 0))
axes[-1, 0].set_ylabel('.\n', color=(0, 0, 0, 0))
for s_plot, ax in enumerate(axes.flat):
ax.scatter(x=range(20), y=z[:,s_plot])
fig.suptitle("The Title\nSecond Line\n", fontsize=12)
plt.show()
This produces:
I tried setting constrained_layout to False and also experimented with subplots_adjust, but it does not change the layout of my plots.
I am currently using matplotlib 3.0.2. Was there a major change I have missed? I am puzzled about how to solve this.

Using matplotlib 3.0.2 the plot would look as follows
Using constrained_layout=True
Using constrained_layout=False
Both outcomes are expected. In the case of constrained_layout being used the title appears off-center, because there is more space to the left of the subplots being used by labels than on the right.

I also think this is a problem with pycharm. So for example when I run the code in this standard matplotlib script:
https://matplotlib.org/3.1.1/gallery/subplots_axes_and_figures/figure_title.html
I get this image where the title and suptitle overlap:
However the title and suptitle do not overlap when saved to png.
I have raised an issue with pycharm to hopefully get this resolved:
https://youtrack.jetbrains.com/issue/PY-42545
In the meantime I suggest splitting your editor screen to display the .png file which you can refresh using CTRL+ALT+Y every time you run the code.

Related

Matplotlib.collections.PathCollection

https://www.youtube.com/watch?v=pl3D4SosO_4&list=PL9mhv0CavXYjiIniCLj_5KKN58PaxJBVj&index=2
Right at time stamp 2:13.
I am trying to follow a youtube tutorial and I have hit a road block. There is no documentation online that tells me how to implement matplotlib.collections.PathCollection
The youtuber in this video that I am following runs the first bit of his code (at about 2:13) and a plot appears with some color data points. Above this plot it says <matplotlib.collections.PathCollection at 0x208cd62cef0>
If anyone could tell me how this youtuber got this plot to appear I would be forever grateful.
I have found documentation for matplotlib.collections, but zero information on how it is used, I asked the youtuber how he got to this point in the comments and am waiting on an answer.
Thank you Craig, I am adding the code that doesn't work for me here
EDIT:
(I have been attempting this in a pycharm IDE and the video is using Jupyter, idk if that makes a difference)
import numpy as np
from matplotlib import plyplot as plt
from sklearn.datasets import make_blobs
X,y = make_blobs(n_samples = 500, centers = 5, random_state = 3)
plt.figure(0)
plt.grid(True)
plt.scatter(X[:,0], X[:,1],c=y)
when this is run in the video a plot with color clusters appears.
Maybe I should be trying this in jupyter, maybe some image libraries are pre-loaded there?
Jupyter is a special interactive environment and it automatically renders matplotlib plots when it runs a cell that creates a plot. If you are doing the same thing in an IDE, then you will need to explicitly render the plot by calling plt.show() when you want the plot to appear. You can do this for your code by adding it to the end:
import numpy as np
from matplotlib import plyplot as plt
from sklearn.datasets import make_blobs
X,y = make_blobs(n_samples = 500, centers = 5, random_state = 3)
plt.figure(0)
plt.grid(True)
plt.scatter(X[:,0], X[:,1],c=y)
plt.show() # <-- show the plot

Matplotlib savefig background always transparent

Problem
I cannot seem to get savefig() to actually save a PNG file without a transparent figure background.
This is having read and tried all the suggestions previously posted, answered, cursed about and also going through the API docs a bunch of times. I've read it all, but still can't get non-transparent figure faces
Background
I'm using matplotlib and savefig to create a PNG file. (env: macos - latest anaconda modules using PY 3.7).
I am trying this out of jupyter however - so hopefully it's not something completely screwed up with only how ipython in jupyter does it - though I don't see how that could be the case
I did read through the previous many posts about the (confusing as hell) nature of savefig doing it's own thing with backgrounds, and did/tried everything as suggested (and as written in the latest savefig api docs).
In particular, I've tried all the following without sucess:
specifying facecolor in the savefig() call (with/without transparency)
savefig.facecolor: white in the style mpl file I'm using
When savefig'ing my figure background is always transparent.
Can anyone tell me what the !##$!# I'm missing here???
Code
Here's what I''m using, which spits out figure with transparent background, regardless of what I do.
In particular the 2nd call below (with savefig(..., transparent=False)) will make the axes not transparent - but the figure itself is still transparent!)
import numpy as np
import matplotlib as mpl
import matplotlib.style as style
a = np.array([-3.2, 0.1, 1.5, 3.3, 8.5])
b = np.array([1.1, 1.8, 1.95, 2.3, 4.3])
labels = ['a', 'bc', 'def', 'g', 'ggghhh']
stylefile = './util/plot_config/aqs_default.mplstyle'
# the file above does contain an entry of:
# savefig.facecolor: white
#
to_res = 1024
dpi = 100
inches = (to_res/dpi, to_res/dpi)
style.use(stylefile)
%matplotlib
fig = mpl.figure.Figure(figsize=inches, dpi=dpi, facecolor='white')
ax = fig.subplots()
for x, y, l in zip(a,b,labels):
ax.scatter(x,y,label=l)
ax.legend()
ax.set_xlabel('Some x')
ax.set_ylabel('Attenuation $\mu$ (cm$^{-1}$)')
ax.set_title('blah', y=1.03)
fig.suptitle('Linearity $\mu$')
# for me, _both_ calls below result in the figure having a transparent background:
fig.savefig('a.png', facecolor=fig.get_facecolor(), transparent=True)
fig.savefig('b.png', facecolor=fig.get_facecolor(), transparent=False)
Unfortunately, it seems that frameon is not supported anymore as of matplotlib 3.3.
I solved the transparency issue by setting facecolor='white', transparent=False options in savefig()
FYI for anyone else with a similiar problem.
The cause (and fix) turned out to be because I was creating a figure with frameon set to False.
I had actually had this set to False in a style file I was using.
Changing frameon to True fixed the problem.
This was confusing and not very obvious at all from any documentation - here is some background on the issue from the MPL github issues:
https://github.com/matplotlib/matplotlib/issues/14339

Incomple text while saving seaborn figures [duplicate]

Updated MRE with subplots
I'm not sure of the usefulness of the original question and MRE. The margin padding seems to be properly adjusted for large x and y labels.
The issue is reproducible with subplots.
Using matplotlib 3.4.2
fig, axes = plt.subplots(ncols=2, nrows=2, figsize=(8, 6))
axes = axes.flatten()
for ax in axes:
ax.set_ylabel(r'$\ln\left(\frac{x_a-x_b}{x_a-x_c}\right)$')
ax.set_xlabel(r'$\ln\left(\frac{x_a-x_d}{x_a-x_e}\right)$')
plt.show()
Original
I am plotting a dataset using matplotlib where I have an xlabel that is quite "tall" (it's a formula rendered in TeX that contains a fraction and is therefore has the height equivalent of a couple of lines of text).
In any case, the bottom of the formula is always cut off when I draw the figures. Changing figure size doesn't seem to help this, and I haven't been able to figure out how to shift the x-axis "up" to make room for the xlabel. Something like that would be a reasonable temporary solution, but what would be nice would be to have a way to make matplotlib recognize automatically that the label is cut off and resize accordingly.
Here's an example of what I mean:
import matplotlib.pyplot as plt
plt.figure()
plt.ylabel(r'$\ln\left(\frac{x_a-x_b}{x_a-x_c}\right)$')
plt.xlabel(r'$\ln\left(\frac{x_a-x_d}{x_a-x_e}\right)$', fontsize=50)
plt.title('Example with matplotlib 3.4.2\nMRE no longer an issue')
plt.show()
The entire ylabel is visible, however, the xlabel is cut off at the bottom.
In the case this is a machine-specific problem, I am running this on OSX 10.6.8 with matplotlib 1.0.0
Use:
import matplotlib.pyplot as plt
plt.gcf().subplots_adjust(bottom=0.15)
# alternate option without .gcf
plt.subplots_adjust(bottom=0.15)
to make room for the label, where plt.gcf() means get the current figure. plt.gca(), which gets the current Axes, can also be used.
Edit:
Since I gave the answer, matplotlib has added the plt.tight_layout() function.
See matplotlib Tutorials: Tight Layout Guide
So I suggest using it:
fig, axes = plt.subplots(ncols=2, nrows=2, figsize=(8, 6))
axes = axes.flatten()
for ax in axes:
ax.set_ylabel(r'$\ln\left(\frac{x_a-x_b}{x_a-x_c}\right)$')
ax.set_xlabel(r'$\ln\left(\frac{x_a-x_d}{x_a-x_e}\right)$')
plt.tight_layout()
plt.show()
In case you want to store it to a file, you solve it using bbox_inches="tight" argument:
plt.savefig('myfile.png', bbox_inches="tight")
An easy option is to configure matplotlib to automatically adjust the plot size. It works perfectly for me and I'm not sure why it's not activated by default.
Method 1
Set this in your matplotlibrc file
figure.autolayout : True
See here for more information on customizing the matplotlibrc file: http://matplotlib.org/users/customizing.html
Method 2
Update the rcParams during runtime like this
from matplotlib import rcParams
rcParams.update({'figure.autolayout': True})
The advantage of using this approach is that your code will produce the same graphs on differently-configured machines.
plt.autoscale() worked for me.
You can also set custom padding as defaults in your $HOME/.matplotlib/matplotlib_rc as follows. In the example below I have modified both the bottom and left out-of-the-box padding:
# The figure subplot parameters. All dimensions are a fraction of the
# figure width or height
figure.subplot.left : 0.1 #left side of the subplots of the figure
#figure.subplot.right : 0.9
figure.subplot.bottom : 0.15
...
There is also a way to do this using the OOP interface, applying tight_layout directly to a figure:
fig, ax = plt.subplots()
fig.set_tight_layout(True)
https://matplotlib.org/stable/api/figure_api.html
for some reason sharex was set to True so I turned it back to False and it worked fine.
df.plot(........,sharex=False)
You need to use sizzors to modify the axis-range:
import sizzors as sizzors_module
sizzors_module.reshape_the_axis(plt).save("literlymylief.tiff")

formatting to group of bars using matplotlib

I am trying to learn python mainly for plotting. Here is my sample code:
import numpy as np
import matplotlib.pyplot as plt
a=[[1,2,3,4],[2,3,4,5],[3,4,5,6]]
x=np.arange(len(a[0]))
width=0.2
fig, ax = plt.subplots(figsize=(8,6))
patterns=['/','\\','*']
for bar in a:
ax.bar(x,bar,width,edgecolor='black',color='lightgray', hatch=patterns.pop(0))
x=x+width
plt.show()
Now the problem is that, I need black edge colour for all bars as well as given hatch patter. However, the formatting is applied to first set of bars only. Here is my output. (I am using python3).
What's missing here or what's wrong? I have looked around but did not find any fix.
Update:
I have tried different options :python2, python3 and pdf/png. Here are results
python2 png --fine
python3 png -- shown above
python2 pdf -- see
python3 pdf -- see
I have also tried 'backend' as matplotlib.use('Agg'). I have update my matplotlib version (2.1.0).
There is a current issue in matplotlib 2.1 that only the first bar's edgecolor is applied. The same for the hatch, see this issue. Also see this question.
It may be that you are using matplotlib 2.1 for python3 but not for python2, hence in python2 it works for you. If I run your code in python 2 with matplotlib 2.1 I get the same undesired behaviour.
The issue will be fixed, once matplotlib 2.1.1 is released.
In the meantime, a workaround is to set the edgecolor and hatch on the individual bars:
import numpy as np
import matplotlib.pyplot as plt
a=[[1,2,3,4],[2,3,4,5],[3,4,5,6]]
x=np.arange(len(a[0]))
width=0.2
fig, ax = plt.subplots(figsize=(8,6))
patterns=['/','\\','*']
for y in a:
bars = ax.bar(x,y,width,color='lightgray')
hatch= patterns.pop(0)
for bar in bars:
bar.set_edgecolor("black")
bar.set_hatch(hatch)
x=x+width
plt.show()
It looks something's wrong with edgecolor tuple's alpha value. Set it to 1 will solve the problem.

subplots_adjust in matplotlib does not work in IPython Notebook

I have the following code that did not work:
import matplotlib.pyplot as plt
# Make the plot
fig, axs = plt.subplots(3, 1, figsize=(3.27, 6))
axs[0].plot(range(5), range(5), label='label 1')
axs[0].plot(range(5), range(4, -1, -1), label='label 2')
axs[0].legend(bbox_to_anchor=(0, 1.1, 1., 0.1), mode='expand', ncol=2, frameon=True, borderaxespad=0.)
# Adjust subplots to make room
fig.subplots_adjust(top=.5)
fig.savefig('test.png', format='png', dpi=300)
It can be seen that the fig.subplots_adjust did not work at all.
I am using WinPython 3.3.2.3 64 bit, with matplotlib version 1.3.0 and CPython 3.3. This happened in IPython Notebook. The backend is the in-line one. The output from the notebook is complete, but the output file is improperly cropped. In both notebook & saved file, the subplots_adjust command has no effect.
With the help of tcaswell, I got it solved by entirely closing the IPython Notebook and re-run the code via the ipython-qtconsole. It seems that the subplots_adjust() simply doesn't work for python 3 in ipython-notebook. I am new to python, and is really interested in what difference is there between the qtconsole and the notebook, backend-wise, if anyone has got ideas.
Anyways - good to have this problem solved!

Categories

Resources