Интерактивный сюжет matplotlib с двумя слайдерами
Я использовал matplotlib для создания некоторого графика, который зависит от 8 переменных. Я хотел бы изучить, как меняется сюжет, когда я меняю некоторые из них. Я создал сценарий, который вызывает matplotlib и генерирует различные снимки, которые позже я конвертирую в фильм, это не плохо, но немного неуклюже.
Интересно, смогу ли я как-то взаимодействовать с регенерацией графика, используя клавиши клавиатуры, чтобы увеличить / уменьшить значения некоторых переменных и сразу увидеть, как меняется график.
Каков наилучший подход для этого?
Также, можете ли вы указать мне интересные ссылки или ссылку с примером сюжета с двумя слайдерами?
7 ответов
В дополнение к тому, что упоминается @triplepoint, взгляните на виджет слайдера.
На странице примеров matplotlib есть пример. Это графическая ползунок, а не привязки к клавиатуре, но она отлично работает для того, что вы хотите сделать.
Также обратите внимание, что для обеспечения того, чтобы ползунки и кнопки оставались отзывчивыми и не собирались мусором, ссылки на объекты (amp_slider
, freq_slider
и т. д.) должны поддерживаться самостоятельно.
(Я делаю это сообщество вики, так как я просто копирую из примера. Этот конкретный пример учит плохих привычек (например, from pylab import *
), но это все понятно. Пример был исправлен, чтобы избежать использования pylab
.)
from numpy import pi, sin
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
def signal(amp, freq):
return amp * sin(2 * pi * freq * t)
axis_color = 'lightgoldenrodyellow'
fig = plt.figure()
ax = fig.add_subplot(111)
# Adjust the subplots region to leave some space for the sliders and buttons
fig.subplots_adjust(left=0.25, bottom=0.25)
t = np.arange(0.0, 1.0, 0.001)
amp_0 = 5
freq_0 = 3
# Draw the initial plot
# The 'line' variable is used for modifying the line later
[line] = ax.plot(t, signal(amp_0, freq_0), linewidth=2, color='red')
ax.set_xlim([0, 1])
ax.set_ylim([-10, 10])
# Add two sliders for tweaking the parameters
# Define an axes area and draw a slider in it
amp_slider_ax = fig.add_axes([0.25, 0.15, 0.65, 0.03], axisbg=axis_color)
amp_slider = Slider(amp_slider_ax, 'Amp', 0.1, 10.0, valinit=amp_0)
# Draw another slider
freq_slider_ax = fig.add_axes([0.25, 0.1, 0.65, 0.03], axisbg=axis_color)
freq_slider = Slider(freq_slider_ax, 'Freq', 0.1, 30.0, valinit=freq_0)
# Define an action for modifying the line when any slider's value changes
def sliders_on_changed(val):
line.set_ydata(signal(amp_slider.val, freq_slider.val))
fig.canvas.draw_idle()
amp_slider.on_changed(sliders_on_changed)
freq_slider.on_changed(sliders_on_changed)
# Add a button for resetting the parameters
reset_button_ax = fig.add_axes([0.8, 0.025, 0.1, 0.04])
reset_button = Button(reset_button_ax, 'Reset', color=axis_color, hovercolor='0.975')
def reset_button_on_clicked(mouse_event):
freq_slider.reset()
amp_slider.reset()
reset_button.on_clicked(reset_button_on_clicked)
# Add a set of radio buttons for changing color
color_radios_ax = fig.add_axes([0.025, 0.5, 0.15, 0.15], axisbg=axis_color)
color_radios = RadioButtons(color_radios_ax, ('red', 'blue', 'green'), active=0)
def color_radios_on_clicked(label):
line.set_color(label)
fig.canvas.draw_idle()
color_radios.on_clicked(color_radios_on_clicked)
plt.show()
Я последовал совету проверить виджеты в jupyter, и они очень хорошо работают. Пример скрипта загружен в GitHub https://github.com/LeonidBystrykh/course-python-for-beginners/blob/master/Interactive_dots.ipynb
from __future__ import print_function
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
import matplotlib.pyplot as plt, random
def series(dots, colr):
a,b=[],[]
for i in range(dots):
a.append(random.randint(1,100))
b.append(random.randint(1,100))
plt.scatter(a,b, c=colr)
return()
interact(series, dots=(1,100,1), colr=["red","orange","brown"]);
Копия изображения ниже
Matplotlib обладает довольно приятным графическим интерфейсом. Есть несколько примеров документации в архиве исходного кода matplotlib, в /examples/user_interfaces и matplotlib>/examples/event_handling. Конкретно по обработке ключей это: http://matplotlib.sourceforge.net/examples/event_handling/keypress_demo.html
Я сделал нечто похожее на то, к чему вы стремитесь:
import numpy as np
import pylab
class plotter:
def __init__(self, initial_values):
self.values
self.fig = pylab.figure()
pylab.gray()
self.ax = self.fig.add_subplot(111)
self.draw()
self.fig.canvas.mpl_connect('key_press_event',self.key)
def draw(self):
im = your_function(self.values)
pylab.show()
self.ax.imshow(im)
def key(self, event):
if event.key=='right':
self.values = modify()
elif event.key == 'left':
self.values = modify()
self.draw()
self.fig.canvas.draw()
Я использовал это для переключения между отображением различных изображений в стеке на нажатиях клавиш, но вы должны иметь возможность вводить логику для изменения ваших значений с помощью ввода с клавиатуры.
Если вы хотите сделать что-то вроде ввода значений пользователем, я думаю, что в примерах есть варианты для диалоговых окон, но если вы просто хотите увеличить / уменьшить количество переменных, просто определите пары клавиатур для них таким образом, что может работать хорошо
Для ноутбуков ipython или jupyter вы можете использовать ipywidgets:
from ipywidgets import *
def update(w=0,h=0):
print(h+w)
interact(update, w= widgets.IntSlider(value=1, min=0, max=7, step=1) ,
h= widgets.IntSlider(value=1, min=0, max=7, step=1) );
См. Документацию здесь: https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html
Использование waitforbuttonpress(timeout=0.001)
тогда сюжет увидит твои тики мыши.
Вы также можете рассмотреть возможность использования пакета Quibbler .
Quibbler автоматически делает вашу обычную графику matplotlib интерактивной. Нет необходимости писать функции обратного вызова.
См. несколько примеров в документации Quibbler . В частности, см. конкретный пример графика с двумя ползунками .
from pyquibbler import iquib, initialize_quibbler
initialize_quibbler()
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import numpy as np
%matplotlib tk
# Figure setup:
fig = plt.figure(figsize=(4, 6))
axs = fig.add_axes([0, 0.36, 1, 0.64])
axs.axis('square')
axs.axis((-10, 10, -10, 10))
axs.axis('off')
axs_slider1 = fig.add_axes([0.3, 0.16, 0.55, 0.03])
axs_slider2 = fig.add_axes([0.3, 0.06, 0.55, 0.03])
# Defining quib input variables:
nPoints = iquib(120)
nCycles = iquib(30)
# Define downstream function quib calculations based on the quib inputs:
phi = np.linspace(0, 2 * np.pi * nCycles, nPoints)
r = np.linspace(0, 10, nPoints)
# Plot the data:
axs.plot(r * np.cos(phi), r * np.sin(phi), 'r-')
# Create quib-linked slider widgets:
Slider(ax=axs_slider1, label='nCycles', valmin=0, valmax=200, valstep=1, valinit=nCycles)
Slider(ax=axs_slider2, label='nPoints', valmin=0, valmax=200, valstep=1, valinit=nPoints)
Для прозрачности: я один из разработчиков Quibbler.
Я не думаю, что просто построение графиков с использованием plt.plot
позволит вам сделать это. Вам нужно будет сделать собственный скрипт / приложение с графическим интерфейсом, вставив в него Matplotlib. В настоящее время Matplotlib поддерживает все основные инструменты GUI - PyGTK+, PyQt4 и wxPython.
Я использую wxPython, и встраивать в него matplotlib довольно легко. Аналогичное должно быть в случае с другими инструментами GUI. Вы можете получить всю необходимую для этого информацию в книге -
Это доступно на Амазонке здесь.