11

I couldn't find another thread or documentation on this topic - has anyone ever been successful underlining in pythons matplotlib package? The syntax I am using is something like this for all the other attributes:

plt.text(0.05, 0.90, 'Parameters: ', fontsize=12)

However, I can't figure out how to underline this text short of actually coding a line into the file.

Thoughts?

nodapic
  • 315
  • 1
  • 4
  • 11

2 Answers2

19

Matplotlib can use LaTeX to handle all text, see this page of the documnetation for more information. The command for underlining text in LaTeX is simply \underline. From the docstring of one of the example scripts:

You can use TeX to render all of your matplotlib text if the rc parameter text.usetex is set. This works currently on the agg and ps backends, and requires that you have tex and the other dependencies described at http://matplotlib.sf.net/matplotlib.texmanager.html properly installed on your system. The first time you run a script you will see a lot of output from tex and associated tools. The next time, the run may be silent, as a lot of the information is cached in ~/.tex.cache

So as a simple example we can do

import matplotlib.pyplot as plt
from matplotlib import rc

rc('text', usetex=True)

plt.sunplot(111)

plt.text(0.05, 0.90, r'\underline{Parameters}: ', fontsize=12)

to get underlined text.

Chris
  • 44,602
  • 16
  • 137
  • 156
  • Hi Chris, elegant solution. I was able to get the underline that way but changing the usetex to True also affects the rest of the text in the figure (e.g. numbering on the axes of plots becomes serif and other bolded texts become non-bold.) I presume that I would have to change all those over to tex formatting, too, right? – nodapic May 23 '12 at 21:12
  • Generally I can use LaTeX commands without the `rc` business (which is what I assume causes all your other text to be rendered differently). However, I seem to need it on my Windows machine (normally I work on a Linux machine, not sure if this is an issue). Give it a go without that line and see if the `plt.text` call still works. – Chris May 23 '12 at 21:24
  • I have found that I can use LaTeX commands *without* calling `rc` as long as I don't use `plt.text`, i.e. `plt.xlabel`, `plt.title` etc. work fine. It seems to just be `plt.text` that requires me to configure `rc`. If you find that you need to use `rc` you can also confiure the fonts etc that you want to use. – Chris May 23 '12 at 21:27
  • Yeah, I observed that also. Thank you for your help! – nodapic May 23 '12 at 21:48
0

This is an old question, but I actually had a need for underlining text that didn't use LaTeX so I figured I'd follow up with the solution that I came up with, for others who may encounter the same issue.

Ultimately my solution finds a bounding box for the text object in question and then uses the arrowprop arguments in the annotation command in order to draw a straight line underneath the text. There are some caveats with this approach, but overall I find it quite flexible because then you can customize the underline however you'd like.

An example of my solution is as follows:

import matplotlib.pyplot as plt 
import numpy as np 

def test_plot():
    f = plt.figure()
    ax = plt.gca()
    ax.plot(np.sin(np.linspace(0,2*np.pi,100)))

    text1 = ax.annotate("sin(x)", xy=(.7,.7), xycoords="axes fraction")   
    underline_annotation(text1)

    text2 = ax.annotate("sin(x)", xy=(.7,.6), xycoords="axes fraction",
                        fontsize=15, ha="center")
    underline_annotation(text2)

    plt.show()

def underline_annotation(text):
    f = plt.gcf()
    ax = plt.gca()
    tb = text.get_tightbbox(f.canvas.get_renderer()).transformed(f.transFigure.inverted())
                            # text isn't drawn immediately and must be 
                            # given a renderer if one isn't cached.
                                                    # tightbbox return units are in 
                                                    # 'figure pixels', transformed 
                                                    # to 'figure fraction'.
    ax.annotate('', xy=(tb.xmin,tb.y0), xytext=(tb.xmax,tb.y0),
                xycoords="figure fraction",
                arrowprops=dict(arrowstyle="-", color='k'))
                #uses an arrowprops to draw a straightline anywhere on the axis.

and this produces an underlined annotated sin example.

One thing to note is that if you want to pad the underline, or control the line thickness (note that the line thickness is the same for both annotations) you'll have to do it manually within the 'underline_annotation' command, but this is pretty easy to do by passing more arguments through the arrowprops dict, or augmenting the location of where the line is being drawn.