在 Matplotlib 中将散点图中的标记尺寸正确调整为半径 R

问题描述 投票:0回答:3

我有一个限制为 -1 到 1 的图。 我知道散点图不会以大小作为半径绘制,而是以大小作为点绘制。

我需要根据每个点的大小(我将其作为半径)正确缩放绘图。 修改下面的代码可以吗?

fig, ax = plt.subplots(1)
ax.set_title("Post Synaptic Neurons")
sizes = [x.size * 100 for x in post_synaptic_neurons]
offsets = [(x.origin[0],x.origin[1]) for x in post_synaptic_neurons]
print(sizes)
ax.scatter([x.origin[0] for x in post_synaptic_neurons], [x.origin[1] for x in post_synaptic_neurons], 
  cmap=plt.cm.hsv, s=sizes, alpha=0.5)
ax.set_xlim([-1,1]) 
ax.set_ylim([-1,1])
ax.set_aspect(1)
plt.tight_layout

如果没有,有人可以向我解释一下为什么 matplotlib 没有在绘图比例上绘制具有特定半径的圆的函数吗? 我没想到这是一个问题,但我的困难背后一定有充分的理由。

python matplotlib scatter-plot
3个回答
6
投票

是的,有一种方法可以在绘图比例上绘制具有特定半径的散点图。方法是仔细定义图形大小并以点数指定半径,因为

plt.scatter
的文档表示参数
s
是“以点**2 为单位的标记大小”。

这是一个在位置 [0.5, 0.5] 处绘制半径为 0.1 的圆的示例

import matplotlib.pyplot as plt
plt.figure(figsize=[5, 5])
ax = plt.axes([0.1, 0.1, 0.8, 0.8], xlim=(0, 1), ylim=(0, 1))
points_whole_ax = 5 * 0.8 * 72    # 1 point = dpi / 72 pixels
radius = 0.1
points_radius = 2 * radius / 1.0 * points_whole_ax
ax.scatter(0.5, 0.5, s=points_radius**2, color='r')
plt.grid()
plt.show()

这里的关键是,matplotlib 中点的标准大小是每英寸 72 点 (ppi),无论 dpi 是多少。

points_radius
公式中的因子 2 来自以下事实:该面积是位于区域之外的盒子的面积,即
area = (2 * radius)**2
。输出图如下所示。


4
投票

据我所知,没有高级方法可以做到这一点,但您可以使用

EllipseCollection
使其工作。由于您的数据不可用,我做了一些并编写了以下代码:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.collections import EllipseCollection

x, y = 1500 * np.random.rand(2, 100)
size = 50 + 10 * np.random.randn(100)
color = np.random.rand(100)
cmap = plt.cm.hsv

fig, ax = plt.subplots(1, 2, figsize=(16, 6),
                       sharex=True, sharey=True)
ax[0].scatter(x, y, s=size, c=color, cmap=cmap)

offsets = list(zip(x, y))
ax[1].add_collection(EllipseCollection(widths=size, heights=size, angles=0, units='xy',
                                       facecolors=plt.cm.hsv(color),
                                       offsets=offsets, transOffset=ax[1].transData))
ax[1].axis('equal') # set aspect ratio to equal
ax[1].axis([-400, 1800, -200, 1600])

结果就是你所希望的;左边是简单的散点图,右边是缩放图:

如果缩放绘图,例如将轴限制更改为

ax[1].axis([200, 1000, 300, 900])
,则右侧绘图上的圆圈将根据需要缩放:

您可以在 matplotlib 文档中找到更多使用集合的示例。


0
投票

该问题现有解决方案的局限性:

我已经尝试过Jordan He和jakevdp的解决方案(这个问题下面有两个答案),我发现Jordan He的解决方案仅适用于精心(手动)设计的图形尺寸。 Jakevdp 的代码是 Python-2,不适合 Python-3。

何乔丹的解决方案最大的问题是“分散”的大小仅限于圆形。也就是说,当 x 轴和 y 轴的范围不相等时,“散点”虽然看起来是圆形,但实际上在数值上是椭圆形。

我的解决方案:

总之,我参考了matplotlib关于椭圆的演示

我使用

matplotlib.patches.Ellipse
绘制一个椭圆(以数字方式),并使其精确到我手动设置的尺寸(不是英寸,而是像轴中的值)。

这是我的代码:

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

x = 5
y = 5
e = Ellipse(xy=(x,y), width=6, height=10, angle=0) # set the width and heiget with number you want, this would be precisely numerical to the axis

fig = plt.figure(0)
# ax = fig.add_subplot(1,1,1)
ax = fig.add_subplot(1,1,1, aspect='equal') # add a plot, making the x-axis and y-axis equally looked

ax.add_artist(e)
e.set_clip_box(ax.bbox)
e.set_facecolor('#C0C0C0') # color here could be RGB like (0,0,0)

ax.set_xlim(0, 10) # set the range of x-axis
ax.set_ylim(0, 10) # set the range of y-axis

plt.grid()
plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.