如何使用Python和Glade刷新GTK3中的matplotlib图表
我已经使用GTK3、Python和Glade将两个matplotlib图插入到一个容器中。它们使用来自第三方API的数据绘制区域的天气。当我输入一个新的区域设置并按下刷新按钮时,我希望图形更新 下面的每个解决方案都以不同的问题结束。太多了,无法描绘。通常情况下,他们会设法用新图表显示主窗口的另一个实例,但用旧图表显示的旧实例仍然保持打开状态。我试过:如何使用Python和Glade刷新GTK3中的matplotlib图表,python,gtk,gtk3,glade,Python,Gtk,Gtk3,Glade,我已经使用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()
# 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()