1

I have implemented a sync block which plots inside its work function using the input_items values. Now the problem is that the plotting mechanism isn't fast enough for the input stream ( the value of input_items keeps on changing ).

I have tried to simplify the code as much as possible and added comments. Here it is:

....
import matplotlib
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure
temp = ''
class xyz(gr.sync_block):
    def __init__(self,parent,title,order):
        a = []
        self.count = 1
        gr.sync_block.__init__(self,
                name="xyz",
                in_sig=[numpy.float32,numpy.float32],
                out_sig=None)
        self.win = xyzPlot(parent) #I have a Top Block(wxFrame). I am just making it the parent of xyzPlot(wxPanel) here.

    def work(self, input_items, output_items):
        global temp
        if (self.count == 1):
            temp = input_items+list()
        bool = not(np.allclose(temp,input_items))#bool will be true if the value of `input_items` changes. 
        .......
        #the code that evaluates z1,z2 depending on the value of input_items    
        .......
        if ( bool or self.count == 1 ):
        #If bool is true or it is the first time then I am calling plot() which plots the graph. 
            self.win.plot(tf(self.z1,self.z3),None,True,True,True,True)
        self.count = 0
        temp = input_items+list()
        return len(input_items[0])

class xyzPlot(wx.Panel):
    def __init__(self, parent, dB=None, Hz=None, deg=None):
        wx.Panel.__init__(self , parent , -1 ,size=(600,475))
        self.fig = Figure()
        self.axes = self.fig.add_subplot(111)

    def plot(self, syslist, omega=None, dB=None, Hz=None, deg=None, Plot=True, *args , **kwargs):
        self.axes.clear() #I clear the graph here so that new values can be plotted.
        .....
        self.axes.semilogx(omega,mag,*args,**kwargs)
        self.canvas = FigCanvas(self, -1, self.fig)
        self.canvas.draw()

As you can see I am working with wxPython but the panel freezes whenever I change the value of input_items too fast ( It works fine if I change it slowly ). Any recommendations? I am new to this.

Karup
  • 2,024
  • 3
  • 22
  • 48
  • Don't clear the axes and rebuild the artist. Create it once, and keep a reference to it. Then you can use `set_data` to only change the data points. Same holds for the canvas. Only create it once, then calling `draw` should be enough to update the figure. – hitzg Jun 26 '15 at 08:38
  • @hitzg: True, but the problem seems to be that he's asynchronously and at high rates plotting things in a thread that's not the GUI thread. I think you might be better used to matplotlib/wx integration, so I'd love to see your comment under my [answer](http://stackoverflow.com/a/31068633/4433386). – Marcus Müller Jun 26 '15 at 08:41
  • @MarcusMüllerꕺꕺ Not really. My comment is merely a recommendation on how to speed up the update of a plot. – hitzg Jun 26 '15 at 08:47
  • @hitzg: I understood the change with respect to the canvas. How to use `set_data` in his case as he is using `semilogx`? – Sailesh Sriram Jun 26 '15 at 09:04
  • `semilogx` works exactly as `plot`. It returns a list of artists. – hitzg Jun 26 '15 at 09:09

1 Answers1

1

To cite another answer I gave:

This will quickly also get a multithreading problem. To be clear: What you're trying to do (call a plotting function from a block thread) is problematic and usually won't work.

The problem is that you're working in a complex multithreading environment:

  • each GNU Radio block works in its own thread
  • The WX Gui main loop runs continously to update the screen.

What you're doing here is, from a GNU Radio block thread, change what is shown in the window. That is a bad thing, because it changes things that are in the context of the WX Gui thread. This can work, if these changes don't conflict, and if the WX Gui thread doesn't access this kind of data while you're changing it (at some point, it has to access it -- otherwise, noone will update your window).

This is a problem common to all kind of updated GUIs, not only to GNU Radio!

Whether or not that happens is a mere case of probability: With a slowly updated display, your probability of conflict is low, but when you update often, it approaches 1.

The existing visualizations are written in C++ and take very great care to do things the right way -- which is, letting your Gui toolkit (WX in your case, though I explicitely recommend, and have recommended, to move away from that) know that things need to be updated, and then offering WX a function to update the display in its own thread.

Community
  • 1
  • 1
Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • Thanks for your answer. Are there any tutorials available on how to feed an existing visualizer with samples? Could you please guide me to them or to files which implement a similar thing so I could go through the code? – Karup Jun 26 '15 at 10:39
  • @PuRaK: the guided tutorials are your friend. You just stream in samples. The source code is openly available, http://github.com/gnuradio/gnuradio . Look into the gr-qtgui/lib (or if you really want to do that, don't do that, WX is dead, gr-wxgui) folder. – Marcus Müller Jun 29 '15 at 09:36