具有不同因子和基数的对数刻度
Log scale with a different factor and base
我看到 set_xscale
接受一个 base
参数,但我也想用一个因子进行缩放;即,如果基数为 4,因数为 10,则:
40, 160, 640, ...
另外,文档说 subsx
表示的子网格值应该是整数,但我想要浮点值。
最干净的方法是什么?
我不知道有任何内置方法可以在指数后应用比例因子,但您可以通过子类化 matplotlib.ticker.LogLocator
and matplotlib.ticker.LogFormatter
.
创建自定义刻度定位器和格式化程序
这是一个相当快速但简单的技巧,可以满足您的需求:
from matplotlib import pyplot as plt
from matplotlib.ticker import LogLocator, LogFormatter, ScalarFormatter, \
is_close_to_int, nearest_long
import numpy as np
import math
class ScaledLogLocator(LogLocator):
def __init__(self, *args, scale=10.0, **kwargs):
self._scale = scale
LogLocator.__init__(self, *args, **kwargs)
def view_limits(self, vmin, vmax):
s = self._scale
vmin, vmax = LogLocator.view_limits(self, vmin / s, vmax / s)
return s * vmin, s * vmax
def tick_values(self, vmin, vmax):
s = self._scale
locs = LogLocator.tick_values(self, vmin / s, vmax / s)
return s * locs
class ScaledLogFormatter(LogFormatter):
def __init__(self, *args, scale=10.0, **kwargs):
self._scale = scale
LogFormatter.__init__(self, *args, **kwargs)
def __call__(self, x, pos=None):
b = self._base
s = self._scale
# only label the decades
if x == 0:
return '$\mathdefault{0}$'
fx = math.log(abs(x / s)) / math.log(b)
is_decade = is_close_to_int(fx)
sign_string = '-' if x < 0 else ''
# use string formatting of the base if it is not an integer
if b % 1 == 0.0:
base = '%d' % b
else:
base = '%s' % b
scale = '%d' % s
if not is_decade and self.labelOnlyBase:
return ''
elif not is_decade:
return ('$\mathdefault{%s%s\times%s^{%.2f}}$'
% (sign_string, scale, base, fx))
else:
return (r'$%s%s\times%s^{%d}$'
% (sign_string, scale, base, nearest_long(fx)))
例如:
fig, ax = plt.subplots(1, 1)
x = np.arange(1000)
y = np.random.randn(1000)
ax.plot(x, y)
ax.set_xscale('log')
subs = np.linspace(0, 1, 10)
majloc = ScaledLogLocator(scale=10, base=4)
minloc = ScaledLogLocator(scale=10, base=4, subs=subs)
fmt = ScaledLogFormatter(scale=10, base=4)
ax.xaxis.set_major_locator(majloc)
ax.xaxis.set_minor_locator(minloc)
ax.xaxis.set_major_formatter(fmt)
ax.grid(True)
# show the same tick locations with non-exponential labels
ax2 = ax.twiny()
ax2.set_xscale('log')
ax2.set_xlim(*ax.get_xlim())
fmt2 = ScalarFormatter()
ax2.xaxis.set_major_locator(majloc)
ax2.xaxis.set_minor_locator(minloc)
ax2.xaxis.set_major_formatter(fmt2)
我看到 set_xscale
接受一个 base
参数,但我也想用一个因子进行缩放;即,如果基数为 4,因数为 10,则:
40, 160, 640, ...
另外,文档说 subsx
表示的子网格值应该是整数,但我想要浮点值。
最干净的方法是什么?
我不知道有任何内置方法可以在指数后应用比例因子,但您可以通过子类化 matplotlib.ticker.LogLocator
and matplotlib.ticker.LogFormatter
.
这是一个相当快速但简单的技巧,可以满足您的需求:
from matplotlib import pyplot as plt
from matplotlib.ticker import LogLocator, LogFormatter, ScalarFormatter, \
is_close_to_int, nearest_long
import numpy as np
import math
class ScaledLogLocator(LogLocator):
def __init__(self, *args, scale=10.0, **kwargs):
self._scale = scale
LogLocator.__init__(self, *args, **kwargs)
def view_limits(self, vmin, vmax):
s = self._scale
vmin, vmax = LogLocator.view_limits(self, vmin / s, vmax / s)
return s * vmin, s * vmax
def tick_values(self, vmin, vmax):
s = self._scale
locs = LogLocator.tick_values(self, vmin / s, vmax / s)
return s * locs
class ScaledLogFormatter(LogFormatter):
def __init__(self, *args, scale=10.0, **kwargs):
self._scale = scale
LogFormatter.__init__(self, *args, **kwargs)
def __call__(self, x, pos=None):
b = self._base
s = self._scale
# only label the decades
if x == 0:
return '$\mathdefault{0}$'
fx = math.log(abs(x / s)) / math.log(b)
is_decade = is_close_to_int(fx)
sign_string = '-' if x < 0 else ''
# use string formatting of the base if it is not an integer
if b % 1 == 0.0:
base = '%d' % b
else:
base = '%s' % b
scale = '%d' % s
if not is_decade and self.labelOnlyBase:
return ''
elif not is_decade:
return ('$\mathdefault{%s%s\times%s^{%.2f}}$'
% (sign_string, scale, base, fx))
else:
return (r'$%s%s\times%s^{%d}$'
% (sign_string, scale, base, nearest_long(fx)))
例如:
fig, ax = plt.subplots(1, 1)
x = np.arange(1000)
y = np.random.randn(1000)
ax.plot(x, y)
ax.set_xscale('log')
subs = np.linspace(0, 1, 10)
majloc = ScaledLogLocator(scale=10, base=4)
minloc = ScaledLogLocator(scale=10, base=4, subs=subs)
fmt = ScaledLogFormatter(scale=10, base=4)
ax.xaxis.set_major_locator(majloc)
ax.xaxis.set_minor_locator(minloc)
ax.xaxis.set_major_formatter(fmt)
ax.grid(True)
# show the same tick locations with non-exponential labels
ax2 = ax.twiny()
ax2.set_xscale('log')
ax2.set_xlim(*ax.get_xlim())
fmt2 = ScalarFormatter()
ax2.xaxis.set_major_locator(majloc)
ax2.xaxis.set_minor_locator(minloc)
ax2.xaxis.set_major_formatter(fmt2)