Сведение ломаной горизонтальной гистограммы в линейный график или тепловую карту

У меня есть данные за все время, что я потратил на программирование. Эти данные представлены в виде словаря, где ключом является дата, а значением — список кортежей, содержащих время начала сеанса кодирования и продолжительность сеанса кодирования.

Я успешно изобразил это на сломанной_полосе, используя приведенный ниже код, где ось Y — это дата, ось X — время в этот день, а каждая сломанная полоса — это отдельный сеанс.

for i,subSessions in enumerate(sessions.values()):
    plt.broken_barh(subSessions, (i,1))
months = {}
start = getStartMonth()
for month in period_range(start=start,end=datetime.today(),freq = "M"):
    month = str(month)
    months[month] = (datetime.strptime(month,'%Y-%m')-start).days
plt.yticks(list(months.values()),months.keys())
plt.xticks(range(0,24*3600,3600),[str(i)+":00" for i in range(24)],rotation=45)
plt.gca().invert_yaxis()
plt.show()

Сведение ломаной горизонтальной гистограммы в линейный график или тепловую карту

Я хочу использовать эти данные, чтобы узнать, в какое время дня я трачу больше всего времени на программирование, но из приведенной выше диаграммы это не очень ясно, поэтому я хотел бы отобразить их в виде линейного графика или тепловой карты, где ось Y — это количество дней, которые я потратил на программирование в то время по оси x (или, другими словами, сколько сеансов присутствует в этом столбце на приведенной выше диаграмме). Как мне это сделать?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете найти отличные примеры создания тепловой карты на сайте matplotlib.

Вот базовый код с некоторыми случайными данными:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

index_labels = np.arange(0,24)
column_labels = pd.date_range(start='1/1/2022', end='1/31/2022').strftime('%m/%d')

#random data
np.random.seed(12345)
data = np.random.randint(0,60, size=(len(index_labels), len(column_labels)))
df = pd.DataFrame(data=data, columns=column_labels, index=index_labels)

#heatmap function
def heatmap(df, ax, cbarlabel = "", cmap = "Greens", label_num_dec_place=0):
    df = df.copy()
    
    # Ploting a blank heatmap
    im = ax.imshow(df.values, cmap)

    # create a customized colorbar
    cbar = ax.figure.colorbar(im, ax=ax, fraction=0.05, extend='both', extendfrac=0.05)
    cbar.ax.set_ylabel(cbarlabel, rotation=-90, va = "bottom", fontsize=14)

    # Setting ticks
    ax.set_xticks(np.arange(df.shape[1]), labels=df.columns, fontsize=12)
    ax.set_yticks(np.arange(df.shape[0]), labels=list(df.index), fontsize=12)

    # proper placement of ticks
    ax.tick_params(axis='x', top=True, bottom=False,
                   labeltop=True, labelbottom=False)

    ax.spines[:].set_visible(False)
    ax.grid(which = "both", visible = "False", color = "white", linestyle='solid', linewidth=2)
    ax.grid(False)
    
    # Rotation of tick labels
    plt.setp(ax.get_xticklabels(), rotation=-60, 
             ha = "right", rotation_mode=None)
    plt.setp(ax.get_yticklabels(), rotation=30)

#plotting and saving
fig, ax = plt.subplots(facecolor=(1,1,1), figsize=(20,8), dpi=200)
heatmap(df=df, ax=ax, cbarlabel = "time (min)", cmap = "Greens", label_num_dec_place=0)
plt.savefig('time_heatmap.png', 
            bbox_inches='tight', 
            facecolor=fig.get_facecolor(), 
            transparent=True,
           )

Вывод:

Извините, проблема не в построении данных, а в их получении. Кроме того, для моей проблемы потребуется одномерная тепловая карта, поскольку ось Y будет отображаться через цвет.

hopperelec 19.11.2022 01:31
Ответ принят как подходящий

Один из способов сделать это — использовать выборку. Выберите, сколько выборок вы хотите взять в заданном интервале (точность, например, 288 выборок в день), разделите каждый интервал на это количество выборок и подсчитайте, сколько сеансов в этой выборке. Недостатком этого является то, что он не может быть точным на 100%, а увеличение точности увеличивает время, необходимое для создания (у меня требуется несколько минут для создания изображения с точностью до секунды, хотя этот уровень точности практически не делает ничего). разница в результате).

Вот некоторый код, который может создавать как тепловую карту, так и линейный график.

# Configuration options
precisionPerDay = 288
timeTicksPerDay = 24
timeTickRotation = 60
timeTickFontSize = 6
heatmap = True

# Constants
hoursInDay = 24
secondsInHour = 3600
secondsInDay = hoursInDay*secondsInHour
xInterval = secondsInDay/precisionPerDay
timeTickSecondInterval = precisionPerDay/timeTicksPerDay
timeTickHourInterval = hoursInDay/timeTicksPerDay

# Calculating x-axis (time) ticks
xAxis = range(precisionPerDay)
timeTickLabels = []
timeTickLocations = []
for timeTick in range(timeTicksPerDay):
    timeTickLocations.append(int(timeTick*timeTickSecondInterval))
    hours = timeTick/timeTicksPerDay*hoursInDay
    hour = int(hours)
    minute = int((hours-hour)*60)
    timeTickLabels.append(f"{hour:02d}:{minute:02d}")

# Calculating y-axis (height)
heights = []
for dayX in xAxis:
    rangeStart = dayX*xInterval
    rangeEnd = rangeStart+xInterval
    y = 0
    for date,sessions in sessions.items():
        for session in sessions:
            if session[0] < rangeEnd and session[0]+session[1] > rangeStart:
                y += 1
    heights.append(y)

# Plotting data
if heatmap:
    plt.yticks([])
    plt.imshow([heights], aspect = "auto")
else:
    plt.plot(xAxis,heights)
    plt.ylim(ymin=0)
plt.xlim(xmin=0,xmax=len(heights))
plt.xlabel("Time of day")
plt.ylabel("How often I've coded at that time")
plt.xticks(timeTickLocations,timeTickLabels,
           fontsize=timeTickFontSize,rotation=timeTickRotation)
plt.show()

А вот и примеры результатов

График, созданный с использованием тех же параметров конфигурации, что и в приведенном выше коде. Graph produced by same configuration options shown in above code

Те же данные, но в виде линейного графика с меньшей точностью (24 в день) и большим количеством тактов (48) Same data but as a line graph with a lower precision (24 per day) and more time ticks (48)

Это доказывает как пример того, что я ищу, но я бы предпочел метод, который является точным на 100% и генерирует быстрее. Если такой метод будет предоставлен в качестве ответа, я приму это, иначе это будет принятый ответ

hopperelec 19.11.2022 01:55

Другие вопросы по теме