3

What I'm Trying to Do

I am using matplotlib and I want to be able to create some dynamic footnotes with the capability to both wrap and highlight left-aligned text.

The easiest solution would be to identify a reliable method to convert fontsize scale to graph axes scale (e.g. how much does space on the y axis does text take up if fontsize is 8 vs 30) but I would be open to a smarter way to solve the problem.

For Example:

         enter image description here

My hokey code:

I modified some code from this question but it still requires highlighted text be on a new line so word wrap isn't exactly ideal.

Basically it assumes the paragraph is split into three categories, and formats each accordingly:

  1. Plain Text
  2. Highlighted Text
  3. One, really large, word or number

This code feels pretty weak in general so, in addition to finding something that can both wrap and highlight text, I would also be open to cleaner solutions. **Note that this only works in interactive mode (e.g. ipython notebook or similar) because text.draw(fig.canvas.get_renderer()) doesn't work from non-interactive.

from matplotlib import transforms
from matplotlib import pyplot as plt

def parse_text_type(story, highlight_text, bold, num_tag, highlight_tag):

    str_list = []
    for x in story.split("___"):
        if x == 'highlight':
            str_list.append([highlight_text,highlight_tag])
        elif x == 'bold':
            str_list.append([bold,num_tag])
        elif x != '':
            str_list.append([x,"___background___"])
    return str_list

def make_plot(parsed_story):

    ax = plt.subplot(111)
    plt.plot([0,0.5],[0,1],lw=0)
    t = plt.gca().transData
    fig = plt.gcf()


    for i,x in enumerate(parsed_story):

        if x[1] == '___background___':
            text = plt.text(
            -1, 1, x[0], ha='left', transform=t,
            va='top', fontsize=18, color='#999999')

        elif x[1] == '___highlight___':
            text = plt.text(
                -1, 1, x[0], ha='left', transform=t, weight='bold',
                va='top', fontsize=18, color='#32618b'
            )

        elif x[1] == '___bold___':
            text = plt.text(
                -1, 1, x[0], ha='left', transform=t,
                va='top', fontsize=100, color='#32618b', rasterized=None
            )

        text.draw(fig.canvas.get_renderer())
        ex = text.get_window_extent()
        t = transforms.offset_copy(text._transform, y=-ex.height - 5, units='dots')

        plt.axis('off');

    return fig, ax


def generate_wordplot(number, highlight_text, story):

    num_tag = '___number___'
    highlight_tag = '___highlight___'

    story = story.format(number=num_tag, highlight=highlight_tag)
    parsed_story = parse_text_type(story,highlight_text, number, num_tag, highlight_tag)

    return make_plot(parsed_story)

if __name__ == '__main__':

    bold = "99.9%"
    highlight_text = "humans drink water"
    story = "One survey found that {bold}of {highlight}"

    fig, ax = generate_wordplot(bold, highlight_text, story)
Community
  • 1
  • 1
Chris
  • 12,900
  • 12
  • 43
  • 65
  • first, code had an error, that I tried to fix according to what I think was the intent, but I still don't get an output. Second, it would be easier to answer if the question was more focused on a single critical point and the few relevant lines of code, what are you trying to do and what goes wrong. How it is now it is not clear what is the desired result and what you want to improve, it sounds more something like 'help me to optimize my code'. – Vincenzooo May 27 '16 at 20:53
  • The code above only works in interactive mode because fig.canvas.get_renderer() doesn't work unless you are interactive. I am open to many solutions rather than a single critical point but in this scenario the problem would be solved if I had a mechanism to convert graph axis scale to font scale. Right now I can't create a word wrap because I can't identify the correct location to place a word depending on whether the font changes in size. – Chris May 27 '16 at 22:54
  • Presenting styled text is not really what matplotlib is made for. Why are you using matplotlib for this task? – BrenBarn May 28 '16 at 06:20
  • I often need to include a "plain text" callout inside of a subplot as a component of an infographic. See http://www.storytellingwithdata.com/blog/2012/06/power-of-simple-text for an example of how this is used. – Chris May 28 '16 at 09:58

0 Answers0