Matplotlib日志的错误刻度/标签(双轴)
我正在用matplotlib创建日志图。如下图所示,默认记号选择得很糟糕(最多);右y轴甚至根本没有(在线性等价物中有),而两个x轴都只有一个 有没有一种方法可以通过标签获得合理数量的刻度,而不用手动为每个绘图指定刻度Matplotlib日志的错误刻度/标签(双轴),matplotlib,plot,Matplotlib,Plot,我正在用matplotlib创建日志图。如下图所示,默认记号选择得很糟糕(最多);右y轴甚至根本没有(在线性等价物中有),而两个x轴都只有一个 有没有一种方法可以通过标签获得合理数量的刻度,而不用手动为每个绘图指定刻度 编辑:确切的代码太长,但下面是一个简短的问题示例: x = linspace(4, 18, 20) y = 1 / (x ** 4) fig = figure() ax = fig.add_axes([.1, .1, .8, .8]) ax.loglog(x, y) ax.s
编辑:确切的代码太长,但下面是一个简短的问题示例:
x = linspace(4, 18, 20)
y = 1 / (x ** 4)
fig = figure()
ax = fig.add_axes([.1, .1, .8, .8])
ax.loglog(x, y)
ax.set_xlim([4, 18])
ax2 = ax.twiny()
ax2.set_xlim([4 / 3., 18 / 3.])
ax2.set_xscale('log')
show()
我一直在和你展示的东西做斗争(轴范围内只有一个大刻度)。没有一个matplotlib tick格式化程序让我满意,所以我使用
matplotlib.ticker.FuncFormatter
来实现我想要的。我还没有测试过双轴,但我的感觉是它无论如何都应该工作
import matplotlib.pyplot as plt
from matplotlib import ticker
import numpy as np
#@Mark: thanks for the suggestion :D
mi, ma, conv = 4, 8, 1./3.
x = np.linspace(mi, ma, 20)
y = 1 / (x ** 4)
fig, ax = plt.subplots()
ax.plot(x, y) # plot the lines
ax.set_xscale('log') #convert to log
ax.set_yscale('log')
ax.set_xlim([0.2, 1.8]) #large enough, but should show only 1 tick
def ticks_format(value, index):
"""
This function decompose value in base*10^{exp} and return a latex string.
If 0<=value<99: return the value as it is.
if 0.1<value<0: returns as it is rounded to the first decimal
otherwise returns $base*10^{exp}$
I've designed the function to be use with values for which the decomposition
returns integers
"""
exp = np.floor(np.log10(value))
base = value/10**exp
if exp == 0 or exp == 1:
return '${0:d}$'.format(int(value))
if exp == -1:
return '${0:.1f}$'.format(value)
else:
return '${0:d}\\times10^{{{1:d}}}$'.format(int(base), int(exp))
# here specify which minor ticks per decate you want
# likely all of them give you a too crowed axis
subs = [1., 3., 6.]
# set the minor locators
ax.xaxis.set_minor_locator(ticker.LogLocator(subs=subs))
ax.yaxis.set_minor_locator(ticker.LogLocator(subs=subs))
# remove the tick labels for the major ticks:
# if not done they will be printed with the custom ones (you don't want it)
# plus you want to remove them to avoid font missmatch: the above function
# returns latex string, and I don't know how matplotlib does exponents in labels
ax.xaxis.set_major_formatter(ticker.NullFormatter())
ax.yaxis.set_major_formatter(ticker.NullFormatter())
# set the desired minor tick labels using the above function
ax.xaxis.set_minor_formatter(ticker.FuncFormatter(ticks_format))
ax.yaxis.set_minor_formatter(ticker.FuncFormatter(ticks_format))
导入matplotlib.pyplot作为plt
从matplotlib导入代码
将numpy作为np导入
#@马克:谢谢你的建议
mi,ma,conv=4,8,1./3。
x=np.linspace(mi,ma,20)
y=1/(x**4)
图,ax=plt.子批次()
画(x,y)#画线
ax.setxscale('log')#转换为log
ax.set_yscale('log'))
ax.set_xlim([0.2,1.8])#足够大,但应仅显示1个刻度
def ticks_格式(值、索引):
"""
此函数分解base*10^{exp}中的值并返回一个latex字符串。
如果最后是0,这是我在其他答案的帮助下所能想到的最好答案,而其他答案是:
在左边,x和y仅在一个数量级的一部分上变化,标签工作得相当好。在左边,x在1到2个数量级之间变化。它工作正常,但方法已达到极限。y值变化了许多数量级,并且自动使用标准标签
from matplotlib import ticker
from numpy import linspace, logspace, log10, floor
from warnings import warn
def round_to_n(x, n):
''' http://stackoverflow.com/questions/3410976/how-to-round-a-number-to-significant-figures-in-python '''
return round(x, -int(floor(log10(abs(x)))) + (n - 1))
def ticks_log_format(value, index):
''' http://stackoverflow.com/questions/19239297/matplotlib-bad-ticks-labels-for-loglog-twin-axis '''
pwr = floor(log10(value))
base = value / (10 ** pwr)
if pwr == 0 or pwr == 1:
return '${0:d}$'.format(int(value))
if -3 <= pwr < 0:
return '${0:.3g}$'.format(value)
if 0 < pwr <= 3:
return '${0:d}$'.format(int(value))
else:
return '${0:d}\\times10^{{{1:d}}}$'.format(int(base), int(pwr))
def calc_ticks(domain, tick_count, equidistant):
if equidistant:
ticks = logspace(log10(domain[0]), log10(domain[1]), num = tick_count, base = 10)
else:
ticks = linspace(domain[0], domain[1], num = tick_count)
for n in range(1, 6):
if len(set(round_to_n(tick, n) for tick in ticks)) == tick_count:
break
return list(round_to_n(tick, n) for tick in ticks)
''' small domain log ticks '''
def sdlt_x(ax, domain, tick_count = 4, equidistant = True):
''' http://stackoverflow.com/questions/3410976/how-to-round-a-number-to-significant-figures-in-python '''
if min(domain) <= 0:
warn('domain %g-%g contains values lower than 0' % (domain[0], domain[1]))
domain = [max(value, 0.) for value in domain]
ax.set_xscale('log')
ax.set_xlim(domain)
ax.xaxis.set_major_formatter(ticker.FuncFormatter(ticks_log_format))
if log10(max(domain) / min(domain)) > 1.7:
return
ticks = calc_ticks(domain, tick_count = tick_count, equidistant = equidistant)
ax.set_xticks(ticks)
''' any way to prevent this code duplication? '''
def sdlt_y(ax, domain, tick_count = 5, equidistant = True):
''' http://stackoverflow.com/questions/3410976/how-to-round-a-number-to-significant-figures-in-python '''
if min(domain) <= 0:
warn('domain %g-%g contains values lower than 0' % (domain[0], domain[1]))
domain = [max(value, 1e-8) for value in domain]
ax.set_yscale('log')
ax.set_ylim(domain)
ax.yaxis.set_major_formatter(ticker.FuncFormatter(ticks_log_format))
if log10(max(domain) / min(domain)) > 1.7:
return
ticks = calc_ticks(domain, tick_count = tick_count, equidistant = equidistant)
ax.set_yticks(ticks)
''' demo '''
fig, (ax1, ax2,) = plt.subplots(1, 2)
for mi, ma, ax in ((100, 130, ax1,), (10, 400, ax2,), ):
x = np.linspace(mi, ma, 50)
y = 1 / ((x + random(50) * 0.1 * (ma - mi)) ** 4)
ax.scatter(x, y)
sdlt_x(ax, (mi, ma, ))
sdlt_y(ax, (min(y), max(y), ))
show()
从matplotlib导入代码
从numpy导入linspace、logspace、log10、floor
从警告导入警告
def四舍五入到四舍五入(x,n):
''' http://stackoverflow.com/questions/3410976/how-to-round-a-number-to-significant-figures-in-python '''
返回轮(x,-int(地面(log10(abs(x)))+(n-1))
def ticks_log_格式(值、索引):
''' http://stackoverflow.com/questions/19239297/matplotlib-bad-ticks-labels-for-loglog-twin-axis '''
压水堆=地板(log10(值))
基准=值/(10**pwr)
如果pwr==0或pwr==1:
返回“${0:d}$”。格式(int(value))
如果-3,默认值只会在十年内打勾(并且您的时间少于十年)你能给我们看一下你用来生成这个的代码吗?可能是重复的。进一步看,看起来你在hartee/bohr轴上做所有的绘图,并且使用twinx
和twiny
来获得eV和angstrom轴,但不要对它们进行任何绘图。你需要明确设置它们的限制以匹配其他轴上的限制(正确转换)@tcaswell:你是对的,我从来没有给他们画过任何东西,但我已经设定了限制,我认为它们是正确的。我会看看可能的重复。另一个问题类似,但我不认为它是重复的,因为它手动设置了刻度点,这是我不想要的。它适用于大约一个数量级的变化ose到0我认为,这是一个常见的问题。如果你需要在较小的域上使用日志比例,小刻度没有多大帮助,但这可能是例外…而且格式很酷!