Как добавить подплот к каждому прямоугольнику в древовидной карте? - PullRequest
1 голос
/ 01 апреля 2020

Я создал эту древовидную карту, используя Matplotlib и Squarify: enter image description here

Теперь я хотел бы добавить линейный график для каждого прямоугольника в древовидной карте. Это возможно?

Ответы [ 2 ]

1 голос
/ 01 апреля 2020
График

Squarify - это удобная функция для непосредственного построения карты дерева с заданными значениями и метками. Но этот процесс также может быть выполнен шаг за шагом. Одним из шагов является вычисление положений прямоугольников, для которых мы предполагаем фигуру, которая имеет координаты от 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()

resulting plot

Вот еще один пример, напоминающий изображение в вопросе, с основным сюжетом и цветовой шкалой. Стандартные значения 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()

plot with colorbar

1 голос
/ 01 апреля 2020

Да, это возможно. Вам нужно будет написать код, чтобы извлечь точные позиции, в которые вы хотите поместить новый график.

Вам нужно установить положение новой фигуры, используя f.canvas.manager.window.SetPosition

Этот ответ очень поможет { ссылка }

...