当多边形变得太小,使用多边形集合绘制的图表消失。

6
我正在使用PolyCollection来绘制不同大小的数据。有时,多边形非常小。如果它们太小,它们根本不会被绘制出来。我希望至少能显示轮廓线,这样你就可以知道一些数据存在。有没有设置来控制这个问题?
以下是用于复现问题以及输出图像的一些代码:
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from matplotlib import colors

fig = plt.figure()
ax = fig.add_subplot(111)
verts = []

edge_col = colors.colorConverter.to_rgb('lime')
face_col = [(2.0 + val) / 3.0 for val in edge_col] # a little lighter

for i in range(10):
    w = 0.5 * 10**(-i)
    xs = [i - w, i - w, i + w, i - w]
    ys = [-w, w, 0, -w]

    verts.append(list(zip(xs, ys)))

ax.set_xlim(-1, 11)
ax.set_ylim(-2, 2)

ax.add_collection(PolyCollection(verts, lw=3, alpha=0.5, edgecolor=edge_col, facecolor=face_col))

plt.savefig('out.png')

out

请注意,只有六个多边形是可见的,而应该有十个。

编辑:我知道我可以放大看到其他的,但是我希望在不这样做的情况下能看到一个点或轮廓或其他东西。

编辑2:通过使用PolyCollection绘制面并使用一系列Line2D绘制边缘(基于Patol75的答案),可以实现所需的效果。我的应用程序是一个具有许多多边形的matplotlib动画,因此我希望为了效率而避免使用Line2D,如果不需要两次绘制图形就更好了,所以我仍然希望得到更好的答案。

ax.add_collection(PolyCollection(verts, lw=3, alpha=0.5, edgecolor=None, facecolor=face_col, zorder=1))

for pts in verts:
    ax.add_line(Line2D([pt[0] for pt in pts], [pt[1] for pt in pts], lw=3, alpha=0.5, color=edge_col,
                                 marker='.', ms=1, mec=edge_col, solid_capstyle='projecting', zorder=2))

out_line2d

2个回答

2

您可以引入一些最小单位minw,它是一个形状可以拥有的最小尺寸。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from matplotlib import colors

fig = plt.figure()
ax = fig.add_subplot(111)
verts = []

edge_col = colors.colorConverter.to_rgb('lime')
face_col = [(2.0 + val) / 3.0 for val in edge_col] # a little lighter

ax.set_xlim(-1, 11)
ax.set_ylim(-2, 2)

u = np.diff(np.array([ax.get_xlim(), ax.get_ylim()]), axis=1).min()
px = np.max(fig.get_size_inches())*fig.dpi
minw = u/px/2

for i in range(10):
    w = 0.5 * 10**(-i)
    if w < minw:
        w = minw
    xs = [i - w, i - w, i + w, i - w]
    ys = [-w, w, 0, -w]

    verts.append(list(zip(xs, ys)))


ax.add_collection(PolyCollection(verts, lw=3, alpha=0.5, edgecolor=edge_col, facecolor=face_col))

plt.savefig('out.png')
plt.show()

enter image description here


使用 get_xlimget_ylimfig.get_size_inchesfig.dpi 进行计算是一种不错的方法,但这是一个解决问题的变通方法。在实际应用中,我正在进行动画制作,其中轴限可能会发生变化,因此这种方法在这种情况下并不完全适用。形状也有点复杂,但你可以使用顶点计算边界框并将其用于宽度。 - Stanley Bak
当然,您可以在轴限制更改时每次重新计算PolyCollection。(不确定这种情况会发生多少次?) - ImportanceOfBeingErnest

2
放大绘图窗口,你会发现另外两个多边形正在被绘制,只是它们太小了以至于你看不到。一个让你确信这一点的方法是替换原来的代码。
ax.set_xlim(-1, 6)
ax.set_ylim(-2, 2)

by

ax.set_xlim(1e-1, 1e1)
ax.set_ylim(1e-5, 1e0)
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_aspect('equal')

您的五边形现在可见,但是对于缩放比例取对数的方式,您只能看到正轴上的内容。

enter image description here

现在我们来提供一种解决方案。如果您使用线性坐标轴,由于多个数量级的五边形大小,您将无法看到它们所有。您可以在图表中添加一个艺术家,指定它们的位置。这可以用一个标记、一个箭头等来实现。以标记为例,如您所说,我们只想在无法看到五边形时才看到该标记。在调用plot()函数时,关键字zorder允许指定哪个艺术家在图像上具有显示优先权。请参考下面的示例。

import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
fig = plt.figure()
ax = fig.add_subplot(111)
verts = []
for i in range(5):
    w = 0.5 * 10**(-i)
    xs = [i - w, i - w, i + w, i + w, i - w]
    ys = [-w, w, w, -w, -w]
    ax.plot((xs[2] + xs[1]) / 2, (ys[1] + ys[0]) / 2, linestyle='none',
            marker='o', color='xkcd:crimson',  markersize=1, zorder=-1)
    verts.append(list(zip(xs, ys)))
ax.set_xlim(-1, 6)
ax.set_ylim(-2, 2)
poly = PolyCollection(verts, lw=5, edgecolor='black', facecolor='gray')
ax.add_collection(poly)
plt.show()

这段文字涉及到IT技术,其中提到了matplotlib图形库。如果你放大matplotlib图形中的最后两个点,你会发现实际上看不到标记,而是看到了多边形。


确实,如果我放大图像,我可以看到它们,但在实际程序中,将绘制到文件中,我事先不知道多边形的大小。我希望对于小的多边形,我能够在图表上看到一个点,或者至少能看到轮廓线或其他东西。 - Stanley Bak
你可以在多边形的中心绘制一个标记。 - Patol75
寻找通用多边形的中心需要额外的计算(例如,通过解决4个线性规划问题可以得到边界框的中心)。此外,我只希望在没有多边形时显示标记,否则可能会出现两者都可见的丑陋情况。 - Stanley Bak
更好了。真正的多边形有alpha值,因此在下面绘制的东西会显示出来。使用多边形和标记分别绘制两次的想法似乎可行(我将更新问题)。我会暂时不颁发奖励,以防有人提出更清晰/更有效的解决方案。 - Stanley Bak
你可以添加一个if条件,只有当多边形太小时才调用Line2D。你可以通过跟踪每个多边形的边缘大小,并为新边缘设置阈值来确定它是否太小。 - Patol75

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接