Python散点图。标记的大小和样式

40

我有一组数据,想要将它们以散点图的形式展示。我希望每个点都被绘制成大小为dx的正方形。

          x = [0.5,0.1,0.3]
          y = [0.2,0.7,0.8]
          z = [10.,15.,12.]
          dx = [0.05,0.2,0.1]

          scatter(x,y,c=z,s=dx,marker='s')
问题在于 scatter 函数读取的大小 s 是平方点,而我想要每个点用实际单位中 dx² 的面积表示。我希望你能明白我的意思。
还有一个问题,scatter 函数将标记绘制为带黑色边框的点,如何取消这个选项使其没有任何边框?
3个回答

43

用户数据坐标系转换为显示坐标系。

使用edgecolors='none'来绘制没有边框线的面。

import numpy as np

fig = figure()
ax = fig.add_subplot(111)
dx_in_points = np.diff(ax.transData.transform(zip([0]*len(dx), dx))) 
scatter(x,y,c=z,s=dx_in_points**2,marker='s', edgecolors='none')

8
这并不是OP请求的以“图形单位”绘制正方形的方法,而是绘制固定大小、无法调整大小的正方形(例如通过手动更改图形框架大小)。 - joaquin
1
这可能是一个愚蠢的问题。但如果dx不是一个数组,而是对于每个点(x,y,z)都相同,那么如何更改上面的代码?此外,我真正需要使用add_subplot吗? - Brian
1
你是怎么发现 edgecolors 参数的? - Dror

23

我认为通过使用一组补丁可以做得更好。根据文档:

这个(PatchCollection)可以更容易地将颜色映射分配给异构的补丁集合。

这也可能会提高绘图速度,因为 PatchCollection 比大量补丁的绘制速度更快。

假设您希望绘制一个散点图,其中包含以数据单位给定半径的圆形:

def circles(x, y, s, c='b', vmin=None, vmax=None, **kwargs):
    """
    Make a scatter of circles plot of x vs y, where x and y are sequence 
    like objects of the same lengths. The size of circles are in data scale.

    Parameters
    ----------
    x,y : scalar or array_like, shape (n, )
        Input data
    s : scalar or array_like, shape (n, ) 
        Radius of circle in data unit.
    c : color or sequence of color, optional, default : 'b'
        `c` can be a single color format string, or a sequence of color
        specifications of length `N`, or a sequence of `N` numbers to be
        mapped to colors using the `cmap` and `norm` specified via kwargs.
        Note that `c` should not be a single numeric RGB or RGBA sequence 
        because that is indistinguishable from an array of values
        to be colormapped. (If you insist, use `color` instead.)  
        `c` can be a 2-D array in which the rows are RGB or RGBA, however. 
    vmin, vmax : scalar, optional, default: None
        `vmin` and `vmax` are used in conjunction with `norm` to normalize
        luminance data.  If either are `None`, the min and max of the
        color array is used.
    kwargs : `~matplotlib.collections.Collection` properties
        Eg. alpha, edgecolor(ec), facecolor(fc), linewidth(lw), linestyle(ls), 
        norm, cmap, transform, etc.

    Returns
    -------
    paths : `~matplotlib.collections.PathCollection`

    Examples
    --------
    a = np.arange(11)
    circles(a, a, a*0.2, c=a, alpha=0.5, edgecolor='none')
    plt.colorbar()

    License
    --------
    This code is under [The BSD 3-Clause License]
    (http://opensource.org/licenses/BSD-3-Clause)
    """
    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.patches import Circle
    from matplotlib.collections import PatchCollection

    if np.isscalar(c):
        kwargs.setdefault('color', c)
        c = None
    if 'fc' in kwargs: kwargs.setdefault('facecolor', kwargs.pop('fc'))
    if 'ec' in kwargs: kwargs.setdefault('edgecolor', kwargs.pop('ec'))
    if 'ls' in kwargs: kwargs.setdefault('linestyle', kwargs.pop('ls'))
    if 'lw' in kwargs: kwargs.setdefault('linewidth', kwargs.pop('lw'))

    patches = [Circle((x_, y_), s_) for x_, y_, s_ in np.broadcast(x, y, s)]
    collection = PatchCollection(patches, **kwargs)
    if c is not None:
        collection.set_array(np.asarray(c))
        collection.set_clim(vmin, vmax)

    ax = plt.gca()
    ax.add_collection(collection)
    ax.autoscale_view()
    if c is not None:
        plt.sci(collection)
    return collection

scatter函数的所有参数和关键字(除了marker)都能以类似的方式工作。我写了一个gist,包括圆形椭圆形正方形/矩形。如果你想要其他形状的集合,可以自己修改。

如果你想要绘制色条,只需运行colorbar()或将返回的集合对象传递给colorbar函数。

一个例子:

from pylab import *
figure(figsize=(6,4))
ax = subplot(aspect='equal')

#plot a set of circle
a = arange(11)
out = circles(a, a, a*0.2, c=a, alpha=0.5, ec='none')
colorbar()

#plot one circle (the lower-right one)
circles(1, 0, 0.4, 'r', ls='--', lw=5, fc='none', transform=ax.transAxes)

xlim(0,10)
ylim(0,10)

输出:

示例图


1
我想在一个开源项目中使用你的函数,但是不能这样做,因为默认情况下所有的 SO 代码都属于CC BY-SA 许可证。你能否明确声明你的代码许可证,最好是类似 BSD 的? - letmaik
1
@neo 很高兴知道这个。我不熟悉许可证,我认为它应该与matplotlib保持一致,因为我只是基于“scatter”函数编写了这段代码。所以应该是PSF或其他什么? - Syrtis Major
你的代码片段不是matplotlib的衍生作品,因此你可以根据任何许可证对你的代码进行许可。我建议使用BSD 3-clause,在Python世界中非常常见。 - letmaik
1
@neo 没问题,我会使用BSD 3条款。 - Syrtis Major

21

如果你想要随着图形大小调整大小的标记,可以使用patches:

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

x = [0.5, 0.1, 0.3]
y = [0.2 ,0.7, 0.8]
z = [10, 15, 12]
dx = [0.05, 0.2, 0.1]

cmap = plt.cm.hot
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')

for x, y, c, h in zip(x, y, z, dx):
    ax.add_artist(Rectangle(xy=(x, y),
                  color=cmap(c**2),        # I did c**2 to get nice colors from your numbers
                  width=h, height=h))      # Gives a square of area h*h

plt.show()

图片描述

注意:

  1. 正方形不是以 (x,y) 为中心,而是以其左下角的坐标表示。我这样做是为了简化代码。你应该使用 (x + dx/2, y + dx/2)
  2. 颜色是从热色图获取的。我使用了 z**2 来给出颜色。你也应该根据自己的需求进行适当调整。

最后针对你的第二个问题,你可以通过传递关键字参数 edgecoloredgecolors 来获取散点标记的边框。这两个参数都接受 matplotlib 的颜色参数或 RGBA 元组的序列。如果将参数设置为 'None',则不绘制边框。


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