为多个子图设置具有固定指数和有效数字的科学记数法

为多个子图设置具有固定指数和有效数字的科学记数法

问题描述:

我正在尝试将坐标轴固定为两组不同数据的科学记数法,其中一组是 [1-9]x1e-3,另一组是 [1-9]x1e-4.我想将两个轴都设置为 10^-4 并在小数点后保留一位数(例如 %.1e).这是我尝试使用的一个简单版本:我希望轴上的数字至少为 1,并且我希望两个幂相同.

I am trying to fix the axes to scientific notation of two different sets of data where one is [1-9]x1e-3 and the other is [1-9]x1e-4. I would like to set both axes to be 10^-4 and have the one digits after decimal (e.g. %.1e). Here is a simple version that I have tried to play around with: I would like the numbers on the axes to be at least 1 and I want both powers to be the same.

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(1,9,9)
y1 = x*10**(-4)
y2 = x*10**(-3)

fig, ax = plt.subplots(2,1,sharex=True)

ax[0].plot(x,y1)
ax[0].ticklabel_format(axis='y', style='sci', scilimits=(-4,-4))
ax[0].yaxis.major.formatter._useMathText = True
ax[1].plot(x,y2)
ax[1].ticklabel_format(axis='y', style='sci', scilimits=(-4,-4))
ax[1].yaxis.major.formatter._useMathText = True

plt.show()

您可以子类化 matplotlib.ticker.ScalarFormatter 并将 orderOfMagnitude 属性固定为您喜欢的数字(在这种情况下 -4).
以同样的方式,您可以修复要使用的格式.

You can subclass matplotlib.ticker.ScalarFormatter and fix the orderOfMagnitude attribute to the number you like (in this case -4).
In the same way you can fix the format to be used.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker

class OOMFormatter(matplotlib.ticker.ScalarFormatter):
    def __init__(self, order=0, fformat="%1.1f", offset=True, mathText=True):
        self.oom = order
        self.fformat = fformat
        matplotlib.ticker.ScalarFormatter.__init__(self,useOffset=offset,useMathText=mathText)
    def _set_order_of_magnitude(self):
        self.orderOfMagnitude = self.oom
    def _set_format(self, vmin=None, vmax=None):
        self.format = self.fformat
        if self._useMathText:
            self.format = r'$mathdefault{%s}$' % self.format


x = np.linspace(1,9,9)
y1 = x*10**(-4)
y2 = x*10**(-3)

fig, ax = plt.subplots(2,1,sharex=True)

ax[0].plot(x,y1)
ax[1].plot(x,y2)

for axe in ax:
    axe.yaxis.set_major_formatter(OOMFormatter(-4, "%1.1f"))
    axe.ticklabel_format(axis='y', style='sci', scilimits=(-4,-4))

plt.show()

虽然这乍一看似乎很复杂,但它真正做的唯一一件事就是覆盖私有方法 _set_orderOfMagnitude_set_format,从而防止它们在我们不想要的背景.因为最后,我们需要的是,与内部发生的事情无关,self.orderOfMagnitude 总是 -4self.format 是总是"%1.1f".

While this may seem complicated at first sight the only thing it really does is overwrite the private methods _set_orderOfMagnitude and _set_format and thereby prevent them from doing some sophisticated stuff in the background that we don't want. Because in the end, all we need is that, independent of what happens internally, self.orderOfMagnitude is always -4 and self.format is always "%1.1f".

注意:在 matplotlib <3.1 类需要看起来像

Note: In matplotlib < 3.1 the class needed to look like

class OOMFormatter(matplotlib.ticker.ScalarFormatter):
        def __init__(self, order=0, fformat="%1.1f", offset=True, mathText=True):
            self.oom = order
            self.fformat = fformat
            matplotlib.ticker.ScalarFormatter.__init__(self,useOffset=offset,useMathText=mathText)
        def _set_orderOfMagnitude(self, nothing=None):
            self.orderOfMagnitude = self.oom
        def _set_format(self, vmin=None, vmax=None):
            self.format = self.fformat
            if self._useMathText:
                self.format = '$%s$' % matplotlib.ticker._mathdefault(self.format)