6

I want to plot data monthly and show year label once per each year. Here is the data:

timedates = ['2013-01-01', '2013-02-01', '2013-03-01', '2013-04-01', '2013-05-01', '2013-06-01', '2013-07-01', 
         '2013-08-01', '2013-09-01', '2013-10-01', '2013-11-01', '2013-12-01', '2014-01-01', '2014-02-01', 
         '2014-03-01', '2014-04-01', '2014-05-01', '2014-06-01', '2014-07-01', '2014-08-01', '2014-09-01', 
         '2014-10-01', '2014-11-01', '2014-12-01']

timedates = pd.to_datetime(timedates)

amount = [38870, 42501, 44855, 44504, 41194, 42087, 43687, 42347, 45098, 43783, 47275, 49767, 
      39502, 35951, 47059, 47639, 44236, 40826, 46087, 41462, 38384, 41452, 36811, 37943]

types = ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 
     'A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C']

df_x = pd.DataFrame({'timedates': timedates, 'amount': amount, 'types': types})

I found out how to do that with matplotlib

plt.style.use('ggplot')

fig, ax = plt.subplots()
ax.plot_date(df_x.timedates, df_x.amount, 'v-')
ax.xaxis.set_minor_locator(md.MonthLocator()) 
ax.xaxis.set_minor_formatter(md.DateFormatter('%m'))

ax.xaxis.grid(True, which="minor")
ax.yaxis.grid()

ax.xaxis.set_major_locator(md.YearLocator())
ax.xaxis.set_major_formatter(md.DateFormatter('\n\n%Y'))
plt.show()

Plot data monthly with labels

Now I move to seaborn to take into account different types of data. Is it possible to have the same style of ticks using seaborn FacetGrid?

g = sns.FacetGrid(df_x, hue='types', size=8, aspect=1.5)
g.map(sns.pointplot, 'timedates', 'amount')
plt.show()

Seaborn timedata ticks When I try to apply ticks formatting - they just disappear.

Katerina
  • 2,580
  • 1
  • 22
  • 25
  • 1
    Did you see this http://stackoverflow.com/questions/31810316/seaborn-matplotlib-date-axis-barplot-minor-major-tick-formatting and https://github.com/mwaskom/seaborn/issues/498. Sounds like an incompatibility between labels and dates between Pandas/Seaborne and matplotlib. You could solve using `g.ax.set_xticks([dates, in, format, you, want])` manually... – Ed Smith Aug 24 '16 at 09:20
  • @EdSmith yes, I saw the first link, but there is no answer. And thanks for the second one and the code, I'll check if it is possible to do smth. – Katerina Aug 24 '16 at 10:51
  • You can iterate over g, for example: `for ax in g.axes.flat: ax.xaxis.set_major_locator(ticker.MultipleLocator(6))` – tauft Apr 04 '21 at 05:01

3 Answers3

6

You could format the xticks to just include the month and year of the datetime object and get a pointplot with xticks corresponding to the position of scatter plot points.

df['timedates'] = df['timedates'].map(lambda x: x.strftime('%Y-%m'))


def plot(x, y, data=None, label=None, **kwargs):
    sns.pointplot(x, y, data=data, label=label, **kwargs)

g = sns.FacetGrid(df, hue='types', size=8, aspect=1.5)
g.map_dataframe(plot, 'timedates', 'amount')
plt.show()

Image

Nickil Maveli
  • 29,155
  • 8
  • 82
  • 85
  • 1
    Thanks a lot! That's not what I originally was looking for, but it can be a solution! If there are not too many data periods :) – Katerina Aug 24 '16 at 11:13
  • Also, if you want to use `pandas` for plotting large datasets, you could suppress the overlapping behavior of the `xticks` by using `x_compat=True`. – Nickil Maveli Aug 24 '16 at 11:16
0

By far, I did it manually. Just separated lines by type and plotted them together.

Changed this line

ax.plot_date(df_x.timedates, df_x.amount, 'v-')

Into three plot-lines:

types_levels = df_x.types.unique()

for i in types_levels:
    ax.plot_date(df_x[df_x.types==i].timedates, df_x[df_x.types==i].amount, 'v-')

plt.legend(types_levels)

Multiple lines on plot_date

Though it's not an answer, I can't use other advantages of seaborn FacetGrid.

Katerina
  • 2,580
  • 1
  • 22
  • 25
0

You can just use the same code you used for matplotlib!

for ax in g.axes.flat:
     # Paste in your own code!
r02
  • 191
  • 2
  • 7