|
From: Paul T. <pau...@gm...> - 2012-10-11 00:53:11
|
A bit of searching gave me this much simpler solution:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import datetime
import matplotlib.dates as m_dates
import matplotlib.ticker as ticker
def make_month_axis(dates, y, ax, fig):
newax = fig.add_axes(ax.get_position())
newax.spines['bottom'].set_position(('outward', 25))
newax.patch.set_visible(False)
newax.yaxis.set_visible(False)
newax.plot_date(dates, y, visible=False)
newax.xaxis.set_major_locator(m_dates.MonthLocator())
newax.xaxis.set_minor_locator(m_dates.MonthLocator(bymonthday=15))
newax.xaxis.set_major_formatter(ticker.NullFormatter())
newax.xaxis.set_minor_formatter(m_dates.DateFormatter('%b'))
for tick in newax.xaxis.get_minor_ticks():
tick.tick1line.set_markersize(0)
tick.tick2line.set_markersize(0)
tick.label1.set_horizontalalignment('center')
start = datetime.datetime(2012, 8, 26)
dates = [start]
for i in range(1,10):
dates.append(dates[-1] + datetime.timedelta(days=7))
y = np.random.normal(10, 5, len(dates))
fig = plt.figure()
fig.subplots_adjust(bottom=0.2, right=0.85, wspace=.8, hspace=.8)
ax = fig.add_subplot(1,1,1)
ax.plot(dates, y)
ax.xaxis.set_major_formatter( matplotlib.dates.DateFormatter('%W'))
make_month_axis(dates = dates, y = y, ax = ax, fig = fig)
plt.show()
Paul
On 10/8/12 11:03 PM, Paul Tremblay wrote:
> I often have to make graphs with time series, with each point being
> the start of a week. Below is the result I wish:
>
> However, in order to make the secondary x axis the the month labels, I
> need something like 40 lines of code. My strategy consists in first
> drawing the rates in the normal way and using matplotlib's
> dateFormatter to set the week numbers. That part is easy.
>
> In order to draw the x axis below to show when the weeks occur, I draw
> two more lines, and makes these lines invisible. The first line has as
> the x points the start of each month, and the y values as the
> corresponding rate. The second line has as its x value the middle of
> each month, with the corresponding y value.
>
> Below is my code. I have to use such a graph quite often--so often, in
> fact, that if I don't find an easier way to make the secondary x axis,
> I will store the code in my own library for re-use. Does anyone know
> of a simpler, more elegant way?
>
> Thanks!
>
> Paul
>
> import matplotlib
> import matplotlib.pyplot as plt
> import numpy as np
> import matplotlib.dates
> from datetime import datetime
> from datetime import timedelta
>
>
> def unique_months(dates, rates):
> """
> returns two lists, one of the first time a month occurs, the
> second, the
> rates representing that month
>
> """
> y = [rates[0]]
> temp = dates[0] - timedelta(days=dates[0].day)
> months = [temp]
> found = [dates[0].month]
> counter = 0
> for d in dates:
> month = d.month
> if month not in found:
> new_date = d - timedelta(days=d.day)
> months.append(new_date)
> y.append(rates[counter])
> found.append(month)
> counter += 1
> return (months, y)
>
> def half_months(dates, defects):
> """
> returns two lists, one the middle of the month occurs, the second, the
> rates representing that month
>
> """
> months, y = unique_months(dates, defects)
> new_months =[]
> new_y = []
> counter = 0
> for m in months:
> new_date = m - timedelta(days=m.day) + timedelta(days=15)
> if new_date <= months[-1]:
> new_months.append(new_date)
> new_y.append(y[counter])
> counter += 1
> return new_months, new_y
>
> dates = [datetime(2012,8,19), datetime(2012,8,26),datetime(2012, 9,
> 3), datetime(2012,9,10), datetime(2012,9,17), datetime(2012,9,24),
> datetime(2012,10,1), datetime(2012,10,8)]
> rates = [2,3,4,2,5,3,7,2]
> fig = plt.figure()
> fig.set_size_inches(3,3)
> x1, y1 = unique_months(dates, rates)
> ax = fig.add_subplot(1,1,1)
> ax.yaxis.grid(True, linestyle='-', which='major', color='lightgrey',
> alpha=0.5)
> ax.set_axisbelow(True)
> fig.subplots_adjust(bottom=0.2, right=0.85, wspace=.8, hspace=.8)
> # plot dates and rates
> ax.plot(dates, rates)
> ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%W'))
>
> # start with bottom axis
>
> x2, y2 = half_months(dates, rates)
>
> # add tick marks for start of month
> # x1 starts at first of each mont; y1 doesn't matter
> newax = fig.add_axes(ax.get_position())
> newax.spines['bottom'].set_position(('outward', 25))
> newax.patch.set_visible(False)
> newax.yaxis.set_visible(False)
> newax.plot_date(x1, y1, visible=False)
> newax.xaxis.set_major_locator( matplotlib.dates.MonthLocator())
> newax.set_xticklabels([])
>
> # set labels for months, inbetween tick marsk
> # x2 is 15th of each month
> axmlab = fig.add_axes(ax.get_position())
> axmlab.spines['bottom'].set_position(('outward', 25))
> axmlab.patch.set_visible(False)
> axmlab.yaxis.set_visible(False)
> axmlab.plot_date(x2, y2, visible=False)
> axmlab.xaxis.set_major_formatter( matplotlib.dates.DateFormatter('%b'))
> axmlab.xaxis.set_major_locator(matplotlib.dates.DayLocator(bymonthday=1))
> # get rid of tick marks for this axis
> for i, line in enumerate(axmlab.get_xticklines() +
> newax.get_yticklines()):
> line.set_visible(False)
> axmlab.plot_date(x2, y2, visible=False)
> axmlab.xaxis.set_major_locator( matplotlib.dates.MonthLocator())
>
> plt.xlabel('Week in Year')
> ax.set_ylabel('Rates')
> plt.savefig('temp.png', dpi=100)
>
>
|