在Jupyter Notebook中,当我在另一个单元格中创建的3d轴对象上调用.scatter
时,它似乎不会在上面散布任何东西。
具体地,考虑以下import语句,
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
字符串
假设下面的代码块在Jupyter Notebook的一个单元中,
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection = "3d")
ax.scatter([0], [0], [0], s = 5)
型
然后不用问,一个图像出现了,我可以看到一个点。
然而,如果
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection = "3d")
型
和/或
ax.scatter([0], [0], [0], s = 5)
型
在不同的单元格中,那么看起来第二个返回<mpl_toolkits.mplot3d.art3d.Path3DCollection at 0xblablabla>
,并且没有图像出现,即使我稍后调用plt.show()
。如果我稍后调用plt.savefig("test.png")
,则保存一个空图像(没有绘制空轴框)。
它不理解这种行为。我希望能够连续添加的东西轴对象,可能在不同的细胞。
1条答案
按热度按时间ioekq8ef1#
在运行单元格结束时,现代Jupyter关闭绘图对象,并显示绘图对象,如果它检测到一个正在单元格中构建的对象,并且在遇到单元格的末尾时存在。
这就解释了为什么在你的第二个代码块之后,你的这句话“然后不用问,一个图像出现了,我可以看到它上面的一个点。”Jupyter检测到正在构建的maptlotlib axes对象并显示它。
接下来要解决这两个问题:
因此,如果你想像你说的那样开始构建一个图,在前面的单元格中使用但不完成它,就像你在下面的代码中建议的那样:
字符串
虽然您还没有在其中添加任何数据,但您已经创建了一个绘图轴对象,因此如果这是一个先前已经完成导入的单元格,则Jupyter会看到绘图轴并显示它们(如上所述)。
最简单的处理方法是在到达单元格末尾之前告诉Matplotlib/Jupyter你想关闭plot对象。这样就不存在在该单元格中构建的绘图对象,并且该单元格的输出不显示任何内容。
因此,将所有这些与导入放在一起,您可以在单个单元格中运行一些用于绘图的初始代码,但通过将以下内容作为第一个单元格来显示没有轴:
型
(我在an answer to 'How can I display image data in Jupyter notebook AND control its position? '中以类似的方式使用
plt.close()
。Here使用它来允许您将绘图作为函数。)现在你可以把下一个单元格添加到你的axes对象中,并告诉Jupyter通过调用它作为下一个单元格中的最后一个对象来显示它。(
ax.figure
或fig.figure
都适用于您的示例。)因此第二个单元格将是:型
请注意,第二个单元中单独的
ax.scatter([0], [0], [0], s = 5)
不起作用。你会看到类似于你在文章中报告的内容,因为返回的是对scatter的调用,比如<mpl_toolkits.mplot3d.art3d.Path3DCollection at 0x7f9216de2860>
,并返回和显示在notebook中计算的最后一个表达式的结果。相反,要将图显示为第二个单元格的输出,您需要调用关联的图形。由于您没有在那里构建新的轴,因此Jupyter不会自动显示相关的轴。(参见here和here了解更多信息。稍后将绘图保存为图像。
你提到你也在挣扎:
如果稍后调用plt.savefig(“test.png”),则会保存一个空图像(未绘制空轴框)。
你只是没有提到正确的事情。此时,
plt.
方法默认作用的对象不再存在。为了更好地解释这一点,让我们先把情况简单化。想象一下,你把文章中的前两个代码块作为一个单元来运行。如上所述,与
plt.()
方法所作用的单元格相关联的对象在该单元格运行后被关闭并且不存在。但是,您可以从代码中引用赋值对象,因为幸运的是,您在创建它们时通过将它们赋值给变量来放置句柄。所以你可以在事后通过引用它并添加savefig()
方法来保存关联的plot figure,如下所示:型
只要您没有创建新的
fig
对象,或者没有清除名称空间,或者没有重新启动内核,那么这将使许多单元格远离早期的单元格。