【问题标题】:Matplotlib reuse figure created by another scriptMatplotlib 重用另一个脚本创建的图形
【发布时间】:2017-12-21 18:38:19
【问题描述】:

我在 MacOS 上使用带有 Sulime Text 的 Matplotlib。 我使用Python 3.5Matplotlib 2.0

当我处理一个图形时,我通常有一个绘制数据的脚本,并将图形保存在一个带有plt.savefig() 的 .pdf 文件中。然后我使用Skim(pdf 查看器)以便在每次修改和运行脚本时刷新文件。这使我可以将我的工作布局设置为干净:有一个脚本窗口,一个窗口用于自动刷新的图形。

我想保持相同的布局,但使用 Matplotlib 图形(因为它们是交互式的)。我正在寻找一种使用plt.show() 的方法,但总是在同一个图中,这是我第一次运行脚本时创建的。

例如:

1。第一次运行

import matplotlib.pyplot as plt
import numpy as np 

fig, ax = plt.figure()    

noise = np.random.rand(1, 100)
ax(noise)
plt.show()

2。以下运行

import matplotlib.pyplot as plt
import numpy as np 

# This is the super command I am looking for
fig = plt.get_previous_run_figure()
ax = fig.axes

noise = np.random.rand(1, 100)
ax.plot(noise)
plt.draw()

当然,在这种情况下,我必须与主脚本分开执行首次运行脚本。有谁知道有没有可能?

【问题讨论】:

  • 我理解正确吗 fig = plt.figure(0); fig.clf() 对你不起作用,因为你想重用另一个 python 实例的窗口?
  • 您正在寻找的“超级命令”在 python 中称为酸洗。请参阅我建议的重复问题作为示例
  • @tom 酸洗会在运行之间保持窗口打开吗?我认为这就是 OP 要求的......
  • @kazemakase 啊,不,可能不是。我可能误解了这个问题。如果你关闭你的 python 会话,我怀疑你是否可以保持一个窗口打开,但是酸洗至少应该允许你重新打开前一个会话中的一个图。

标签: python matplotlib


【解决方案1】:

您希望多个连续的 python 会话共享一个通用的 Matplotlib 窗口。我认为无法从不同的进程共享此窗口,尤其是当原始所有者可能随时终止时。

但是,您可以执行与当前工作流程类似的操作,其中您有一个外部 pdf 查看器来查看您从多个 python 实例更新的输出文件。

有关如何腌制 matplotlib 图,请参阅此问题/答案: Store and reload matplotlib.pyplot object

在每个脚本中,将您的 matplotlib 图形输出为腌制对象,而不是调用 plt.show():

import matplotlib.pyplot as plt
import numpy as np
import pickle

ax = plt.subplot(111)
x = np.linspace(0, 10)
y = np.exp(x)
plt.plot(x, y)
pickle.dump(ax, file('myplot.pickle', 'w'))

然后,启动一个专门的 python 会话来加载这个腌制对象并调用 plt.show()。让这个脚本循环运行,检查磁盘上腌制文件的更新,并在必要时重新加载:

import matplotlib.pyplot as plt
import pickle

while True:
   ax = pickle.load(file('myplot.pickle'))
   plt.show()

另类

我通常有一个运行不同脚本的 Ipython 会话,而不是单独的 python 会话。通过选择相同的图形窗口,我最终得到了与您描述的大部分相似的设置,其中相同的图形窗口全天重复使用。

import matplotlib.pyplot as plt

fig = plt.figure(0)
fig.clf()

plt.show()

【讨论】:

  • 感谢您的回答。我试过你的代码,但plt.show() 无论如何都会打开一个新图来显示循环中新加载的腌制轴(即使你假设plt.ion() 被激活以防止plt.show() 阻塞循环)。我还尝试先创建一个图形并在循环之前用plt.show(block=False) 显示它,它仍然给出相同的结果。
  • 如果新窗口与旧窗口在同一个位置打开,您会这样做吗?
  • 我从 MacOSX 后端迁移到了 TkAgg,它让您的解决方案工作得很好!
  • 另一个快速的解决方案是使用 WebAgg,并设置默认端口(例如:8888)。每次脚本停止并重新启动时,端口都会更新为新图形,并且网络浏览器会自动刷新。
【解决方案2】:

原则上,在两个不同脚本之间建立连接可以使用系统范围的剪贴板来完成。 (据我所知,Windows 和 macOS 中的剪贴板是系统范围的。)

所以想法可以是使用 tk 或 pyqt 建立一个应用程序,并实现一个通用的 FigureCanvas。这个应用程序可以有一个事件监听器来监听剪贴板的变化。

然后,另一个主工作流脚本将调用一些函数,将当前图形包装到一个 pickle 对象中并将其发送到剪贴板,从那里它被 GUI 应用程序捕获,被取消腌制并显示在画布中。

这听起来有点工作,但应该满足问题中非常严格的要求。

【讨论】:

    【解决方案3】:

    Daan 的替代方案对我有用。这里还有一些代码。我在 Tkinter 交互式 GUI 中使用它来重用/更新 matplotlib 图形窗口:

    fig1 = None
    if fig1:
        #if exists, clear figure 1
        plt.figure(1).clf() 
        plt.suptitle("New Fig Title", fontsize=18, fontweight='bold')
        #reuse window of figure 1 for new figure
        fig1 = plt.scatter(points.T[0], points.T[1], color='red', **plot_kwds)      
    else:
        #initialize
        fig1 = plt.figure(num=1,figsize=(7, int(7*imgRatio)), dpi=80)
        plt.tick_params(axis='both', which='major', labelsize=14)
        plt.tick_params(axis='both', which='minor', labelsize=14)           
        plt.suptitle("Title", fontsize=18, fontweight='bold')
        fig1 = plt.scatter(points.T[0], points.T[1], color='red', **plot_kwds)
    

    该图正在重用(交互式)plt 窗口。为此,我必须在 matplotlibrc 文件中设置 interactive : True(请参阅我的评论 here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-11
      • 2016-06-28
      • 2013-07-08
      • 1970-01-01
      • 2017-01-26
      • 1970-01-01
      相关资源
      最近更新 更多