一组数据的两个 y 轴刻度,对齐两组刻度

Two y-axes ticks for one set of data, aligning both sets of ticks

我已经设法在右侧以百分比形式绘制 y 轴刻度,但标签并不吸引人我想将它们更改为 10 的倍数。如何更改刻度以使它们为 10 ^2% (100%)、10^1%、10^0% 等,但它们仍然匹配左侧的刻度?

from datetime import datetime
from dateutil.relativedelta import relativedelta
from numpy import nan, arange
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
import sys

twentytwo = {}
twentytwo[60.0] = [578, 85, 14, 5, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

totNEA2014 = 1266

def to_percent(y, position):
    # Ignore the passed in position. This has the effect of scaling the default
    # tick locations.
    s = str(100 * (y/totNEA2014))
    if matplotlib.rcParams['text.usetex'] == True:
        return s + r'$\%$'
    else:
        return s + '%'

# Plot Details
bar_width = 0.18
line_width = 1
opacity = 1.
centre_bar_positions = arange(20)
zeros = [0 for k in range(len(centre_bar_positions))]

# Make bar plots
fig = plt.figure(figsize=[12, 9])
ax1 = fig.add_subplot(111)
bar_60_22 = plt.bar(centre_bar_positions, twentytwo[60.0], bar_width, bottom=10**-1, alpha=opacity, color='green', log=True, label='V < 22')

plt.title("Some Place")
plt.ylabel("Number of NEAs")
plt.xlabel("Number of apparitions")
ax1.set_ylim([ax1.set_ylim()[0], totNEA2014])
ax1.set_yscale("log")
plt.legend(loc='best')

ax2 = ax1.twinx()
ax2.yaxis.set_label_position("right")
plt.bar(centre_bar_positions, zeros, bar_width, bottom=10**-1, color='white', edgecolor='grey', linewidth=line_width, hatch='0', log=True)
ax2.set_ylim([ax1.set_ylim()[0], ax1.set_ylim()[1]])
formatter = FuncFormatter(to_percent)
plt.gca().yaxis.set_major_formatter(formatter)
plt.ylabel("Percentage of NEAs discovered in 2014")

plt.xlim([.6, 5.8])
plt.show()

这是我的代码当前生成的结果(我减少了上面代码中的条数):

就像@julien-spronck,我可能不明白你need/what你的情节是什么意思,但我同意我会在哪里修复它。如果你只是想以不同的格式显示相同的数字(右边的百分比,左边的对数百分比(?)),那么

s = str(totNEA2014 * (y/totNEA2014))

产量:

我很困惑:左 yaxis 下降到 0.1,但被标记为 "Number of NEAs"; NEA 的计数真的小于一吗?您是否希望左 yaxis 带有计数、0 手数和右 yaxis 百分比且不从 0 开始?

我想我明白了。您希望右轴从 0% 到 100% 并采用对数刻度。我认为这应该可以解决问题。

totNEA2014 = 1266

def to_percent(y, position):
    # Ignore the passed in position. This has the effect of scaling the default
    # tick locations.
    s = str(100 * y)
    if matplotlib.rcParams['text.usetex'] == True:
        return s + r'$\%$'
    else:
        return s + '%'

# Plot Details
bar_width = 0.18
line_width = 1
opacity = 1.
centre_bar_positions = arange(20)
zeros = [0 for k in range(len(centre_bar_positions))]

# Make bar plots
fig = plt.figure(figsize=[12, 9])
ax1 = fig.add_subplot(111)
bar_60_22 = plt.bar(centre_bar_positions, twentytwo[60.0], bar_width, bottom=10**-1, alpha=opacity, color='green', log=True, label='V < 22')

plt.title("Some Place")
plt.ylabel("Number of NEAs")
plt.xlabel("Number of apparitions")
ax1.set_ylim([ax1.set_ylim()[0], totNEA2014])
ax1.set_yscale("log")
plt.legend(loc='best')

ax2 = ax1.twinx()
ax2.yaxis.set_label_position("right")
ax2.set_yscale("log")
ax1.bar(centre_bar_positions, zeros, bar_width, bottom=10**-1, color='white', edgecolor='grey', linewidth=line_width, hatch='0', log=True)
ax2.set_ylim([0.0001, 1])
ax2.set_yticks([0.0001, 0.001, 0.01, 0.1, 1.])
formatter = FuncFormatter(to_percent)
ax2.get_yaxis().set_major_formatter(formatter)
plt.ylabel("Percentage of NEAs discovered in 2014")

plt.xlim([.6, 5.8])
plt.show()

请注意,我更改了您的格式化程序函数以及绘图线(现在只绘制到 ax1 而不是两个轴)

使用 .add_artist(matplotlib.axis.YAxis(ax1)) 添加额外的轴比使用 .twinx() 更可靠。

添加一个带有 .twinx() 的额外 Axes 对象似乎有些过分,因为您只需要一个额外的 axis。使用问题中提出的 .twinx() 也有第二个轴与数据分离的缺点,因此您需要一些 hack 使其对应于数据和另一个轴,例如更改 ylim (在其他答案中以各种方式完成)——但是,一旦您在原始轴上更改 ylim,这就会中断。

见下文。我更改了 to_percent 函数中的第一行以获得漂亮的数字格式和名为 "ADD SECOND Y-AXIS".

的块
from datetime import datetime
from dateutil.relativedelta import relativedelta
from numpy import nan, arange
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
import sys

twentytwo = {}
twentytwo[60.0] = [578, 85, 14, 5, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

totNEA2014 = 1266

def to_percent(y, position):
    # Ignore the passed in position. This has the effect of scaling the default
    # tick locations.
    s = '%g' % (100 * (y/totNEA2014))
    if matplotlib.rcParams['text.usetex'] == True:
        return s + r'$\%$'
    else:
        return s + '%'

# Plot Details
bar_width = 0.18
line_width = 1
opacity = 1.
centre_bar_positions = arange(20)
zeros = [0 for k in range(len(centre_bar_positions))]

# Make bar plots
fig = plt.figure(figsize=[12, 9])
ax1 = fig.add_subplot(111)
bar_60_22 = plt.bar(centre_bar_positions, twentytwo[60.0], bar_width, bottom=10**-1, alpha=opacity, color='green', log=True, label='V < 22')

plt.title("Some Place")
plt.ylabel("Number of NEAs")
plt.xlabel("Number of apparitions")
ax1.set_ylim([ax1.set_ylim()[0], totNEA2014])
ax1.set_yscale("log")
plt.legend(loc='best')

# ADD SECOND Y-AXIS    
extra_axis = matplotlib.axis.YAxis(ax1)
extra_axis.tick_right()
formatter = FuncFormatter(to_percent)
extra_axis.set_major_formatter(formatter)
extra_axis.set_ticks([totNEA2014*10**p for p in range(-4, 1)])
extra_axis.set_label_text("Percentage of NEAs discovered in 2014")
extra_axis.set_label_position('right')
ax1.add_artist(extra_axis)

plt.xlim([.6, 5.8])
plt.show()