5

I have a matplotlib hexbin embedded in a GTK.Window that graphs some data (x,y). I want the plot to update when new data is received (via UDP). I am having some trouble though.

I can get it to work in several different ways, but none have been "efficient" (Meaning - redrawing the plot takes too long). I looked here and attempted to model my hexbin after the suggested answer but could not get this to work at all. I keep receiving the following error:

TypeError: 'PolyCollection' object is not iterable.

I'm guessing that hexbins cannot be update in the same way as standard plots.

Sample Code:

class graph:
    def __init__(self):
        self.window = gtk.Window()
        self.figure = plt.figure()
        self.ax = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.figure)
        self.window.add(self.canvas)

        self.graph = None

    def plot(self, xData, yData):
        if len(xData) > 1 and len(yData) > 1:
            self.graph, = self.ax.hexbin(self.xData, self.yData) 
            ###############################################
            ####This is where the code throws the error####

    def update(self, xData, yData):
        self.graph.set_xdata(np.append(self.graph.get_xdata(), xData))
        self.graph.set_ydata(np.append(self.graph.get_ydata(), yData))
        self.figure.canvas.draw()

The code is used like this:

graph = graph()
graph.plot(someXData, someYData)
# when new data is received
graph.update(newXData, newYData)

This is just a very small example of how I'm using the code. I don't have much experience with matplotlib so there is chance I could be going about this completely wrong. (which is most likely what I am doing)

So my ultimate question is - How do you update a matplotlib hexbin plot?


Edit: Thanks to danodonovan's answer, I altered my code and removed the ',' after self.graph = self.ax.hexbin(...)

The new error thrown is: AttributeError: 'PolyCollection' object has no attribute 'set_xdata'

Community
  • 1
  • 1
Jordan Carroll
  • 696
  • 2
  • 11
  • 29
  • If you could provide the lines above your error in your stack trace, it might help us workout what part of the code is throwing that exception. – danodonovan Feb 06 '13 at 17:06

3 Answers3

2

The line:

 self.graph, = self.ax.hexbin(self.xData, self.yData)

(if that is where your stack trace is throwing it's exception) would be because of the comma, implying that self.ax.hexbin is an iterable object. Changing to

 self.graph = self.ax.hexbin(self.xData, self.yData)

might stop the TypeError exception. Next time, provide a few more lines in the stack trace - it might help to clarify things.

danodonovan
  • 19,636
  • 10
  • 70
  • 78
  • That fixed that error, but now I am getting `AttributeError: 'PolyCollection' object has no attribute 'set_xdata'`. I will post more lines from the stack trace next time! I am still new to Python and don't know my way around it completely yet. So I'm not exactly sure how to easily access the stack trace. – Jordan Carroll Feb 06 '13 at 17:23
  • Cool - I think your new error might warrant a new question! PS The stack trace is just the lines above the Exception line - it helps dig down to the root of the error. – danodonovan Feb 06 '13 at 17:25
  • I think it might warrant an edit, because my question still remains unanswered. Thanks for your help. – Jordan Carroll Feb 06 '13 at 17:26
  • I know that, the question remains though "How do I update a matplotlib hexbin?" and that is still unanswered. – Jordan Carroll Feb 06 '13 at 17:28
2

I don't think that this can be done currently, hexbin converts list of x,y -> a collections of polygons. The polyCollection is just a list of verticies, edges, and face colors, I don't think it carries any semantic information about how it was generated.

The best approach is to nuke the old hexbin and replace it with a new one.

If you really want to be able to update in-place either use a square 2d histogram (so you can use imshow), or you can modify hexbin to return a list of patches (instead of a polyCollection) and keep track of the binning your self.

user3666197
  • 1
  • 6
  • 50
  • 92
tacaswell
  • 84,579
  • 22
  • 210
  • 199
0

To answer your anticipated question, instead of calling set_xdata try something like update_from. I'm not promising this will work, but I would try

def update(self, xData, yData):
    # update your data structures
    self.xData = np.append(self.xData, xData)
    self.yData = np.append(self.yData, yData)

    # create a new hexbin - not connected to anything, with the new data
    new_hexbin = self.ax.hexbin(self.xData, self.yData)

    # update the viewed hexbin from the new one
    self.graph.update_from(new_hexbin)
    self.figure.canvas.draw()

Do note that without more code or explanation, this is really just guess work! The documentation for this class is here and the update_from method is from the parent class.

danodonovan
  • 19,636
  • 10
  • 70
  • 78