fresh
fresh

Reputation: 43

How to color area when x values are pandas time series

I've got the following line diagram with two time series values and two vertical lines and would like to colour the area where "FromGen" is larger than "ToCons" and on the outside of the two vertical lines.

start_date="2019-06-18"
end_date="2019-06-19"

x0='2019-06-18 9:00:00'
x1='2019-06-18 17:00:00'

x1= pd.to_datetime(x1, format="%Y-%m-%d", utc=True)
x2= pd.to_datetime(x2, format="%Y-%m-%d", utc=True)

zeit = (df['DateTime'] > start_date) & (df['DateTime'] <= end_date)
zeit = df.loc[zeit]

zeit.plot(figsize=(15,10),x="DateTime", y=["FromGen", "ToCons"])
plt.xlabel("Zeit") 
plt.ylabel("Wh")
legend = plt.legend(title="comp",
                    loc=1, fontsize='large', fancybox=True,  labels=['FromGen', 'ToCons'])
plt.axvline(x=x0, color='red')
plt.axvline(x=x1, color='red')

kde_x, kde_y = ax.lines[0].get_data()
ax.fill_between(kde_x, kde_y, where=(kde_x<x0) | (kde_x>x1) , 
                interpolate=True, color='#8FF536')
plt.show()

I already found that the code on the last few lines might be helpful - but at the moment I'm struggeling with this error:

'<' not supported between instances of 'numpy.ndarray' and 'str'

Many thanks in advance!

Green area should be coloured

EDIT: This is how my code looks at the moment- if I don't convert the df into the correct tz everything works perfect. But when I do the green area gets moved. I guess that I'm missing a Timezone convert somewhere but can't find out where....

from datetime import datetime from pytz import timezone

df= pd.read_csv("filename.csv", error_bad_lines=False, sep=";") df['DateTime'] = pd.to_datetime(df['DateTime'], format="%Y-%m-%d", utc=True)

#df['DateTime'] = df['DateTime'].dt.tz_convert('Europe/Berlin') #Works great without this line! But when I use it the coloured area seems to be in the wrong timezone

start_date = "2019-06-18" end_date = "2019-06-19"

x0 = '2019-06-18 9:00:00' x1 = '2019-06-18 16:00:00'


zeit = df.loc[(df['DateTime'] > start_date) & (df['DateTime'] <= end_date)]

ax = zeit.plot(figsize=(15, 10), x="DateTime", y=["FromGen", "ToCons"])

ax.set_xlabel("Zeit") ax.set_ylabel("Wh") legend = ax.legend(title="comp",
                   loc='upper right', fontsize='large', fancybox=True, labels=['FromGen', 'ToCons']) ax.axvline(x=x0, color='red') ax.axvline(x=x1, color='red')

x0 = datetime_obj.replace(tzinfo=timezone('UTC'))

ax.fill_between(zeit['DateTime'].values, zeit['FromGen'], zeit['ToCons'],
                where=((zeit['FromGen'] > zeit['ToCons']) & ((zeit['DateTime'] <= x0) | (zeit['DateTime'] >=x1))),
                interpolate=False, color='#8FF536') plt.show()

Upvotes: 2

Views: 238

Answers (1)

JohanC
JohanC

Reputation: 80574

Working with dates has evolved a lot in the last pandas and matplotlib versions. Therefore, referring to old posts can be misleading. The following code has been tested with matplotlib 3.4.1 and pandas 1.2.4.

Something strange in the code of the question, is that first x0 and x1 are used, and thereafter x1 and x2 without giving a value to x2.

plt.fill_between() can work directly with the numerical columns. To work with the datatime column, now it is happy with ...['DateTime'].values. For the where clause, to compare the datetime column, the x0 and x1 need to be converted with pd.to_datetime(...). As the datetime values in my example don't have utc, the comparison doesn't work when using x0 = pd.to_datetime(..., utc=True).

Also note that pandas plotting (zeit.plot(...)) returns a matplotlib ax.

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

start_date = "2019-06-18"
end_date = "2019-06-19"

x0 = '2019-06-18 9:00:00'
x1 = '2019-06-18 17:00:00'

N = 200
df = pd.DataFrame({'DateTime': pd.date_range(start_date, freq='10min', periods=N),
                   'FromGen': 8 * np.exp(-(np.arange(N) - 80) ** 2 / 1000) + np.random.uniform(0, 0.4, N),
                   'ToCons': np.random.uniform(1, 1.5, N)})

x0 = pd.to_datetime(x0, format="%Y-%m-%d")
x1 = pd.to_datetime(x1, format="%Y-%m-%d")

zeit = df.loc[(df['DateTime'] > start_date) & (df['DateTime'] <= end_date)]

ax = zeit.plot(figsize=(15, 10), x="DateTime", y=["FromGen", "ToCons"])

ax.set_xlabel("Zeit")
ax.set_ylabel("Wh")
legend = ax.legend(title="comp",
                   loc='upper right', fontsize='large', fancybox=True, labels=['FromGen', 'ToCons'])
ax.axvline(x=x0, color='red')
ax.axvline(x=x1, color='red')

ax.fill_between(zeit['DateTime'].values, zeit['FromGen'], zeit['ToCons'],
                where=(zeit['FromGen'] > zeit['ToCons']) & ((zeit['DateTime'] <= x0) | (zeit['DateTime'] >= x1)),
                interpolate=False, color='#8FF536')
plt.show()

fill_between with pandas datetime

Upvotes: 2

Related Questions