```
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn
%matplotlib inline
```

# Setting nice axes labels in matplotlib¶

In this post I want to collect some ideas I had on setting nice labels in matplotlib. In particular, for scientific papers we usually want a label like "time [s]". Then, if the data is very large we may put the exponent next to the units like "time [$10^{-6}$s]", better still is to use an SI prefix e.g "time [$\mu$s]".

### The defaults¶

`Matplotlib`

already has useful routines to format the ticks, but it usually puts the exponent somewhere near to the top of the axis. Here is a typical example using the defaults

```
x = np.linspace(0, 10, 1000)
y = 1e10 * np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
```

### Improving on the defaults¶

For a scientific publication we tend to use $\times10^{10}$ or $10^{10}$, this can easily be achieved with the ScalarFormatter. There is an example on the docs, but here is a simpler one:

```
x = np.linspace(0, 10, 1000)
y = 1e8 + 1e6 * np.sin(x)
fig, ax = plt.subplots()
ax.yaxis.set_major_formatter(mpl.ticker.ScalarFormatter(useMathText=True, useOffset=False))
ax.plot(x, y)
plt.show()
```

Note there are two options set here, the first `useMathText`

forces the scientific notation, while the `useOffset`

stops the offset being used which makes most plots illegible in my opinion

### Customing the results¶

At some point I ran into an issue with the location of where the exponent was positioned, it was overlapping with other subplots. I did the usual trick and went to StackOverflow and was helpfully redirected to this post which by chance was posted the same day. Building on the ideas posted there I have developed the following:

```
def update_label(old_label, exponent_text):
if exponent_text == "":
return old_label
try:
units = old_label[old_label.index("[") + 1:old_label.rindex("]")]
except ValueError:
units = ""
label = old_label.replace("[{}]".format(units), "")
exponent_text = exponent_text.replace("\\times", "")
return "{} [{} {}]".format(label, exponent_text, units)
def format_label_string_with_exponent(ax, axis='both'):
""" Format the label string with the exponent from the ScalarFormatter """
ax.ticklabel_format(axis=axis, style='sci')
axes_instances = []
if axis in ['x', 'both']:
axes_instances.append(ax.xaxis)
if axis in ['y', 'both']:
axes_instances.append(ax.yaxis)
for ax in axes_instances:
ax.major.formatter._useMathText = True
plt.draw() # Update the text
exponent_text = ax.get_offset_text().get_text()
label = ax.get_label().get_text()
ax.offsetText.set_visible(False)
ax.set_label_text(update_label(label, exponent_text))
```

Which can be used like this

```
fig, ax = plt.subplots()
x = np.linspace(0, 1e8, 1000)
y = 1e10 * np.sin(1e-7*x)
ax.plot(x, y)
ax.set_ylabel("amplitude")
ax.set_xlabel("time [s]")
format_label_string_with_exponent(ax, axis='both')
plt.show()
```

As you will see, the label is edited and given the exponent, if units exist they are appended to that. While this isn't the most flexible solution, it is quite a standard notation.

### An interactive widget to check it works in all the right ways¶

```
x = np.linspace(0, 10, 1000)
y = 1e10 * np.sin(x)
def plot(xlabel="time [s]", ylabel="amplitude [Watts]", axis="both"):
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_ylabel(xlabel)
ax.set_xlabel(ylabel)
format_label_string_with_exponent(ax, axis=axis)
plt.show()
```

```
from IPython.html.widgets import interact
interact(plot, axis=["x", "y", "both"])
```