2

Goal

  • Plot two lines or curves in a figure, together with corresponding filled areas which indicate accuracy. See MWE.
  • Challenge: all handlers overlap in the legend entry. How could I specify vertical spacing such that dotted and solid lines don't overlap?
  • Desired output: one legend entry with red and blue lines and one filled area (either blue or red).

Desired output desired output

Note This is a simplified extension of this question.

Code

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.legend_handler import HandlerTuple

n = 11
x1 = np.linspace(0,1,n)
x2 = np.linspace(0,2,n)
y1 = x1 + 10
y2 = x2 + 5
y1err = 0.25 * np.ones(len(y1))
y2err = 0.50 * np.ones(len(y2))

handlers = []
labels = []

fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111)

label1 = 'hello'
label2 = 'world'
p1, = ax.plot(x1,y1, linestyle='dotted', color='red')
f1 = ax.fill_between(x1,y1-y1err,y1+y1err, alpha=0.16, color='red')
p2, = ax.plot(x2,y2, linestyle='solid', color='blue')
f2 = ax.fill_between(x2,y2-y2err,y2+y2err, alpha=0.16, color='blue')

handlers.append((p1,f1,p2,f2))
labels.append((label1+'\n'+label2))
ax.legend(handlers,labels)
ax.grid()
ax.set_xlim(np.min(x2),np.max(x2))
plt.show()

Output output

ejok
  • 53
  • 6

1 Answers1

0

The plot requires the specification of legend for the respective plot and its label. This can be done by specifying the plt.legend([plot1, plot2],[label1, label1])

It could be achieved as mentioned below:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.legend_handler import HandlerTuple

n = 11
x1 = np.linspace(0,1,n)
x2 = np.linspace(0,2,n)
y1 = x1 + 10
y2 = x2 + 5
y1err = 0.25 * np.ones(len(y1))
y2err = 0.50 * np.ones(len(y2))

handlers = []
labels = []

fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111)

label1 = 'hello'
label2 = 'world'
p1, = ax.plot(x1,y1, linestyle='dotted', color='red')
f1 = ax.fill_between(x1,y1-y1err,y1+y1err, alpha=0.16, color='red')
p2, = ax.plot(x2,y2, linestyle='solid', color='blue')
f2 = ax.fill_between(x2,y2-y2err,y2+y2err, alpha=0.16, color='blue')

handlers.append((p1,f1,p2,f2))
labels.append((label1+'\n'+label2))
ax.legend(handlers,labels)
ax.grid()
ax.set_xlim(np.min(x2),np.max(x2))
plt.legend([(p1,f1), (p2,f2)],[label1,label2])
plt.show()
Roxy
  • 1,015
  • 7
  • 20
  • Thanks for your suggestion. However, the desired output is slightly different (all lines should be in a single legend entry). I have attached a sketch in the original question. – ejok Aug 31 '21 at 13:27
  • How about the legend text? Do you need them as well? I don't see it in the above added picture – Roxy Aug 31 '21 at 13:58
  • Yes, the text should be in there as well (as shown in the first picture) – ejok Aug 31 '21 at 16:37
  • 1
    This post seems to accomplish what I would like to do, but it fixes the label color (and some other properties), whereas I would like to make it dynamic. Ideas are welcome. https://stackoverflow.com/questions/41752309/single-legend-item-with-two-lines – ejok Aug 31 '21 at 20:57
  • That's informative. I would do that when available. :) – Roxy Aug 31 '21 at 21:08