Как создать разбитые вертикальные гистограммы в matplotlib? - PullRequest
6 голосов
/ 03 апреля 2012

Я бы хотел создать разбитую вертикальную гистограмму в matplotlib.

Чтобы получить лучшее представление о результате, к которому я стремлюсь, я привел пример с Balsamiq :

enter image description here

Я посмотрел на matpltolib docs и examples , но не могу найти подходящий тип диаграммы для использования. Единственное, что выглядит отдаленно похожим, это boxplot , но это не то, что мне нужно.

  • Я бы предпочел не рисовать график вручную с графическим примитивом.
  • Я могу преобразовать данные в нужную форму.

PS: Если вы знаете хорошую библиотеку, которая делает это на другом языке (например, javascript), я был бы благодарен за указатель тоже.

1 Ответ

11 голосов
/ 03 апреля 2012

Похоже, у вас есть несколько серий начальных и конечных дат.

В этом случае просто используйте bar для построения графиков и скажите matplotlib, что оси - это даты.

Чтобы узнать время, вы можете использовать тот факт, что внутренний формат даты matplotlib представляет собой число с плавающей точкой, где каждое целое число соответствует 0:00 этого дня.Поэтому, чтобы узнать время, мы можем просто сделать times = dates % 1.

В качестве примера (90% этого - генерация и манипулирование датами. Построение графика - это всего лишь один вызов bar.):

import datetime as dt
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

def main():
    start, stop = dt.datetime(2012,3,1), dt.datetime(2012,4,1)

    fig, ax = plt.subplots()
    for color in ['blue', 'red', 'green']:
        starts, stops = generate_data(start, stop)
        plot_durations(starts, stops, ax, facecolor=color, alpha=0.5)
    plt.show()

def plot_durations(starts, stops, ax=None, **kwargs):
    if ax is None:
        ax = plt.gca()
    # Make the default alignment center, unless specified otherwise
    kwargs['align'] = kwargs.get('align', 'center')

    # Convert things to matplotlib's internal date format...
    starts, stops = mpl.dates.date2num(starts), mpl.dates.date2num(stops)

    # Break things into start days and start times 
    start_times = starts % 1
    start_days = starts - start_times
    durations = stops - starts
    start_times += int(starts[0]) # So that we have a valid date...

    # Plot the bars
    artist = ax.bar(start_days, durations, bottom=start_times, **kwargs)

    # Tell matplotlib to treat the axes as dates...
    ax.xaxis_date()
    ax.yaxis_date()
    ax.figure.autofmt_xdate()
    return artist

def generate_data(start, stop):
    """Generate some random data..."""
    # Make a series of events 1 day apart
    starts = mpl.dates.drange(start, stop, dt.timedelta(days=1))

    # Vary the datetimes so that they occur at random times
    # Remember, 1.0 is equivalent to 1 day in this case...
    starts += np.random.random(starts.size)

    # Make some random stopping times...
    stops = starts + 0.2 * np.random.random(starts.size)

    # Convert back to datetime objects...
    return mpl.dates.num2date(starts), mpl.dates.num2date(stops)

if __name__ == '__main__':
    main()

enter image description here

С другой стороны, для событий, которые начинаются в один день и заканчиваются в следующий, это продлит ось Y на следующий день.Вы можете справиться с этим другими способами, если хотите, но я думаю, что это самый простой вариант.

...