考虑以下玩具代码:
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
def draw_circle_arrangement(ax, drawing_origin, drawing_space, scale, num_circles, box_height, box_width):
bw = drawing_space*(box_width*scale)
drawing_origin[0] = drawing_origin[0] - bw*0.5
circle_diameter = drawing_space*scale
circle_radius = 0.5*circle_diameter
y_delta = np.array([0., circle_diameter])
x_delta = np.array([circle_diameter, 0.])
cell_origin = drawing_origin + np.array([circle_radius, circle_radius])
y_delta_index = 0
x_delta_index = 0
for ci in range(num_circles):
cell_patch = mpatches.Circle(cell_origin + y_delta_index*y_delta + x_delta_index*x_delta, radius=circle_radius, color='k', fill=False, ls='solid', clip_on=False)
ax.add_artist(cell_patch)
if y_delta_index == box_height - 1:
y_delta_index = 0
x_delta_index += 1
else:
y_delta_index += 1
fig, ax = plt.subplots()
# each tuple is: number of circles, height of box containing circles, width of box containing circle
circle_arrangements = [(10, 2, 5), (3, 1, 3), (1, 1, 1)]
data = np.random.rand(3)
ax.set_ylim([0, 1])
ax.plot(np.arange(3) + 1, data, marker='o')
ax.get_xaxis().set_ticklabels([])
scale = 1./10.
for i, ca in enumerate(circle_arrangements):
do = np.array([1.0 + i, -0.2])
nc, bh, bw = ca
draw_circle_arrangement(ax, do, 0.8, scale, nc, bh, bw)
如您所见,圆圈不是圆圈!他们被压扁了。解决这个问题的一种方法是设置ax.set_aspect('equal')
,但如果我不一定希望轴纵横比相等,我怎么还能以这种方式生成补丁呢?
答案 0 :(得分:2)
不能仅将轴方面的一部分设置为相等。解决方案是在不同的坐标系中绘制圆,或者使用使用不同坐标系的不同框。
我发现后一种解决方案更可取。这将涉及使用可以放在DrawingArea
内的AnnotationBbox
。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.offsetbox import DrawingArea, AnnotationBbox
def draw_circle_arrangement(ax, drawing_origin, radius,
num_circles, box_height, box_width):
y_delta_index = 0
x_delta_index = 0
origin = np.array([radius,radius])
y_delta = np.array([0., 2*radius])
x_delta = np.array([2*radius, 0.])
da = DrawingArea(box_width*2*radius, box_height*2*radius, 0, 0)
for ci in range(num_circles):
cell_patch = mpatches.Circle(origin+y_delta_index*y_delta + x_delta_index*x_delta,
radius=radius, color='k', fill=False, ls='solid',clip_on=False)
da.add_artist(cell_patch)
if y_delta_index == box_height - 1:
y_delta_index = 0
x_delta_index += 1
else:
y_delta_index += 1
ab = AnnotationBbox(da, xy=(drawing_origin[0],0),
xybox=drawing_origin,
xycoords=("data", "axes fraction"),
boxcoords=("data", "axes fraction"),
box_alignment=(0.5,0.5), frameon=False)
ax.add_artist(ab)
fig, ax = plt.subplots()
# each tuple is: number of circles, height of box containing circles, width of
#box containing circle
circle_arrangements = [(10, 2, 5), (3, 1, 3), (1, 1, 1)]
data = np.random.rand(3)
ax.set_ylim([0, 1])
ax.plot(np.arange(3) + 1, data, marker='o')
ax.get_xaxis().set_ticklabels([])
for i, ca in enumerate(circle_arrangements):
do = np.array([1.0 + i, -0.06])
nc, bh, bw = ca
draw_circle_arrangement(ax, do, 5, nc, bh, bw)
plt.show()
DrawingArea
的单位是积分。例如。在第一种情况下,我们创建一个5 * 2 * 5 = 50点宽度的DrawingArea,并在其中放置5个半径为5个点的圆圈(5个圆圈填满整个50个点)。一个点是~1.4像素。 AnnotationBox的位置在x位置的数据坐标中给出,在y位置的轴分数中给出。可以使用boxcoords
参数更改此设置。对于xy
参数也是如此,我们确保y坐标为0,因此在轴内(这样就显示了AnnotationsBox)。