python - 如何在 google colab 中创建实时 matplotlib.pyplot 图?

标签 python matplotlib google-colaboratory openai-gym stable-baselines

遗憾的是,无法使用 %matplotlib notebook 在 google colab notebook 中创建实时绘图,就像在我 PC 上的离线 jupyter notebook 中一样。

我发现了两个类似的问题,回答了如何为 plotly plots ( link_1 , link_2 ) 实现这一点。 但是我无法设法使其适应 matplotlib 或者根本不知道这是否可能。

我在这里遵循本教程中的代码:GitHub link . 特别是我想运行这段代码,它创建一个回调,绘制训练步骤中每一步的奖励:

import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook


class PlottingCallback(BaseCallback):
    """
    Callback for plotting the performance in realtime.

    :param verbose: (int)
    """
    def __init__(self, verbose=1):
        super(PlottingCallback, self).__init__(verbose)
        self._plot = None

    def _on_step(self) -> bool:
        # get the monitor's data
        x, y = ts2xy(load_results(log_dir), 'timesteps')
      if self._plot is None: # make the plot
          plt.ion()
          fig = plt.figure(figsize=(6,3))
          ax = fig.add_subplot(111)
          line, = ax.plot(x, y)
          self._plot = (line, ax, fig)
          plt.show()
      else: # update and rescale the plot
          self._plot[0].set_data(x, y)
          self._plot[-2].relim()
          self._plot[-2].set_xlim([self.locals["total_timesteps"] * -0.02, 
                                   self.locals["total_timesteps"] * 1.02])
          self._plot[-2].autoscale_view(True,True,True)
          self._plot[-1].canvas.draw()

# Create log dir
log_dir = "/tmp/gym/"
os.makedirs(log_dir, exist_ok=True)

# Create and wrap the environment
env = make_vec_env('MountainCarContinuous-v0', n_envs=1, monitor_dir=log_dir)

plotting_callback = PlottingCallback()

model = PPO2('MlpPolicy', env, verbose=0)
model.learn(20000, callback=plotting_callback)

最佳答案

您可以使用的一种 hack,是使用与在 jupyter notbook 上使用的代码相同的代码,创建一个按钮,然后使用 JavaScript 来单击该按钮,欺骗前端请求更新,以便它不断更新值(value)观。

这是一个使用ipywidgets的例子。

from IPython.display import display
import ipywidgets
progress = ipywidgets.FloatProgress(value=0.0, min=0.0, max=1.0)
import asyncio
async def work(progress):
    total = 100
    for i in range(total):
        await asyncio.sleep(0.2)
        progress.value = float(i+1)/total
display(progress)
asyncio.get_event_loop().create_task(work(progress))
button = ipywidgets.Button(description="This button does nothing... except send a\
 socket request to google servers to receive updated information since the \
 frontend wants to change..")

display(button,ipywidgets.HTML(
    value="""<script>
      var b=setInterval(a=>{
    //Hopefully this is the first button
    document.querySelector('#output-body button').click()},
    1000);
    setTimeout(c=>clearInterval(b),1000*60*1);
    //Stops clicking the button after 1 minute
    </script>"""
))

专门处理 matplotlib 有点复杂,我想我可以简单地在 asyncio 函数上调用 matplotlib plot,但它确实延迟了更新,因为它似乎在没有人看到绘图的背景中进行了不必要的渲染。所以另一个解决方法是更新按钮更新代码的情节。 此代码也受到 Add points to matlibplot scatter plot live 的启发。和 Matplotlib graphic image to base64 原因是没有必要为每个地 block 创建一个地 block 图,您可以只修改已有的地 block 。这当然意味着更多的代码。

from IPython.display import display
import ipywidgets
import matplotlib.pyplot as plt
import numpy as np
import io
import base64
def pltToImg(plt):
 s = io.BytesIO()
 plt.savefig(s, format='png', bbox_inches="tight")
 s = base64.b64encode(s.getvalue()).decode("utf-8").replace("\n", "")
 #plt.close()
 return '<img align="left" src="data:image/png;base64,%s">' % s
progress = ipywidgets.FloatProgress(value=0.0, min=0.0, max=1.0)
import asyncio
async def work(progress):
    total = 100
    for i in range(total):
        await asyncio.sleep(0.5)
        progress.value = float(i+1)/total
display(progress)
asyncio.get_event_loop().create_task(work(progress))
button = ipywidgets.Button(description="Update =D")
a=ipywidgets.HTML(
    value="image here"
)
output = ipywidgets.Output()
plt.ion()
fig, ax = plt.subplots()
plot = ax.scatter([], [])
point = np.random.normal(0, 1, 2)
array = plot.get_offsets()
array = np.append(array, [point], axis=0)
plot.set_offsets(array)
plt.close()
ii=0
def on_button_clicked(b):
       global ii
       ii+=1
       point=np.r_[ii,np.random.normal(0, 1, 1)]
       array = plot.get_offsets()
       array = np.append(array, [point], axis=0)
       plot.set_offsets(array)
       ax.set_xlim(array[:, 0].min() - 0.5, array[:,0].max() + 0.5)
       ax.set_ylim(array[:, 1].min() - 0.5, array[:, 1].max() + 0.5)
       a.value=(pltToImg(fig))
       a.value+=str(progress.value)
       a.value+=" </br>"
       a.value+=str(ii)

button.on_click(on_button_clicked)
display(output,button,ipywidgets.HTML(
    value="""<script>
      var b=setInterval(a=>{
    //Hopefully this is the first button
    document.querySelector('#output-body button')?.click()},
    500);
    setTimeout(c=>clearInterval(b),1000*60*1);
    //Stops clicking the button after 1 minute
    </script>"""
),a)

关于python - 如何在 google colab 中创建实时 matplotlib.pyplot 图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61530194/

相关文章:

python - 第一次运行后出现 Scrapy 'twisted.internet.error.ReactorNotRestartable' 错误

python - 使用 Python 从文本文件中提取数字数据

python - 将内容为utf-8字符串的unicode转成str

python - Python 中图像处理时出现 UnicodeDecodeError

python - 如何从一个 Google colab notebook 导入到另一个?

python - 在不阻塞其他任务的情况下限制 celery 任务的速率

python - 整个子图的颜色图

python - 在 python 3.6 中安装 matplotlib 的问题

python - 如何在 Google Colab 上 plotly 导入

python - 从给定 URL 下载文件并使用 Google Colab 保存文件时出现问题