I have set the following xlim on my x axis:
axA.set_xlim(datetime.date(2016, 12, 1), datetime.date(2018, 1, 30))
and now I would like to get the position of the 12th of October (2017-10-12) on my X axis, so that I can then put an annotation there.
I tried to figure that out the using date2num and datestr2num:
release_date = datetime.datetime(2017, 10, 12)
print(mdates.date2num(release_date))
print(mdates.datestr2num('2017-10-12'))
print(axA.get_xlim())
The above code output:
-736614.0
736614.0
(17136.0, 17561.0)
First it seems like date2num and datestr2num don't give an identical result, but more problematically, those results are not within the range of xlim.
How can I find the X position of a date (to place an annotation), given the xlim I set above?
Code to reproduce the problem:
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime
def get_dataframe():
values = [12, 16, 20]
dates = [
datetime(2017, 12, 24),
datetime(2017, 12, 23),
datetime(2017, 12, 22)
]
df = pd.DataFrame(data={'date': dates, 'value': values})
df = df.set_index(['date']).sort_index()
return df
def plot(dataA):
fig, axA = plt.subplots()
dataA.plot(ax=axA)
axA.set_xlim(datetime(2016, 12, 1), datetime(2018, 1, 30))
release = datetime(2017, 10, 12)
print(mdates.date2num(release))
print(mdates.datestr2num('2017-10-12'))
print(axA.get_xlim())
df = get_dataframe()
plot(df)
plt.show()
You can use a date object directly if you have a date xaxis:
ax.annotate('hello', xy=(datetime.datetime(2017, 10, 12), 1),
xytext=(datetime.datetime(2017, 10, 12), 5),
arrowprops={'facecolor': 'r'})
Related
I have a numpy array which contains hours from 4 days:
s = np.array([0.0, 1.0, 2.0, 3.0, 4.0 ....96.0])
I want to create a datetime object from that.
I know that the first element is at timestamp 2021-03-21 00:00,
so:
start_date = datetime.datetime.strptime('2021-03-21 00:00', '%Y-%m-%d %H:%M')
How can I create a new array which contains datetimes, incremented by an hour from the s array.
Use timedelta to build your new array:
>>> import numpy as np
>>> from datetime import datetime, timedelta
>>> s = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 96.0])
>>> start_date = datetime.strptime('2021-03-21 00:00', '%Y-%m-%d %H:%M')
>>> [start_date + timedelta(hours=diff) for diff in s]
[datetime.datetime(2021, 3, 21, 0, 0), datetime.datetime(2021, 3, 21, 1, 0), datetime.datetime(2021, 3, 21, 2, 0), datetime.datetime(2021, 3, 21, 3, 0), datetime.datetime(2021, 3, 21, 4, 0), datetime.datetime(2021, 3, 25, 0, 0)]
These codes produce a chart
import numpy as np
import matplotlib.pyplot as plt
N = 5
menMeans = (20, 35, 30, 35, 27)
womenMeans = (25, 32, 34, 20, 25)
menStd = (2, 3, 4, 1, 2)
womenStd = (3, 5, 2, 3, 3)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars: can also be len(x) sequence
p1 = plt.bar(ind, menMeans, width, yerr=menStd)
p2 = plt.bar(ind, womenMeans, width,
bottom=menMeans, yerr=womenStd)
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
plt.yticks(np.arange(0, 81, 10))
plt.legend((p1[0], p2[0]), ('Men', 'Women'))
Jupyter notebook automatically print the chart, even I didn't call plt.show(). I don't want to show the chart in the same cell with the code but the next cell by running a really short code such as plt.show(). In order to keep the cell as concise as possible.
Just enclose all your plot-related statements inside a function called plot_and_show(). Then you can call the function when you are ready.
import matplotlib.pyplot as plt
import numpy as np
N = 5
menMeans = (20, 35, 30, 35, 27)
womenMeans = (25, 32, 34, 20, 25)
menStd = (2, 3, 4, 1, 2)
womenStd = (3, 5, 2, 3, 3)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars: can also be len(x) sequence
def plot_and_show():
p1 = plt.bar(ind, menMeans, width, yerr=menStd)
p2 = plt.bar(ind, womenMeans, width,
bottom=menMeans, yerr=womenStd)
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
plt.yticks(np.arange(0, 81, 10))
plt.legend((p1[0], p2[0]), ('Men', 'Women'))
plot_and_show()
I have the following code that plots COVID-19 confirmed cases country-wise against some dates.
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
df = pd.DataFrame({'Countries': ['Australia', 'India', 'UAE', 'UK'],
'3/1/20': [ 27, 3, 21, 36],
'3/2/20': [ 30, 5, 21, 40],
'3/3/20': [ 39, 5, 27, 51],
'3/4/20': [ 52, 28, 27, 86],
},
index = [0, 1, 2, 3])
print('Datframe:\n')
print(df)
dft=df.T
print('\n Transposed data:\n')
print(dft)
print(dft.columns)
dft.columns=dft.iloc[0]
dft=dft[1:]
print('\n Final data:\n')
print(dft)
dft.plot.bar(align='center')
# Set date ticks with 2-day interval
plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=2))
# Change date format
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%d-%m-%Y'))
''' Note: If I comment above two lines, I get back x-axis ticks. '''
# Autoformatting dates ticks
plt.gcf().autofmt_xdate()
plt.title('COVID-19 confirmed cases')
plt.show()
Here I intended to show the dates on the x-axis ticks with 2-day intervals and get the dates formatted in a different style. However, in the plot, I don't get any ticks and labels on the x-axis as shown in the figure below.
However, when I comment out the instructions with matplotlib.dates, I get back the x-ticks and labels.
Can this be explained and fixed in a simple way? Also, can we get the same result using fig, ax = plt.subplots()?
You were almost there. All you need to do is to restructure your dataframe. index the date. One way to do this is as follows;
Data
df = pd.DataFrame({'Countries': ['Australia', 'India', 'UAE', 'UK'],
'3/1/20': [ 27, 3, 21, 36],
'3/2/20': [ 30, 5, 21, 40],
'3/3/20': [ 39, 5, 27, 51],
'3/4/20': [ 52, 28, 27, 86],
},
index = [0, 1, 2, 3])
df2=df.set_index('Countries').T.unstack().reset_index()
df2#.plot(kind='bar')
df2.columns=['Countries','Date','Count']
df2['Date']=pd.to_datetime(df2['Date'])
df2.dtypes
Coarce date to datetime
df2.set_index('Date', inplace=True)
Groupby date, countries and unstack before plotting
df2.groupby([df2.index.date,df2['Countries']])['Count'].sum().unstack().plot.bar()
Outcome
I'm trying to get the X position of a date on my X axis (made of datetimes).
My X axis is the dates between December 2016 and January 2018:
axA.set_xlim(datetime(2016, 12, 1), datetime(2018, 1, 30))
print(axA.get_xlim())
output >> (17136.0, 17561.0)
I would like to place an annotation on the 12th of October, and for that I need to know the position of that date on the axis. I read the docs and tried doing it in two different ways:
release = datetime(2017, 10, 12)
print(mdates.date2num(release))
print(mdates.datestr2num('2017-10-12'))
output >> 736614.0
output >> 736614.0
The value returned by date2num and datestr2num is not within the range of my X axis ((17136.0, 17561.0), see above), despite the date provided clearly being within the range.
Minimal code to reproduce the problem:
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime
def get_dataframe():
values = [12, 16, 20]
dates = [
datetime(2017, 12, 24),
datetime(2017, 12, 23),
datetime(2017, 12, 22)
]
df = pd.DataFrame(data={'date': dates, 'value': values})
df = df.set_index(['date']).sort_index()
return df
def plot(dataA):
fig, axA = plt.subplots()
dataA.plot(ax=axA)
axA.set_xlim(datetime(2016, 12, 1), datetime(2018, 1, 30))
release = datetime(2017, 10, 12)
print(mdates.date2num(release))
print(mdates.datestr2num('2017-10-12'))
print(axA.get_xlim())
df = get_dataframe()
plot(df)
plt.show()
NB: I just noticed that setting the xlim before plotting the data appears to return the date in the given range, but then my graph starts in January year 3986!
I'm using:
$ python --version
Python 3.6.3
$ pip freeze | grep matplot
matplotlib==2.1.1
thanks to a LOT of help from overflowers I have FINALLY got formatted dates on my plot HOORAY!! BUT now there are too many of them! Can anyone see why please? I have only included the relevant list being plotted not the code.
here is the x_list
x_list [datetime.date(2015, 8, 4), datetime.date(2015, 8, 5), datetime.date(2015, 8, 6), datetime.date(2015, 8, 7)]
here's the format
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
here's the plot
It would be easier to answer if you had included your code but I think this should fix it. You just need to specify what ticks should be included, using set_ticks():
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import datetime
x_list = [datetime.date(2015, 8, 4), datetime.date(2015, 8, 5), datetime.date(2015, 8, 6), datetime.date(2015, 8, 7)]
y = [5, 7, 3, 9] # just an example
fig = plt.figure()
ax = fig.add_subplot(111)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
ax.plot(x_list, y)
ax.xaxis.set_ticks(x_list)
plt.show()