Matplotlib半对数图:当范围较大时,次要刻度线消失

vshtjzan  于 2022-11-15  发布在  其他
关注(0)|答案(5)|浏览(232)

在绘制半对数图(y为对数)时,y轴上的小刻度线(每10年8个)会自动出现,但似乎当轴范围超过10**10时,它们就会消失。我尝试了许多方法来强制它们重新出现,但都没有效果。可能是为了避免过度拥挤,它们在较大范围内消失了,但我们应该有选择吗?

bq3bfh9z

bq3bfh9z1#

matplotlib的解决方案〉= 2.0.2

让我们考虑以下示例

它由以下代码生成:

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

y = np.arange(12)
x = 10.0**y

fig, ax=plt.subplots()
ax.plot(x,y)
ax.set_xscale("log")
plt.show()

次要的ticklabel确实消失了,通常显示它们的方法(如plt.tick_params(axis='x', which='minor'))失败了。
第一步是在轴上显示10的所有幂,

locmaj = matplotlib.ticker.LogLocator(base=10,numticks=12) 
ax.xaxis.set_major_locator(locmaj)

其中技巧是将numticks设置为等于或大于滴答数的数(即,在这种情况下为12或更大)。
然后,我们可以将次要刻度标签添加为

locmin = matplotlib.ticker.LogLocator(base=10.0,subs=(0.2,0.4,0.6,0.8),numticks=12)
ax.xaxis.set_minor_locator(locmin)
ax.xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())

请注意,我将其限制为每十进位包含4个小刻度(使用8也是可能的,但在本例中会使轴过于拥挤)。
最后,我们需要对次要刻度使用NullFormatter(),以便不为它们显示任何刻度标签。

matplotlib 2.0.0的解决方案

  • 以下内容适用于matplotlib 2.0.0或更低版本,但不适用于matplotlib 2.0.2。*

让我们考虑以下示例

它由以下代码生成:

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

y = np.arange(12)
x = 10.0**y

fig, ax=plt.subplots()
ax.plot(x,y)
ax.set_xscale("log")
plt.show()

次要的ticklabel确实消失了,通常显示它们的方法(如plt.tick_params(axis='x', which='minor'))失败了。
第一步是在轴上显示10的所有幂,

locmaj = matplotlib.ticker.LogLocator(base=10.0, subs=(0.1,1.0, ))
ax.xaxis.set_major_locator(locmaj)

x1c4d 1x指令集
然后,我们可以将次要刻度标签添加为

locmin = matplotlib.ticker.LogLocator(base=10.0, subs=(0.1,0.2,0.4,0.6,0.8,1,2,4,6,8,10 )) 
ax.xaxis.set_minor_locator(locmin)
ax.xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())

请注意,我将其限制为每10年包含4个小刻度(使用8个小刻度也是可能的,但在本例中会使轴过于拥挤)。还要注意--这可能是这里的关键--subs参数(它给出了放置刻度的基数的整数幂的倍数(参见文档))被给出了一个20年而不是1年的列表。
最后,我们需要对次要刻度使用NullFormatter(),以便不为它们显示任何刻度标签。

guz6ccqo

guz6ccqo2#

带有空标签的主要记号将生成记号,但不生成标签。

ax.set_yticks([1.E-6,1.E-5,1.E-4,1.E-3,1.E-2,1.E-1,1.E0,1.E1,1.E2,1.E3,1.E4,1.E5,])

ax.set_yticklabels(['$10^{-6}$','','','$10^{-3}$','','','$1$','','','$10^{3}$','',''])

hmae6n7t

hmae6n7t3#

matplotlib >= 2.0.2importanceofbeingernest中的excellent answer Package 到函数中:

import matplotlib.pyplot as plt
from typing import Optional

def restore_minor_ticks_log_plot(
    ax: Optional[plt.Axes] = None, n_subticks=9
) -> None:
    """For axes with a logrithmic scale where the span (max-min) exceeds
    10 orders of magnitude, matplotlib will not set logarithmic minor ticks.
    If you don't like this, call this function to restore minor ticks.

    Args:
        ax:
        n_subticks: Number of Should be either 4 or 9.

    Returns:
        None
    """
    if ax is None:
        ax = plt.gca()
    # Method from SO user importanceofbeingernest at
    # https://stackoverflow.com/a/44079725/5972175
    locmaj = mpl.ticker.LogLocator(base=10, numticks=1000)
    ax.xaxis.set_major_locator(locmaj)
    locmin = mpl.ticker.LogLocator(
        base=10.0, subs=np.linspace(0, 1.0, n_subticks + 2)[1:-1], numticks=1000
    )
    ax.xaxis.set_minor_locator(locmin)
    ax.xaxis.set_minor_formatter(mpl.ticker.NullFormatter())

然后,可以将此函数调用为

plt.plot(x,y)
plt.xscale("log")
restore_minor_ticks_log_plot()

或更明确地

_, ax = plt.subplots()
ax.plot(x, y)
ax.set_xscale("log")
restore_minor_ticks_log_plot(ax)
ykejflvf

ykejflvf4#

据我所知,截至Matplotlib 3.5.2:

  • 如果主刻度线不超过8个,则次刻度线显示
  • 如果有9到11个主要刻度线,subs="auto"将显示次要刻度线
  • 对于12个或更多,您需要手动设置subs

使用subs="auto"

from matplotlib import pyplot as plt, ticker as mticker

fig, ax = plt.subplots()
y = np.arange(11)
x = 10.0**y

ax.semilogx(x, y)
ax.xaxis.set_major_locator(mticker.LogLocator(numticks=999))
ax.xaxis.set_minor_locator(mticker.LogLocator(numticks=999, subs="auto"))

手动设置接头

from matplotlib import pyplot as plt, ticker as mticker

fig, ax = plt.subplots()
y = np.arange(12)
x = 10.0**y

ax.semilogx(x, y)
ax.xaxis.set_major_locator(mticker.LogLocator(numticks=999))
ax.xaxis.set_minor_locator(mticker.LogLocator(numticks=999, subs=(.2, .4, .6, .8)))

ktca8awb

ktca8awb5#

这里的答案忽略了一个方便的事实,即对数坐标轴已经有了必要的定位器。至少在Matplotlib 3.6中,使用set_params()和强制小刻度的值就足够了:

import matplotlib.pyplot as plt
import numpy as np

y = np.arange(12)
x = 10.0**y

fig, ax = plt.subplots()

ax.plot(x, y)

ax.set_xscale('log')

ax.xaxis.get_major_locator().set_params(numticks=99)
ax.xaxis.get_minor_locator().set_params(numticks=99, subs=[.2, .4, .6, .8])

plt.show()

相关问题