2017-01-14 6 views
0

私はGtk +ウィンドウにmatplotlibプロットをカプセル化しました。ボタンをクリックするとそのプロットを更新しようとしています(ガウスサークルの問題です)。問題は、プロットをイベントで更新する方法を正確にはわかりません。これまでのところ、私は以下を持っています。私はここから行くの場所を正確にはわからないMatplotlibプロットをGtk +ボタンイベントで更新する

#! /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のを伝える方法を知りません。

enter image description here

また、これは、それはあなたが(:P私はまた、縦方向右側の列に2つのボタンウィジェットを中心にしようとしている)、それを実行することができない場合のように、現在に見えるものです

答えて

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() 

私は、バイナリイメージプロットおよび再構造化メソッド呼び出しのパリティを入れ替えボタンをも追加しました。

これは遅い/簡単なスタートですが、私たちはどこかで始めなければならないと思います!コメントと提案は大歓迎です。

0

は、あなたがやっていることに全く適切ではないかもしれませんが、(いくつかのJavaソースコードと醜いが、便利なイラスト付き)ガウス円の問題についても同様にシンプルでより高速なアルゴリズムがあります:https://stackoverflow.com/a/42373448/5298879

それは周りの3.4ですxは、四半期のうちの1つのポイントをカウントするよりも早く、さらに、コードの行を1つだけ取って、現在実行している中心と軸上の点を合計したものです。

あなたは単に刻まれた正方形を想像し、その円の内側のその正方形の外側にあるもののわずか8分の1を数えます。

関連する問題