微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

考虑以下熊猫系列和情节

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

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

解决方法:

当然,可以获得标题的边界框,这是一个Text元素.这可以通过以下方式完成

title = ax.set_title(...) 
bb = title.get_bBox_patch() 

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

我不知道设置边界框的其他方法.例如,可以通过设置图例的边界框
plt.legend(bBox_to_anchor =(0.,1.02,1.,.010),loc = 3,mode =“expand”),使其在整个轴范围内扩展(见here).对Text也有相同的选项非常有用.但就目前而言,我们没有.

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

这些盒子实际上是解决问题的关键.它们都继承自BoxStyle._Base,并且 – 可以在the bottom of the annotations guide看到 – 可以定义自定义形状,子类化BoxStyle._Base.

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

作为奖励,我们可以注册一个事件处理程序,使得该宽度一旦由于窗口的大小而改变,就会被调整.

这是代码

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()

enter image description here

为了防止有人对更轻的解决方案感兴趣,还可以选择使用标题边界框的mutation_aspect,在绘制标题时显然保持不变.虽然mutation_aspect本身基本上只改变了盒子的高度,但是可以对盒子使用非常大的填充,并将mutation_aspect设置为非常小的数量,这样最后盒子看起来在宽度上延伸.此解决方案的明显缺点是,填充和方面的值必须通过反复试验找到,并且将针对不同的字体和图形大小进行更改.
在我的例子中,mutation_aspect = 0.04和pad = 11.9的值产生了期望的结果,但是在其他系统上,它们当然可以是不同的.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

s = pd.Series(np.random.lognormal(.001, .01, 100))
ax = s.cumprod().plot()
title = ax.set_title('My Log normal Example', position=(.5, 1.02),
             backgroundcolor='black', color='white',
             verticalalignment="bottom", horizontalalignment="center")
title._bBox_patch._mutation_aspect = 0.04
title.get_bBox_patch().set_Boxstyle("square", pad=11.9)
plt.tight_layout()
plt.savefig(__file__+".png")
plt.show()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐