在Jupyter Notebook中使用VSCode取消裁剪3D图表。

huangapple go评论75阅读模式
英文:

Uncrop 3d plots in jupyter notebook with VSCode

问题

我正在使用VSCode中的Jupyter笔记本制作一些3D散点图,但它们显示不正确。

我去了Matlab的文档,并下载了3D散点图的Jupyter笔记本,然后在VSCode中尝试运行它,结果是一样的,Z轴标签被截断了。

我看到了很多关于使用Matplotlib魔术功能使图表交互的问题,其中一些解决方案(%matplotlib qt)确实有效(图像不再被裁剪,但在单独的窗口中创建)。我希望图表是内联的,因为我要制作很多这样的图表,每次创建40个窗口都很麻烦。

我尝试了魔术命令%matplotlib widget%matplotlib notebook,如这里建议的,以及%matplotlib ipympl这里建议的,但当我使用这些命令时,图表不再显示,只有在我切换到%matplotlib inline后才显示,此时显示之前创建的任何图表(都被裁剪)。

我还在Jupyter Lab中检查了代码,没有这个问题,图像显示完全正常,因此似乎是在VSCode中的Jupyter笔记本中出现的问题。

我并不试图改变Z轴的位置,它在哪里都没问题,我只是想让图像变大,以便Z轴标签可以正确显示。

以防万一,我尝试了Trenton McKinney的评论,执行ax.zaxis._axinfo['juggled'] = (1, 2, 2)将Z标签更改到图像的另一侧,但它仍然被截断,只是在图像的另一侧。

所以这不是Z轴和标签所在位置的问题。

PS:按照要求,我将示例代码放在这里以供使用。

import matplotlib.pyplot as plt
import numpy as np

# 为了可重复性固定随机状态
np.random.seed(19680801)

def randrange(n, vmin, vmax):
    """
    辅助函数,用于生成形状为(n,)的随机数数组,每个数字分布在Uniform(vmin, vmax)之间。
    """
    return (vmax - vmin)*np.random.rand(n) + vmin

fig = plt.figure()
ax = fig.add_subplot(projection='3d')

n = 100

# 对于每组样式和范围设置,将在定义为x在[23, 32]、y在[0, 100]、z在[zlow, zhigh]的框中绘制n个随机点。
for m, zlow, zhigh in [('o', -50, -25), ('^', -30, -5)]:
    xs = randrange(n, 23, 32)
    ys = randrange(n, 0, 100)
    zs = randrange(n, zlow, zhigh)
    ax.scatter(xs, ys, zs, marker=m)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

更新: 我在GitHub的VSCode存储库中发布了一个问题,链接在这里

更新的最新消息: 发现问题是Matplotlib/Jupyter的问题,因此我在Matplotlib存储库中打开了一个新问题,链接在这里

英文:

I'm doing some 3d scatter plots with jupyter notebooks in VSCode, and they aren't showing properly.

在Jupyter Notebook中使用VSCode取消裁剪3D图表。

I went to the documentation in matlab and downloaded the jupyter notebook for the 3d scatter plot and tried running that in vscode, getting the same results, the z label gets cut off.

I've seen a lot of questions about making the plot interactive with matplotlib magic, and some of those solutions (%matplotlib qt) do work (the image isn't cropped anymore, but gets created in a separate window. I want the plot to be inline, because I'm doing a lot of them and having one 40 windows created every time is a mess.

I've tried the magic %matplotlib widget and %matplotlib notebook, as suggested here, and the %matplotlib ipympl as suggested here but when I use those the plot stops showing, appearing only after I change to %matplotlib inline and showing any plot I've done before at that point (all cropped).

I've also checked the code in jupyter lab and it does not have this problem, the image shows completely fine, so it seems to be a problem with Jupyter notebooks in VsCode.

I'm not trying to change the position of the z axis, It's fine where it is, I just want to make the image bigger so the z label is shown properly.

Just in case, I've tried the comment of Trenton McKinney of doing ax.zaxis._axinfo['juggled'] = (1, 2, 2) to change the z-label to the other side, and it still gets cut, just in the other side of the image.

在Jupyter Notebook中使用VSCode取消裁剪3D图表。

So it's not an issue of where the z axes and label are.

PS: As requested, I put the from the example here for ease of use.

import matplotlib.pyplot as plt
import numpy as np

# Fixing random state for reproducibility
np.random.seed(19680801)


def randrange(n, vmin, vmax):
    """
    Helper function to make an array of random numbers having shape (n, )
    with each number distributed Uniform(vmin, vmax).
    """
    return (vmax - vmin)*np.random.rand(n) + vmin

fig = plt.figure()
ax = fig.add_subplot(projection='3d')

n = 100

# For each set of style and range settings, plot n random points in the box
# defined by x in [23, 32], y in [0, 100], z in [zlow, zhigh].
for m, zlow, zhigh in [('o', -50, -25), ('^', -30, -5)]:
    xs = randrange(n, 23, 32)
    ys = randrange(n, 0, 100)
    zs = randrange(n, zlow, zhigh)
    ax.scatter(xs, ys, zs, marker=m)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

Update: I've posted an issue in the github VSCode repo, link here

Update on the update: The issue has been found to be a matplotlib/jupyter problem, so I've opened a new issue in the matplotlib repo, link here

答案1

得分: 1

在GitHub的一对问题之后,我终于找到了答案。我会在这里在GitHub上留下答案以供参考。

问题似乎是由默认的内联后端将图形保存为bbox_inches='tight'引起的,这会导致图像被裁剪。这个问题可以通过使用内联魔术命令来解决:

%config InlineBackend.print_figure_kwargs = {'bbox_inches':None}

这会覆盖默认设置,为您提供一个具有足够空间用于标签和其他内容的大图像。如果这不起作用(创建的图像太大),我在这里留下了链接到文档。

另一个选项是添加填充,可以使用以下魔术命令来完成:

%config InlineBackend.print_figure_kwargs = {'pad_inches': .3}

这个选项可能需要一些试验和错误来获取正确的大小。在我的情况下,0.3效果很好。

英文:

So, after a pair of issues in github, I've finally found an answer. I'll leave here the answer in github for reference

It appears the problem is caused by the default inline backend saving the figure with bbox_inches= 'tight' which causes the code to crop the image. this can be solved using the inline magic

%config InlineBackend.print_figure_kwargs = {'bbox_inches':None}

which overthrows the default and gives you a nice, big image with plenty of room for labels and everything else. In case this doesn't work (the image created is rather big) I leave here the link to the docs.

Another option is to add padding, which can be done with the magic

%config InlineBackend.print_figure_kwargs = {'pad_inches': .3}

This option might need some trial and error to get the size right. In my case 0.3 worked as a charm.

huangapple
  • 本文由 发表于 2023年5月29日 23:45:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76358689.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定