制作半对数图(y 是对数)时,y 轴上的小刻度线(十进制 8)会自动出现,但似乎当轴范围超过 10**10 时,它们就会消失。我尝试了很多方法来强行让他们回来,但都没有效果。也许他们会去大范围以避免过度拥挤,但人们应该有选择?
让我们考虑以下示例
由这段代码生成:
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()
小刻度标签确实消失了,通常显示它们的方法(如
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 个同样可能,但在本例中会使轴过度拥挤)。另请注意,
numticks
再次(非常不直观)为 12 或更大。
最后,我们需要对小刻度使用
NullFormatter()
,以免出现任何刻度标签。
以下内容在 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()
小刻度标签确实消失了,通常显示它们的方法(如
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)
然后,我们可以添加小刻度标签为
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())
请注意,我将其限制为每十年包含 4 个小刻度(使用 8 个同样可能,但在本例中会使轴过度拥挤)。另请注意 - 这可能是这里的关键 -
subs
参数给出了放置刻度的基数整数幂的倍数(请参阅文档),给出了一个范围超过二十年的列表,而不是一个。
最后,我们需要对小刻度使用
NullFormatter()
,以免出现任何刻度标签。
据我所知,从 Matplotlib 3.5.2 开始:
subs="auto"
将显示次要刻度线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)))
这里的答案忽略了一个方便的事实,即对数刻度轴已经具有必要的定位器。至少从 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()
将matplotlib >= 2.0.2
的importanceofbeingernest中的
优秀答案包装到一个函数中:
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)