Saorsa
Saorsa

Reputation: 23

change matplotlib data in gui

I've developed an gui with python pyqt. There I have a matplotlib figure with x,y-Data and vlines that needs to change dynamically with a QSlider.

Right now I change the data just with deleting everything and plot again but this is not effective

This is how I do it:

 def update_verticalLines(self, Data, xData, valueSlider1, valueSlider2, PlotNr, width_wg):
    if PlotNr == 2:
        self.axes.cla()
        self.axes.plot(xData, Data, color='b', linewidth=2)             
        self.axes.vlines(valueSlider1,min(Data),max(Data),color='r',linewidth=1.5, zorder = 4)
        self.axes.vlines(valueSlider2,min(Data),max(Data),color='r',linewidth=1.5, zorder = 4)
        self.axes.text(1,0.8*max(Data),str(np.round(width_wg,2))+u"µm", fontsize=16, bbox=dict(facecolor='m', alpha=0.5))
        self.axes.text(1,0.6*max(Data),"Pos1: "+str(round(valueSlider1,2))+u"µm", fontsize=16, bbox=dict(facecolor='m', alpha=0.5))
        self.axes.text(1,0.4*max(Data),"Pos2: "+str(round(valueSlider2,2))+u"µm", fontsize=16, bbox=dict(facecolor='m', alpha=0.5))
        self.axes.grid(True)
        self.draw()

"vlines" are LineCollections in matplotlib. I searched in the documentation but could not find any hint to a function like 'set_xdata' How can I change the x value of vertical lines when they are already drawn and embedded into FigureCanvas?

I have the same problem with changing the x and y data. When trying the known functions of matplotlib like 'set_data', I get an error that AxisSubPlot does not have this attribute.

In the following is my code for the FigureCanvas Class. The def update_verticalLines should only contain commands for changing the x coord of the vlines and not complete redraw.

class MplCanvas(FigureCanvas):    

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)   
        FigureCanvas.__init__(self, fig)
        self.setParent(parent)
        
class DynamicMplCanvas(MplCanvas):    

    def __init__(self, *args, **kwargs):
        
        MplCanvas.__init__(self, *args, **kwargs)
        

    def update_figure(self, Data, xData, Path, PlotNr):
        
        if PlotNr==0:
            self.axes.cla()
            self.style1(self.axes)
            self.axes.grid(True)  
            self.axes.plot(xData, Data, color='r', linewidth=2)  
            self.axes.set_xlim(0,max(xData))  
            self.axes.set_ylim(1.1*min(Data),1.1*max(Data))              
            self.draw()
            
        if PlotNr==1:
            self.axes.cla()
            self.style2(self.axes)
            self.axes.grid(True)
            self.axes.plot(xData, Data, color='b', linewidth=2) 
            self.axes.set_xlim(0,max(xData))  
            self.axes.set_ylim(1.1*min(Data),1.1*max(Data)) 
            self.vLine1 = self.axes.axvline(color='r')#vlines(len(Data)/4,min(Data),max(Data),color='r',linewidth=1.5, zorder = 4)         
            self.vLine2 = self.axes.vlines(len(Data)/2,min(Data),max(Data),color='r',linewidth=1.5, zorder = 4)
            #self.vLine1.set_xdata(0)
            self.draw() 
       
            
    def update_verticalLines(self, Data, xData, valueSlider1, valueSlider2, PlotNr, width_wg):
        if PlotNr == 2:
            self.axes.cla()
            self.axes.plot(xData, Data, color='b', linewidth=2) 
            self.axes.set_ydata(xData)            
            self.axes.vlines(valueSlider1,min(Data),max(Data),color='r',linewidth=1.5, zorder = 4)
            self.axes.vlines(valueSlider2,min(Data),max(Data),color='r',linewidth=1.5, zorder = 4)
            self.axes.text(1,0.8*max(Data),str(np.round(width_wg,2))+u"µm", fontsize=16, bbox=dict(facecolor='m', alpha=0.5))
            self.axes.text(1,0.6*max(Data),"Pos1: "+str(round(valueSlider1,2))+u"µm", fontsize=16, bbox=dict(facecolor='m', alpha=0.5))
            self.axes.text(1,0.4*max(Data),"Pos2: "+str(round(valueSlider2,2))+u"µm", fontsize=16, bbox=dict(facecolor='m', alpha=0.5))
            self.axes.grid(True)
            self.draw()
            #test=self.axes
            #self.vLine1 = plt.vlines(0,min(Data),max(Data),color='r',linewidth=1.5, zorder = 4)
            #help(test)
            #print test.get_axes()
            #print test.properties()
            #test.set_axes()
            #return test
            self.style2(self.axes)
            self.axes.relim()
            self.axes.autoscale_view(True,True,True)
            self.draw()  
        if PlotNr == 1:
            self.axes.cla()
            self.axes.plot(xData, Data, color='r', linewidth=2)             
            self.axes.vlines(valueSlider1,min(Data),max(Data),color='b',linewidth=1.5, zorder = 4)
            self.axes.vlines(valueSlider2,min(Data),max(Data),color='b',linewidth=1.5, zorder = 4)
            self.axes.grid(True)
            self.style1(self.axes)
            self.axes.relim()
            self.axes.autoscale_view(True,True,True)
            self.draw()  

Thanks

Upvotes: 1

Views: 305

Answers (2)

vvvvv
vvvvv

Reputation: 31730

Thanks @Craigular Joe. This was not exactly how it worked for me. I needed to change something:

def update_verticalLines(self, Data, xData, valueSlider1, valueSlider2, PlotNr, width_wg):
                
    self.vLine1.remove()
    self.vLine1 = self.axes.vlines(valueSlider1,min(Data), max(Data), color='g', linewidth=1.5, zorder = 4)
    self.vLine2.remove()
    self.vLine2 = self.axes.vlines(valueSlider2,min(Data), max(Data), color='g', linewidth=1.5, zorder = 4)            
    self.axes.draw_artist(self.vLine1)
    self.axes.draw_artist(self.vLine2)
    #self.update()
    #self.flush_events()        
    self.draw() 

update() did not work without draw(). (The old vlines stayed) flush_events() did some crazy stuff. I have two instances of FigureCanvas. flush_events() caused that within the second instance call the vlines moved with the slider but moved then back to the start position.


This answer was posted as an edit to the question change matplotlib data in gui by the OP Saorsa under CC BY-SA 3.0.

Upvotes: 0

Craigular Joe
Craigular Joe

Reputation: 98

When you create the vlines, save a reference to them, e.g.

self.my_vlines = self.axes.vlines(...)

so that when you want to change them, you can just remove and replace them, e.g.

self.my_vlines.remove()
self.my_vlines = self.axes.vlines(...)

# Redraw vline
self.axes.draw_artist(self.my_vlines)
# Add newly-rendered lines to drawing backend
self.update()
# Flush GUI events for figure
self.flush_events()

By the way, in the future you should try your best to pare down your code sample to just the essential parts. Having a lot of unnecessary sample code makes it hard to understand your question. :)

Upvotes: 0

Related Questions