0

I have a page that contains multiple matplotlib subplots. I originally added a title for these subplots by deploying the following code:

title = fig.suptitle('This is a title',horizontalalignment='center',verticalalignment='top')

However, I wanted to add a solid background color to this title and it did not seem that I could using the above method.

Therefore, I set the title using the below code:

fig.text(x=0.5,y=0.97,ha='center',va='top',s='This is a title',color='w',backgroundcolor='blue')

This does add the background color, but it only extends as far as just outside the text itself, as per the attached image.

enter image description here

What I want to do is to be able to have the text where it is, but extend the background color to the width of my page (this page as an example), so that the whole title bar is blue, with the white text displaying in the center where it is at the moment.

Is there a way to achieve this by writing directly onto the figure canvas i.e. with the fig.suptitle or the fig.text methods. Open to other solutions that achieve the goal, but I am looking to avoid deploying a subplot ax object in itself as a title (this seems a bit crude).

Hope that makes sense!

Thanks!

* Update *

I have attempted to deploy the following code:

title = fig.text(x=0.5,y=0.97,ha='center',va='top',s='This is a title',color='w',backgroundcolor='blue')

bb = title.get_bbox_patch()

bb.set_width(w=100)

This relates to the suggestion to look at a similar post in the comments. However, the above code does not provide a solution. The title is simply unaffected by the bbox implementation. Still looking for a solution.

Thanks!

* Update *

Further looking through the other post, gives this as a potential solution and this does work!

title = fig.text(x=0.5,y=0.97,ha='center',va='top',s='This is a title',color='w',backgroundcolor='blue')

title._bbox_patch._mutation_aspect = 0.02

title.get_bbox_patch().set_boxstyle("square", pad=47.8)

However, this seems incredibly crude. An inordinate amount of time is spent with trial and error setting the mutation aspect and the pad so that the background color fits as desired.

See updated image below:

enter image description here

There must be a more prescribed Pythonic method for affecting this outcome, but with more specific control over the positioning and size of the background color! This is the solution that I am really looking for!

Thanks!

agftrading
  • 784
  • 3
  • 8
  • 21
  • Did you look into [How do I make the width of the title box span the entire plot?](https://stackoverflow.com/questions/40796117/how-do-i-make-the-width-of-the-title-box-span-the-entire-plot/40923440#40923440) I'm not sure what you mean by "the width of my page" though. – ImportanceOfBeingErnest Jul 23 '18 at 17:05
  • Thanks, will have a look. To be clear this is an overall title for the entire page of subplots (not a title for a particular subplot) if this makes a significant difference. I am ultimately deploying the subplots to a .pdf file and want the color box for the overall title to span the width of that page i.e. the figure canvas that I have originally created on which to place the subplots. Hope that makes more sense. – agftrading Jul 23 '18 at 17:42
  • In that case the solution may be much simpler. I will check later. – ImportanceOfBeingErnest Jul 23 '18 at 17:44
  • I have attempted to deploy the code per the original post that you suggested. This does not work. See the update in the original question! Thanks for the suggestion. Still looking at it here also. – agftrading Jul 24 '18 at 12:21
  • Further update, now above also!... – agftrading Jul 24 '18 at 12:31
  • The linked solution is much more extensive than just adding one single line. But it will work here too. I have spent some thoughts about easier solutions, but have not come up with something nicer. – ImportanceOfBeingErnest Jul 24 '18 at 12:34
  • Thanks, the linked solution was pretty extensive and I have just continued with it and posted the update above. I agree, surely there is something clean, precise and pythonic to affect the outcome instead. Thanks for help thus far either way!... – agftrading Jul 24 '18 at 12:38
  • I did have some concerns that the other solution would only work for the title of a specific subplot, which is what it seems to be working with, but as above it does seem to work for the overall title, not just the subplot specific titles... – agftrading Jul 24 '18 at 12:41
  • In the solution using mutation aspect I clearly wrote that this involves trial and error. If you don't want that, don't use it. The primary solution does not involve trial and error and is directly applicable here. It just seems you left out most of the code from that solution. – ImportanceOfBeingErnest Jul 24 '18 at 13:04

1 Answers1

1

You may directly apply the solution provided in How do I make the width of the title box span the entire plot? with only small modifications, using the figure width instead of the subplot width for the horizontal size of the subplot.

import matplotlib.pyplot as plt

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


# register the custom style
BoxStyle._style_list["ext"] = ExtendedTextBox

fig, ax = plt.subplots()
# set the title position to the horizontal center (0.5) of the axes
title = fig.suptitle('My Log Normal Example', position=(.5, 0.96), 
                     backgroundcolor='black', color='white')
# set the box style of the title text box to our custom box
bb = title.get_bbox_patch()


def resize(event):
    # use the figure width as width of the text box 
    bb.set_boxstyle("ext", pad=0.4, width=fig.get_size_inches()[0]*fig.dpi )

resize(None)
# Optionally: use eventhandler to resize the title box, in case the window is resized
cid = plt.gcf().canvas.mpl_connect('resize_event', resize)

# use the same dpi for saving to file as for plotting on screen
plt.savefig(__file__+".png", dpi="figure")
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712