Skip to content

Commit 59b31d2

Browse files
committed
Use ConciseDateFormatter; allow datetime obj as x data
1 parent eea0cb4 commit 59b31d2

File tree

1 file changed

+10
-107
lines changed

1 file changed

+10
-107
lines changed

plot_utils/time_series.py

Lines changed: 10 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -348,114 +348,15 @@ def _calc_month_interval(date_array):
348348
return delta_months
349349

350350
#%%============================================================================
351-
def _format_xlabel(ax, month_width):
352-
'''
353-
Format the x axis label (which represents dates) in accordance to the width
354-
of each time interval (month or day).
355-
356-
For narrower cases, year will be put below month.
351+
def _format_xlabel(ax, *args):
352+
locator = mpl.dates.AutoDateLocator()
353+
formatter = mpl.dates.ConciseDateFormatter(locator)
357354

358-
For even narrower cases, not every month will be displayed as a label.
355+
ax.xaxis.set_major_locator(locator)
356+
ax.xaxis.set_major_formatter(formatter)
359357

360-
For very narrow cases (e.g., many years), months will not be displayed, and
361-
sometimes not every year will be displayed.
362-
'''
363-
rot = None # degree of rotation
364-
y_int = None # year interval
365-
d_int = None # day interval
366-
if month_width < 0.038:
367-
m_int = None # month interval
368-
y_int = 3 * int(0.038/month_width) # interval increases with narrower size
369-
elif month_width < 0.043:
370-
m_int = None
371-
y_int = 2
372-
elif month_width < 0.05:
373-
m_int = None
374-
rot = 30
375-
elif month_width < 0.055:
376-
m_int = 6 # display month label for every 6 months
377-
rot = 30
378-
elif month_width < 0.06:
379-
m_int = 6
380-
elif month_width < 0.09:
381-
m_int = 5
382-
elif month_width < 0.11:
383-
m_int = 4
384-
elif month_width < 0.16:
385-
m_int = 3
386-
elif month_width < 0.29:
387-
m_int = 2
388-
else:
389-
m_int = 1
390-
if month_width < 1.9:
391-
pass # d_int is still None
392-
elif month_width < 2.9:
393-
d_int = 15
394-
elif month_width < 3.5:
395-
d_int = 10
396-
elif month_width < 4:
397-
d_int = 9
398-
elif month_width < 5:
399-
d_int = 8
400-
elif month_width < 6:
401-
d_int = 7
402-
elif month_width < 7:
403-
d_int = 6
404-
elif month_width < 8.5:
405-
d_int = 5
406-
elif month_width < 11:
407-
d_int = 4
408-
elif month_width < 15:
409-
d_int = 3
410-
rot = 30
411-
elif month_width < 25.5:
412-
d_int = 2
413-
rot = 30
414-
else:
415-
d_int = 1
416-
rot = 30
417-
418-
if y_int: # show only every 'y_int' years
419-
years = mpl.dates.YearLocator(base=y_int)
420-
else: # show year on January of every year
421-
years = mpl.dates.YearLocator()
422-
423-
xlim = ax.get_xlim() # number of days since 0001/Jan/1-00:00:00 UTC plus one
424-
xlim_ = [mpl.dates.num2date(i) for i in xlim] # convert to datetime object
425-
if xlim_[0].year == xlim_[1].year: # if date range is within same year
426-
if xlim_[0].day > 1: # not first day of month: show year on next month
427-
years = mpl.dates.YearLocator(base=1,month=xlim_[0].month+1,day=1)
428-
else: # first day of month: show year on this month
429-
years = mpl.dates.YearLocator(base=1,month=xlim_[0].month ,day=1)
430-
431-
if not d_int: # no day labels will be shown
432-
months_fmt = mpl.dates.DateFormatter('%m')
433-
else:
434-
months_fmt = mpl.dates.DateFormatter('%m/%d')
435-
436-
if m_int: # show every 'm_int' months
437-
if d_int: # day labels will be shown
438-
months = mpl.dates.DayLocator(interval=d_int)
439-
else:
440-
months = mpl.dates.MonthLocator(interval=m_int)
441-
ax.xaxis.set_minor_locator(months)
442-
ax.xaxis.set_minor_formatter(months_fmt)
443-
if d_int and rot: # days are shown as rotated
444-
years_fmt = mpl.dates.DateFormatter('\n\n%Y') # show year on next next line
445-
else:
446-
years_fmt = mpl.dates.DateFormatter('\n%Y') # show year on next line
447-
else: # do not show months in x axis label
448-
years_fmt = mpl.dates.DateFormatter('%Y') # show year on current line
449-
450-
ax.xaxis.set_major_locator(years)
451-
ax.xaxis.set_major_formatter(years_fmt)
452358
ax.tick_params(labelright=True) # also show y axis on right edge of figure
453359

454-
if rot and d_int: # days/months are shown as rotated
455-
plt.setp(ax.xaxis.get_minorticklabels(), rotation=rot)
456-
elif rot and not d_int: # only show years as rotated
457-
plt.setp(ax.xaxis.get_majorticklabels(), rotation=rot)
458-
459360
return ax
460361

461362
#%%============================================================================
@@ -477,6 +378,7 @@ def _as_date(raw_date, date_fmt=None):
477378
[1] 201310
478379
[2] 201210.0
479380
(D) A pandas Series, of length 1 or length larger than 1
381+
(E) A list of Python datetime object
480382
481383
Parameters
482384
----------
@@ -514,7 +416,7 @@ def _as_date(raw_date, date_fmt=None):
514416
if len(raw_date) == 0: # empty list
515417
date_list = None # return an empty object
516418
elif len(raw_date) == 1: # length of string is 1
517-
date_ = str(int(raw_date[0])) # simply unpack it and convert to str int
419+
date_ = str(int(raw_date[0])) # unpack and convert to str
518420
date_list = pd.to_datetime(date_, format=date_fmt)
519421
else: # length is larger than 1
520422
nr = len(raw_date)
@@ -527,9 +429,10 @@ def _as_date(raw_date, date_fmt=None):
527429
date_ = j_th
528430
elif isinstance(j_th,(int,np.integer,np.float)):
529431
date_ = str(int(j_th)) # robustness not guarenteed!
432+
elif isinstance(j_th, dt.datetime):
433+
date_ = j_th.strftime('%Y-%m-%d')
530434
else:
531-
raise TypeError('Date type of the element(s) in '
532-
'`raw_date` not recognized.')
435+
raise TypeError('Invalid data type in `raw_date')
533436
date_list[j] = pd.to_datetime(date_, format=date_fmt)
534437
elif type(raw_date) == dt.date: # if a datetime.date object
535438
date_list = raw_date # no need for conversion

0 commit comments

Comments
 (0)