Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Python和Glade刷新GTK3中的matplotlib图表_Python_Gtk_Gtk3_Glade - Fatal编程技术网

如何使用Python和Glade刷新GTK3中的matplotlib图表

如何使用Python和Glade刷新GTK3中的matplotlib图表,python,gtk,gtk3,glade,Python,Gtk,Gtk3,Glade,我已经使用GTK3、Python和Glade将两个matplotlib图插入到一个容器中。它们使用来自第三方API的数据绘制区域的天气。当我输入一个新的区域设置并按下刷新按钮时,我希望图形更新 下面的每个解决方案都以不同的问题结束。太多了,无法描绘。通常情况下,他们会设法用新图表显示主窗口的另一个实例,但用旧图表显示的旧实例仍然保持打开状态。我试过: 销毁父容器,然后重新加载更新的容器。以下代码产生分段错误。代码尝试将对象从生成器的新实例传递到旧实例。我认为这是我的主要问题。我不知道如何将正在

我已经使用GTK3、Python和Glade将两个matplotlib图插入到一个容器中。它们使用来自第三方API的数据绘制区域的天气。当我输入一个新的区域设置并按下刷新按钮时,我希望图形更新

下面的每个解决方案都以不同的问题结束。太多了,无法描绘。通常情况下,他们会设法用新图表显示主窗口的另一个实例,但用旧图表显示的旧实例仍然保持打开状态。我试过:

  • 销毁父容器,然后重新加载更新的容器。以下代码产生分段错误。代码尝试将对象从生成器的新实例传递到旧实例。我认为这是我的主要问题。我不知道如何将正在使用的生成器的实例传递到刷新按钮上的
    中,而不必将所有内容重写到单个类中

    def on_refresh_button_click(self, widget):
    
        parent = self.get_parent()
        grandparent = parent.get_parent()
        parent.destroy()
    
        city_name = "yerevan"
        db = "test.db"
    
        get_updated_data(city_name)
    
        builder = builder_with_signals()
        read_weather_from_db(db, builder, city_name)
        grandparent.add(parent)
    
        parent.show_all()
    
  • 使用
    self.get_parent()
    获取按钮的父容器作为要处理的对象。我想这几乎奏效了。我可以
    remove()
    destroy()
    包含图形的容器。我想我也成功地添加了更新的一个。但我没能把它表现出来。守则:

    def on_refresh_button_click(self, widget):
    
        parent = self.get_parent()
    
        city_name = "yerevan"
        db = "test.db"
    
        get_updated_data(city_name)
        fig_list = read_weather_from_db(db, city_name)
    
        for child in parent:
            try:
                for grandchild in child:
                    if Gtk.Buildable.get_name(grandchild) == "chart_past":
                        parent = child # Confusing, yes.
                        old = grandchild
                        new = FigureCanvas(fig_list[0])
    
                        props = {}
                        for key in parent.list_child_properties():
                            props[key.name] = parent.child_get_property(old, key.name)
    
                        parent.remove(old)
                        parent.add(new)
    
                        for name, value in props.items():
                            parent.child_set_property(new, name, value)
    
                        parent.show_all()
                        child.show_all()
                        grandchild.show_all()
    
                        # Try to find the newly added object
                        for item in parent:
                            print("trying to find another:", Gtk.Buildable.get_name(item))
        except:
            print(Gtk.Buildable.get_name(child))
    
  • 使用以下代码删除旧容器/小部件,然后添加新容器/小部件:

  • 在使用其他区域设置从头开始运行脚本之前销毁主窗口:

    def on_refresh_button_click(self, widget):
        builder = setup_builder()
        add_signals(builder)
        window = builder.get_object("window1")
        window.destroy()
        display_data("yerevan")
    
  • 关闭程序并重新启动,这对我来说都没有意义,但是:

    def on_refresh_button_click(self, widget):
        Gtk.main_quit()
        display_data("yerevan")
    
  • 使用canvas.draw()from和

  • add\u替换为
    viewport()
    替换为
    add()

也读了这篇文章的不同部分,尝试了其他一些东西,但这两天太长了,所以我忘了

大多数示例似乎使用GTK3和Python构建应用程序,但没有Glade。他们也使用类。我现在不想使用类。我想在我把整个事情重写成一个类之前,看看是否有人知道一个解决方案。我可能只是误会了或者错过了什么

我是GTK和Glade的新手,这是我第一次尝试,所以请原谅我的混乱。我省略了SQL CRUD代码和向API发送请求的代码。这些很好用。有关守则:

# SETUP THE BUILDER
def setup_builder():
    return Gtk.Builder()

def add_signals(builder):
    builder.add_objects_from_file('weather.xml', ('window1', 'refresh_button', 'box_charts'))

    return builder.connect_signals({'on_window1_destroy': (on_window1_destroy,'window1'),
                                    'on_refresh_button_click': (on_refresh_button_click,),
                                    })
def builder_with_signals():
    builder = setup_builder()
    add_signals(builder)
    return builder


# READ DATA FROM DATABASE
def read_weather_from_db(db, builder, city_name):
    chart_future_values = read_db(db, "chart_future", city_name)
    chart_past_values = read_db(db, "chart_past", city_name)

    fig_future = embed_chart("day and time", "temp", chart_future_values["xticks"], chart_future_values["datetimes_x_axis"], chart_future_values["temps"])
    fig_past = embed_chart("day and time", "temp", chart_past_values["xticks"], chart_past_values["datetimes_x_axis"], chart_past_values["temps"])

    add_canvas(builder, "chart_future", fig_future)
    add_canvas(builder, "chart_past", fig_past)

    return builder


# EMBED THE CHARTS INTO CONTAINERS
def embed_chart(xlabel, ylabel, xticks, xticklabels, yticks):

    fig = Figure(figsize=(5, 5), dpi=100)
    chart = fig.add_subplot(111)
    chart.set_xlabel(xlabel)
    chart.set_ylabel(ylabel)
    chart.set_xticks(xticks)
    chart.set_xticklabels(xticklabels, rotation=90)
    chart.plot(xticks, yticks)
    return fig

def add_canvas(builder, chart_container, fig):
    canvas = FigureCanvas(fig)
    subbox_chart = builder.get_object(chart_container)
    subbox_chart.add(canvas)


# THIS RUNS THE SCRIPT
def display_data(city_name="isfahan"):
    get_updated_data(city_name)
    builder = builder_with_signals()
    read_weather_from_db("test.db", builder, city_name)
    show_gtk(builder)

def on_window1_destroy(self, widget):
    Gtk.main_quit()

# HERE IS THE IMPORTANT BIT
def on_refresh_button_click(self, widget):
    # I DON'T KNOW WHAT TO PUT HERE

def show_gtk(builder):
    window_main = builder.get_object('window1')
    window_main.show_all()
    Gtk.main()
我认为您不需要Glade xml文件,但我不确定,因为我对这一点非常陌生:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <signal name="destroy" handler="on_window1_destroy" swapped="no"/>
    <child type="titlebar">
      <placeholder/>
    </child>
    <child>
      <object class="GtkBox" id="box_main">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <placeholder/>
        </child>
        <child>
          <object class="GtkBox" id="box_charts">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkScrolledWindow" id="chart_past">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="shadow_type">in</property>
                <property name="min_content_width">500</property>
                <property name="min_content_height">500</property>
                <child>
                  <placeholder/>
                </child>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkScrolledWindow" id="chart_future">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="shadow_type">in</property>
                <property name="min_content_width">500</property>
                <property name="min_content_height">500</property>
                <child>
                  <placeholder/>
                </child>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="refresh_button">
            <property name="label" translatable="yes">refresh</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <signal name="button-press-event" handler="on_refresh_button_click" swapped="no"/>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

错误的
符合事实的
错误的
竖的
符合事实的
错误的
符合事实的
符合事实的
在里面
500
500
错误的
符合事实的
0
符合事实的
符合事实的
在里面
500
500
错误的
符合事实的
1.
错误的
符合事实的
1.
刷新
符合事实的
符合事实的
符合事实的
错误的
符合事实的
2.

我不确定能否给您提供一个适用于现有代码的示例,但以下是我是如何做到这一点的:

Figure = None
def invoice_chart_clicked (self, button):
        global Figure
        if Figure == None:
            from matplotlib.figure import Figure
            from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas
            from matplotlib.pyplot import pie
            self.figure = Figure(figsize=(4, 4), dpi=100)
            canvas = FigureCanvas(self.figure)  # a Gtk.DrawingArea
            canvas.set_size_request(800, 500)
            overlay = self.builder.get_object('overlay1')
            overlay.add (canvas)
        a = self.figure.add_subplot(111)
        labels = list()
        fractions = list()
        unpaid = 0
        self.cursor.execute("SELECT SUM(amount_due), c.name FROM invoices "
                            "JOIN contacts AS c ON c.id = invoices.customer_id "
                            "WHERE (canceled, paid, posted) = "
                            "(False, False, True) GROUP BY customer_id, c.name "
                            "ORDER BY SUM(amount_due)")
        for row in self.cursor.fetchall():
            customer_total = row[0]
            customer_name = row[1]
            fractions.append(customer_total)
            labels.append(customer_name)
            unpaid += 1
        if unpaid == 0:
            labels.append("None")
            fractions.append(1.00)
        a.pie(fractions, labels=labels, autopct='%1.f%%', radius=0.7)
        window = self.builder.get_object('window1')
        window.show_all()

每次重新加载此函数时,将重新生成绘图。您可以找到完整的代码。我从来没有运行过任何测试来查看所有内存是否被正确释放,等等。也许它会提供足够的内存来执行这些操作。

创建一个单独的绘图窗口,如图所示,GUI中的按钮将触发刷新?
连续运行的funcanimation应该为您提供所需的“刷新”功能。

事实证明,使用
self.parent()
作为起点可能是最理想的选择,因为我不想将整个过程重写为一个类。但是:

  • 销毁/删除包含该图形的子容器意味着现在没有更多的容器可以放入新图形
  • 我假设无法删除子容器中的图形。这种假设是错误的
删除图表需要一些努力。让我们假设
child
是保存容器对象的变量。打印
child.get_children()
返回
None
。这部分是导致我错误假设的原因

但我注意到,当我尝试
add()
一个更新的图形时,它给了我这个错误:
gtk\u滚动的\u窗口\u添加:断言'child\u widget==NULL'失败
。里面有东西

我看不到它,但我可以删除这个
child\u小部件吗

# This successfully removes any descendent in `child`.
# It leaves the container empty, so to speak.
for grandkid in child.get_children():
    child.remove(grandkid)

# This adds and displays the updated figure.
new = FigureCanvas(fig)
child.add(new)
child.show_all()
成功了

# This successfully removes any descendent in `child`.
# It leaves the container empty, so to speak.
for grandkid in child.get_children():
    child.remove(grandkid)

# This adds and displays the updated figure.
new = FigureCanvas(fig)
child.add(new)
child.show_all()