我使用 Matplotlib 和 Squarify 创建了这个树图:
现在我想在树图中的每个矩形上添加一个线图。那可能吗?
我使用 Matplotlib 和 Squarify 创建了这个树图:
现在我想在树图中的每个矩形上添加一个线图。那可能吗?
对的,这是可能的。您必须编写代码来提取要放置新绘图的确切位置。
您需要使用设置新图形的位置f.canvas.manager.window.SetPosition
Squarify的 plot 是一个方便的函数,可以直接绘制给定值和标签的树形图。但是,这个过程也可以逐步执行。其中一个步骤是计算矩形的位置,我们假设一个图形的坐标从左下到右上从 0,0 到 1,1。
使用这些矩形,我们可以手动定位要绘制的轴。目前还不清楚是否需要蜱虫。如果需要,它们可以放在里面。或者轴可以完全移动到每个子图的中心。或者只有没有标签的刻度。
下面是一些演示代码:
import numpy as np
import matplotlib.pyplot as plt
import squarify
values = [500, 433, 331, 254, 119]
values.sort(reverse=True) # values must be sorted descending (and positive)
# the sum of the values must equal the total area to be laid out; i.e., sum(values) == width * height
values = squarify.normalize_sizes(values, 1, 1)
rects = squarify.squarify(values, 0, 0, 1, 1)
fig = plt.figure(figsize=(7, 5))
axes = [fig.add_axes([rect['x'], rect['y'], rect['dx'], rect['dy'], ]) for rect in rects]
for ax, color in zip(axes, plt.cm.Pastel1.colors):
x = np.linspace(0, 10, 100)
y = np.random.normal(0.01, 0.1, 100).cumsum()
ax.plot(x, y)
ax.tick_params(axis="y", direction="in", pad=-15)
ax.tick_params(axis="x", direction="in", pad=-15)
plt.setp(ax.get_yticklabels(), ha="left")
ax.set_facecolor(color)
plt.show()
这是另一个类似于问题中图像的示例,带有主图和颜色条。默认的 mplcursors 会与所有这些轴混淆,但也可以手动添加悬停时的注释。
import numpy as np
import matplotlib.pyplot as plt
import squarify
values = [4000, 1500, 1500, 1200, 1000, 500]
fig, mainax = plt.subplots(figsize=(6, 4))
mainax.set_xlim(0, 1000)
mainax.set_ylim(0, 1000)
mainax.grid(False)
cmap = plt.cm.get_cmap('Greens')
norm = plt.Normalize(vmin=0, vmax=max(values))
plt.colorbar(plt.cm.ScalarMappable(cmap=cmap, norm=norm))
pos = mainax.get_position()
values.sort(reverse=True)
normalized_values = squarify.normalize_sizes(values, pos.width, pos.height)
rects = squarify.squarify(normalized_values, pos.x0, pos.y0, pos.width, pos.height)
axes = [fig.add_axes([rect['x'], rect['y'], rect['dx'], rect['dy'], ]) for rect in rects]
for ax, val in zip(axes, values):
x = np.linspace(0, 10, 100)
y = np.random.normal(0.01, 0.1, 100).cumsum()
ax.plot(x, y)
ax.set_xticks([])
ax.set_yticks([])
ax.set_facecolor(cmap(norm(val)))
mainax.set_facecolor('none') # prevent that the mainax blocks the other axes
mainax.set_zorder(20) # high z-order because the annotations are drawn using this ax
labels = ['a', 'b', 'c', 'd', 'e', 'f']
sum_val = sum(values)
annotations = [mainax.annotate(f"'{lbl}': {val}\n{val * 100.0 / sum_val:.1f} %",
xy=(0, 0), xycoords='figure pixels',
xytext=(0, 0), textcoords='offset points',
bbox=dict(boxstyle='round', fc='lemonchiffon'),
ha='center', va='bottom')
for ax, val, lbl in zip(axes, values, labels)]
for annot in annotations:
annot.set_visible(False)
def hover(event):
for ax, annot in zip(axes, annotations):
if ax.bbox.contains(event.x, event.y):
annot.xy = (event.x, event.y)
annot.set_visible(True)
else:
annot.set_visible(False)
fig.canvas.draw_idle()
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()