在MATPLOTLIB中绘制多个子图时,条形图损坏

时间:2012-12-14 13:04:36

标签: python matplotlib

我创建了一个允许用户将几个图表添加到MATPLOTLIB窗口的类。这些可以是折线图或条形图。它还具有以下功能:当图表已添加到窗口(从rowID标识)而不是绘制新图时,它将替换旧图中的数据。即它允许更新(动画)

这对于线条图很有效,但是在绘制几个条形图时我会腐败。该课程如下:

  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

这有点长,总结一下:

addChart - 基本上添加了一个新的子图

addPlot - 在现有子图上添加新行或条

replaceChartDataIfChartExists - 如果ID已存在,则刷新数据

我正在使用的虚拟数据只是连续绘制正梯度和负梯度线。然而,我的情节可能会进入一个/部分或全部条形图被破坏的状态。它看起来几乎像x / y轴已旋转,各个条不从x轴开始。问题是间歇性的;有时我会得到几个预期的情节。一旦情节被破坏,所有未来的更新仍然会被破坏。

Corrupted Data Plot

根据要求,剩下的代码:

class TIndexConverter():    
    def __init__(self, numCols):                                      
        self.evenCounter = 0
        self.oddCounter = numCols

    def _getSubPlotIndex(self, arrayIndex):
        if arrayIndex%2==0:
            self.evenCounter += 1
            return self.evenCounter
        else:        
            self.oddCounter += 1
            return self.oddCounter


class TChart():
    def __init__(self, rowID, plotType, point_lists):
        self.subPlot = None
        self.plots = [TPlot(rowID, plotType, point_lists)]

class TPlot():
    def __init__(self, rowID, plotType, point_lists):                     
        self.plotItem = None        
        self.plotType = plotType  
        self.rowID = rowID           
        self.points = point_lists

一些客户端代码:

def _updateData(self, state, data): 
    if self.plot is not None:
        if not self.plot.replaceChartDataIfChartExists(data, state.comm.rowID):
            if self.createNewChart == True:
                self.plot.addChart(data, state.setting.plotType, state.comm.rowID)    
            else:
                self.plot.addPlot(data, state.setting.plotType, state.comm.rowID)

1 个答案:

答案 0 :(得分:0)

这可能相关也可能不相关,但您可以使用以下内容替换_calculateleastDiff

def _calculateleastDiff(self, xValues):
    return np.min(np.diff(sorted(xValues)))

这段代码方式过于复杂,无论它做什么。我怀疑你可以摆脱TChartTPlot类。我会保留一份数据列表(所以[ [subplot1_data1,subplot1_data2],[subplot2_data1],[...]])列出axes个对象,并列出一些内容,以便跟踪您想要的图表类型。

另外,尽量不要使用matplotlib中已经使用的名称,这会使你的代码更难阅读。