【问题标题】:Use Matplotlib Plot and Widgets in function and return user input在函数中使用 Matplotlib Plot 和 Widgets 并返回用户输入
【发布时间】:2018-07-27 09:38:29
【问题描述】:

我的问题如下:

我创建了一个 Matplotlib 图形,包括一些小部件滑块和一个用于关闭图形的按钮。这行得通。我该怎么做才能在返回例如的函数中使用此代码单击“关闭图”按钮后幻灯片的值?

这里是代码(im3d是一个3d图像numpy数组):

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button

class IndexTracker(object):
    def __init__(self, ax, data3d, title):
        self.ax = ax
        ax.set_title(title)

        self.data3d = data3d
        rows, cols, self.slices = data3d.shape
        self.ind = self.slices//2

        self.im = ax.imshow(self.data3d[:, :, self.ind])
        self.update()

    def update(self):
        self.im.set_data(self.data3d[:, :, self.ind])
        ax.set_ylabel('slice %s' % self.ind)
        self.im.axes.figure.canvas.draw()
#
fig = plt.figure(figsize=(18, 8), dpi=80, facecolor='w', edgecolor='b')
ax  = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)

tracker1 = IndexTracker(ax, im3d, 'Select First Image')
tracker2 = IndexTracker(ax2, im3d, 'Select Last Image')

def slider_changed(value, tracker):
    numb = int(round(value))    
    tracker.ind = numb    
    tracker.update()

max0 = im3d.shape[2] -1

ax_start  = fig.add_axes([0.1, 0.85, 0.35, 0.03])
sl_start = Slider(ax_start, 'START', 0, max0, valinit=0, valfmt="%i")

ax_end  = fig.add_axes([0.6, 0.85, 0.35, 0.03])
sl_end = Slider(ax_end, 'END', 0, max0, valinit=0, valfmt="%i")

def sl_start_changed(val):
    slider_changed(sl_start.val,tracker1)

def sl_end_changed(val):
    slider_changed(sl_end.val,tracker2)

sl_start.on_changed(sl_start_changed)
sl_end.on_changed(sl_end_changed)

class Index(object):

    def close_figure(self, event):
        plt.close(fig)    

callback = Index()
ax_button = fig.add_axes([0.7, 0.06, 0.15, 0.075])
button = Button(ax_button, 'DONE')
button.on_clicked(callback.close_figure)
fig.canvas.manager.window.raise_()

plt.plot()

我的第一个想法是在 plt.plot() 之后运行一个 while 循环,如下所示:

while not_done:
   time.sleep(0.5)

并在函数 close_figure 中将 not_done 更改为 False。但在这种情况下,情节不会显示。

【问题讨论】:

  • 请提供您的源代码,以便我们可以参考。

标签: python matplotlib matplotlib-widget


【解决方案1】:

图形关闭后滑块仍然可用。因此,您可以在关闭图形后访问其val 属性

fig, ax = plt.subplots()

slider = Slider(...)

# .. callbacks

plt.show() # you may use plt.show(block=True) when this is run in interactive mode

print(slider.val)

澄清后编辑:

您正在运行 spyder 并在其中使用 IPython 控制台。这有几个含义。

  • 你需要关闭交互模式,plt.ioff()
  • 您需要停用对 matplotlib 的“支持”

那么下面的代码运行正常,只打印图关闭后的值。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button

plt.ioff()

im3d = np.random.rand(20,20,10)


class IndexTracker(object):
    def __init__(self, ax, data3d, title):
        self.ax = ax
        ax.set_title(title)

        self.data3d = data3d
        rows, cols, self.slices = data3d.shape
        self.ind = self.slices//2

        self.im = ax.imshow(self.data3d[:, :, self.ind])
        self.update()

    def update(self):
        self.im.set_data(self.data3d[:, :, self.ind])
        ax.set_ylabel('slice %s' % self.ind)
        self.im.axes.figure.canvas.draw()
#
fig = plt.figure(figsize=(18, 8), dpi=80, facecolor='w', edgecolor='b')
ax  = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)

tracker1 = IndexTracker(ax, im3d, 'Select First Image')
tracker2 = IndexTracker(ax2, im3d, 'Select Last Image')

def slider_changed(value, tracker):
    numb = int(round(value))    
    tracker.ind = numb    
    tracker.update()

max0 = im3d.shape[2] -1

ax_start  = fig.add_axes([0.1, 0.85, 0.35, 0.03])
sl_start = Slider(ax_start, 'START', 0, max0, valinit=0, valfmt="%i")

ax_end  = fig.add_axes([0.6, 0.85, 0.35, 0.03])
sl_end = Slider(ax_end, 'END', 0, max0, valinit=0, valfmt="%i")

def sl_start_changed(val):
    slider_changed(sl_start.val,tracker1)

def sl_end_changed(val):
    slider_changed(sl_end.val,tracker2)

sl_start.on_changed(sl_start_changed)
sl_end.on_changed(sl_end_changed)

class Index(object):

    def close_figure(self, event):
        plt.close(fig)    

callback = Index()
ax_button = fig.add_axes([0.7, 0.06, 0.15, 0.075])
button = Button(ax_button, 'DONE')
button.on_clicked(callback.close_figure)
fig.canvas.manager.window.raise_()

plt.show()

print(sl_start.val, sl_end.val)

或者,您可以只在外部命令行中运行完整的代码,而不需要plt.ioff()

【讨论】:

  • 谢谢,我知道了。但是如何让程序在 plt.show() 之后停止,让用户与图形交互并仅在图形关闭后继续打印(slider.val)?
  • 关闭图后才打印该值。
  • 不在我的机器上。如果我把上面的代码包装在 def my_function(im3d) 中:....... return sl_start.val,sl_end.val 函数在我关闭图之前返回。
  • 如果你把plt.ioff()放在代码的开头会发生什么?一般来说,我们越了解您在何处以及如何运行代码、使用哪些版本等,就越有可能找到适合您的解决方案。
  • 使用 plt.ioff() 绘图根本不显示。我使用 python 3.6.3 和 IPython 6.1.0。
猜你喜欢
  • 2020-08-06
  • 2014-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-18
  • 2012-02-27
  • 1970-01-01
相关资源
最近更新 更多