Reputation: 551
Using matplotlib I'd like to create a graph in which all date values from my dataframe (df) are shown on the x axis. In principle, the code line plt.gca().xaxis.set_major_locator(matplotlib.dates.DayLocator(interval=1))
should do the job but it doesn't, probably because I'm using a custom formatter!? The custom formatter is required here because I'd prevent matplotlib from interpolating weekend date values which are not part of my dataframe (have a look at this question here).
Also I'd like to use the date format '%d.%m.%Y'.
While the code works with matplotlib 3.3.3/Python 3.8, I have to use matplotlib 3.2.2/Python 3.6 for my project, and under these conditions, the code does not return the desired output
Here is the code:
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import Formatter
import pandas as pd
import numpy as np
df = pd.DataFrame(data={"col1": [1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979,
1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979],
"date": ['2018-01-08', '2018-01-09', '2018-01-10', '2018-01-11', '2018-01-12',
'2018-01-15', '2018-01-16', '2018-01-17', '2018-01-18', '2018-01-19',
'2018-01-22', '2018-01-23', '2018-01-24', '2018-01-25',]})
df["date"] = pd.to_datetime(df["date"])
class CustomFormatter(Formatter):
def __init__(self, dates, fmt='%d.%m.%Y'):
self.dates = dates
self.fmt = fmt
def __call__(self, x, pos=0):
'Return the label for time x at position pos'
ind = int(np.round(x))
if ind >= len(self.dates) or ind < 0:
return ''
return self.dates[ind].strftime(self.fmt)
fig = plt.figure()
plt.gca().xaxis.set_major_formatter(CustomFormatter(df["date"]))
plt.plot(np.arange(df.shape[0]), df["col1"])
plt.gcf().autofmt_xdate()
#plt.gca().xaxis.set_major_locator(matplotlib.dates.DayLocator(interval=1)) # <-- this line should do the job, in theory!
Output with matplotlib 3.2.2
Expected output (matplotlib 3.3.3)
Thank you for your help!
Upvotes: 1
Views: 2491
Reputation: 5932
I think you should just use the date tools, but make sure you are actually plotting a date, not np.arange(df.shape[0])
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
df = pd.DataFrame(data={"col1": [1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979,
1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979],
"date": ['2018-01-08', '2018-01-09', '2018-01-10', '2018-01-11', '2018-01-12',
'2018-01-15', '2018-01-16', '2018-01-17', '2018-01-18', '2018-01-19',
'2018-01-22', '2018-01-23', '2018-01-24', '2018-01-25',]})
df["date"] = pd.to_datetime(df["date"])
fig, ax = plt.subplots()
ax.xaxis.set_major_locator(matplotlib.dates.DayLocator(interval=1))
ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%d.%m.%Y'))
ax.plot(df["date"], df["col1"])
fig.autofmt_xdate()
plt.show()
Upvotes: 2
Reputation: 12410
Since you do not plot against dates but against an index, the DateLocator
might be the wrong choice here:
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import Formatter, FixedLocator
import pandas as pd
import numpy as np
df = pd.DataFrame(data={"col1": [1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979,
1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979],
"date": ['2018-01-08', '2018-01-09', '2018-01-10', '2018-01-11', '2018-01-12',
'2018-01-15', '2018-01-16', '2018-01-17', '2018-01-18', '2018-01-19',
'2018-01-22', '2018-01-23', '2018-01-24', '2018-01-25',]})
df["date"] = pd.to_datetime(df["date"])
class CustomFormatter(Formatter):
def __init__(self, dates, fmt='%d.%m.%Y'):
self.dates = dates
self.fmt = fmt
def __call__(self, x, pos=0):
'Return the label for time x at position pos'
ind = int(np.round(x))
if ind >= len(self.dates) or ind < 0:
return ''
return self.dates[ind].strftime(self.fmt)
fig = plt.figure()
plt.plot(np.arange(df.shape[0]), df["col1"])
plt.gca().xaxis.set_major_locator(FixedLocator(np.arange(df.shape[0])))
plt.gca().xaxis.set_major_formatter(CustomFormatter(df["date"]))
plt.gcf().autofmt_xdate()
#print(matplotlib.__version__)
plt.show()
Output:
But since you plot against the index anyhow, you would not need the class definition:
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import FixedLocator
import pandas as pd
import numpy as np
df = pd.DataFrame(data={"col1": [1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979,
1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979],
"date": ['2018-01-08', '2018-01-09', '2018-01-10', '2018-01-11', '2018-01-12',
'2018-01-15', '2018-01-16', '2018-01-17', '2018-01-18', '2018-01-19',
'2018-01-22', '2018-01-23', '2018-01-24', '2018-01-25',]})
df["date"] = pd.to_datetime(df["date"])
fig = plt.figure()
plt.plot(np.arange(df.shape[0]), df["col1"])
plt.gca().xaxis.set_major_locator(FixedLocator(np.arange(df.shape[0])))
plt.xticks(np.arange(df.shape[0]), df["date"].dt.strftime("%d.%m.%Y"))
plt.gcf().autofmt_xdate()
#print(matplotlib.__version__)
plt.show()
Output: see above
Upvotes: 1
Reputation: 11532
A possible solution to your problem, that does not involve classes is to do this (obs! All the imports might not be necessary):
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.ticker as ticker
import seaborn as sns
from IPython.display import display
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
from matplotlib.lines import Line2D
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=[30,30])
gs = gridspec.GridSpec(100,100)
ax21 = fig.add_subplot(gs[0:100,0:100])
a = df['col1']
ax21 = sns.lineplot(x=df['date'], y=df['col1'].values, palette="Reds", ax=ax21)
ax21.set_xlabel('whatever', c='w', fontsize=16)
ax21.set_ylabel('Other ever', c='w', fontsize=16)
ax21.set_title('This is it', c='w', fontsize=20, weight = 'bold')
plt.show()
Upvotes: 1