ASKSAGE: Sage Q&A Forum - Individual question feedhttp://ask.sagemath.org/questions/Q&A Forum for SageenCopyright Sage, 2010. Some rights reserved under creative commons license.Wed, 01 May 2019 03:23:32 -0500Legend attached to curve in plot ("PlotLabels")http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/Hello,
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)
p.show()
-----
Using [slelievre answer](https://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?answer=46411#post-id-46411) (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)
p.show(xmin=5*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.Mon, 29 Apr 2019 13:10:15 -0500http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/Comment by Bacco for <p>Hello,</p>
<p>I have a plot with several curves (say, 5) and I need to clearly mark them.</p>
<p>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.</p>
<p>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.</p>
<p>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):</p>
<pre><code>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)
p.show()
</code></pre>
<hr>
<p>Using <a href="https://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?answer=46411#post-id-46411">slelievre answer</a> (and imitating the PlotLabels idea, putting gray lines between plot and label), I came up with this:</p>
<pre><code>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)
p.show(xmin=5*10^-2, xmax=10)
</code></pre>
<p>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.</p>
http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?comment=46422#post-id-46422Having 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.Wed, 01 May 2019 03:23:32 -0500http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?comment=46422#post-id-46422Comment by slelievre for <p>Hello,</p>
<p>I have a plot with several curves (say, 5) and I need to clearly mark them.</p>
<p>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.</p>
<p>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.</p>
<p>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):</p>
<pre><code>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)
p.show()
</code></pre>
<hr>
<p>Using <a href="https://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?answer=46411#post-id-46411">slelievre answer</a> (and imitating the PlotLabels idea, putting gray lines between plot and label), I came up with this:</p>
<pre><code>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)
p.show(xmin=5*10^-2, xmax=10)
</code></pre>
<p>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.</p>
http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?comment=46412#post-id-46412Even without uploading the picture, please provide the code for plotting the curves.
This will help others come up with helpful answers.Tue, 30 Apr 2019 08:50:38 -0500http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?comment=46412#post-id-46412Answer by slelievre for <p>Hello,</p>
<p>I have a plot with several curves (say, 5) and I need to clearly mark them.</p>
<p>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.</p>
<p>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.</p>
<p>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):</p>
<pre><code>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)
p.show()
</code></pre>
<hr>
<p>Using <a href="https://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?answer=46411#post-id-46411">slelievre answer</a> (and imitating the PlotLabels idea, putting gray lines between plot and label), I came up with this:</p>
<pre><code>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)
p.show(xmin=5*10^-2, xmax=10)
</code></pre>
<p>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.</p>
http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?answer=46411#post-id-46411The 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:
sage: p.show()
![Curves with labels](https://i.imgur.com/qAp6v1f.png)
Tue, 30 Apr 2019 08:48:32 -0500http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?answer=46411#post-id-46411Comment by Bacco for <p>The following might be a step in the right direction.</p>
<p>Define a list of functions to plot:</p>
<pre><code>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,
....: ]
</code></pre>
<p>Initialize an empty graphics object:</p>
<pre><code>sage: p = Graphics()
</code></pre>
<p>Set some text options:</p>
<pre><code>sage: text_options = {
....: 'horizontal_alignment': 'right',
....: 'vertical_alignment': 'bottom',
....: 'fontsize': 'large'}
</code></pre>
<p>Plot each function and add a label at the end of the curve:</p>
<pre><code>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)
</code></pre>
<p>Show the result:</p>
<pre><code>sage: p.show()
</code></pre>
<p><img alt="Curves with labels" src="https://i.imgur.com/qAp6v1f.png"></p>
http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?comment=46421#post-id-46421This is very useful: it's simple and works out of the box in many cases.Wed, 01 May 2019 03:17:36 -0500http://ask.sagemath.org/question/46404/legend-attached-to-curve-in-plot-plotlabels/?comment=46421#post-id-46421