Issue
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!
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()
Solution
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()
Answered By - JohanC
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.