8

I want to produce plots with axis labels both at the tops and bottoms (or left and right) of my subfigures. Other posts have detailed how I can move the axis labels (for example, here).

However, I'm having a problem with the exponentials from scientific notation. A minimal-ish working example illustrates the problem best:

import numpy as np
import matplotlib.pyplot as plt

vars = 4
length = 10000

array = np.zeros((length, vars))
array[:,0] = np.random.normal(0.0, 1.0e6, (length))
array[:,1] = 1.0e6 * np.tanh(array[:,0]/1.0e6)
array[:,2] = 1.0e5 * np.random.random((length))
array[:,3] = array[:,1] * array[:,2] / 1.0e5

labels = ["var1", "var2", "var3", "var4"]

plt.figure(figsize=(15, 15))

for i in range(vars):
    for j in range(0, vars):
        ax = plt.subplot(vars, vars, vars*i + j + 1)
        ax.xaxis.get_major_formatter().set_powerlimits((-2, 3))
        ax.yaxis.get_major_formatter().set_powerlimits((-2, 3))
        ax.locator_params(nbins=5)

        if (j == i):
            weights = np.ones_like(array[:,i])/len(array[:,i])
            ax.hist(array[:,i], 25, weights=weights)
        else:
            ax.plot(array[:,j], array[:,i], '.', markersize=0.5)

        if ((j == 0) & (i % 2 == 0)):
            ax.yaxis.tick_left()
            ax.xaxis.set_ticks_position("both")
            ax.yaxis.set_label_position("left")
            ax.get_yaxis().get_offset_text().offset_text_position = "left"
            ax.set_ylabel(labels[i])
        elif ((j == vars - 1) & (i % 2 == 1)):
            ax.yaxis.tick_right()
            ax.xaxis.set_ticks_position("both")
            ax.yaxis.set_label_position("right")
            ax.get_yaxis().get_offset_text().offset_text_position = "right"
            ax.set_ylabel(labels[i])
        else:
            ax.get_yaxis().set_ticklabels([])

        if ((i == 0) & (j % 2 == 1)):
            ax.xaxis.tick_top()
            ax.xaxis.set_ticks_position("both")
            ax.xaxis.set_label_position("top")
            ax.get_xaxis().get_offset_text().offset_text_position = "top"
            ax.set_xlabel(labels[j])
        elif ((i == vars - 1) & (j % 2 == 0)):
            ax.xaxis.tick_bottom()
            ax.xaxis.set_ticks_position("both")
            ax.xaxis.set_label_position("bottom")
            ax.get_xaxis().get_offset_text().offset_text_position = "bottom"
            ax.set_xlabel(labels[j])
        else:
            ax.get_xaxis().set_ticklabels([])

plt.savefig("test.png")

This produces: enter image description here

As you can see, the exponentials have not moved with the rest of the ticks. I tried

ax.get_yaxis().get_offset_text().offset_text_position = "right"

and

ax.get_xaxis().get_offset_text().offset_text_position = "top"

but they seem to have no effect.

Community
  • 1
  • 1
Jack Yates
  • 961
  • 7
  • 12
  • For what it's worth, the "offset text" is the offset (e.g. `+1e3`) not the multiplier (`1e3`), which is why `get_offset_text().offset_text_position` isn't having any effect. – Joe Kington May 26 '15 at 14:35
  • Ah, that makes sense, actually! I had assumed that "offset" referred to the position of the text, not the actual contents. So do you know what I should be doing instead? – Jack Yates May 26 '15 at 14:40
  • 1
    Ignore what I said about the different between the offset and the multiplier (though there's a common gotcha with that, too, e.g.: http://stackoverflow.com/questions/28371674/prevent-scientific-notation-in-matplotlib-pyplot/28373421#28373421) The root of your problem is that you want `ax.xaxis.offset_text_position = "top"` instead of `ax.xaxis.get_offset_text().offset_text_position() = "top"`. – Joe Kington May 26 '15 at 14:48
  • 2
    Also, there appears to be a bug with this in the current version of matplotlib. Filing a bug report now... – Joe Kington May 26 '15 at 14:56
  • I tried doing as you suggested and it doesn't seem to have done anything. Is that the bug that you're referring to? I also tried `ax.get_xaxis().get_offset_text().set_y(1)` but that had no effect either. – Jack Yates May 26 '15 at 15:01
  • Yeah, that's the bug I was referring to... Trying to get to the bottom of it now. However, it's also possible that I'm just missing something obvious and there's another way to do it. To the best of my knowledge, though, `ax.axis.offset_text_position` is the main control for what you want. – Joe Kington May 26 '15 at 15:03
  • Just for info, I came across this bug looking at another question and remembered this one. It looks highly related to me https://github.com/matplotlib/matplotlib/issues/4043 . Note it is fixed, milestone 1.5.0 release – J Richard Snape Jun 10 '15 at 20:20
  • Sounds like a problem I had yesterday, solution is here http://stackoverflow.com/questions/30763437/matplotlib-subplot-y-axis-scale-overlaps-with-plot-above – Dave Jun 11 '15 at 17:16
  • I will see if I can update matplotlib and test it again. – Jack Yates Jun 17 '15 at 15:10

1 Answers1

3

This is the bug that Joe Klington reported: https://github.com/matplotlib/matplotlib/issues/4476 If you look at that link, there seems to be a workaround to position to offset text where you want, but it is not simple.

Ramon Crehuet
  • 3,679
  • 1
  • 22
  • 37