如何使标题框的宽度跨越整个图?

时间:2016-11-25 00:23:55

标签: python pandas matplotlib

考虑以下pandas系列s和情节

import pandas as pd
import numpy as np

s = pd.Series(np.random.lognormal(.001, .01, 100))
ax = s.cumprod().plot()
ax.set_title('My Log Normal Example', position=(.5, 1.02),
             backgroundcolor='black', color='white')

enter image description here

如何让包含标题的框跨越整个图?

2 个答案:

答案 0 :(得分:23)

当然,可以获得标题的边界框,即Text元素。这可以通过

完成
title = ax.set_title(...) 
bb = title.get_bbox_patch() 

原则上,人们可以操纵边界框,例如通过 bb.set_width(...)。但是,一旦matplotlib将标题绘制到画布上,所有设置都将丢失。至少这是我解释Text的{​​{1}}方法的方法。

我不知道设置边界框的其他方法。例如,可以通过
设置draw()的边界框 legend使其在整个轴范围内扩展(参见here)。为plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, mode="expand")提供相同的选项也非常有用。但就目前而言,我们没有。

Text对象允许设置bbox参数,该参数通常用于设置边界框的样式。无法设置边界框范围,但它接受周围框的属性字典。其中一个被接受的属性是boxstyle。默认情况下,这是Text,但可以设置为圆形或箭头或其他奇怪的形状。

那些square实际上是解决问题的关键。它们都继承自boxstyle,而且 - 可以在the bottom of the annotations guide看到 - 可以定义自定义形状,继承BoxStyle._Base

以下解决方案基于子类化BoxStyle._Base,它接受​​轴的宽度作为参数,并绘制标题的矩形路径,使其具有正确的宽度。

作为奖励,我们可以注册一个事件处理程序,以便在调整窗口大小后,此宽度会被调整。

以下是代码:

BoxStyle._Base

enter image description here

如果有人对更轻松的解决方案感兴趣,还可以选择使用标题边框的import matplotlib.pyplot as plt import pandas as pd import numpy as np from matplotlib.path import Path from matplotlib.patches import BoxStyle class ExtendedTextBox(BoxStyle._Base): """ An Extended Text Box that expands to the axes limits if set in the middle of the axes """ def __init__(self, pad=0.3, width=500.): """ width: width of the textbox. Use `ax.get_window_extent().width` to get the width of the axes. pad: amount of padding (in vertical direction only) """ self.width=width self.pad = pad super(ExtendedTextBox, self).__init__() def transmute(self, x0, y0, width, height, mutation_size): """ x0 and y0 are the lower left corner of original text box They are set automatically by matplotlib """ # padding pad = mutation_size * self.pad # we add the padding only to the box height height = height + 2.*pad # boundary of the padded box y0 = y0 - pad y1 = y0 + height _x0 = x0 x0 = _x0 +width /2. - self.width/2. x1 = _x0 +width /2. + self.width/2. cp = [(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)] com = [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY] path = Path(cp, com) return path dpi = 80 # register the custom style BoxStyle._style_list["ext"] = ExtendedTextBox plt.figure(dpi=dpi) s = pd.Series(np.random.lognormal(.001, .01, 100)) ax = s.cumprod().plot() # set the title position to the horizontal center (0.5) of the axes title = ax.set_title('My Log Normal Example', position=(.5, 1.02), backgroundcolor='black', color='white') # set the box style of the title text box toour custom box bb = title.get_bbox_patch() # use the axes' width as width of the text box bb.set_boxstyle("ext", pad=0.4, width=ax.get_window_extent().width ) # Optionally: use eventhandler to resize the title box, in case the window is resized def on_resize(event): print "resize" bb.set_boxstyle("ext", pad=0.4, width=ax.get_window_extent().width ) cid = plt.gcf().canvas.mpl_connect('resize_event', on_resize) # use the same dpi for saving to file as for plotting on screen plt.savefig(__file__+".png", dpi=dpi) plt.show() ,这在绘制标题时显然保持不变。虽然mutation_aspect本身基本上只改变了框的高度,但是可以为框使用非常大的填充,并将mutation_aspect设置为非常小的数字,以便最后框显示为宽度扩展。此解决方案的明显缺点是,填充和方面的值必须通过反复试验找到,并且将针对不同的字体和图形大小进行更改。 就我而言,mutation_aspectmutation_aspect = 0.04的值会产生预期的结果,但在其他系统上,它们当然可能不同。

pad=11.9

答案 1 :(得分:13)

不是缩放标题文本本身的边界框,而是可以在主要文本上方创建辅助轴,并将其用作"框"为你的头衔。由于轴通常不显示为方框,我们将关闭其轴标签和刻度,并将背景颜色设置为黑色以匹配OP。

我使用相同的方法将辅助匹配轴设为here

此外,我已使用AnchoredText将标题文字捕捉到轴,以便它可以轻松地位于其中心。

import matplotlib.pyplot as plt 
from matplotlib.offsetbox import AnchoredText
from mpl_toolkits.axes_grid1 import make_axes_locatable
import pandas as pd
import numpy as np

s = pd.Series(np.random.lognormal(.001, .01, 100))
ax = s.cumprod().plot()

divider = make_axes_locatable(ax)
cax = divider.append_axes("top", size="11%", pad=0)
cax.get_xaxis().set_visible(False)
cax.get_yaxis().set_visible(False)
cax.set_facecolor('black')

at = AnchoredText("My Log Normal Example", loc=10,
                  prop=dict(backgroundcolor='black',
                            size=12, color='white'))
cax.add_artist(at)

plt.show()

enter image description here

对于较旧的matplotlib版本,

修改,在设置背景颜色时可能需要切换为cax.set_axis_bgcolor('black')