在matplotlib中保存show()之后的无花果内容?

时间:2017-12-02 07:35:39

标签: python python-3.x matplotlib

我正在创建一些数据的小提琴图,然后我将一个散点图与单个数据点(例如红点)渲染到三个子图。

enter image description here

由于小提琴图的生成相对耗时,我只生成一次小提琴图,然后为一个数据行添加散点图,写入结果文件,从轴中删除散点图并添加散点图下一行。

一切正常,但我想在保存之前添加选项,以显示()每个图。

如果我使用plt.show(),图形会正确显示,但之后图像似乎被清除,在下一次迭代中,我没有小提琴图。

有没有办法在plt.show()之后保留图的内容?

简而言之,我的代码是

fig = generate_plot(ws, show=False) #returns the fig instance of the violin plot

#if I do plt.show() here (or in "generate_plot()"), the violin plots are gone.

ax1, ax3, ax2 = fig.get_axes()
scatter1 = ax1.scatter(...) #draw scatter plot for first axes
[...] #same vor every axis
plt.savefig(...)
scatter1.remove()

3 个答案:

答案 0 :(得分:2)

我在想可能的选择是使用事件循环来推进这些图。以下将定义更新功能,该功能仅更改散点,绘制图像并保存。我们可以通过一个带有key_press回调的类来管理它 - 这样当你点击 Space 时,会显示下一个图像;在最后一张图像上按 Space 时,图表将被关闭。

import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
import numpy as np

class NextPlotter(object):
    def __init__(self, fig, func, n):
        self.__dict__.update(locals())
        self.i = 0
        self.cid = self.fig.canvas.mpl_connect("key_press_event", self.adv)

    def adv(self, evt):
        if evt.key == " " and self.i < self.n:
            self.func(self.i)
            self.i+=1
        elif self.i >= self.n:
            plt.close("all")

#Start of code:
# Create data
pos = [1, 2, 4, 5, 7, 8]
data = [np.random.normal(0, std, size=100) for std in pos]
data2 = [np.random.rayleigh(std, size=100) for std in pos]
scatterdata = np.random.normal(0, 5, size=(10,len(pos)))

#Create plot
fig, axes = plt.subplots(ncols=2)

axes[0].violinplot(data, pos, points=40, widths=0.9,
                      showmeans=True, showextrema=True, showmedians=True)
axes[1].violinplot(data2, pos, points=40, widths=0.9,
                      showmeans=True, showextrema=True, showmedians=True)

scatter = axes[0].scatter(pos, scatterdata[0,:], c="crimson", s=60)
scatter2 = axes[1].scatter(pos, scatterdata[1,:], c="crimson", s=60)  

# define updating function
def update(i):
    scatter.set_offsets(np.c_[pos,scatterdata[2*i,:]])
    scatter2.set_offsets(np.c_[pos,scatterdata[2*i+1,:]])
    fig.canvas.draw()
    plt.savefig("plot{i}.png".format(i=i))

# instantiate NextPlotter; press <space> to advance to the next image        
c = NextPlotter(fig, update, len(scatterdata)//2)

plt.show()

答案 1 :(得分:0)

解决方法可能是不删除散点图。

为什么不保留散点图轴,只更新该组轴的数据?

更新散点图数据后,您很可能需要plt.draw()才能强制进行新的渲染。

答案 2 :(得分:0)

我找到了一种以交互方式绘制数字的方法hereplt.ion()阻止input()进程似乎很重要。

import matplotlib.pyplot as plt
plt.ion()

fig = plt.figure()
ax = plt.subplot(1,1,1)
ax.set_xlim([-1, 5])
ax.set_ylim([-1, 5])
ax.grid('on')

for i in range(5):
    lineObject = ax.plot(i,i,'ro')
    fig.savefig('%02d.png'%i)
    # plt.draw() # not necessary?
    input()
    lineObject[0].remove()

我还尝试使用time.sleep(1)阻止该过程,但它根本不起作用。