我已经在Gtk +窗口中封装了一个matplotlib图,我试图在点击一个按钮时更新该图(它的高斯'圆问题)。麻烦的是,我不确定如何通过事件更新情节。到目前为止,我有以下内容。
#! /usr/bin/env python3.4
# -*- coding: utf-8 -*-
""" Main application--embed Matplotlib figure in window with UI """
import gi
gi.require_version('Gtk', '3.0')
import numpy as np
from gi.repository import Gtk, GObject
from matplotlib.figure import Figure
# make sure cairocffi is installed, pycairo doesn't support FigureCanvasGTK3Agg
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg \
as FigureCanvas
from matplotlib.patches import Ellipse
from typing import List, Tuple
from math import sqrt
class Main(Gtk.Window):
""" Main window UI """
SIGMA = 10
def __init__(self):
Gtk.Window.__init__(self, title='Gauss\' Circle Problem')
self.connect('destroy', lambda _: Gtk.main_quit())
self.set_border_width(10)
self.set_default_size(600, 450)
# Set up the l/r box layout
self.box = Gtk.Box(spacing=10)
self.add(self.box)
# Set up the right column
self.rcolumn = Gtk.Grid()
self.box.pack_end(self.rcolumn, False, False, 1)
# Set up spin button
adjustment = Gtk.Adjustment(10, 3, 100, 1, 0, 0)
self.spinbutton = Gtk.SpinButton()
self.spinbutton.set_adjustment(adjustment)
self.rcolumn.attach(self.spinbutton, 0, 0, 1, 1)
# Set up update button
self.update_plot_button = Gtk.Button(label='Update')
self.update_plot_button.connect('clicked', self.update_sigma_event)
self.rcolumn.attach_next_to(self.update_plot_button,
self.spinbutton, Gtk.PackDirection.BTT, 1, 1)
self._add_plot()
def update_sigma_event(self, button) -> None:
""" Update sigma and replot """
self.SIGMA = self.spinbutton.get_value()
self._add_plot()
def _add_plot(self) -> None:
""" Add the plot to the window """
fig = Figure(figsize=(5, 4))
ax = fig.add_subplot(111, aspect='equal')
arr = np.zeros([self.SIGMA * 2 + 1] * 2)
points = self.collect(int(self.SIGMA), int(self.SIGMA), self.SIGMA)
# flip pixel value if it lies inside (or on) the circle
for p in points:
arr[p] = 1
# plot ellipse on top of boxes to show their centroids lie inside
circ = Ellipse(\
xy=(int(self.SIGMA), int(self.SIGMA)),
width=2 * self.SIGMA,
height=2 * self.SIGMA,
angle=0.0
)
ax.add_artist(circ)
circ.set_clip_box(ax.bbox)
circ.set_alpha(0.2)
circ.set_facecolor((1, 1, 1))
ax.set_xlim(-0.5, 2 * self.SIGMA + 0.5)
ax.set_ylim(-0.5, 2 * self.SIGMA + 0.5)
# Plot the pixel centers
ax.scatter(*zip(*points), marker='.', color='white')
# now plot the array that's been created
ax.imshow(-arr, interpolation='none', cmap='gray')
# add it to the window
canvas = FigureCanvas(fig)
self.box.pack_start(canvas, True, True, 0)
@staticmethod
def collect(x: int, y: int, sigma: float =3.0) -> List[Tuple[int, int]]:
""" create a small collection of points in a neighborhood of some
point
"""
neighborhood = []
X = int(sigma)
for i in range(-X, X + 1):
Y = int(pow(sigma * sigma - i * i, 1/2))
for j in range(-Y, Y + 1):
neighborhood.append((x + i, y + j))
return neighborhood
if __name__ == '__main__':
window = Main()
window.show_all()
Gtk.main()
我不确定从何处开始,我只知道更新SpinButton
确实会调整self.SIGMA
,但我不知道如何告诉matplotlib更新窗口中的情节。
此外,如果您无法运行它,目前看起来就是这样(我还尝试将右侧列中的两个按钮小部件垂直居中:P):
答案 0 :(得分:1)
这是我发现问题的解决方案:
#! /usr/bin/env python3.4
# -*- coding: utf-8 -*-
""" Main application--embed Matplotlib figure in window with UI """
import gi
gi.require_version('Gtk', '3.0')
import numpy as np
from gi.repository import Gtk, GObject
from matplotlib.figure import Figure
# make sure cairocffi is installed, pycairo doesn't support FigureCanvasGTK3Agg
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg \
as FigureCanvas
from matplotlib.patches import Ellipse
from typing import List, Tuple, Union
from math import sqrt
class Main(Gtk.Window):
""" Main window UI """
SIGMA = 10
INVERT = -1
def __init__(self) -> None:
Gtk.Window.__init__(self, title='Gauss\' Circle Problem')
self.connect('destroy', lambda _: Gtk.main_quit())
self.set_border_width(10)
self.set_default_size(650, 500)
# Set up the l/r box layout
self.box = Gtk.Box(spacing=10)
self.add(self.box)
# Set up the right column
self.rcolumn = Gtk.VBox(spacing=0)
self.rcolumn.set_spacing(10)
self.box.pack_end(self.rcolumn, False, False, 20)
# Set up spin button
adjustment = Gtk.Adjustment(self.SIGMA, 1, 30, 1, 0, 0)
self.spinbutton = Gtk.SpinButton()
self.spinbutton.set_adjustment(adjustment)
self.rcolumn.pack_start(self.spinbutton, False, False, 0)
# Set up invert checkbox
self.invertbutton = Gtk.CheckButton('Invert')
self.invertbutton.set_active(True)
self.invertbutton.connect('toggled', self.switch_toggle_parity, 'invert')
self.rcolumn.add(self.invertbutton)
# Set up update button
self.update_plot_button = Gtk.Button(label='Update')
self.update_plot_button.connect('clicked', self.update_sigma_event)
self.rcolumn.add(self.update_plot_button)
self.initial_plot()
def calculate(self) -> None:
""" Re-calculate using the formula """
arr = np.zeros([self.SIGMA * 2 + 1] * 2)
points = self.collect(int(self.SIGMA), int(self.SIGMA), self.SIGMA)
# flip pixel value if it lies inside (or on) the circle
for p in points:
arr[p] = 1
# plot ellipse on top of boxes to show their centroids lie inside
circ = Ellipse(
xy=(int(self.SIGMA), int(self.SIGMA)),
width=2 * self.SIGMA,
height=2 * self.SIGMA,
angle=0.0
)
self.ax.clear()
self.ax.add_artist(circ)
circ.set_clip_box(self.ax.bbox)
circ.set_alpha(0.2)
circ.set_facecolor((1, 1, 1))
self.ax.set_xlim(-0.5, 2 * self.SIGMA + 0.5)
self.ax.set_ylim(-0.5, 2 * self.SIGMA + 0.5)
# Plot the pixel centers
self.ax.scatter(*zip(*points), marker='.',
color='white' if self.INVERT == -1 else 'black')
# now plot the array that's been created
self.ax.imshow(self.INVERT * arr, interpolation='none', cmap='gray')
def initial_plot(self) -> None:
""" Set up the initial plot; only called once """
self.fig = Figure(figsize=(5, 4))
self.canvas = FigureCanvas(self.fig)
self.box.pack_start(self.canvas, True, True, 0)
self.ax = self.fig.add_subplot(111, aspect='equal')
self.calculate()
self.draw_plot()
def update_sigma_event(self, button: Union[Gtk.Button, None] =None) -> None:
""" Update sigma and trigger a replot """
self.SIGMA = int(self.spinbutton.get_value())
self.calculate()
self.draw_plot()
def switch_toggle_parity(self, button: Union[Gtk.CheckButton, None] =None,
name: str ='') -> None:
""" Switch the parity of the plot before update """
self.INVERT *= -1
def draw_plot(self) -> None:
""" Draw or update the current plot """
self.fig.canvas.draw()
@staticmethod
def collect(x: int, y: int, sigma: float =3.0) -> List[Tuple[int, int]]:
""" create a small collection of points in a neighborhood of some
point
"""
neighborhood = []
X = int(sigma)
for i in range(-X, X + 1):
Y = int(pow(sigma * sigma - i * i, 1/2))
for j in range(-Y, Y + 1):
neighborhood.append((x + i, y + j))
return neighborhood
if __name__ == '__main__':
window = Main()
window.show_all()
Gtk.main()
我还添加了一个按钮,用于交换二进制图像图的奇偶校验并重新构造方法调用。
这是一个缓慢/简单的开始,但我想我们都必须从某个地方开始!欢迎提出意见和建议。
答案 1 :(得分:0)
可能不完全适合你正在做的事情,但是对于高斯圆问题(使用一些Java源代码和一个丑陋但方便的插图)也有类似的简单但更快的算法:{{3} }
它比其中一个季度中的点数加上中心,加上轴上的点数快了大约3.4倍,你现在正在做,而只需再多行一行代码。
你只需要想象一个刻有铭文的正方形,只计算那个圆圈内那个正方形外面的八分之一。