Добавление линейного графика с использованием второй оси к столбчатому графику с использованием пользовательских дат в виде x тиков matplotlib - PullRequest
1 голос
/ 09 июля 2020

У меня есть составной столбчатый график, который создается следующим образом:

fig, ax1 = plt.subplots(figsize=(16,12))

bars_old= np.add(old_data['green'], old_data['orange']).tolist()
bars_new = np.add(df_['Green'], df_['Orange']).tolist()

today = pd.to_datetime(dt.date.today())
edge_colors = np.where(date_list==(today.strftime('%d %b')), 'black', 'white')
line_width= np.where(date_list==(today.strftime('%d %b')), 4, 0.5)


ax1.bar(old_dates, old_data['green'], color='green', zorder=5, linewidth=0.5, edgecolor='white')
ax1.bar(old_dates, old_data['orange'], color='orange', bottom=old_data['green'], zorder=5, linewidth=0.5, edgecolor='white')
ax1.bar(old_dates, old_data['red'], color='red', bottom=bars_old, zorder=5, linewidth=0.5, edgecolor='white')


ax1.bar(date_list, df_['Green'], color='green', zorder=5, linewidth=line_width, edgecolor=edge_colors)
ax1.bar(date_list, df_['Orange'], color='orange', bottom=df_['Green'], linewidth=line_width, zorder=5, edgecolor=edge_colors)
ax1.bar(date_list, df_['Red'], color='red', bottom=bars_new, zorder=5, linewidth=line_width, edgecolor=edge_colors)
plt.ylim(0,678)

Фактические данные в этом случае не важны, а скорее даты, указанные для оси x.

old_dates

Index(['01 Jul', '02 Jul', '03 Jul', '04 Jul', '05 Jul', '06 Jul', '07 Jul',
       '08 Jul'],
      dtype='object')

date_list

Index(['09 Jul', '10 Jul', '11 Jul', '12 Jul', '13 Jul', '14 Jul', '15 Jul',
       '16 Jul', '17 Jul', '18 Jul', '19 Jul', '20 Jul', '21 Jul', '22 Jul'],
      dtype='object')

Как видите, даты с 01 июля по 22 июля и полностью связаны, и сюжет отображает то, что я хочу. Однако теперь я пытаюсь добавить линейный график на второй оси следующим образом:

ax2 = ax1.twinx()
ax2.plot(delta_dates, deltas, 'r', marker='o',markersize=15, lw=5)
plt.ylim(-2.5, 2.5)

delta_dates

Index(['09 Jul', '10 Jul', '11 Jul', '12 Jul', '13 Jul', '14 Jul', '15 Jul',
       '16 Jul', '17 Jul', '18 Jul', '19 Jul', '20 Jul', '21 Jul'],
      dtype='object')

print (np.shape(deltas))
(13,)

Как видите, дельты и delta_dates имеют одинаковый размер. Однако, когда я пытаюсь добавить это к моему существующему графику столбцов, линия отображается в правильные даты, но она сдвигает более старые даты вправо и оставляет за собой xlabels. Что именно здесь происходит? Изображения предоставлены для большей наглядности.

image1 image2

1 Ответ

3 голосов
/ 09 июля 2020

Проблема в том, что вы рисуете строки по оси x, не даты . Вы можете видеть, что dtype ваших дат - это object.

Если вы создадите аналогичный график вместо datetime -подобных данных на оси x, вы получите желаемый результат. Вам просто нужно использовать matplotlib.dates для форматирования ваших осей:

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

old_dates = pd.date_range('07-01-2020','07-12-2020',freq='1D')
date_list = pd.date_range('07-13-2020','07-23-2020',freq='1D')

fig, ax = plt.subplots()

ax.bar(old_dates, np.random.rand(len(old_dates)))
ax.bar(date_list, np.random.rand(len(date_list)))

ax2 = ax.twinx()
ax2.plot(date_list, np.random.rand(len(date_list)))

enter image description here

But if you instead convert the times to str, matplotlib basically creates a numeric position for each string, and it is not smart enough to (or it intentionally doesn't) assign them an order / identity in the way you are trying to do. So when you create the twin axes, it is basically resetting the position for ax2 and you get the problem you are seeing:

str1 = pd.Series(dr1).astype(str)
str2 = pd.Series(dr2).astype(str)

fig, ax = plt.subplots()

ax.bar(str1, np.random.rand(len(str1)))
ax.bar(str2, np.random.rand(len(str2)))

ax2 = ax.twinx()
ax2.plot(str2, np.random.rand(len(str2)))

enter image description here

The ticks are the full timestamp names in this example (causing more clutter), but the problem would be the same if they were fixed to the same "MONTH ##" format. I wrote in другой пост как не имеет значения, что строки "выглядят как" datetime Информация; они по-прежнему являются строками, и информация, на которую они ссылаются, не может быть нанесена на график по порядку.

...