Quantcast

Bar chart corruption when plotting multiple subplots in MATPLOTLIB

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Bar chart corruption when plotting multiple subplots in MATPLOTLIB

p.bingham
I've created a class that allows a user to add several charts to a MATPLOTLIB window. These can be either a line chart or a bar chart. It also has the feature that when a chart has already been added to the window (as identified from rowID) rather than draw a new plot it will replace the data in the old plot. ie it allows for updates (animation)

This works grand for the line plot but I get corruption when plotting several bar charts. The class looks like:

  import math

  class TFrmPlot():

    def __init__(self, point_lists, deleteCallback, plotType, rowID):                    
            import matplotlib
            matplotlib.interactive( True )
            matplotlib.use( 'WXAgg' )  

            import matplotlib.pyplot as plt
            self.plt = plt
            self.fig = plt.figure()      
            self.fig.canvas.mpl_connect('close_event', self.on_close)    

            import matplotlib.axes as ax    
            self.ax = ax

            self.deleteCallback = deleteCallback
            self.chartArray = []              
            self.addChart(point_lists, plotType, rowID)

        def close(self):    
            self.plt.close('all')
            #self.fig.close()

        def replaceChartDataIfChartExists(self, point_lists, rowID):
            if rowID==0:
                pass
            for chart in self.chartArray:
                for plot in chart.plots:
                    if plot.rowID == rowID:
                        plot.points = point_lists                              
                        if plot.plotType=="Point":                        
                            plot.plotItem.set_data(point_lists[0],point_lists[1])                          
                            chart.subPlot.draw_artist(plot.plotItem)                        
                            self.fig.canvas.blit(chart.subPlot.bbox)
                        else:                      
                            for rect, h in zip(plot.plotItem, point_lists[1]):
                                rect.set_height(h)  
                        chart.subPlot.relim()                    
                        chart.subPlot.autoscale_view(True,True,True)                                                      
                        self.plt.draw()
                        return True
            return False    

        def addChart(self, point_lists, plotType, rowID):
            self.chartArray.append(TChart(rowID,plotType,point_lists))
            self._drawAll()

        def addPlot(self, point_lists, plotType, rowID):          
            chartNum = len(self.chartArray)
            self.chartArray[chartNum-1].plots.append(TPlot(rowID,plotType,point_lists))  
            self._drawAll()

        def on_close(self, event):
            self.deleteCallback()

        def _drawAll(self):    
            self.plt.clf()
            numSubPlots = len(self.chartArray)
            numCols = self._noCols(numSubPlots)
            IndexConverter = TIndexConverter(numCols)
            subPlot = None
            for chartIndex in range(0,numSubPlots):
                if numSubPlots==1:                
                    subPlot = self.fig.add_subplot(1,1,1)
                elif numSubPlots==2:                            
                    subPlot = self.fig.add_subplot(1,2,chartIndex+1)
                else:
                    subPlot = self.fig.add_subplot(2,numCols,IndexConverter._getSubPlotIndex(chartIndex))
                subPlot.relim()          
                subPlot.autoscale_view(True,True,True)
                self.chartArray[chartIndex].subPlot = subPlot
                self._drawSubs(self.chartArray[chartIndex])                  
            self.plt.show()

        def _drawSubs(self, chart):
            for plot in chart.plots:
                if plot.plotType=="Point":          
                    chart.subPlot.plot(plot.points[0],plot.points[1])
                    plot.plotItem = chart.subPlot.lines[len(chart.subPlot.lines)-1]
                else:
                    kwargs = {"alpha":0.5}
                    plot.plotItem = chart.subPlot.bar(plot.points[0],plot.points[1], width=self._calculateleastDiff(plot.points[0]), **kwargs)    

        def _noCols(self, numSubPlots):
            return math.ceil(float(numSubPlots)/2.0)  

        def _calculateleastDiff(self, xValues):
            xValues2 = sorted(xValues)
            leastDiff = None
            lastValue = None
            for value in xValues2:
                if lastValue is not None:
                    diff = value-lastValue            
                    if leastDiff is None or diff < leastDiff:
                        leastDiff = diff
                lastValue = value
            return leastDiff

This is a bit long so to summarise:

addChart -- basically adds a new subplot

addPlot -- adds a new line or bar to an existing subplot

replaceChartDataIfChartExists -- refreshes the data if the ID already exists

The dummy data that I'm using just plots a positive gradient and a negative gradient line in succession. My plots however can get into a state where one/some or all of the bar plots become corrupted. It looks almost like the x/y axis has been rotated, with the individual bars not starting from the x-axis. The issue is intermittent; sometimes I will get several plots as expected. Once a plot becomes corrupted all future updates remain corrupted.

Corrupted Chart:
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Bar chart corruption when plotting multiple subplots in MATPLOTLIB

Benjamin Root-2


On Fri, Dec 14, 2012 at 8:55 AM, p.bingham <[hidden email]> wrote:
I've created a class that allows a user to add several charts to a MATPLOTLIB
window. These can be either a line chart or a bar chart. It also has the
feature that when a chart has already been added to the window (as
identified from rowID) rather than draw a new plot it will replace the data
in the old plot. ie it allows for updates (animation)

This works grand for the line plot but I get corruption when plotting
several bar charts. The class looks like:

  import math

  class TFrmPlot():

    def __init__(self, point_lists, deleteCallback, plotType, rowID):
            import matplotlib
            matplotlib.interactive( True )
            matplotlib.use( 'WXAgg' )

            import matplotlib.pyplot as plt
            self.plt = plt
            self.fig = plt.figure()
            self.fig.canvas.mpl_connect('close_event', self.on_close)

            import matplotlib.axes as ax
            self.ax = ax

            self.deleteCallback = deleteCallback
            self.chartArray = []
            self.addChart(point_lists, plotType, rowID)

        def close(self):
            self.plt.close('all')
            #self.fig.close()

        def replaceChartDataIfChartExists(self, point_lists, rowID):
            if rowID==0:
                pass
            for chart in self.chartArray:
                for plot in chart.plots:
                    if plot.rowID == rowID:
                        plot.points = point_lists
                        if plot.plotType=="Point":

plot.plotItem.set_data(point_lists[0],point_lists[1])
                            chart.subPlot.draw_artist(plot.plotItem)
                            self.fig.canvas.blit(chart.subPlot.bbox)
                        else:
                            for rect, h in zip(plot.plotItem,
point_lists[1]):
                                rect.set_height(h)
                        chart.subPlot.relim()
                        chart.subPlot.autoscale_view(True,True,True)
                        self.plt.draw()
                        return True
            return False

        def addChart(self, point_lists, plotType, rowID):
            self.chartArray.append(TChart(rowID,plotType,point_lists))
            self._drawAll()

        def addPlot(self, point_lists, plotType, rowID):
            chartNum = len(self.chartArray)

self.chartArray[chartNum-1].plots.append(TPlot(rowID,plotType,point_lists))
            self._drawAll()

        def on_close(self, event):
            self.deleteCallback()

        def _drawAll(self):
            self.plt.clf()
            numSubPlots = len(self.chartArray)
            numCols = self._noCols(numSubPlots)
            IndexConverter = TIndexConverter(numCols)
            subPlot = None
            for chartIndex in range(0,numSubPlots):
                if numSubPlots==1:
                    subPlot = self.fig.add_subplot(1,1,1)
                elif numSubPlots==2:
                    subPlot = self.fig.add_subplot(1,2,chartIndex+1)
                else:
                    subPlot =
self.fig.add_subplot(2,numCols,IndexConverter._getSubPlotIndex(chartIndex))
                subPlot.relim()
                subPlot.autoscale_view(True,True,True)
                self.chartArray[chartIndex].subPlot = subPlot
                self._drawSubs(self.chartArray[chartIndex])
            self.plt.show()

        def _drawSubs(self, chart):
            for plot in chart.plots:
                if plot.plotType=="Point":
                    chart.subPlot.plot(plot.points[0],plot.points[1])
                    plot.plotItem =
chart.subPlot.lines[len(chart.subPlot.lines)-1]
                else:
                    kwargs = {"alpha":0.5}
                    plot.plotItem =
chart.subPlot.bar(plot.points[0],plot.points[1],
width=self._calculateleastDiff(plot.points[0]), **kwargs)

        def _noCols(self, numSubPlots):
            return math.ceil(float(numSubPlots)/2.0)

        def _calculateleastDiff(self, xValues):
            xValues2 = sorted(xValues)
            leastDiff = None
            lastValue = None
            for value in xValues2:
                if lastValue is not None:
                    diff = value-lastValue
                    if leastDiff is None or diff < leastDiff:
                        leastDiff = diff
                lastValue = value
            return leastDiff

This is a bit long so to summarise:

addChart -- basically adds a new subplot

addPlot -- adds a new line or bar to an existing subplot

replaceChartDataIfChartExists -- refreshes the data if the ID already exists

The dummy data that I'm using just plots a positive gradient and a negative
gradient line in succession. My plots however can get into a state where
one/some or all of the bar plots become corrupted. It looks almost like the
x/y axis has been rotated, with the individual bars not starting from the
x-axis. The issue is intermittent; sometimes I will get several plots as
expected. Once a plot becomes corrupted all future updates remain corrupted.

Corrupted Chart:
<http://matplotlib.1069221.n5.nabble.com/file/n40023/corrupted.png>


Your code is needlessly complex, and it is more likely that the bug lies in there rather than with matplotlib.  First, you really shouldn't ever do imports within a class, and it makes no sense to assign those imports as members of the class.  Second, you shouldn't need to do complex subplot management to do what you need, matplotlib has done it for you already.  For example, the fig.add_subplot() command will simply return the axes to you if it has already been created.  Alternatively, you might be interested in using the mpl_toolkit.axes_grid1 module:

http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html

but it might be overkill in your case.

If you can simplify your code significantly, and still encounter the corruption issue, please come back and post the code so we can help you out.

Cheers!
Ben Root


------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
_______________________________________________
Matplotlib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Bar chart corruption when plotting multiple subplots in MATPLOTLIB

p.bingham
This post has NOT been accepted by the mailing list yet.
Hi Ben

The matplotlib stuff above is an optional extra to an application that I've created. I don't want the users to have to install the matplotlib package unless they have to. The only way I could figure of achieving this is to import within the class scope. They are assigned as members to allow later reference. Without the assignment I cannot access the matplot lib module. If you know a better way of achieving what I'm looking for please let me know.

I've deprioritised this bug as it only occurs when the bar data vacillates between positive and negative values and I'm just looking to plot FFTs. When I get some time I plan to reduce the problem down and will post here when I do so. Sorry but I really shouldn't have posted my class directly.

Thanks for the feedback.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Bar chart corruption when plotting multiple subplots in MATPLOTLIB

p.bingham
In reply to this post by Benjamin Root-2
Hi Ben and thanks for the reply

The matplotlib stuff above is an optional extra to an application that I've created. I don't want the users to have to install the matplotlib package unless they have to. The only way I could figure of achieving this is to import within the class scope. They are assigned as members to allow later reference. Without the assignment I cannot access the matplot lib module. If you know a better way of achieving what I'm looking for please let me know.
 
I've deprioritised this bug as it only occurs when the bar data vacillates between positive and negative values and I'm just looking to plot FFTs. When I get some time I plan to reduce the problem down and will post here when I do so. Sorry but I really shouldn't have posted my class directly.
 
Thanks for the feedback.
Loading...