2013-06-23 10 views
1

Я думаю, что наткнулся на ошибку в Matplotlib, хотя я действительно надеюсь, что это просто что-то простое, что мне не хватает.Кнопка не работает во второй (вложенной) фигуре

Код, над которым я работаю, хорошо работал на Ubuntu 11.10, Ubuntu 12.04 и MacOS. Недавно я установил Fedora 18 на свою машину, и я заметил, что у Matplotlib возникают некоторые проблемы: у меня есть фигура с кнопкой. Нажмите кнопку, откроется другое окно, в котором также есть несколько кнопок. Кнопки во втором окне неактивны в моей системе Fedora. Они не реагируют на зависание (они не меняют цвет), и они не реагируют на щелчок.

Вот небольшой фрагмент кода, который имитирует эту проблему. Это хорошо работает на моем Ubuntu 12.04, но не на Fedora. Он должен работать следующим образом: показать фигуру с большой кнопкой, если вы нажмете кнопку, она покажет другую фигуру, которая, в свою очередь, тоже имеет кнопку. Если все хорошо, вторая кнопка должна реагировать на зависание и печатать что-то на терминал при нажатии.

import pylab 
from matplotlib.widgets import Button 


def draw_button1(event): 

    pylab.figure() 
    a = pylab.axes([0.1, 0.1, 0.8, 0.8]) 
    b = Button(a, 'Button 1') 

    def say_something(event): 
     print "This works." 

    b.on_clicked(say_something) 
    pylab.show() 

def draw_button2(): 
    pylab.figure() 
    a = pylab.axes([0.1, 0.1, 0.8, 0.8]) 
    b = Button(a, 'Button 2') 
    b.on_clicked(draw_button1) 
    pylab.show() 

draw_button2() 

Я не знаю, что вызывает это. Я попробовал несколько вещей:

  1. Я установил Matplitlib 1.2.0, 1.2.1 из репозитория ня и последняя 1.3.0rc2 который я построил из источника. Они все делают то же самое. Я также установил все соответствующие зависимости Matplotlib, даже те, которые необязательны.

  2. Я пытался удаленно запустить свой кусок кода на Ubuntu 12.04 с моей машины Fedora .. Может быть, есть проблема с тем, как X создает эти окна? Все еще работает на моем Ubuntu, рендеринг на моей Fedora.

  3. Furious googling по этому вопросу, который на самом деле не помог. Люди предлагают использовать pylab.ion() и pylab.ioff() для интерактивных сюжетов, но это тоже не помогло.

Если это помогает в любом случае, вот мой Matplotlib сборки:

BUILDING MATPLOTLIB 
      matplotlib: yes [1.3.0rc2] 
       python: yes [2.7.3 (default, Aug 9 2012, 17:23:57) [GCC 
         4.7.1 20120720 (Red Hat 4.7.1-5)]] 
       platform: yes [linux2] 

REQUIRED DEPENDENCIES AND EXTENSIONS 
       numpy: yes [version 1.7.1] 
       dateutil: yes [using dateutil version 1.5] 
       tornado: yes [using tornado version 3.1] 
      pyparsing: yes [using pyparsing version 1.5.6] 
       pycxx: yes [Couldn't import. Using local copy.] 
       libagg: yes [pkg-config information for 'libagg' could not 
         be found. Using local copy.] 
       freetype: yes [version 15.0.9] 
        png: yes [version 1.5.13] 

OPTIONAL SUBPACKAGES 
      sample_data: yes [installing] 
       toolkits: yes [installing] 
       tests: yes [using nose version 1.3.0] 

OPTIONAL BACKEND EXTENSIONS 
       macosx: no [Mac OS-X only] 
       qt4agg: no [PyQt4 not found] 
       gtk3agg: yes [version 3.4.6] 
      gtk3cairo: yes [version 3.4.6] 
       gtkagg: yes [Gtk: 2.24.18 pygtk: 2.24.0] 
       tkagg: no [The C/C++ header for Tk (tk.h) could not be 
         found. You may need to install the development 
         package.] 
       wxagg: no [requires wxPython] 
        gtk: yes [Gtk: 2.24.18 pygtk: 2.24.0] 
        agg: yes [installing] 
       cairo: yes [version 1.8.10] 
      windowing: no [Microsoft Windows only] 

OPTIONAL LATEX DEPENDENCIES 
       dvipng: yes [version 1.14] 
      ghostscript: yes [version 9.06] 
       latex: no 
       pdftops: yes [version 0.20.2] 

Большое спасибо заранее!

ответ

2

Вы столкнулись с проблемами обзора. Когда объект кнопки выходит из области видимости, все обратные вызовы на нем очищаются. Чтобы ваши кнопки работали, вам необходимо сохранить ссылку на объект Button.

def draw_button2(): 
    pylab.figure() 
    a = pylab.axes([0.1, 0.1, 0.8, 0.8]) 
    b = Button(a, 'Button 2') 
    b.on_clicked(draw_button1) 
    pylab.show() 
    return b 

b = draw_button2() 

Это сделает вашу кнопку первую работу, но, чтобы получить вторую работу, вы будете нуждаться в какой-то глобальной структуры. Elegent способ сделать это, чтобы обернуть все эти функции в классе, чтобы следить за ними, то Hacky способ сделать это, чтобы добавить атрибуты к объектам фигуры:

import pylab 
from matplotlib.widgets import Button 


def draw_button1(event): 
    fig = pylab.figure() 
    a = pylab.axes([0.1, 0.1, 0.8, 0.8]) 
    b = Button(a, 'Button 1') 

    def say_something(event): 
     print "This works." 

    b.on_clicked(say_something) 
    fig._my_btn = b 
    pylab.show() 

def draw_button2(): 
    fig = pylab.figure() 
    a = pylab.axes([0.1, 0.1, 0.1, 0.1]) 
    b = Button(a, 'Button 2') 
    b.on_clicked(draw_button1) 
    pylab.show() 
    fig._my_btn = b 


draw_button2() 
+0

Спасибо! Это действительно исправлено! Так что действительно, это должно было не сработать на моих других системах ... – Diana

+0

И еще раз, когда я думал, что обнаружил ошибку в какой-то библиотеке, это оказалось по вине. :) – Diana

+0

@Diana Вы прочитали пример кнопки? (http://matplotlib.org/examples/widgets/buttons.html). Если это так, я отправлю PR, чтобы было ясно, что это важно. Что касается того, почему он работал в любом месте, произошли некоторые изменения в том, как обратный звонок работал некоторое время назад (изменено -> weakrefs), но я не уверен, где это закончилось в выпущенных версиях. – tacaswell