Ask Your Question

Legend attached to curve in plot ("PlotLabels")

asked 2019-04-29 13:10:15 -0500

Bacco gravatar image

updated 2019-05-01 06:21:36 -0500


I have a plot with several curves (say, 5) and I need to clearly mark them.

The plot should be grayscale friendly (I am giving curves different shades, but it is not enough), and line style (dotted...) already has a different meaning. I am using a legend, but it goes in a separate box and does not really help a lot.

Since the different curves never cross in a given plot, just attaching the legend label to the curve tail would be great: how can I achieve this? To be clear, I am looking for an equivalent of Mathematica PlotLabels.

The following example gives an idea of the 'most overlapping' case I can be interested in (actually an exaggeration, a real plot would stop at nexp=2.5):

f(x,n) = e^(-1/(n*x))
listexp = srange(0.5, 3+0.1, 0.5)
lenght = float(len(listexp))
xMinPlot = 0.1

p = Graphics()
for i,nexp in enumerate(listexp) :
    c = 10^nexp
    p += plot_semilogx(f(x,c), (x, xMinPlot, 10), hue=i/lenght)

Using slelievre answer (and imitating the PlotLabels idea, putting gray lines between plot and label), I came up with this:

text_options = {...}
offsets = [0.01, 0.01, 0.01, -0.02, -0.02, 0.02]
xlabel = xMinPlot*0.85
xline  = xMinPlot*0.97

for i,nexp in enumerate(listexp) :
    c = 10^nexp
    yline = f(xMinPlot,c)
    p += line(((xline,yline),(xlabel,yline+offsets[i])), color='gray', thickness=0.5)
    p += text('$c = 10^{{ {:.1f} }}$'.format(float(nexp)),
        (xlabel, yline+offsets[i]), **text_options)*10^-2, xmax=10)

This approach requires to analyse each plot case by case and playing around to find a solution, but I am afraid there is nothing one can do to partially automate it. Also, I am not sure that I am doing this the best way, or whether the result could look better/more professional.

edit retag flag offensive close merge delete


Even without uploading the picture, please provide the code for plotting the curves.

This will help others come up with helpful answers.

slelievre gravatar imageslelievre ( 2019-04-30 08:50:38 -0500 )edit

Having read the solution ("add labels manually") I now see why a more concrete example than f(x) = n*x is useful. I will add a simplified version of one of my real plots.

Bacco gravatar imageBacco ( 2019-05-01 03:23:32 -0500 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2019-04-30 08:48:32 -0500

slelievre gravatar image

The following might be a step in the right direction.

Define a list of functions to plot:

sage: ff = [
....:     lambda x: 1 + exp(-x^2/8)*sin(x^2)/x^1,
....:     lambda x: 2 + exp(-x^2/8)*sin(x^3)/x^2,
....:     lambda x: 3 + exp(-x^2/8)*sin(x^4)/x^3,
....:     lambda x: 4 + exp(-x^2/8)*sin(x^5)/x^4,
....:     ]

Initialize an empty graphics object:

sage: p = Graphics()

Set some text options:

sage: text_options = {
....:     'horizontal_alignment': 'right',
....:     'vertical_alignment': 'bottom',
....:     'fontsize': 'large'}

Plot each function and add a label at the end of the curve:

sage: for i, f in enumerate(ff):
....:     p += plot(f, (-5, 5), hue=(2*i+1)/10)
....:     p += text('$y = f_{}(x)$'.format(i), (5, f(5)), **text_options)

Show the result:


Curves with labels

edit flag offensive delete link more


This is very useful: it's simple and works out of the box in many cases.

Bacco gravatar imageBacco ( 2019-05-01 03:17:36 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower


Asked: 2019-04-29 13:10:15 -0500

Seen: 59 times

Last updated: May 01