Axis interval spacing when plotting with pandas timedelta - python

I'm trying to plot some columns in a dataframe that has pandas timedelta values as its index. When I plot it, all the points are evenly spaced along the x axis even if there's a variable time between.
time = [pd.Timestamp('9/3/2016')-pd.Timestamp('9/1/2016'),pd.Timestamp('9/8/2016')-pd.Timestamp('9/1/2016'),pd.Timestam\p('9/29/2016')-pd.Timestamp('9/1/2016')]
df = pd.DataFrame(index=time, columns=['y'],data=[5,0,10])
df.plot()
plt.show()
Wrong spacing
If instead I used dates instead of timedelta, I get the proper spacing on the x axis:
time = [pd.Timestamp('9/3/2016'),pd.Timestamp('9/5/2016'),pd.Timestamp('9/20/2016')]
df = pd.DataFrame(index=time, columns=['y'],data=[5,0,10])
df.plot()
plt.show()
Right spacing
Is there a way to get this to display correctly?

At the moment, it's not fully supported yet in pandas. Please see this issue on Github for more info.
For a quick workaround, you can use:
import matplotlib.pyplot as plt
plt.plot(df.index, df.values)
Here's an example of how you could play with the ticks to make them readable (rather than just a very large number)
import matplotlib as mpl
import datetime
fig, ax = plt.subplots()
ax.plot(df.index, df.values)
plt.xticks([t.value for t in df.index], df.index, rotation=45)
plt.show()

Related

Vertically align time series (plot and barplot) sharing same x-axis in matplotlib

Is there an easy way to align two subplots of a time series of different kinds (plot and barplot) in matplotlib? I use the pandas wrapper since I am dealing with pd.Series objects:
import pandas as pd
import matplotlib.pyplot as plt
series = pd._testing.makeTimeSeries()
fig, axes = plt.subplots(2, 1)
series.head(3).plot(marker='o', ax=axes[0])
series.head(3).plot.bar(ax=axes[1])
plt.tight_layout()
The result is not visually great, it would be great to keep the code simplicity and:
Vertically align data points in the top plot to the bars on the bottom plot
Share the axis of the bar plot with the first and remove the visibility on x-axis labels of the top plot altogether (but keep grids whenever present)
Based on the ideas thrown in the comments, I think that this is the simplest solution (giving up the pandas API), which is exactly what I needed:
import pandas as pd
import matplotlib.pyplot as plt
series = pd._testing.makeTimeSeries()
fig, axes = plt.subplots(2, 1, sharex=True)
axes[0].plot(series.head(3), marker='o')
axes[1].bar(series.head(3).index, series.head(3))
plt.tight_layout()
With eventual fix on the xticks for cases with missing values, where the xticks are not plotted daily (e.g. plt.xticks(series.head(3).index)).
Thanks for the help!

Matplotlib - uneven intervals between x-axis with datetime

I am currently experiencing an issue where the spaces between ticks on my plot appear to have uneven intervals when using a DatetimeIndex for my x-axis. The code is as follows:
x = pd.date_range('2018-11-03', '2018-12-30')
plt.plot(x, np.arange(len(x)))
plt.xticks(rotation=45)
Note the two instances in which the dates do not increment by the typical 7-day period. Even after extending the time period, the issue persists:
x = pd.date_range('2018-11-03', '2019-03-20')
plt.plot(x, np.arange(len(x)))
plt.xticks(rotation=45)
How can I override this behavior to have standard 7-day intervals on my plot? Thank you.
You can use matplotlib's ticker module to customize tick locations:
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.ticker as ticker
x = pd.date_range('2018-11-03', '2019-03-20')
plt.plot(x, np.arange(len(x)))
plt.xticks(rotation=45)
ax=plt.gca()
ax.xaxis.set_major_locator(ticker.MultipleLocator(7))
The above script returns the following image:

how to round date format on x axis in matplotlib

I am trying to plot a curve in between two others filled and as soon as I have these two "plots", my x-axis become strange.
Here is my MWE:
import matplotlib.pyplot as plt
from matplotlib import dates as mdates
import datetime
import numpy as np
dates=[u'0600', u'0630', u'0700', u'0730', u'0800', u'0830', u'0900', u'0930', u'1000', u'1030']#["0800","0830","0900"]
x=[datetime.datetime.strptime(h,'%H%M') for h in dates]
y=np.arange(len(x))
tmin=y/2.
tmax=y*2.
fig, ax = plt.subplots()
ax.plot(x,y,'r')
ax.fill_between(x,tmin,tmax)
hfmt = mdates.DateFormatter('%H:%M')
ax.xaxis.set_major_formatter(hfmt)
fig.autofmt_xdate()
plt.savefig('plot.png')
plt.show()
where the x-axis should looks like
which can easily be obtained by commenting one of the plot or fill_between command line.
Any idea of how to have the second x-axis in the first figure ?
The easiest way would probably be to use
ax.x_axis.set_major_locator(mdates.MinuteLocator(byminute=[0,30]))

Seaborn/Matplotlib Date Axis barplot minor-major tick formatting

I'm building a Seaborn barplot. The x-axis are dates, and the y-axis are integers.
I'd like to format major/minor ticks for the dates. I'd like Mondays' ticks to be bold and a different color (ie, "major ticks"), with the rest of the week less bold.
I have not been able to get major and minor tick formatting on the x-axis to work with Seaborn barplots. I'm stumped, and thus turning here for help.
I'm starting with the stackoverflow example that answered this question: Pandas timeseries plot setting x-axis major and minor ticks and labels
If I do a simple modification it to use a Seaborn barplot and I lose my X-axis ticks:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as dates
import seaborn as sns
idx = pd.date_range('2011-05-01', '2011-07-01')
s = pd.Series(np.random.randn(len(idx)), index=idx)
###########################################
## Swap out these two lines of code:
#fig, ax = plt.subplots()
#ax.plot_date(idx.to_pydatetime(), s, 'v-')
## with this one
ax = sns.barplot(idx.to_pydatetime(), s)
###########################################
ax.xaxis.set_minor_locator(dates.WeekdayLocator(byweekday=(1),
interval=1))
ax.xaxis.set_minor_formatter(dates.DateFormatter('%d\n%a'))
ax.xaxis.grid(True, which="minor")
ax.yaxis.grid()
ax.xaxis.set_major_locator(dates.MonthLocator())
ax.xaxis.set_major_formatter(dates.DateFormatter('\n\n\n%b\n%Y'))
plt.tight_layout()
## save the result to a png instead of plotting to screen:
myFigure = plt.gcf()
myFigure.autofmt_xdate()
myFigure.set_size_inches(11,3.8)
plt.title('Example Chart', loc='center')
plt.savefig('/tmp/chartexample.png', format='png', bbox_inches='tight')
I've tried a variety of approaches but something in Seaborn seems to be overriding or undoing any attempts at major and minor axis formatting that I've managed to cook up yet beyond some simple styling for all ticks when I use set_xticklabels().
I can sort of get formatting on just the major ticks by using MultipleLocator(), but I can't get any formatting on the minor ticks.
I've also experimented with myFigure.autofmt_xdate() to see if it would help, but it doesn't seem to like mixed major & minor ticks on the same axis either.
I came across this while trying to solve the same problem. Based on the useful pointer from #mwaskom (that categorical plots like boxplots lose their structure and just become date-named categories) and ended up doing the location and formatting in Python as so:
from datetime import datetime
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as dates
import seaborn as sns
idx = pd.date_range('2011-05-01', '2011-07-01')
s = pd.Series(np.random.randn(len(idx)), index=idx)
fig, ax = plt.subplots(figsize = (12,6))
ax = sns.barplot(idx.to_pydatetime(), s, ax = ax)
major_ticks = []
major_tick_labels = []
minor_ticks = []
minor_tick_labels = []
for loc, label in zip(ax.get_xticks(), ax.get_xticklabels()):
when = datetime.strptime(label.get_text(), '%Y-%m-%d %H:%M:%S')
if when.day == 1:
major_ticks.append(loc)
major_tick_labels.append(when.strftime("\n\n\n%b\n%Y"))
else:
minor_ticks.append(loc)
if when.weekday() == 0:
minor_tick_labels.append(when.strftime("%d\n%a"))
else:
minor_tick_labels.append(when.strftime("%d"))
ax.set_xticks(major_ticks)
ax.set_xticklabels(major_tick_labels)
ax.set_xticks(minor_ticks, minor=True)
ax.set_xticklabels(minor_tick_labels, minor=True)
Of course, you don't have to set the ticks based on parsing the labels which were installed from the data, if it's easier to start with the source data and just keep the indices aligned, but I prefer to have a single source of truth.
You can also mess with font weight, rotation, etc, on individual labels by getting the Text objects for the relevant label and calling set_ methods on it.

python pandas timeseries plots, how to set xlim and xticks outside ts.plot()?

fig = plt.figure()
ax = fig.gca()
ts.plot(ax=ax)
I know I can set xlim inside pandas plotting routine: ts.plot(xlim = ...), but how to change it after pandas plotting is done?
ax.set_xlim(( t0.toordinal(), t1.toordinal() )
works sometimes, but if pandas is formatting the xaxis as months from epoch, not days, this will fail hard.
Is there anyway to know how pandas has converted the dates to xaxis and then convert my xlim in the same way?
Thanks.
It works for me (with pandas 0.16.2) if I set the x-axis limits using pd.Timestamp values.
Example:
import pandas as pd
# Create a random time series with values over 100 days
# starting from 1st March.
N = 100
dates = pd.date_range(start='2015-03-01', periods=N, freq='D')
ts = pd.DataFrame({'date': dates,
'values': np.random.randn(N)}).set_index('date')
# Create the plot and adjust x/y limits. The new x-axis
# ranges from mid-February till 1st July.
ax = ts.plot()
ax.set_xlim(pd.Timestamp('2015-02-15'), pd.Timestamp('2015-07-01'))
ax.set_ylim(-5, 5)
Result:
Note that if you plot multiple time series in the same figure then make sure to set xlim/ylim after the last ts.plot() command, otherwise pandas will automatically reset the limits to match the contents.

Categories

Resources