【问题标题】:matplotlib.pyplot in a wx.Panelwx.Panel 中的 matplotlib.pyplot
【发布时间】:2018-07-31 09:09:31
【问题描述】:

在此类的.__init__() 中,我有以下几行:

class report_order_totals_by_photographer(wx.Panel):
    def __init__(...):
        ...
        self.figure = matplotlib.figure.Figure()
        self.canvas = matplotlib.backends.backend_wxagg.FigureCanvasWxAgg(panel_canvas, -1, self.figure)

在事件处理程序中我有:

    self.figure.clf()

    datapoints = range(len(self.data))
    values = [x[1] for x in self.data]
    labelpositions = [x + 0.5 for x in range(len(self.data))]
    labeltext = [x[0] for x in self.data]

    bars = matplotlib.pyplot.barh(datapoints, values)
    labels = matplotlib.pyplot.yticks(labelpositions, labeltext)

    self.figure.artists.extend(bars)
    self.figure.axes.extend(labels)

    self.canvas.draw()

看起来像这样:

http://i.imgur.com/SnjWD.png

或者在调整大小时:

http://i.imgur.com/t2gGtEt.png

这令人困惑和沮丧。我希望它看起来像这样:

data = db.get_order_totals_for_photographers(*season_to_dates("14w"))
import matplotlib.pyplot as plt
plt.barh(range(len(data)), [x[1] for x in data])
plt.yticks([x + 0.5 for x in range(len(data))], [y[0] for y in data])
plt.show()

i.imgur.com/BD1RXOq.png

(这也令人困惑和沮丧,因为名称超出了页面,但无论如何,我稍后会关心)。

我的两个主要问题是它没有根据它所在的框架调整大小,而且我只能绘制条形图,而不能绘制其他任何东西。

在我的工作示例中,我使用了 matplotlib 教程所称的“围绕 matplotlib 的 API 的瘦状态包装器”,这让我很奇怪,我不喜欢它。幸运的是,本教程接着说:“如果您发现这种状态性令人讨厌,请不要绝望,这只是面向对象 API 的一个薄状态包装,您可以使用它来代替(参见 Artist 教程)”。在艺术家教程中,我可以使用的有用信息非常少,但有一些提示可以引导我前往self.figure.artists.extend(bars)

我在self.figure.texts.extend(labels[1]) 上取得了稍大的成功,但这只是把所有名字都堆在了一起,(而且我认为在情节的右边,勾号是堆在彼此之上的),所以我仍然无知。

任何帮助将不胜感激。

【问题讨论】:

    标签: python matplotlib wxpython


    【解决方案1】:

    该死的,这比它需要的更难。这是一个独立的示例。

    (我已经创建了一个repository,代码更好)。

    import wx
    import matplotlib.backends.backend_wxagg
    import matplotlib.pyplot
    import matplotlib.figure
    import numpy
    
    data = [
        [
            ["Arse", 5],
            ["Genitals", 12],
            ["Bum", 2]
            ],
        [
            ["Fart", 3],
            ["Guff", 2],
            ["EXPLOSION", 6]
            ],
        [
            ["Clam", 2],
            ["Stench trench", 7],
            ["Axe wound", 3],
            ["Fourth euphemism", 9]
            ]
        ]
    
    class panel_plot(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent, style = wx.NO_FULL_REPAINT_ON_RESIZE)
    
            self.figure = matplotlib.figure.Figure()
            self.canvas = matplotlib.backends.backend_wxagg.FigureCanvasWxAgg(self, -1, self.figure)
    
            self.set_size()
            self.draw()
    
            self._resize_flag = False
    
            self.Bind(wx.EVT_IDLE, self.on_idle)
            self.Bind(wx.EVT_SIZE, self.on_size)
    
        def on_idle(self, event):
            if self._resize_flag:
                self._resize_flag = False
                self.set_size()
    
        def on_size(self, event):
            self._resize_flag = True
    
        def set_size(self):
            pixels = tuple(self.GetSize())
            self.SetSize(pixels)
            self.canvas.SetSize(pixels)
            self.figure.set_size_inches([float(x) / self.figure.get_dpi() for x in pixels])
    
        def draw(self):
            self.canvas.draw()
    
    class frame_main ( wx.Frame ):
        def __init__( self, parent ):
            wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
    
            self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
    
            sizer_bg = wx.BoxSizer( wx.VERTICAL )
    
            self.panel_bg = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
            sizer_main = wx.BoxSizer( wx.VERTICAL )
    
            self.button_change = wx.Button( self.panel_bg, wx.ID_ANY, u"Change data", wx.DefaultPosition, wx.DefaultSize, 0 )
            sizer_main.Add( self.button_change, 0, wx.ALL, 5 )
    
            self.panel_matplotlib = panel_plot(self.panel_bg)
            sizer_main.Add( self.panel_matplotlib, 1, wx.EXPAND |wx.ALL, 5 )
    
    
            self.panel_bg.SetSizer( sizer_main )
            self.panel_bg.Layout()
            sizer_main.Fit( self.panel_bg )
            sizer_bg.Add( self.panel_bg, 1, wx.EXPAND, 5 )
    
    
            self.SetSizer( sizer_bg )
            self.Layout()
    
            self.i = 0
    
            self.on_change()
    
            self.setbinds()
    
        def setbinds(self):
            self.button_change.Bind(wx.EVT_BUTTON, self.on_change)
    
        def on_change(self, event = None):
            self.panel_matplotlib.figure.clf()
            axes = self.panel_matplotlib.figure.gca()
    
            self.i += 1
            _data = numpy.array(data[self.i%3])
    
            datapoints = numpy.array(range(len(_data)))
            values = numpy.array([int(x[1]) for x in _data])
            labelpositions = numpy.array([x + 0.4 for x in range(len(_data))])
            labeltext = numpy.array([x[0] for x in _data])
    
            axes.barh(datapoints, values)
            axes.set_yticks(labelpositions)
            axes.set_yticklabels(labeltext)
    
            self.panel_matplotlib.draw()
    
    
    class App(wx.App):
        def __init__(self):
            super(App, self).__init__()
            self.mainframe = frame_main(None)
            self.mainframe.Show()
            self.MainLoop()
    
    App()
    

    考虑到我来源的文章没有管理的关键点:

    1. 一切都必须是numpy 数组。 matplotlib 习惯于在arraylikes 上使用+ 运算符,而对于python 列表,这只是一个扩展。
    2. 看起来 matplotlib.pyplot 中的所有 dank 函数也在 axes 上,即 matplotlib.figure.Figure().gca()
    3. axes.set_yticks() 需要在.set_yticklabels 之前完成,以便标签的位置正确。
    4. super(panel_plot, self).__init__(...) 似乎不起作用,没有立即明显的原因。
    5. panel_plot.set_size() 中,第一行需要包含self.GetSize()不是 self.Parent.GetClientSize()GetClientSize() 有点过大;我认为它计算了可绘制区域和边框。

    这些是我拼凑的文章:

    【讨论】:

    • 对年轻的我的粗鲁表示歉意。
    【解决方案2】:

    几件事 - 你读过这些部分吗?

    http://matplotlib.org/faq/howto_faq.html#move-the-edge-of-an-axes-to-make-room-for-tick-labels

    http://matplotlib.org/faq/howto_faq.html#automatically-make-room-for-tick-labels

    他们可能会帮助解释您遇到此问题的原因以及如何对其进行排序。看起来您必须像上面的示例一样编写代码来处理元素的布局和间距,因为您在更新标签之后可能会导致对齐和格式化。

    另外,我认为您需要退后一步,也许花一点时间熟悉 Matplotlib API 以及不同的类和对象如何协同工作。现在看起来你有点试图猜测你的方式,作为一个曾经在那里做过的人,它不会有好的结局:-)。一旦您了解了 matplotlib 的 OOP 结构以及事情如何协同工作,您应该对如何处理事情有了更好的了解。

    您是否也阅读过这些示例? http://matplotlib.org/examples/user_interfaces/index.html

    我运行了 QT 示例,它运行良好。研究它们还应该让您了解如何构建事物以及不同元素如何一起发挥作用。

    【讨论】:

      猜你喜欢
      • 2014-02-20
      • 2010-11-05
      • 2011-01-22
      • 1970-01-01
      • 2011-03-29
      • 1970-01-01
      • 2012-02-09
      • 2013-08-13
      • 1970-01-01
      相关资源
      最近更新 更多