Plot a vertical line using datetime.time and axvline - python

I am trying to use the axvline function to plot datetime.time values and seeing this error. please help.
Here is the code:
import datetime as dt
from datetime import datetime
import matplotlib.pyplot as plt
i='wpt'
x = [datetime.time(12,10), datetime.time(12, 15)]
fig, axs = plt.subplots(3, sharex = True, figsize = (12,9), constrained_layout = True)
axs[i].axvline(x[0], color = 'lightskyblue', ls = '--', lw = 1)
When i run the code, i get the following error
TypeError: '>' not supported between instances of 'float' and 'datetime.time'
I checked online and found no solution that uses axvline with datetime.time

matplotlib expects a numeric x coordinate, not a datetime object.
You need to convert the time to a number, e.g. by using the matplotlib.dates.date2num function:
import matplotlib.dates as mdates
axs[i].axvline(mdates.date2num(datetime.combine(date.today(), x[0])), ...)
This will convert the time to a floating point number representing the number of days since January 1, 0001. Matplotlib will then use its date plotting machinery to format the axis appropriately.
Note that I used datetime.combine here to convert the time into a full datetime object by adding today's date.

Related

How to set datetime as zaxis without error: OverflowError: Python int too large to convert to C long for 3D plot

I am trying to plot a 3D image where z is time.
When I try to set the zaxis label to Year, month I receive an error.
For this:
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.scatter3D(df85['Messwert'], df85['average_cux'], df85['Datum'],c=df85['code'], cmap="jet_r")
ax.zaxis.set_major_formatter(dates.DateFormatter('%Y-%M'))
I got this error:
OverflowError: Python int too large to convert to C long
<Figure size 432x288 with 1 Axes>
Without the set zaxis code I get this image:
Thanks in advance!!!
at bottom of 'Datum':
Name: Datum, Length: 81, dtype: object
The overflow error occurs because Matplotlib's DateFormatter fails to plot np.datetime64 data directly, which should be the case with your data. You need to explicitly convert your dates to datetime.date objects.
Please have a look at this :
https://matplotlib.org/3.1.1/gallery/recipes/common_date_problems.html
The overflow error occurs because Matplotlib's DateFormatter fails to plot np.datetime64 data directly, which should be the case with your data. You need to explicitly convert your dates to datetime.date objects.
Please have a look at this :
https://matplotlib.org/3.1.1/gallery/recipes/common_date_problems.html
Edit :
This might be useful to you.
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.dates import date2num, DateFormatter
import numpy as np
import pandas as pd
from mpl_toolkits.mplot3d import Axes3D
from datetime import datetime, timedelta
# a test dataframe
df = pd.DataFrame({
'date': np.array([str(datetime(2020,3,30).date()+timedelta(x+1))+' 00:00:00' for x in range(200)], dtype='object'),
'sales': np.random.randint(low=1, high=200, size=200),
'%sales in US' : 30 * np.random.random_sample(size=200) + 20
})
# appropriate type conversions
df['date']= pd.to_datetime(df['date'])
df['date'] = df['date'].apply(date2num)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.scatter3D(df['sales'], df['%sales in US'], df['date'], c=df['date'], cmap="jet_r")
ax.zaxis.set_major_formatter(matplotlib.dates.DateFormatter('%Y-%M'))
plt.xlabel('sales', fontsize=20)
plt.ylabel('%sales in US', fontsize=16)
ax.set_zlabel('date', fontsize=16)
plt.show()
Output : https://imgur.com/a/WXM07it.jpg

Plotting dates with matplotlib

I've been attempting to plot data from a comma delimited csv file which contains a date and a float:
Date,Price (€)
01062017,20.90
02062017,30.90
03062017,40.90
04062017,60.90
05062017,50.90
I then attempt to plot this with the following code:
import matplotlib.pyplot as plt
import numpy as np
import datetime
dates,cost = np.loadtxt('price_check.csv',delimiter=',',skiprows=1,unpack=True)
xdates = [datetime.datetime.strptime(str(int(date)),'%d%m%Y') for date in dates]
fig = plt.figure()
ax = plt.subplot(111)
plt.plot(xdates, cost,'o-',label='Cost')
plt.legend(loc=4)
plt.ylabel('Price (Euro)')
plt.xlabel('date')
plt.gcf().autofmt_xdate()
plt.grid()
plt.savefig('sunglasses_cost.png')
plt.show()
However, when the data is plotted, it looks like the leading zero in in the date string is being dropped:
Is there an easy way for the full date to be used in the plot?
The problem are the dates, which are converted to integers and loose their leading zero. Then
"01062017" becomes 1062017 and is then interpreted as (2017, 6, 10, 0, 0), so 2 digits as day, one digit month. For 5062017, because there is no 50th of june, it is interpreted differently and correctly as (2017, 6, 5, 0, 0).
The least invasive method to overcome this would be to format the string such that it always has 8 digist before datetime conversion:
xdates = [datetime.datetime.strptime('{:08}'.format(int(date)),'%d%m%Y') for date in dates]
This will then result in the correct plot. However, the xticklabels may show in an inconvenient way. This could be adjusted by choosing some locator and formatter
import matplotlib.dates as mdates
plt.gca().xaxis.set_major_locator(mdates.DayLocator())
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%d-%m-%Y'))
As a last comment: If you have the choice to select the format of your input file, it might be worth specifing it in a non-ambiguous way, e.g. 20170601.

Using datetime in Python

I have an amount of times written in the format hh:mm:ss, if I use the code below and print what x is I get 1900, 1, 1, 10, 29, 34 for every timestamp. How can I take away the year, month and date? As I want to have the time in the format hh:mm:ss
EDIT: Updated with the whole code as it looks now with help from comments.
import matplotlib.pyplot as plt
import matplotlib.ticker
import time
import datetime
x = ['10:29:55', '10:34:44']
sy1 = [679.162, 679.802]
x_labels = [datetime.datetime.strptime(elem, '%H:%M:%S') for elem in x]
formatter = matplotlib.ticker. FixedFormatter(x_labels)
plt.gca().xaxis.set_major_formatter(formatter)
plt.gca().xaxis.set_minor_formatter(formatter)
plt.plot(x_labels, sy1, 'ro')
plt.xlabel('Time')
plt.ylabel('Position')
plt.show()
But obviously it displays the time when taking into account the year, month and date too.
Plotting (wrong) time against y values
If I use strftime instead of strptime I get a TypeError: descriptor 'strftime' requires a 'datetime.date' object but received a 'str'
Ok. There are a few ways to get what you want.
If you're willing to settle for having microseconds, you should be really close to what you need:
import matplotlib.pyplot as plt
import datetime
time_strings = ['10:29:55', '10:34:44']
sy1 = [679.162, 679.802]
times = [datetime.datetime.strptime(elem, '%H:%M:%S') for elem in time_strings]
plt.plot(times, sy1, 'ro')
plt.xlabel('Time')
plt.ylabel('Position')
plt.show()
This should show the times you want in a plot, just with microseconds in the formatting. The microseconds make it all ugly, but my only changes were ones for clarity - I didn't import time or import matplotlib.ticker, I changed your x to a more accurate variable name, and created the datetimes as you did. To get rid of the microseconds, things get uglier. You can't just use the FixedFormatter because we only set 2 values, and the standard plot has more than 2 ticks; you have to find a way to get the FuncFormatter to work. This works as desired, but is still too noisy, so I'm adding in the plt.gcf().autofmt_xdate() as well.
import matplotlib.pyplot as plt
import matplotlib.ticker
import datetime
import pylab
time_strings = ['10:29:55', '10:34:44']
sy1 = [679.162, 679.802]
times = [datetime.datetime.strptime(elem, '%H:%M:%S') for elem in time_strings]
plt.plot(times, sy1, 'ro')
formatter = matplotlib.ticker.FuncFormatter(lambda tick_value, _: datetime.datetime.strftime(pylab.num2date(tick_value), '%H:%M:%S'))
plt.gca().xaxis.set_major_formatter(formatter)
plt.gca().xaxis.set_minor_formatter(formatter)
plt.xlabel('Time')
plt.ylabel('Position')
plt.gcf().autofmt_xdate()
plt.show()
The line defining the FuncFormatter is messy. I define a lambda, which is a function defined on a single line. FuncFormatter expects it to take 2 arguments. The first one is the tick_value, and we don't really care what the second one is, so I gave it the standard variable name of _ to show we don't care. The tick values are datetimes or timestamps. The way we get from the tick value to a datetime is by calling pylab.num2date.
You'll find that this second solution is just what you need. The key thing you needed to do was keep track of what your variable types were, and what variable types were needed where.

Formatting of Dates in Python with matplotlib and datetime: x axis error - float

I try to plot a graph with a set of data. The y-axis is no problem, it's simple floats.
Problem is the x-axis: Its data is formatted by datetime to '%Y-%m-%d %H:%M:%S'. When trying to plot it occurs of course the error of no float possible... I tried quite many ways and it still wouldn't work...
So input so far are two arrays:
x is ['2016-02-05 17:14:55', '2016-02-05 17:14:51', '2016-02-05 17:14:49', ...].
y is ['35.764299', '20.3008', '36.94704', ...]
You can make use mapplotlib's DateFormatter:
Parse your date strings into datetime objects.
Convert your datetime objects into matplotlib numbers using date2num()
Create a DateFormatter() using your desired output format
Apply the DataFormatter() as the major tick format for the x-axis.
Also convert your float strings to actual floats.
Try the following:
import matplotlib
import matplotlib.pyplot as plt
from datetime import datetime
x_orig = ['2016-02-05 17:14:55', '2016-02-05 17:14:51', '2016-02-05 17:14:49']
x = [datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in x_orig]
y = ['35.764299', '20.3008', '36.94704']
xs = matplotlib.dates.date2num(x)
y_float = list(map(float, y)) # Convert y values to floats
hfmt = matplotlib.dates.DateFormatter('%H:%M:%S')
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.xaxis.set_major_formatter(hfmt)
plt.setp(ax.get_xticklabels(), rotation=15)
ax.plot(xs, y_float)
plt.show()
This would display the following:

Plotting time in Python with Matplotlib

I have an array of timestamps in the format (HH:MM:SS.mmmmmm) and another array of floating point numbers, each corresponding to a value in the timestamp array.
Can I plot time on the x axis and the numbers on the y-axis using Matplotlib?
I was trying to, but somehow it was only accepting arrays of floats. How can I get it to plot the time? Do I have to modify the format in any way?
Update:
This answer is outdated since matplotlib version 3.5. The plot function now handles datetime data directly. See https://matplotlib.org/3.5.1/api/_as_gen/matplotlib.pyplot.plot_date.html
The use of plot_date is discouraged. This method exists for historic
reasons and may be deprecated in the future.
datetime-like data should directly be plotted using plot.
If you need to plot plain numeric data as Matplotlib date format or
need to set a timezone, call ax.xaxis.axis_date / ax.yaxis.axis_date
before plot. See Axis.axis_date.
Old, outdated answer:
You must first convert your timestamps to Python datetime objects (use datetime.strptime). Then use date2num to convert the dates to matplotlib format.
Plot the dates and values using plot_date:
import matplotlib.pyplot
import matplotlib.dates
from datetime import datetime
x_values = [datetime(2021, 11, 18, 12), datetime(2021, 11, 18, 14), datetime(2021, 11, 18, 16)]
y_values = [1.0, 3.0, 2.0]
dates = matplotlib.dates.date2num(x_values)
matplotlib.pyplot.plot_date(dates, y_values)
You can also plot the timestamp, value pairs using pyplot.plot (after parsing them from their string representation). (Tested with matplotlib versions 1.2.0 and 1.3.1.)
Example:
import datetime
import random
import matplotlib.pyplot as plt
# make up some data
x = [datetime.datetime.now() + datetime.timedelta(hours=i) for i in range(12)]
y = [i+random.gauss(0,1) for i,_ in enumerate(x)]
# plot
plt.plot(x,y)
# beautify the x-labels
plt.gcf().autofmt_xdate()
plt.show()
Resulting image:
Here's the same as a scatter plot:
import datetime
import random
import matplotlib.pyplot as plt
# make up some data
x = [datetime.datetime.now() + datetime.timedelta(hours=i) for i in range(12)]
y = [i+random.gauss(0,1) for i,_ in enumerate(x)]
# plot
plt.scatter(x,y)
# beautify the x-labels
plt.gcf().autofmt_xdate()
plt.show()
Produces an image similar to this:
7 years later and this code has helped me.
However, my times still were not showing up correctly.
Using Matplotlib 2.0.0 and I had to add the following bit of code from Editing the date formatting of x-axis tick labels in matplotlib by Paul H.
import matplotlib.dates as mdates
myFmt = mdates.DateFormatter('%d')
ax.xaxis.set_major_formatter(myFmt)
I changed the format to (%H:%M) and the time displayed correctly.
All thanks to the community.
I had trouble with this using matplotlib version: 2.0.2. Running the example from above I got a centered stacked set of bubbles.
I "fixed" the problem by adding another line:
plt.plot([],[])
The entire code snippet becomes:
import datetime
import random
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
# make up some data
x = [datetime.datetime.now() + datetime.timedelta(minutes=i) for i in range(12)]
y = [i+random.gauss(0,1) for i,_ in enumerate(x)]
# plot
plt.plot([],[])
plt.scatter(x,y)
# beautify the x-labels
plt.gcf().autofmt_xdate()
myFmt = mdates.DateFormatter('%H:%M')
plt.gca().xaxis.set_major_formatter(myFmt)
plt.show()
plt.close()
This produces an image with the bubbles distributed as desired.
Pandas dataframes haven't been mentioned yet. I wanted to show how these solved my datetime problem. I have datetime to the milisecond 2021-04-01 16:05:37. I am pulling linux/haproxy throughput from /proc so I can really format it however I like. This is nice for feeding data into a live graph animation.
Here's a look at the csv. (Ignore the packets per second column I'm using that in another graph)
head -2 ~/data
date,mbps,pps
2021-04-01 16:05:37,113,9342.00
...
By using print(dataframe.dtype) I can see how the data was read in:
(base) ➜ graphs ./throughput.py
date object
mbps int64
pps float64
dtype: object
Pandas pulls the date string in as "object", which is just type char. Using this as-is in a script:
import matplotlib.pyplot as plt
import pandas as pd
dataframe = pd.read_csv("~/data")
dates = dataframe["date"]
mbps = dataframe["mbps"]
plt.plot(dates, mbps, label="mbps")
plt.title("throughput")
plt.xlabel("time")
plt.ylabel("mbps")
plt.legend()
plt.xticks(rotation=45)
plt.show()
Matplotlib renders all the milisecond time data. I've added plt.xticks(rotation=45) to tilt the dates but it's not what I want. I can convert the date "object" to a datetime64[ns]. Which matplotlib does know how to render.
dataframe["date"] = pd.to_datetime(dataframe["date"])
This time my date is type datetime64[ns]
(base) ➜ graphs ./throughput.py
date datetime64[ns]
mbps int64
pps float64
dtype: object
Same script with 1 line difference.
#!/usr/bin/env python
import matplotlib.pyplot as plt
import pandas as pd
dataframe = pd.read_csv("~/data")
# convert object to datetime64[ns]
dataframe["date"] = pd.to_datetime(dataframe["date"])
dates = dataframe["date"]
mbps = dataframe["mbps"]
plt.plot(dates, mbps, label="mbps")
plt.title("throughput")
plt.xlabel("time")
plt.ylabel("mbps")
plt.legend()
plt.xticks(rotation=45)
plt.show()
This might not have been ideal for your usecase but it might help someone else.

Categories