Discussion:
[pyqtgraph] One legend for multiple plots
Nicolas
2015-01-08 00:14:57 UTC
Permalink
I am developing a GUI with PySide where I have a PyQtGraph GraphicsView
with multiple plots (see the image below). Graphics View to a
GraphicsLayoutWidget. The GUI is designed in Qt Designer, where I promote a
Graphics View to a GraphicsLayoutWidget.

<Loading Image...>
I would like to add a legend to add a legend to this. But rather than
adding a legend to each of the 8 plots, which would be redundant, I want to
add one legend that contains one entry for a green line and one entry for a
red line. Ideally, this legend would be at the bottom center of the
GraphicsView and the two entries would be side by side (as opposed to on
top of each other), in order to waste the least amount of space.

The relevant code where I add the plots is as follows:
DOF = 4
# remove any old plots
for i in range(DOF):
item = self.graphicsView.getItem(0,i)
if item != None:
self.graphicsView.removeItem(item)
item = self.graphicsView.getItem(1,i)
if item != None:
self.graphicsView.removeItem(item)
pg.setConfigOptions(antialias=True)
pen_act = pg.mkPen((0,200,0,255), width=2)
pen_des = pg.mkPen((200,0,0,255), width=2)
brush_fill = (100,0,100,100)
# result is a dictionary containing the data to be plotted
time = result['time'];
del result['time']
for i in range(1,DOF+1):
# position
fig = self.graphicsView.addPlot(row=0, col=i-1, title="Joint "+str(i)+"
position", labels={'left': "Joint angle [rad]", 'bottom': "Time [s]"})
plot1 = fig.plot(x=time, y=result["joint" + str(i) + "_pos_act"], pen=
pen_act)
plot2 = fig.plot(x=time, y=result["joint" + str(i) + "_pos_des"], pen=
pen_des)
fill = pg.FillBetweenItem(plot1, plot2, brush=brush_fill)
fig.addItem(fill)
# velocity
fig = self.graphicsView.addPlot(row=1, col=i-1, title="Joint "+str(i)+"
velocity", labels={'left': "Joint velocity [rad/s]", 'bottom': "Time [s]"})
plot1 = fig.plot(x=time, y=result["joint" + str(i) + "_vel_act"], pen=
pen_act)
plot2 = fig.plot(x=time, y=result["joint" + str(i) + "_vel_des"], pen=
pen_des)
fill = pg.FillBetweenItem(plot1, plot2, brush=brush_fill)
fig.addItem(fill)

How can I achieve this?
I tried to do what is suggested here
<https://groups.google.com/forum/#!msg/pyqtgraph/gASDBfH7Ijo/1CrAMp5v4TgJ>,
but I can't get it to work properly. The legend appears, but it's behind
the plots, so I can only see a little bit of it just at the edge of the
view. Also, this
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/2def6e54-f848-4217-8413-e91a5e43c38c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Mathew Schwartz
2015-01-27 01:13:50 UTC
Permalink
Why dont you just set one of your plots to have a legend and not the others?
Post by Nicolas
I am developing a GUI with PySide where I have a PyQtGraph GraphicsView
with multiple plots (see the image below). Graphics View to a
GraphicsLayoutWidget. The GUI is designed in Qt Designer, where I promote a
Graphics View to a GraphicsLayoutWidget.
<https://lh5.googleusercontent.com/-nlMyuvRt0hY/VK3HwheJhqI/AAAAAAAAGkQ/SLT1Df687Ow/s1600/pyqtgraph_plots.png>
I would like to add a legend to add a legend to this. But rather than
adding a legend to each of the 8 plots, which would be redundant, I want to
add one legend that contains one entry for a green line and one entry for a
red line. Ideally, this legend would be at the bottom center of the
GraphicsView and the two entries would be side by side (as opposed to on
top of each other), in order to waste the least amount of space.
DOF = 4
# remove any old plots
item = self.graphicsView.getItem(0,i)
self.graphicsView.removeItem(item)
item = self.graphicsView.getItem(1,i)
self.graphicsView.removeItem(item)
pg.setConfigOptions(antialias=True)
pen_act = pg.mkPen((0,200,0,255), width=2)
pen_des = pg.mkPen((200,0,0,255), width=2)
brush_fill = (100,0,100,100)
# result is a dictionary containing the data to be plotted
time = result['time'];
del result['time']
# position
fig = self.graphicsView.addPlot(row=0, col=i-1, title="Joint "+str(i)+"
position", labels={'left': "Joint angle [rad]", 'bottom': "Time [s]"})
plot1 = fig.plot(x=time, y=result["joint" + str(i) + "_pos_act"], pen=
pen_act)
plot2 = fig.plot(x=time, y=result["joint" + str(i) + "_pos_des"], pen=
pen_des)
fill = pg.FillBetweenItem(plot1, plot2, brush=brush_fill)
fig.addItem(fill)
# velocity
fig = self.graphicsView.addPlot(row=1, col=i-1, title="Joint "+str(i)+"
velocity", labels={'left': "Joint velocity [rad/s]", 'bottom': "Time [s]"
})
plot1 = fig.plot(x=time, y=result["joint" + str(i) + "_vel_act"], pen=
pen_act)
plot2 = fig.plot(x=time, y=result["joint" + str(i) + "_vel_des"], pen=
pen_des)
fill = pg.FillBetweenItem(plot1, plot2, brush=brush_fill)
fig.addItem(fill)
How can I achieve this?
I tried to do what is suggested here
<https://groups.google.com/forum/#!msg/pyqtgraph/gASDBfH7Ijo/1CrAMp5v4TgJ>,
but I can't get it to work properly. The legend appears, but it's behind
the plots, so I can only see a little bit of it just at the edge of the
view. Also, this
--
You received this message because you are subscribed to the Google Groups
"pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/d/msgid/pyqtgraph/2def6e54-f848-4217-8413-e91a5e43c38c%40googlegroups.com
<https://groups.google.com/d/msgid/pyqtgraph/2def6e54-f848-4217-8413-e91a5e43c38c%40googlegroups.com?utm_medium=email&utm_source=footer>
.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/CADiWwnTc2OX3mTWcaQBORTRUqw58UAM9y8Et7CsAGv%3DKueyt-g%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Nicolas
2015-02-19 18:07:14 UTC
Permalink
Mainly for three reasons:
- I don't want to have the legend cover up any part of a plot.
- Just adding the plots to one plot would make the whole graphics layout
very asymmetrical.
- I would like for the different legend entries to be next to each other,
as opposed to on top of each other. This would make the best use of space
given my layout.

I actually sort of achieved what I wanted, but I'm not very happy with it.
As you can see in the image below, I do have a third row where the the
legend entries are.
It's just a workaround through, because I actually have one independent
legend for each line. Additionally, the horizontal position of the legends
is hardcoded. This means that they are centered only for a specific window
size and their spacing changes with the window size (i.e. they will overlap
if the window is too small). This also means that it's quite a bit of work
to add a new legend entry, which it really shouldn't be.

The relevant code is:

for i in range(6):
labels_pos = {'bottom': "Time [s]"}
labels_vel = {'bottom': "Time [s]"}
if i == 0:
labels_pos['left'] = "Joint position [rad]"
labels_vel['left'] = "Joint velocity [rad/s]"

# plot lines
fig1 = self.graphicsViewResults.addPlot(row=0, col=i, title="Joint " + str(i
+ 1) + " position", labels=labels_pos, enableMenu=False)
plot1 = fig1.plot(x=result['time'], y=result['pos_act'][i], pen=self.
pen_act)

plot2 = fig1.plot(x=result['time'], y=result['pos_des'][i], pen=self.
pen_des)

fill = pg.FillBetweenItem(plot1, plot2, brush=self.brush_fill)
fig1.addItem(fill)

joint_limit_lower = self.robot.joints[i].limit['lower']
plot_limit = fig1.plot(x=[0, 100], y=[joint_limit_lower, joint_limit_lower
], pen=self.pen_lim, fillLevel=-100, brush=self.brush_lim)
joint_limit_upper = self.robot.joints[i].limit['upper']
fig1.plot(x=[0, 100], y=[joint_limit_upper, joint_limit_upper], pen=self.
pen_lim, fillLevel=100, brush=self.brush_lim)

fig2 = self.graphicsViewResults.addPlot(row=1, col=i, title="Joint " + str(i
+ 1) + " velocity", labels=labels_vel, enableMenu=False)
plot3 = fig2.plot(x=result['time'], y=result['vel_act'][i], pen=self.
pen_act)

plot4 = fig2.plot(x=result['time'], y=result['vel_des'][i], pen=self.
pen_des)

fill = pg.FillBetweenItem(plot3, plot4, brush=self.brush_fill)
fig2.addItem(fill)
velocity_limit = self.robot.joints[i].limit['velocity']
fig2.plot(x=[-100, 100], y=[-velocity_limit, -velocity_limit], pen=self.
pen_lim, fillLevel=-1e10, brush=self.brush_lim)
fig2.plot(x=[-100, 100], y=[velocity_limit, velocity_limit], pen=self.
pen_lim, fillLevel=1e10, brush=self.brush_lim)

########
# legend
########

vb = self.graphicsViewResults.addViewBox(row=2, col=0, colspan=DOF)
legend1 = pg.LegendItem()
legend1.addItem(plot1, "Actual")
legend1.setParentItem(vb)
legend1.anchor((0, 0), (0.4, 0))
legend2 = pg.LegendItem()
legend2.addItem(plot2, "Desired")
legend2.setParentItem(vb)
legend2.anchor((0, 0), (0.5, 0))
legend3 = pg.LegendItem()
legend3.addItem(plot_limit, "Joint limits")
legend3.setParentItem(vb)
legend3.anchor((0, 0), (0.6, 0))
self.graphicsViewResults.ci.layout.setRowFixedHeight(2, 50)


If anybody has a better way, I'd be very interested to know about it.

<Loading Image...>
Post by Mathew Schwartz
Why dont you just set one of your plots to have a legend and not the others?
Post by Nicolas
I am developing a GUI with PySide where I have a PyQtGraph GraphicsView
with multiple plots (see the image below). Graphics View to a
GraphicsLayoutWidget. The GUI is designed in Qt Designer, where I promote a
Graphics View to a GraphicsLayoutWidget.
<https://lh5.googleusercontent.com/-nlMyuvRt0hY/VK3HwheJhqI/AAAAAAAAGkQ/SLT1Df687Ow/s1600/pyqtgraph_plots.png>
I would like to add a legend to add a legend to this. But rather than
adding a legend to each of the 8 plots, which would be redundant, I want to
add one legend that contains one entry for a green line and one entry for a
red line. Ideally, this legend would be at the bottom center of the
GraphicsView and the two entries would be side by side (as opposed to on
top of each other), in order to waste the least amount of space.
DOF = 4
# remove any old plots
item = self.graphicsView.getItem(0,i)
self.graphicsView.removeItem(item)
item = self.graphicsView.getItem(1,i)
self.graphicsView.removeItem(item)
pg.setConfigOptions(antialias=True)
pen_act = pg.mkPen((0,200,0,255), width=2)
pen_des = pg.mkPen((200,0,0,255), width=2)
brush_fill = (100,0,100,100)
# result is a dictionary containing the data to be plotted
time = result['time'];
del result['time']
# position
fig = self.graphicsView.addPlot(row=0, col=i-1, title="Joint "+str(i)+"
position", labels={'left': "Joint angle [rad]", 'bottom': "Time [s]"})
plot1 = fig.plot(x=time, y=result["joint" + str(i) + "_pos_act"], pen=
pen_act)
plot2 = fig.plot(x=time, y=result["joint" + str(i) + "_pos_des"], pen=
pen_des)
fill = pg.FillBetweenItem(plot1, plot2, brush=brush_fill)
fig.addItem(fill)
# velocity
fig = self.graphicsView.addPlot(row=1, col=i-1, title="Joint "+str(i)+"
velocity", labels={'left': "Joint velocity [rad/s]", 'bottom': "Time [s]"
})
plot1 = fig.plot(x=time, y=result["joint" + str(i) + "_vel_act"], pen=
pen_act)
plot2 = fig.plot(x=time, y=result["joint" + str(i) + "_vel_des"], pen=
pen_des)
fill = pg.FillBetweenItem(plot1, plot2, brush=brush_fill)
fig.addItem(fill)
How can I achieve this?
I tried to do what is suggested here
<https://groups.google.com/forum/#!msg/pyqtgraph/gASDBfH7Ijo/1CrAMp5v4TgJ>,
but I can't get it to work properly. The legend appears, but it's behind
the plots, so I can only see a little bit of it just at the edge of the
view. Also, this
--
You received this message because you are subscribed to the Google Groups
"pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/d/msgid/pyqtgraph/2def6e54-f848-4217-8413-e91a5e43c38c%40googlegroups.com
<https://groups.google.com/d/msgid/pyqtgraph/2def6e54-f848-4217-8413-e91a5e43c38c%40googlegroups.com?utm_medium=email&utm_source=footer>
.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/79fa8ba0-e93e-4d2e-888e-191b7a348623%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...