Rotating title of Y axis to be horizontal in matplotlib - python

I am trying to rotate the title of the Y axis so it is horizontal. I do not want the tick labels horizontal just the title of the Y axis. I have to use subplots as I am making multiple plots at once. Here is the below script in which I have tried to rotate the Y axis title.
import matplotlib.pyplot as plt
import sys
fig, ax = plt.subplots()
ax.set_title(r'$\alpha$ > \beta_i$', fontsize=20)
ax.set(xlabel='meters $10^1$', ylabel=r'Hertz $(\frac{1}{s})$')
ax.set(xlabel=r's(t) = \mathcal(A)\/\sin(2 \omega t)', ylabel=r'Hertz $(\frac{1}{s})$')
ax.set(ylabel="North $\uparrow$",fontsize=9,rotate=90)
plt.show()
When I run it I get an error:
TypeError: There is no AxesSubplot property "rotate"
How can I tweak this program so that the Y axis is rotating horizontally?

By using ax.set you are attempting to set properties of the axes rather than properties of the ylabel text object.
Rather than using ax.set you can instead use xlabel and ylabel to create the x and y labels and pass in kwargs to modify their appearance. Also the property name is rotation rather than rotate. Also you'll want to set the rotation to 0 as the default is 90 which is why it's rotated in the first place.
plt.title(r'$\alpha > \beta_i$', fontsize=20)
plt.xlabel(r'meters $10^1$', fontsize=9)
plt.ylabel("North $\uparrow$", fontsize=9, rotation=0)

Related

Removing ticks when using grid with imshow matplotlib

In this question, they answer how to correctly use grid with imshow with matplotlib. I am trying to do the same as they do, but I want to remove all ticks (x and y). When I try to do it, it also eliminates the grid and I just the image displayed without grid and ticks. My code is:
fig, ax = plt.subplots()
data = np.random.rand(20,20)
ax.imshow(data)
ax.set_xticks(np.arange(20))
ax.set_xticklabels(np.arange(20))
ax.set_xticks(np.arange(20)+0.5, minor=True)
ax.grid(which='minor',color='w',axis='x',linewidth=6)
ax.axes.xaxis.set_visible(False)
ax.axes.yaxis.set_visible(False)
plt.show()
Does anyone how to remove the ticks while keeping the grid (along the x axis in my case)?
Removing the axes (via set_visible(False)) will also remove the grid.
However, there's a workaround setting both spines and tick marks/labels to be invisible individually:
fig, ax = plt.subplots()
data = np.random.rand(20,20)
ax.imshow(data)
ax.set_xticks(np.arange(20))
ax.set_xticklabels(np.arange(20))
ax.set_xticks(np.arange(20)+0.5, minor=True)
ax.grid(which='minor',color='w',axis='x',linewidth=6)
# set axis spines (the box around the plot) to be invisible
plt.setp(ax.spines.values(), alpha = 0)
# set both tick marks and tick labels to size 0
ax.tick_params(which = 'both', size = 0, labelsize = 0)
plt.show()
Gives you output as:
Note, you might need to adjust xlim/ylim and grid parameters to fit your needs.
This is not perfect, but you can just set the tick label as an empty list.
ax.axes.get_xaxis().set_ticks([])
ax.axes.get_yaxis().set_ticks([])
Only the minor xticks, used in the grid, remain.

Non-overlapping legend and axes (e.g. in matplotlib)

I need the plot legend to appear side-by-side to the plot axes, i.e. outside of the axes and non-overlapping.
The width of the axes and the legend should adjust "automatically" so that they both fill the figure w/o them to overlap or the legend to be cut, even when using tight layout. The legend should occupy a minor portion of the figure (let's say max to 1/3 of figure width so that the remaining 2/3 are dedicated to the actual plot).
Eventually, the font of the legend entries can automatically reduce to meet the requirements.
I've read a number of answers regarding legend and bbox_to_anchor in matplotlib with no luck, among which:
how to put the legend out of the plot
moving matplotlib legend outside of the axis makes it cutoff by the figure box
I tried by creating a dedicated axes in which to put the legend so that plt.tight_layout() would do its job properly but then the legend only takes a minor portion of the dedicated axes, with the result that a lot of space is wasted. Or if there isn't enough space (the figure is too small), the legend overlaps the first axes anyway.
import matplotlib.pyplot as plt
import numpy as np
# generate some data
x = np.arange(1, 100)
# create 2 side-by-side axes
fig, ax = plt.subplots(1,2)
# create a plot with a long legend
for ii in range(20):
ax[0].plot(x, x**2, label='20201110_120000')
ax[0].plot(x, x, label='20201104_110000')
# grab handles and labels from the first ax and pass it to the second
hl = ax[0].get_legend_handles_labels()
leg = ax[1].legend(*hl, ncol=2)
plt.tight_layout()
I'm open to use a package different from matplotlib.
Instead of trying to plot the legend in a separate axis, you can pass loc to legend:
# create 2 side-by-side axes
fig, ax = plt.subplots(figsize=(10,6))
# create a plot with a long legend
for ii in range(20):
ax.plot(x, x**2, label='20201110_120000')
ax.plot(x, x, label='20201104_110000')
# grab handles and labels from the first ax and pass it to the second
ax.legend(ncol=2, loc=[1,0])
plt.tight_layout()
Output:

matplotlib set_major_formatter creating 2 plots

This excerpt from my code changes the value of the y axis labels from exponential to millions. Problem is it creates 2 figures. The first one is an x and y axis with no plot (and the scale of the x axis is used for the y axis as well), and then the 2nd figure is exactly what I want. It is a double bar graph.
I am guessing it has something to do with using f.plot.bar instead of plt.bar but I am not sure. I just want to get rid of the first figure than all will be well.
from matplotlib.ticker import FuncFormatter
def millions(x, pos):
'The two args are the value and tick position'
return '%1.1fM' % (x*1e-6)
formatter = FuncFormatter(millions)
fig, ax = plt.subplots()
ax = tempg.plot.bar(y=['Republican2016Votes', 'Democrat2016Votes'], rot=0,
color = ['DarkRed','Blue'])
ax.yaxis.set_major_formatter(formatter)
plt.show()

Hide axis label only, not entire axis, in Pandas plot

I can clear the text of the xlabel in a Pandas plot with:
plt.xlabel("")
Instead, is it possible to hide the label?
May be something like .xaxis.label.set_visible(False).
From the Pandas docs -
The plot method on Series and DataFrame is just a simple wrapper around plt.plot():
This means that anything you can do with matplolib, you can do with a Pandas DataFrame plot.
pyplot has an axis() method that lets you set axis properties. Calling plt.axis('off') before calling plt.show() will turn off both axes.
df.plot()
plt.axis('off')
plt.show()
plt.close()
To control a single axis, you need to set its properties via the plot's Axes. For the x axis - (pyplot.axes().get_xaxis().....)
df.plot()
ax1 = plt.axes()
x_axis = ax1.axes.get_xaxis()
x_axis.set_visible(False)
plt.show()
plt.close()
Similarly to control an axis label, get the label and turn it off.
df.plot()
ax1 = plt.axes()
x_axis = ax1.axes.get_xaxis()
x_axis.set_label_text('foo')
x_label = x_axis.get_label()
##print isinstance(x_label, matplotlib.artist.Artist)
x_label.set_visible(False)
plt.show()
plt.close()
You can also get to the x axis like this
ax1 = plt.axes()
x_axis = ax1.xaxis
x_axis.set_label_text('foo')
x_axis.label.set_visible(False)
Or this
ax1 = plt.axes()
ax1.xaxis.set_label_text('foo')
ax1.xaxis.label.set_visible(False)
DataFrame.plot
returns a matplotlib.axes.Axes or numpy.ndarray of them
so you can get it/them when you call it.
axs = df.plot()
.set_visible() is an Artist method. The axes and their labels are Artists so they have Artist methods/attributes as well as their own. There are many ways to customize your plots. Sometimes you can find the feature you want browsing the Gallery and Examples
You can remove axis labels and ticks using xlabel= or ylabel= arguments in the plot() call. For example, to remove the xlabel, use xlabel='':
df.plot(xlabel='');
To remove the x-axis ticks, use xticks=[] (for y-axis ticks, use yticks=):
df.plot(xticks=[]);
To remove both:
df.plot(xticks=[], xlabel='');

What is the position of the top of the axis label text in matplotlib?

I'm trying to position some additional annotations to line up with the axis label text in a matplotlib figure. How is this position calculated, as a function of the font size of the tick and axes labels, and the font size of the annotation?
Specifically, given a figure with a single set of tick labels and a single axis label along the x-axis, with font sizes tick_font_size and label_font_size respectively, what is the vertical position y in figure points that would result in
ax.annotate('Some text', (x, y), va='top', ...)
placing 'Some text' with font size annotation_font_size, in vertical alignment with the axis label?
For various reasons, I must use annotate for this, and va='top' is a constraint; and I need to use the font size information above — that is, I'm looking for the function of the form
y = f(tick_font_size, label_font_size, annotation_font_size)
with all values in figure points (i.e., usable with textcoords='offset points' in annotate). Such an algorithm must exist, since it is clearly used by matplotlib to position the axis label in the first place.
Get the object returned when setting xlabel. Render the figure and use get_position to get the position of the label. From there do some transformations and add the annotation.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = x**2
xlabel = plt.xlabel("test")
plt.plot(x, y)
ax = plt.gca()
fig = plt.gcf()
fig.draw(fig.canvas.get_renderer())
trans = xlabel.get_transform()
xpos, ypos = trans.transform(xlabel.get_position()) # convert to display coordinates
xpos, ypos = fig.transFigure.inverted().transform([xpos, ypos]) # convert to figure coordinates
ax.annotate('Some text', (xpos+0.05, ypos), xycoords='figure fraction', va="top")
plt.show()

Categories

Resources