All,
I'm comparing a few time series using matplotlib's broken_barh command---it's a nice way to compare data gaps in multiple, simultaneous, time series. Because broken_barh appears to only take numerical input, I'm using POSIX times.
Once finished, I would like to change the x-axis to display nicely formatted dates and times.
Now, I can do this directly through something like:
xtick_locations = ax.xaxis.get_majorticklocs()
xtick_new_labels = [
'{0:04n}-{1:02n}-{2:02n}\n{3:02n}:{4:02n}:{5:02n}'.format(
t.year,t.month,t.day,t.hour,t.minute,t.second) for t in
[pd.Timestamp(tick,unit='s') for tick in xtick_locations]]
plt.xticks(xticks_locations,xtick_new_labels,rotation='vertical')
But then my times and dates are not located at nice, logical locations, e.g. the start of days, weeks, months, and so forth as dependent upon the plotted range.
Does anyone know a way to use matplotlib.dates.AutoDateLocator and matplotlib.dates.AutoDateFormatter to intelligently calculate and display new tick locations given my original, numerical x-axis? Can I suppress the original axis and overlay it with a new one?
Thanks!
Related
I want to plot a continuous 'Time' column against dates on a simple timeseries linechart in plotly express. The 'Time' column starts out as a string, in the format HH:MM:SS, but when I plot this outright it is treated as discrete values. To remedy this and make it continuous I tried converting to timedelta data type, using pd.to_timedelta. This correctly converts my column into nanoseconds and the shape of the line and axis looks correct. However I do not want to display the axis as nanoseconds, or any other fixed unit, I would like it to display as HH:MM:SS, but am unsure how I might format this.
There is no easy way to do this in express. But if you use Plotly go you can use this piece of code directly from their website.
fig.update_xaxes(
ticktext=["End of Q1", "End of Q2", "End of Q3", "End of Q4"],
tickvals=["2016-04-01", "2016-07-01", "2016-10-01"],
)
It will map ticket vals display name to the matching entry in ticket text. This should maintain scale if tickvals are a scalar. In addition in this example you can have these pieces of text loop every year after.
Here is the link to their website: Plotly Axes with Labels
I have an excel sheet of retail gas prices from years 1990 to 2019. I successfully plotted a graph of their prices against the date(years). The x-axis was created on its own and its scaled to jump every 4 years. The Date is a datetime type and the Gas price is a float.
my plot was created by writing:
date = dataset['Date']
price = dataset['U.S. All Grades All Formulations Retail Gasoline Prices (Dollars per Gallon)']
plt.plot_date(date, price, linestyle='solid')
plt.xlabel("Date")
plt.ylabel("Gaslone Price / Dollar Per Gallon")
plt.tight_layout()
Now I would to "zoom" into the picture and create another graph but I would like that part where there is a steep decline from around years 2007 to 2009.
I tried using plt.xlim but I'm not sure how to input my limits.
Thank you.
Coming to this waaaaaay after the fact, but since I just ran into this in the top of Google results while trying to do the same, I'll go ahead and answer. Assuming that your dates are of datatype DateTime (it looks like they are), you should be able to use the following:
plt.xlim(pd.to_datetime('2007-01-01'), pd.to_datetime('2009-12-31'))
The xlim() function takes two arguments, a left and a right boundary. These can be placed in a tuple (inside parenthesis), but even if you don't include them in a tuple, it seems that matplotlib will still figure it out. The use of pd.to_datetime is necessary to convert the date strings into a datetime object that can be checked against the datetime objects being used on the x-axis, so pyplot can identify where to draw the left and right boundaries. Without this conversion, pyplot would crash with an IndexError, because it would be trying to match a string to a non-string item (the DateTime x-axis objects).
In a scenario where you weren't needing to convert to datetime objects, you could simply pass values into the xlim() function without the conversion to datetime.
So I am trying to set up a chart in python to show the development of an inter-month spread over the year (i.e. Oct/Nov 2015, Oct/Nov 2016, and so on).
Currently when I plot, it shows me the whole timeline on the x-axis from 2015 to however far I go.
Preferably I would like to show number of days rather than actual date on X-axis, since they are all over a year.
I've tried the following code:
#Fetching curve
curve_name = 'Oct/Nov'
OctNov = get_forward_curve_history(name=curve_name, start_date='2019-01-
01', end_date=date)
#plotting spread
Oct/Nov = Med4.loc['2019-10-01':'2019-10-31'].mean() - JKM5.loc['2019-11-
01':'2019-11-30'].mean()
Oct/Nov.plot()
#legend and grid commands
plt.gca().legend(('Oct/Nov17','Oct/Nov18','Oct/Nov19'))
plt.grid()
plt.show()
I would expecting something like the below, where we can see different years but on the same X-axis scale (roughly 365 days):
If I understand correctly you just want to plot a bunch of years worth of data on the same graph?
If so you want to either use the plt.hold(True) option and just add the to the figure again and again then show at the end or ready all the data and plot it all at once.
It is very hard to produce any code without the original data but this may help:
Python equivalent to 'hold on' in Matlab
I am often working interactively in an ipython shell or ipython notebook.
Say, I had a pandas.DataFrame with a DatetimeIndex, like this:
idx = pd.date_range("12:00", periods=400000, freq="S")
df = pd.DataFrame({"temp":np.random.normal(size=len(idx))}, index=idx)
In order to plot it, I can simply do:
plt.plot(df.temp, '.')
As one can see, neither do I have to specify the x-axis data, as it is nicely inferred from the DataFrame, nor do I have to specify that I actually want the x-axis to be date based. (Gone are the times of plt.plot_date)
That's awesome!
But the x-axis looks ugly in two ways:
the labels overlap and are hard to read.
the labels show hours instead of dates.
One can almost repair this problem like, e.g. like this:
plt.plot(df.temp, '.')
import matplotlib.dates as mdates
plt.gca().xaxis.set_major_formatter(
mdates.DateFormatter('%d-%m-%Y %H:%M:%S'))
plt.gcf().autofmt_xdate()
As one can see in the resulting plot, the leftmost date label is clipped.
So by increasing the code size by 300% one can almost get a nice plot.
Now to my question:
I can for my life not remember these 2..3 lines, which I'll have to type in always, when making date based plots. It makes the interface feel clumsy and slow. I always have to google for the solution ...
Can I setup matplotlib in a way, that it kind of remembers what my personal defaults are with regard to date based plotting?
I guess, I could actually hack into the plot function. But maybe there is a way using these matplotlib.rc_params, which I wasn't able to find.
As I said above, plt.plot is going a long way to actually guess what I want. It guesses the x-axis data to be the index of the DataFrame .. and it guesses it should actually plot a date based x-axis instead of a the numerical representation of the dates. How can I add something to this?
I'm thinking of maybe even give it some hints like:
plt.plot(df.temp, '.', date_fmt='%d-%m-%Y %H:%M:%S')
or
plt.plot(df.temp, '.', autofmt_xdate=True)
You can use DateFormatter:
import matplotlib.dates as mdates
fig, ax = plt.subplots(figsize=(8,5))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d-%m-%Y %H:%M:%S'))
#rotates the tick labels automatically
fig.autofmt_xdate()
ax.plot(df["T"], '.')
plt.show()
I am new to python. I am plotting the Bit error rate data w.r.t time and i want to remove these zeros. My x-axis values are like this hh:mm:ss:ffffff. I want to remove the seconds and microseconds as, it is occupying a lot of place on the graph/plot and they are overlapping on each other.
How can i remove the seconds and microseconds (ss::ffffff) from x ticks? and plot only hours and minutes and remove the seconds and microseconds. Is it possible?
You can do this using the MinuteLocator tick locator and a custom formatter (see also this answer)
import matplotlib.dates as mdates
ax.xaxis.set_major_locator(mdates.MinuteLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))