Changing tick label line spacing in matplotlib - python

I have a quite cluttered plot with y-ticklabels that need to be very long. I've resorted into wrapping them into multiline text with textwrap. However that makes the labels overlap (or at least come too close), between categories.
I can't solve it by spacing the ticks, making the graph larger, changing font or making the text smaller. (I've already pushed these limits)
As I see it, I could resolve and make it work if I could adjust the line spacing/height to be less than what the font requests.
So imagine for simplicity's sake the following tick-label desperately needs shorter line distance between lines/line height:
from matplotlib import pyplot as plt
plt.barh(0.75, 10, height=0.5)
plt.ylim(0, 2)
plt.yticks([1], ["A very long label\nbroken into 2 line"])
plt.subplots_adjust(left=0.3)
plt.show()
I've checked plt.tick_params() the rcParams without finding any obvious solution. I'm using latex to format the text, but trying to use \hspace(0.5em} in the tick label string seemed not to work/only make things worse.
Any suggestion as to how the line spacing can be decreased would be much appreciated.

You can use the linespacing keyword in your plt.yticks line. For example:
plt.yticks([1], ["A very long label\nbroken into 2 line"],linespacing=0.5)
You can play with the exact value of linespacing to fit your needs. Hope that helps.
Here's the original output of your code:
And here it is with a linespacing of 0.5:

Attempt using this:
pylab.rcParams['xtick.major.pad']='???'
Mess around with the ??? value to get something you like. You could also try (sing the OO interface):
fig = plt.figure()
ax = fig.add_subplot(111)
ax.tick_params(axis='both', which='major', labelsize=8)
ax.set_yticks([1], ["A very long label\nbroken into 2 line"], linespacing=0.5)
plt.show()
The labelsize command will change the size of your font.
Use a combination of the above with the rcparams setup.

Related

Matplotlib: change position of plot

I did the following plot with the figure size (which should not be changed):
plt.figure(figsize=(14, 5))
Unfortunately, the x-label is not fully visible. My question: Is it possible, to move the whole grafic to the top (because there would be enough space)?
The code:
plt.figure(figsize=(14, 5))
plt.plot(time_load,load, linewidth=1.5)
plt.grid(True)
plt.tick_params(labelsize=16)
plt.xlabel('Time [hours]',fontsize=16)
plt.xlim([0,24])
plt.xticks([0,4,8,12,16,20,24])
plt.legend(loc="upper left",fontsize = 'large')
Thank you very much for your help!
You can also try
plt.subplots_adjust(bottom=0.19)
If 0.19 adds too much or too little space to see the x-label better, then try adjusting little by little up or down.
A very simple approach is to use
plt.tight_layout()
See: http://matplotlib.org/users/tight_layout_guide.html
Thank you very much for your help!
You can use the axes() command that allows you to specify the location as axes. You can also use the xlim() command and ylim() command. In your case, you can use the latter. So just as an example, the xlim method can be used like this:
plt.xlim(X.min()*1.1, X.max()*1.1)
plt.ylim(C.min()*1.1, C.max()*1.1)
This will make some space for the data points to be seen clearly. Hope that helps.
Just seen the code so you're using xlim method. You want to create the subplot somewhere else, for that you can use the axis() method.
plt.axes([0.3, 0.3, .5, .5])
You can adjust plot accordingly. This one will create a subplot in the upper right corner of the figure.

zorder value to force grid to background [duplicate]

In Matplotlib, I make dashed grid lines as follows:
fig = pylab.figure()
ax = fig.add_subplot(1,1,1)
ax.yaxis.grid(color='gray', linestyle='dashed')
however, I can't find out how (or even if it is possible) to make the grid lines be drawn behind other graph elements, such as bars. Changing the order of adding the grid versus adding other elements makes no difference.
Is it possible to make it so that the grid lines appear behind everything else?
According to this - http://matplotlib.1069221.n5.nabble.com/axis-elements-and-zorder-td5346.html - you can use Axis.set_axisbelow(True)
(I am currently installing matplotlib for the first time, so have no idea if that's correct - I just found it by googling "matplotlib z order grid" - "z order" is typically used to describe this kind of thing (z being the axis "out of the page"))
To me, it was unclear how to apply andrew cooke's answer, so this is a complete solution based on that:
ax.set_axisbelow(True)
ax.yaxis.grid(color='gray', linestyle='dashed')
If you want to validate the setting for all figures, you may set
plt.rc('axes', axisbelow=True)
or
plt.rcParams['axes.axisbelow'] = True
It works for Matplotlib>=2.0.
I had the same problem and the following worked:
[line.set_zorder(3) for line in ax.lines]
fig.show() # to update
Increase 3to a higher value if it does not work.
You can also set the zorder kwarg in matplotlib.pyplot.grid
plt.grid(which='major', axis='y', zorder=-1.0)
You can try to use one of Seaborn's styles. For instance:
import seaborn as sns
sns.set_style("whitegrid")
Not only the gridlines will get behind but the looks are nicer.
For some (like me) it might be interesting to draw the grid behind only "some" of the other elements. For granular control of the draw order, you can use matplotlib.artist.Artist.set_zorder on the axes directly:
ax.yaxis.grid(color='gray', linestyle='dashed')
ax.set_zorder(3)
This is mentioned in the notes on matplotlib.axes.Axes.grid.

Why is set_xlim() not setting the x-limits in my figure?

I'm plotting some data with matplotlib. I want the plot to focus on a specific range of x-values, so I'm using set_xlim().
Roughly, my code looks like this:
fig=plt.figure()
ax=fig.add_subplot(111)
for ydata in ydatalist:
ax.plot(x_data,y_data[0],label=ydata[1])
ax.set_xlim(left=0.0,right=1000)
plt.savefig(filename)
When I look at the plot, the x range ends up being from 0 to 12000. This occurs whether set_xlim() occurs before or after plot(). Why is set_xlim() not working in this situation?
Out of curiosity, what about switching in the old xmin and xmax?
fig=plt.figure()
ax=fig.add_subplot(111)
ax.plot(x_data,y_data)
ax.set_xlim(xmin=0.0, xmax=1000)
plt.savefig(filename)
The text of this answer was taken from an answer that was deleted almost immediately after it was posted.
set_xlim() limits the data that is displayed on the plot.
In order to change the bounds of the axis, use set_xbound().
fig=plt.figure()
ax=fig.add_subplot(111)
ax.plot(x_data,y_data)
ax.set_xbound(lower=0.0, upper=1000)
plt.savefig(filename)
In my case the following solutions alone did not work:
ax.set_xlim([0, 5.00])
ax.set_xbound(lower=0.0, upper=5.00)
However, setting the aspect using set_aspect worked, i.e:
ax.set_aspect('auto')
ax.set_xlim([0, 5.00])
ax.set_xbound(lower=0.0, upper=5.00)
I have struggled a lot with the ax.set_xlim() and couldn't get it to work properly and I found out why exactly. After setting the xlim I was setting the xticks and xticklabels (those are the vertical lines on the x-axis and their labels) and this somehow elongated the axis to the needed extent. So if the last tick was at 300 and my xlim was set at 100, it again widened the axis to the 300 just to place the tick there.
So the solution was to put it just after the troublesome code:
ax.set_xlabel(label)
ax.set_xticks(xticks)
ax.set_xticklabels(xticks, rotation=60)
ax.set_xlim(xmin=0.0, xmax=100.0)
The same thing occurred to me today. My issue was that the data was not in the right format, i.e. not floats. The limits I set (itself floats) became meaningless compared to e.g. strings. After putting float() around the data, everything worked as expected.

How to adjust padding with cutoff or overlapping labels

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")

Python graph- change axis marker colours and legend border colours

I'm using Python to plot a couple of graphs and I'm trying to change the formatting and essentially 'brand' the graph. I've managed to change most things using pylab.rcParams[...], but I can't work out how to change the colour of the markers on the axes and the border around the legend. Any help would be much appreciated. The line below is an example of the type of code I've been using to edit other parts. Basically just lines taken from matplotlibrc, but I can't find them to change everything I want.
pylab.rcParams[axes.labelcolor' = '#031F73'
If you just want to use rcParams, the proper parameters are xticks.color and yticks.color. I can't seem to find a key for the legend frame color. You can set that (along with the tick colors) programmatically though.
import pylab
pylab.plot([1,2,3],[4,5,6], label ='test')
lg = pylab.legend()
lg.get_frame().set_edgecolor('blue')
ax = pylab.axes()
for line in ax.yaxis.get_ticklines():
line.set_color('blue')
for line in ax.xaxis.get_ticklines():
line.set_color('blue')
for label in ax.yaxis.get_ticklabels():
label.set_color('blue')
for label in ax.xaxis.get_ticklabels():
label.set_color('blue')
pylab.show()

Categories