Как построить календарь, используя патчи matplotlib - PullRequest
1 голос
/ 06 февраля 2020

Я хотел бы создать демонстрационный календарь, который отражает риск конкретного события, происходящего в каждый день месяца, и для каждого отдельного устройства

Я сталкивался с этим опубликовать в сети:

# Demo plot 
import calendar
import numpy as np
from matplotlib.patches import Rectangle
import matplotlib.pyplot as plt
def plot_calendar(days, months):
    plt.figure(figsize=(9, 3))
    # non days are grayed
    ax = plt.gca().axes
    ax.add_patch(Rectangle((29, 2), width=.8, height=.8, 
                           color='gray', alpha=.3))
    ax.add_patch(Rectangle((30, 2), width=.8, height=.8,
                           color='gray', alpha=.5))
    ax.add_patch(Rectangle((31, 2), width=.8, height=.8,
                           color='gray', alpha=.5))
    ax.add_patch(Rectangle((31, 4), width=.8, height=.8,
                           color='gray', alpha=.5))
    ax.add_patch(Rectangle((31, 6), width=.8, height=.8,
                           color='gray', alpha=.5))
    ax.add_patch(Rectangle((31, 9), width=.8, height=.8,
                           color='gray', alpha=.5))
    ax.add_patch(Rectangle((31, 11), width=.8, height=.8,
                           color='gray', alpha=.5))
    for d, m in zip(days, months):
        ax.add_patch(Rectangle((d, m), 
                               width=.8, height=.8, color='C0'))
    plt.yticks(np.arange(1, 13)+.5, list(calendar.month_abbr)[1:])
    plt.xticks(np.arange(1,32)+.5, np.arange(1,32))
    plt.xlim(1, 32)
    plt.ylim(1, 13)
    plt.gca().invert_yaxis()
    # remove borders and ticks
    for spine in plt.gca().spines.values():
        spine.set_visible(False)
    plt.tick_params(top=False, bottom=False, left=False, right=False)
    plt.show()


from datetime import datetime, timedelta
def get_weekends(year):
    weekend_day = []
    weekend_month = [] 
    start = datetime(year, 1, 1)
    for i in range(365):
        day_of_the_year = start + timedelta(days=i)
        if day_of_the_year.weekday() > 4:
            weekend_day.append(day_of_the_year.day)
            weekend_month.append(day_of_the_year.month)
    return weekend_day, weekend_month
weekend_day, weekend_month = get_weekends(2018)
plot_calendar(weekend_day, weekend_month)

и вернуть календарь ниже:

enter image description here

Сначала я хотел бы создать аналогичный график, но вместо того, чтобы иметь месяцы на Y-axis, я хотел бы иметь от device_1 до device_100, (ie. календарь будет на 100 устройств за один месяц)

Во-вторых, я хочу использовать разные (или только 2) цвета для представления различного уровня риска в сетке.

В любом случае, главная цель - создать демонстрационный календарь для визуализации потенциального риска, и я не знаю, как.

1 Ответ

1 голос
/ 06 февраля 2020

Это может быть достигнуто с помощью следующей адаптации вашего кода. Новая функция принимает параметр days, который должен быть списком (day, color) кортежей, которые нужно пометить для каждого устройства, которое вы хотите построить. Также требуется дополнительный параметр days_in_month для обеспечения совместимости с месяцами, у которых менее 31 дня.

Код:

def plot_device_calendar(days, days_in_month=31):
    plt.figure(figsize=(.3*days_in_month, .3*len(days)))
    ax = plt.gca().axes
    for device, days_to_mark in enumerate(days, start=1):
        for d in days_to_mark:
            ax.add_patch(Rectangle((d[0], device), 
                                   width=.8, height=.8, color=d[1]))
    plt.yticks(np.arange(1, len(days)+1)+.5, [f"device_{i}" for i in range(1, len(days)+1)])
    plt.xticks(np.arange(1,days_in_month+1)+.5, np.arange(1,days_in_month+1))
    plt.xlim(1, days_in_month+1)
    plt.ylim(1, len(days)+1)
    plt.gca().invert_yaxis()
    for spine in plt.gca().spines.values():
        spine.set_visible(False)
    plt.tick_params(top=False, bottom=False, left=False, right=False)
    plt.show()

Пример ввода : (3 устройства, 10 случайных дней и цветов)

>>> l = [[(30, 'r'), (23, 'b'), (31, 'g'), (16, 'm'), (10, 'g'), (7, 'r'), (27, 'g'), (6, 'y'), (3, 'y'), (14, 'g')],
         [(22, 'y'), (21, 'w'), (16, 'y'), (23, 'c'), (8, 'g'), (31, 'w'), (15, 'k'), (12, 'k'), (6, 'm'), (24, 'r')],
         [(31, 'c'), (10, 'c'), (2, 'k'), (17, 'g'), (30, 'y'), (3, 'g'), (14, 'y'), (23, 'y'), (4, 'r'), (22, 'r')]]

Использование:

>>> colors = ['b','g','r','c','m','y','k','w']
>>> l = [random.sample(range(1,32), 10) for i in range(20)]
>>> l = [[(x,random.choice(colors)) for x in sl] for sl in l]
>>> plot_device_calendar(l)

Вывод:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...