4

我正在尝试在 matplotlib 中为散点图创建自定义标记,其中标记是具有固定高度和不同宽度的矩形。每个标记的宽度是 y 值的函数。我使用此代码作为模板进行了这样的尝试,并假设如果给定 verts 一个 N 2-D 元组列表,它会绘制具有相应第一个值的宽度和第二个值的高度的矩形(也许这已经是错误的,但那我该怎么做呢?)。

我有一个 x 和 y 值的列表,每个值都包含以度为单位的角度。然后,我计算每个标记的宽度和高度

field_size = 2.
symb_vec_x = [(field_size / np.cos(i * np.pi / 180.)) for i in y]
symb_vec_y = [field_size for i in range(len(y))]

并构建 verts 列表并绘制所有内容

symb_vec = list(zip(symb_vec_x, symb_vec_y))
fig = plt.figure(1, figsize=(14.40, 9.00))
ax = fig.add_subplot(1,1,1)
sc = ax.scatter(ra_i, dec_i, marker='None', verts=symb_vec)

但是结果图是空的,但是没有错误消息。谁能告诉我我在定义顶点时做错了什么以及如何做对?谢谢!

4

2 回答 2

5

如前所述 'marker='None' 需要被删除,然后指定带有顶点的矩形的适当方法类似于

verts = list(zip([-10.,10.,10.,-10],[-5.,-5.,5.,5]))
ax.scatter([0.5,1.0],[1.0,2.0], marker=(verts,0))

顶点被定义为([x1,x2,x3,x4],[y1,y2,y3,y4])必须注意哪些得到减号等。

这 (verts,0) 在文档中被提及为

为了向后兼容,也接受形式 ( verts , 0),但它等同于仅verts用于提供定义形状的原始顶点集。

但是我发现使用只是verts没有给出正确的形状。

要自动化该过程,您需要执行类似的操作

v_val=1.0
h_val=2.0
verts = list(zip([-h_val,h_val,h_val,-h_val],[-v_val,-v_val,v_val,v_val]))

基本示例:

import pylab as py
ax = py.subplot(111)
v_val=1.0
h_val=2.0
verts = list(zip([-h_val,h_val,h_val,-h_val],[-v_val,-v_val,v_val,v_val]))
ax.scatter([0.5,1.0],[1.0,2.0], marker=(verts,0))

在此处输入图像描述*

编辑

单个标记

因此,您需要为每种情况手动创建一个顶点。这显然取决于您希望矩形如何点对点更改。这是一个例子

import pylab as py
ax = py.subplot(111)


def verts_function(x,y,r):
    # Define the vertex's multiplying the x value by a ratio
    x = x*r
    y = y
    return [(-x,-y),(x,-y),(x,y),(-x,y)]

n=5
for i in range(1,4):
    ax.scatter(i,i, marker=(verts_function(i,i,0.3),0))
    py.show()

在此处输入图像描述

所以在我的简单情况下,我绘制点 i,i 并在它们周围绘制矩形。指定垂直标记的方式是不直观的。在文档中描述如下:

verts: 用于路径顶点的 (x, y) 对列表。标记的中心位于 (0,0) 并且尺寸被标准化,使得创建的路径被封装在单元格内。

因此,以下是等价的:

vert = [(-300.0, -1000), (300.0, -1000), (300.0, 1000), (-300.0, 1000)]
vert = [(-0.3, -1), (0.3, -1), (0.3, 1), (-0.3, 1)]

例如,它们将产生相同的标记。因此,我使用了一个比率,这是您需要投入工作的地方。r 的值(比率)将改变哪个轴保持不变。

这一切都变得非常复杂,我相信一定有更好的方法来做到这一点。

于 2013-04-24T14:33:08.007 回答
2

我从 matplotlib 用户邮件列表的 Ryan 那里得到了解决方案。它非常优雅,所以我将在这里分享他的示例:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.collections import PatchCollection

n = 100

# Get your xy data points, which are the centers of the rectangles.
xy = np.random.rand(n,2)

# Set a fixed height
height = 0.02
# The variable widths of the rectangles
widths = np.random.rand(n)*0.1

# Get a color map and make some colors
cmap = plt.cm.hsv
colors = np.random.rand(n)*10.
# Make a normalized array of colors
colors_norm = colors/colors.max()
# Here's where you have to make a ScalarMappable with the colormap
mappable = plt.cm.ScalarMappable(cmap=cmap)
# Give it your non-normalized color data
mappable.set_array(colors)

rects = []
for p, w in zip(xy, widths):
    xpos = p[0] - w/2 # The x position will be half the width from the center
    ypos = p[1] - height/2 # same for the y position, but with height
    rect = Rectangle( (xpos, ypos), w, height ) # Create a rectangle
    rects.append(rect) # Add the rectangle patch to our list

# Create a collection from the rectangles
col = PatchCollection(rects)
# set the alpha for all rectangles
col.set_alpha(0.3)
# Set the colors using the colormap
col.set_facecolor( cmap(colors_norm) )
# No lines
col.set_linewidth( 0 )
#col.set_edgecolor( 'none' )

# Make a figure and add the collection to the axis.
fig = plt.figure()
ax = fig.add_subplot(111)
ax.add_collection(col)
# Add your ScalarMappable to a figure colorbar
fig.colorbar(mappable)
plt.show()

谢谢你,Ryan,以及所有贡献自己想法的人!

于 2013-04-26T15:45:25.453 回答