One legend for multiple plots

1,214 views
Skip to first unread message

Nicolas

unread,
Jan 7, 2015, 7:14:57 PM1/7/15
to pyqt...@googlegroups.com

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.

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, 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 

Mathew Schwartz

unread,
Jan 26, 2015, 8:13:52 PM1/26/15
to pyqt...@googlegroups.com
Why dont you just set one of your plots to have a legend and not the others?

--
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.

Nicolas

unread,
Feb 19, 2015, 1:07:14 PM2/19/15
to pyqt...@googlegroups.com
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.

Reply all
Reply to author
Forward
0 new messages