我正在使用matplotlib在单个图中显示多个数据集。我想为辅助数据设置多个“外部”y轴,并希望这些轴具有相同的范围,但缩放比主曲线轴的缩放更短。
我正在使用twinx()创建其他y轴,如this post
中所述ax = day6Si.plot(
'time', 'pce_rolling'
)
dataPsc[ dataPsc.day == 5 ].plot(
'time', 'pce_rolling', ax = ax
)
ax3 = ax.twinx()
ax3.fill_between(
day6Si.time, 0, day6Si.temperature
)
rspine = ax3.spines[ 'right' ]
rspine.set_position( ( 'axes', 1.15 ) )
ax3.set_frame_on( True )
ax3.patch.set_visible( False )
ax3.set_ylim( bottom = 0 )
ax2 = ax.twinx()
ax2.fill_between(
day6Si.time, 0, day6Si.intensity
)
rspine = ax2.spines[ 'right' ]
rspine.set_position( ( 'axes', 1.05 ) )
ax2.set_frame_on( True )
ax2.patch.set_visible( False )
ax2.set_ylim( bottom = 0 )
MCV示例
td = np.linspace( 0, np.pi, 101 )
df = pd.DataFrame( data = {
'main': np.sin( td ),
'secondary': 10 * np.sin( td )
} )
ax = df.plot( df.index.values, 'main' )
ax2 = ax.twinx()
ax2.fill_between(
df.index.values, 0, df.secondary,
facecolor = '#a05050',
label = 'Secondary'
)
rspine = ax2.spines[ 'right' ]
rspine.set_position( ( 'axes', 1.05 ) )
ax2.set_frame_on( True )
ax2.patch.set_visible( False )
ax2.set_ylim( bottom = 0 )
ax2.set_ylabel( 'Secondary' )
ax.set_ylim( 0, 1 )
ax.legend( [ 'Main', 'Secondary' ] )
答案 0 :(得分:0)
完成这项工作的关键是操纵每个轴的Bbox。该解决方案构建了this advice for creating multiple y axes
mpl = matplotlib,np = numpy,pd = pandas
创建主轴ax
。
使用ax.get_position()
获取Bbox个轴,然后使用axpos
获取边界点get_points()
。
使用ax.twinx()
创建辅助轴ax2
。
使用ax2
为ax2pos
,mpl.transforms.Bbox( np.copy( axpos ) )
创建Bbox。请务必创建原始Bbox点的副本,否则两者都将被修改。
缩放辅助边界框。这可以通过设置水平缩放的x1
属性或垂直缩放的y1
属性来完成。 (例如ax2pos.y1 = 0.5* ax2pos.y1
)
使用set_position()
设置辅助轴的边界框。
使用ax2.spines[ 'top' ].set_visible( False )
关闭顶部(或右侧,水平缩放)spine。
您可能还需要考虑:
切换每个轴patch,以便不使用ax.patch.set_visible()
在以前的图层上绘画。
使用ax.set_zorder()
调整轴的绘制顺序。
由于缩放,您可能需要调整保存图形时使用的边界框。这可以通过创建另一个Bbox并将其作为bbox_inches
参数传递给savefig()
来完成。
MCV解决方案
td = np.linspace( 0, np.pi, 101 )
df = pd.DataFrame( data = {
'main': np.sin( td ),
'secondary': 10 * np.sin( td )
} )
ax = df.plot( df.index.values, 'main' )
axpos = ax.get_position()
ax2 = ax.twinx()
ax2pos = mpl.transforms.Bbox( np.copy( axpos.get_points() ) ) # clone bounding box
ax2pos.y1 = ax2pos.y1 * 0.5 # scale y axis
ax2.set_position( ax2pos ) # set bounding box
ax2.fill_between(
df.index.values, 0, df.secondary,
facecolor = '#a05050',
label = 'Secondary'
)
ax2.spines[ 'right' ].set_position( ( 'axes', 1.05 ) )
ax2.spines[ 'top' ].set_visible( False )
ax2.set_frame_on( True )
ax2.patch.set_visible( False )
ax2.set_ylim( bottom = 0 )
ax2.set_ylabel( 'Secondary' )
ax.set_ylim( 0, 1 )
ax.legend( [ 'Main', 'Secondary' ] )
完整代码解决方案
ax = day6Si.plot(
'time', 'pce_rolling', kind = 'line', label = 'Si',
zorder = 40
)
dataPsc[ dataPsc.day == 5 ].plot(
'time', 'pce_rolling', kind = 'line', label = 'PSC',
zorder = 30, ax = ax
)
axpos = ax.get_position()
ax.set_zorder( 30 )
ax.patch.set_visible( False )
ax.set_xlim( 124.5, 141.5 )
ax.set_ylim( 10, 20 )
ax.set_ylabel( 'PCE (%)' )
ax.set_xlabel( 'Time' )
ax.set_xticklabels( [ '4', '6', '8', '10', '12', '14', '16', '18', '20' ] )
ax.legend( loc = 'upper right', bbox_to_anchor = ( 1, 1 ) )
# temperature
ax3 = ax.twinx()
ax3.fill_between(
day6Si.time, 0, day6Si.temperature,
facecolor = '#f0c5b5',
label = 'Temperature (Rel)'
)
ax3pos = mpl.transforms.Bbox( np.copy( axpos.get_points() ) ) # clone bounding box
ax3pos.y1 = ax3pos.y1 * 0.5 # scale y axis
ax3.set_position( ax3pos ) # set bounding box
ax3.set_zorder( 10 )
ax3.spines[ 'right' ].set_position( ( 'axes', 1.025 ) ) # shift y axis
ax3.set_frame_on( True )
ax3.spines[ 'top' ].set_visible( False ) # remove top frame line
ax3.patch.set_visible( True )
ax3.set_ylim( bottom = 0, top = 60 )
ax3.set_ylabel( 'Temperature (C)' )
# intensity
ax2 = ax.twinx()
ax2.fill_between(
day6Si.time, 0, day6Si.intensity,
facecolor = '#dddd99',
label = 'Intensity (Rel)'
)
ax2pos = mpl.transforms.Bbox( np.copy( axpos.get_points() ) ) # clone bounding box
ax2pos.y1 = ax2pos.y1 * 0.33 # scale y axis
ax2.set_position( ax2pos ) # set bounding box
ax2.set_zorder( 20 )
ax2.spines[ 'right' ].set_position( ( 'axes', 1.125 ) ) # shift y asix
ax2.set_frame_on( True )
ax2.spines[ 'top' ].set_visible( False ) # remove top frame
ax2.patch.set_visible( False )
ax2.set_ylim( bottom = 0, top = 1 )
ax2.set_ylabel( 'Intensity (suns)' )
savebox = mpl.transforms.Bbox( [ [ 0, 0 ], [ 10* 1.15, 8 ] ] ) # bounding box in inches for saving
plt.gcf().savefig( figloc + '/day6.svg', format = 'svg', bbox_inches = savebox )
<强>更新强>
由于matplotlib库中的更新,必须进行一些小的更改才能实现。执行ax.twinx()
不再允许您控制第二个轴,因此必须手动将其添加到图中。
mpl = matplotlib,plt = matplotlib.pyplot,np = numpy,pd = pandas
使用fig
ax
和轴plt.subplots()
在步骤2,4和5中像以前一样创建Bbox。
使用ax2a
创建辅助轴fig.add_axes()
,并使用所需的边界框。
通过联合ax2a
,ax2a.twinx()
创建正确的y轴。
清理辅助轴。
您可能还需要考虑使用ax.set_xlim()
对齐它们来对齐主轴和副轴的x轴。
MCV解决方案
td = np.linspace( 0, np.pi, 101 )
df = pd.DataFrame( data = {
'main': np.sin( td ),
'secondary': 10 * np.sin( td )
} )
fig, ax = plt.subplots()
df.plot( df.index.values, 'main', ax = ax )
axpos = ax.get_position()
ax2pos = mpl.transforms.Bbox( np.copy( axpos.get_points() ) )
ax2pos.y1 = ax2pos.y1 * 0.5 # scale y axis
ax2a = fig.add_axes( ax2pos ) # create secondary axes
ax2 = ax2a.twinx() # create right y-axis
ax2.fill_between(
df.index.values, 0, df.secondary,
facecolor = '#a05050',
label = 'Secondary'
)
ax2.spines[ 'right' ].set_position( ( 'axes', 1.05 ) )
ax2.spines[ 'top' ].set_visible( False )
ax2.set_frame_on( True )
ax2.patch.set_visible( False )
ax2.set_ylim( bottom = 0 )
ax2.set_ylabel( 'Secondary' )
# clean up secondary axes tick marks and labels
ax2a.tick_params( left = False, bottom = False )
ax2.tick_params( left = False, bottom = False )
ax2a.set_xticklabels( [] )
ax2a.set_yticklabels( [] )
ax.set_ylim( 0, 1 )
ax.legend( [ 'Main', 'Secondary' ] )