Plotting the hours of the day instead of time - python

title probably does not make sense, but I will try to explain.
I am plotting chemical concentrations overtime. The x axis should be hours since midnight local time (i.e., 0,4,8,12,16,20). However, when I do this all of the xticks get smushed together to to left.
xticks = range(0,24,4)
ozoneest["mean"].plot(ax=ax, xticks=xticks,)
Results in:
xticks is only accepting arrays of datetime variables, which have values: 00:00, 04:00, 08:00, 12:00, 16:00, 20:00.
xticks = pd.date_range("2000/01/01", end="2000/01/02", freq="4H").time
ozoneest["mean"].plot(ax=ax, xticks=xticks,)
results in:
This is close to what I want, but I want just the number of the hour
Thanks!

I assume that your data is stored in a pandas dataframe with a DatetimeIndex that has an "Hour" frequency. I cannot exactly reproduce your problem seeing as you have not shared the code generating the ax object. Whether it is created with matplotlib or pandas, the problem is that the x-axis unit is based on the number of time periods (based on the DatetimeIndex frequency in pandas, days in matplotlib) that have passed since 1970-01-01. So the xticks = range(0,24,4) land far to the left relative to your datetimes. You can check the x-axis values of the default xticks with ax.get_xticks().
Here are two ways of formatting the xticks and labels as you want. I suggest that you do not create a new DatetimeIndex for the hours as this makes the code less easy to reuse, use instead the DatetimeIndex of the dataframe as shown in the second solution.
Create sample dataframe
import numpy as np # v 1.20.2
import pandas as pd # v 1.2.5
rng = np.random.default_rng(seed=123) # random number generator
time = pd.date_range(start="2000/01/01", end="2000/01/02", freq="H")[:-1]
mean = rng.normal(size=len(time))
ozoneest = pd.DataFrame(dict(mean=mean), index=time)
ozoneest.head()
Pandas plot with default xticks
ozoneest["mean"].plot()
Simple solution: do not use the DatetimeIndex as the x-axis
xticks = range(0,24,4)
ax = ozoneest["mean"].plot(use_index=False, xticks=xticks)
General solution: select xticks from DatetimeIndex and create labels with strftime
xticks = ozoneest.index[::4]
xticklabels = xticks.strftime("%H")
ax = ozoneest["mean"].plot()
ax.set_xticks(xticks)
ax.set_xticks([], minor=True)
ax.set_xticklabels(xticklabels)
This solution is more general because you do not need to manually adjust the xticks if the range of time of your dataset changes and the tick labels can be easily customized in many ways.
If you want to remove the leading zeros, you can use the following list comprehension:
xticklabels = [tick[1:] if tick[0] == "0" else tick for tick in xticks.strftime("%H")]

Related

how to create a tidy x-axis of datetime indexes of a data for my plot

I'm plotting a dataframe which its index is of type datetime (like 2018-05-29 08:20:00).
I slice the data based on last hour and last day and last week and last month and then I plot them.
The data is collected every one minuet. So, the index of each row differs only one minute.
When I plot the data for last hour, the x axis is plotted like:
Or, for the last month it is like:
which is clean and readable. But, when I plot the last day data the x-axis index is like:
Why it is overlapped? how to fix it?
the codes to plot these time frames are the same, just the given dataframe is changed:
self.canvas.axes.plot(df_day.index, df_day.loc[:, item], linestyle="None", marker='.')
# or df_month or df_week or df_hour
how to make a the x-axis index as the format that I want?
I want it to be printed as hour:minute for last hour, or day hour:minute for last day.
I tried the links, but none of them helped:
Customizing Ticks
matplotlib: how to prevent x-axis labels from overlapping each other
I tried
self.canvas.axes.xaxis.set_major_formatter(self.major_formatter, self.canvas.axes.get_xticklabels())
#ticker.FuncFormatter
def major_formatter(x, pos):
return datetime.datetime.fromtimestamp(x.day / 1e3)
but it returned int46 in x variable, so it wasn't helping.
from the first answer to How to plot day and month which is also an answer from question owner I found the solution:
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot(date, price , label="Price")
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
or in my case:
self.canvas.axes.xaxis.set_major_formatter(mdates.DateFormatter('%d-%b'))
from strftime() and strptime() Format Codes¶, one can learn about formats of dates and times.

How do I make xticks equidistant, despite their value?

I'm trying to graph contaminants measured in a sample over time, and some sample dates are closer together. How do I plot this line with the current datetime values, but make each xtick equidistant?
This is what I've got so far, currently the ticks are bunched together when the samples were taken closer together.
date = df_TCE.SAMPLEDATE.unique()
date_IA14 = df_TCE.SAMPLEDATE[df_TCE.SYS_LOC_CODE == 'IA-14']
IA14 = df_TCE.AL_RESULT_VALUE[df_TCE.SYS_LOC_CODE == 'IA-14']
plt.plot(date_IA14, IA14)
plt.title('TCE Time Series')
plt.xlabel('Date')
plt.ylabel('Contaminant Level')
ax = plt.subplot()
ax.set_xticks(date_IA14)
ax.set_yticks([1, 2, 3, 4, 5, 6, 7])
ax.set_facecolor('seashell')
plt.show()
This is the output with the ticks bunched:
Output
There are a few things you can try.
First, ensure that your dataframe series called SAMPLEDATE are datetime objects by running pandas.to_datetime(df_TCE.SAMPLEDATE). Resolve any parsing errors that arise so that you're truly dealing with a datetime x-axis rather than strings.
Then, check out fig.autofmt_xdate() instead of ax.set_xticks(date_IA14). Once our x axis is filled with proper datetime objects, matplotlib is smart enough to get us to reasonable xtick spacing.
If you dislike the defaults, check out matplotlib.dates.DayLocator() or the HourLocator() or the MonthLocator(), whatever meets your regular interval needs. You can apply it to your axes object like this:
ax.xaxis.set_major_locator(matplotlib.dates.DayLocator())
https://matplotlib.org/3.1.1/api/dates_api.html#matplotlib.dates.DayLocator

Add evenly spaced ticks using matplotlib plot_date [duplicate]

I have a dataframe like this:
data_ = list(range(106))
index_ = pd.period_range('3/1/2004', '12/1/2012', freq='M')
df2_ = pd.DataFrame(data = data_, index = index_, columns = ['data'])
I want to plot this dataframe. Currently, I am using:
df2_.plot()
Now I like to control the labels (and possibly ticks) at the x axis. In particular, I like to have monthly ticks at the axis and possibly a label at every other month or quarterly labels. I also like to have vertical grid lines.
I started looking at this example but I am already failing at constructing the timedelta.
With regards to constructing the timedelta, datetime.timdelta() doesn’t have a parameter to specify months, so it’s probably convenient to stick to pd.date_range(). However, I found that objects of type pandas.tslib.Timestamp don’t play nice with matplotlib ticks so you could convert them to datetime.date objects like so
index_ = [pd.to_datetime(date, format='%Y-%m-%d').date()
for date in pd.date_range('2004-03-01', '2012-12-01', freq="M")]
It’s possible to add gridlines and customise axes labels by first defining a matplotlib axes object, and then passing this to DataFrame.plot()
ax = plt.axes()
df2_.plot(ax=ax)
Now you can add vertical gridlines to your plot
ax.xaxis.grid(True)
And specify quarterly xticks labels by using matplotlib.dates.MonthLocator and setting the interval to 3
ax.xaxis.set_major_locator(dates.MonthLocator(interval=3))
And finally, I found the ticks to be to be very crowded so I formatted them to get a nicer fit
ax.xaxis.set_major_formatter(dates.DateFormatter('%b %y'))
labels = ax.get_xticklabels()
plt.setp(labels, rotation=85, fontsize=8)
To produce the following:

In Pandas, can't show x-axis dates nicely and y-axis in unwanted logs

Here's my chart:
I have two issues; I can't get the datetime objects on the x-axis to come out nicely (i.e. January 1st, 2013) and I would like the y-axis labels to be absolute values, not log values.
Here's my annotated code: (date_sorted is my Pandas dataframe)
fig = plt.figure()
date_sorted.plot( x = ["ReleaseDate"], y = ["DomesticTotalGross"])
plt.title("Domestic Total Gross over Time")
plt.xticks(rotation=45)
plt.yscale('linear') # ---- this doesn't seem to do anything
plt.ticklabel_format(useOffset=False) #--- this gives this error: AttributeError: This method only works with the ScalarFormatter.
fig.autofmt_xdate() #thought this was supposed to convert my x-axis datetime objects into nice dates?
Regarding the date format, one way to achieve your objective would be to reset your index to a date format instead of datetime:
date_sorted.set_index([ts.date for ts in date_sorted.index]).plot(x="ReleaseDate", y="DomesticTotalGross")

Dates in the xaxis for a matplotlib plot with imshow

So I am new to programming with matplotlib. I have created a color plot using imshow() and an array. At first the axis were just the row and column number of my array. I used extent = (xmin,xmax,ymin,ymax) to get the x-axis in unix time and altitude, respectively.
I want to change the x-axis from unix time (982376726,982377321) to UT(02:25:26, 02:35:21). I have created a list of the time range in HH:MM:SS. I am not sure how to replace my current x-axis with these new numbers, without changing the color plot (or making it disappear).
I was looking at datetime.time but I got confused with it.
Any help would be greatly appreciated!
I have put together some example code which should help you with your problem.
The code first generates some randomised data using numpy.random. It then calculates your x-limits and y-limits where the x-limits will be based off of two unix timestamps given in your question and the y-limits are just generic numbers.
The code then plots the randomised data and uses pyplot methods to convert the x-axis formatting to nicely represented strings (rather than unix timestamps or array numbers).
The code is well commented and should explain everything you need, if not please comment and ask for clarification.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime as dt
# Generate some random data for imshow
N = 10
arr = np.random.random((N, N))
# Create your x-limits. Using two of your unix timestamps you first
# create a list of datetime.datetime objects using map.
x_lims = list(map(dt.datetime.fromtimestamp, [982376726, 982377321]))
# You can then convert these datetime.datetime objects to the correct
# format for matplotlib to work with.
x_lims = mdates.date2num(x_lims)
# Set some generic y-limits.
y_lims = [0, 100]
fig, ax = plt.subplots()
# Using ax.imshow we set two keyword arguments. The first is extent.
# We give extent the values from x_lims and y_lims above.
# We also set the aspect to "auto" which should set the plot up nicely.
ax.imshow(arr, extent = [x_lims[0], x_lims[1], y_lims[0], y_lims[1]],
aspect='auto')
# We tell Matplotlib that the x-axis is filled with datetime data,
# this converts it from a float (which is the output of date2num)
# into a nice datetime string.
ax.xaxis_date()
# We can use a DateFormatter to choose how this datetime string will look.
# I have chosen HH:MM:SS though you could add DD/MM/YY if you had data
# over different days.
date_format = mdates.DateFormatter('%H:%M:%S')
ax.xaxis.set_major_formatter(date_format)
# This simply sets the x-axis data to diagonal so it fits better.
fig.autofmt_xdate()
plt.show()

Categories

Resources