Formatting X axis with dates format Matplotlib - python

I have written code which plots the past seven day stock value for a user-determined stock market over time.
The problem I have is that I want to format the x axis in a YYMMDD format.
I also don't understand what 2.014041e7 means at the end of the x axis.
Values for x are:
20140421.0, 20140417.0, 20140416.0, 20140415.0, 20140414.0, 20140411.0, 20140410.0
Values for y are:
531.17, 524.94, 519.01, 517.96, 521.68, 519.61, 523.48
My code is as follows:
mini = min(y)
maxi = max(y)
minimum = mini - 75
maximum = maxi + 75
mini2 = int(min(x))
maxi2 = int(max(x))
plt.close('all')
fig, ax = plt.subplots(1)
pylab.ylim([minimum,maximum])
pylab.xlim([mini2,maxi2])
ax.plot(x, y)
ax.plot(x, y,'ro')
ax.plot(x, m*x + c)
ax.grid()
ax.plot()

When plotting your data using your method you are simply plotting your y data against numbers (floats) in x such as 20140421.0 (which I assume you wish to mean the date 21/04/2014).
You need to convert your data from these floats into an appropriate format for matplotlib to understand. The code below takes your two lists (x, y) and converts them.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime as dt
# Original data
raw_x = [20140421.0, 20140417.0, 20140416.0, 20140415.0, 20140414.0, 20140411.0, 20140410.0]
y = [531.17, 524.94, 519.01, 517.96, 521.68, 519.61, 523.48]
# Convert your x-data into an appropriate format.
# date_fmt is a string giving the correct format for your data. In this case
# we are using 'YYYYMMDD.0' as your dates are actually floats.
date_fmt = '%Y%m%d.0'
# Use a list comprehension to convert your dates into datetime objects.
# In the list comp. strptime is used to convert from a string to a datetime
# object.
dt_x = [dt.datetime.strptime(str(i), date_fmt) for i in raw_x]
# Finally we convert the datetime objects into the format used by matplotlib
# in plotting using matplotlib.dates.date2num
x = [mdates.date2num(i) for i in dt_x]
# Now to actually plot your data.
fig, ax = plt.subplots()
# Use plot_date rather than plot when dealing with time data.
ax.plot_date(x, y, 'bo-')
# Create a DateFormatter object which will format your tick labels properly.
# As given in your question I have chosen "YYMMDD"
date_formatter = mdates.DateFormatter('%y%m%d')
# Set the major tick formatter to use your date formatter.
ax.xaxis.set_major_formatter(date_formatter)
# This simply rotates the x-axis tick labels slightly so they fit nicely.
fig.autofmt_xdate()
plt.show()
The code is commented throughout so should be easily self explanatory. Details on the various modules can be found below:
datetime
matplotlib.dates

Related

Matplotlib dates.DateFormatter forcing the display of nanoseconds

I encounter an issue with Matplotlib.dates.DateFormatter :
I want to convert timestamps in Date format which is simple usually with the straftime but when using it on matplotlib i don't have the dynamic position on my graph so I used the md.DateFormatter('%H:%M:%S.%f') to have the X values as a date format with the dynamic index.
The fact is, my dates have too much values, I don't want the nanoseconds but I don't know how to remove them. I searched on StackOverflow to find a solution but applying a date[:-3] won't work as I have a datetime format...
Do you have a solution? It's maybe trivial but can't find any solution right now...
Thanks in advance.
NB : What I call the dynamic index is when you are on the graph and you can see the exact X and Y value of your pointer at the bottom
Here is an applicable example :
df =
timestamp val
0 2022-03-13 03:19:59.999070 X1
1 2022-03-13 03:20:00.004070 X2
2 2022-03-13 03:20:00.009070 X3
3 2022-03-13 03:20:00.014070 X4
And I try to plot this with :
ax=plt.gca()
xfmt = md.DateFormatter('%H:%M:%S.%f')
ax.xaxis.set_major_formatter(xfmt)
plt.plot(df.timestamp, df.val, linestyle="-", marker = ".")
plt.setp(ax.get_xticklabels(), rotation=40)
plt.show()
In conclusin, what I want is to remove the 070 in the graph but if I remove it beforehand, DateFormatter will replace it by 000 which is as useless as it was..
If you want to change both the tick labels and the format of the number shown on the interactive status bar, you could define your own function to deliver your desired format, then use a FuncFormatter to display those values on your plot.
For example:
import matplotlib.pyplot as plt
import matplotlib.dates as md
import pandas as pd
# dummy data
ts = pd.date_range("2022-03-13 03:19:59.999070",
"2022-03-13 03:20:00.014070", periods=4)
df = pd.DataFrame({'timestamp': ts, 'val':[0, 1, 2, 3]})
fig, ax = plt.subplots()
# define our own function to drop the last three characters
xfmt = lambda x, pos: md.DateFormatter('%H:%M:%S.%f')(x)[:-3]
# use that function as the major formatter, using FuncFormatter
ax.xaxis.set_major_formatter(plt.FuncFormatter(xfmt))
plt.setp(ax.get_xticklabels(), rotation=40)
ax.plot(df.timestamp, df.val, linestyle="-", marker = ".")
plt.tight_layout()
plt.show()
Note the matching tick format and status bar format.
If, however, you do not want to change the tick labels, but only change the value on the status bar, we can do that by reassigning the ax.format_coord function, using the a similar idea for the function we defined above, but also adding in the y value for display
For example:
import matplotlib.pyplot as plt
import matplotlib.dates as md
import pandas as pd
# dummy data
ts = pd.date_range("2022-03-13 03:19:59.999070",
"2022-03-13 03:20:00.014070", periods=4)
df = pd.DataFrame({'timestamp': ts, 'val':[0, 1, 2, 3]})
fig, ax = plt.subplots()
xfmt = md.DateFormatter('%H:%M:%S.%f')
xfmt2 = lambda x, y: "x={}, y={:g}".format(xfmt(x)[:-3], y)
# use original formatter here with microseconds
ax.xaxis.set_major_formatter(plt.FuncFormatter(xfmt))
# and the millisecond function here
ax.format_coord = xfmt2
plt.setp(ax.get_xticklabels(), rotation=40)
ax.plot(df.timestamp, df.val, linestyle="-", marker = ".")
plt.tight_layout()
plt.show()
Note the difference between the status bar and the tick formats here.

Display only time on axis with matplotlib.plot_dates

So I've spent some time managing to plot data using time on the x-axis, and the way I've found to do that is to use matplotlib.plot_date after converting datetime objects to pltdates objects.
X_d = pltdates.date2num(X) # X is an array containing datetime objects
(...)
plt.plot_date(X_d, Y)
It works great, all my data is plotted properly.
Plot with dates appearing on x-axis
However, all the measures I want to plot were made the same day (17/12/2021), the only difference is the time.
As shown on the image, matplotlib still displays the number of the the day (17th) although it is the same within the whole plot.
Anyone has a clue how to keep only the time, still using matplotlib.plot_date?
Use this example:
import matplotlib
import matplotlib.pyplot as plt
from datetime import datetime
origin = ['2020-02-05 04:11:55',
'2020-02-05 05:01:51',
'2020-02-05 07:44:49']
a = [datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in origin]
b = ['35.764299', '20.3008', '36.94704']
x = matplotlib.dates.date2num(a)
formatter = matplotlib.dates.DateFormatter('%H:%M')
figure = plt.figure()
axes = figure.add_subplot(1, 1, 1)
axes.xaxis.set_major_formatter(formatter)
plt.setp(axes.get_xticklabels(), rotation=15)
axes.plot(x, b)
plt.show()

Using matplotlib limit the frequency of the x ticks

I'm having trouble limiting the number of dates on the x-axis to make them legible. I need to plot the word length vs the year but the number of years is too large for the plot size.
The Issue:
Any help is appreciated.
As mentioned in the comments, use datetime (if your dates are in string format, you can easily convert them to datetime). Once you do that it should automatically display years along the x-axis. If you need to change the frequency of ticks to every year (or anything else), you can use mdates, like so:
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import datetime
import math
start = datetime.datetime.strptime("01-01-2000", "%d-%m-%Y")
end = datetime.datetime.strptime("10-04-2019", "%d-%m-%Y")
x = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]
y = [math.sqrt(x) for x in range(len(x))]
fig, ax = plt.subplots()
ax.plot(x, y)
ax.xaxis.set_major_locator(mdates.YearLocator())
fig.autofmt_xdate()
plt.show()
The snippet above generates the following:

Showing entire X Axis Ticks in Graph

I'm trying to have the tick labels of my Graph displayed fully, but I'm not getting the desired result, despite my efforts.
If I merely use autofmt_xdate(), the dates are correctly shown, but not for every data point plotted; however, if I force my x tick labels to be displayed by passing x by datetime objects to xtick(), It only seems to display the year.
fig1 = plt.figure(1)
# x is a list of datetime objects
plt.title('Portfolio Instruments')
plt.subplot(111)
plt.plot(x, y)
plt.xticks(fontsize='small')
plt.yticks([i * 5 for i in range(0, 15)])
fig1.autofmt_xdate()
plt.show()
Graph passing x to plt.xticks():
Graph without passing x to plt.xticks()
Where's my mistake? I can't find it.
Question
How do I plot all of my data points of x and format it to show the entire datetime object I'm passing the graph using autofmt_xdate()?
I have a list of datetime objects which I want to pass as the x values of my plot.
Pass the dates you want ticks at to xticks, and then set the major formatter for the x axis, using plt.gca().xaxis.set_major_formatter:
You can then use the DateFormatter from matplotlib.dates, and use a strftime format string to get the format in your question:
import matplotlib.dates as dates
fig1 = plt.figure(1)
# x is a list of datetime objects
plt.title('Portfolio Instruments')
plt.subplot(111)
plt.plot(x, y)
plt.xticks(x,fontsize='small')
plt.gca().xaxis.set_major_formatter(dates.DateFormatter('%b %d %Y'))
plt.yticks([i * 5 for i in range(0, 15)])
fig1.autofmt_xdate()
plt.show()
Note: I created the data for the above plot using the code below, so x is just a list of datetime objects for each weekday in a month (i.e. without weekends).
import numpy as np
from datetime import datetime,timedelta
start = datetime(2016, 1, 1)
end = datetime(2016, 2, 1)
delta = timedelta(days=1)
d = start
weekend = set([5, 6])
x = []
while d <= end:
if d.weekday() not in weekend:
x.append(d)
d += delta
y = np.random.rand(len(x))*70
I'm pretty sure I had a similar problem, and the way I solved it was to use the following code:
def formatFig():
date_formatter = DateFormatter('%H:%M:%S') #change the format here to whatever you like
plt.gcf().autofmt_xdate()
ax = plt.gca()
ax.xaxis.set_major_formatter(date_formatter)
max_xticks = 10 # sets the number of x ticks shown. Change this to number of data points you have
xloc = plt.MaxNLocator(max_xticks)
ax.xaxis.set_major_locator(xloc)
def makeFig():
plt.plot(xList,yList,color='blue')
formatFig()
makeFig()
plt.show(block=True)
It is a pretty simple example but you should be able to transfer the formatfig() part to use in your code.

Precision plotting in time axis

I have a trouble plotting data, I only want plot HH:MM:SS but the plot shows HH:MM:SS.sssss or HH:MM:SS.%f. Below i gonna detail what I did (matplotlib, numpy are already imported )
Method I
Loading files to plot
import datetime as dt
data=genfromtxt('27JAN12.K7O', delimiter=2*[4]+5*[2]+8*[7])
f245 = data[:, 7]
Generating array for time (1 data per second)
base = dt.datetime(2014,1,27,11,07,59)
time = array([base + dt.timedelta(seconds=i) for i in range(len(data))])
plot(time,f245)
When i did this, i got this plot (with innecesary precision)
here i got time like 18:15:00.000000 (i just like 18:15:00)
Method II
The same way to load data, in this case only I took the time of the data and coverted in time string
t = data[:,1] #in decimals e.g. 18,5 represents 18:30:00
tstr = map(str, [dt.timedelta(seconds=x) for x in t])
time = []
for i in tstr:
try:
time.append(dt.datetime.strptime(i, "%H:%M:%S"))
except ValueError:
time.append(dt.datetime.strptime(i, "%H:%M:%S.%f"))
plot(time,f245)
In this case, i got time like 18:15:00.%f
So, how i could repair this?
You should use plot_date to plot datetime objects using matplotlib.
You can use matplotlib.dates.date2num to convert the datetime objects into the matplotlib format.
Furthermore you can use DateFormatter objects to set the formatting of the x-axis tick labels.
I have now included a small example using generated data, hopefully this will explain everything for you.
import numpy as numpy
import matplotlib.pyplot as plt
from matplotlib.dates import date2num, DateFormatter
import datetime as dt
base = dt.datetime(2014, 1, 27, 11, 7, 59)
x = [base + dt.timedelta(seconds=i) for i in range(10)]
y = [i**2 for i in range(10)]
x = date2num(x) # Convert datetime objects to the correct format for matplotlib.
fig, ax = plt.subplots()
ax.plot_date(x, y) # Use plot_date rather than plot
# Set the xaxis major formatter as a DateFormatter object
# The string argument shows what format you want (HH:MM:SS)
ax.xaxis.set_major_formatter(DateFormatter('%H:%M:%S'))
# This simply makes them look pretty by setting them diagonal.
fig.autofmt_xdate()
plt.show()

Categories

Resources