wx.Panel中的matplotlib.pyplot

时间:2015-03-12 09:25:44

标签: python matplotlib wxpython

在本课程的.__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的瘦状态包装器,你可以使用它(参见艺术家教程)”。在艺术家教程中,我可以使用的信息非常少,但有一些提示引导我self.figure.artists.extend(bars)

我使用self.figure.texts.extend(labels[1])稍微取得了一些成功,但是这只是将所有名字都堆叠在一起,(而且我认为这些蜱是在图的另一侧堆积的),所以我'我仍然无能为力。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分: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中的所有潮湿函数都在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()过分夸大了它;我认为它计算了可绘制区域和边界。
  6. 这些是我拼凑的文章:

答案 1 :(得分:0)

一些事情 - 您是否阅读过这些部分?

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示例,它工作正常。通过它们,还应该让您了解如何构建事物以及不同元素如何一起发挥作用。