88
99import numpy as np
1010
11- from pandas import isnull
12- from pandas .tseries .period import Period
11+ from pandas .tseries .period import Period , PeriodIndex
1312from pandas .tseries .offsets import DateOffset
1413import pandas .tseries .frequencies as frequencies
15- from pandas .tseries .index import DatetimeIndex
16- import pandas .core .common as com
1714
18- from pandas .tseries .converter import (PeriodConverter , TimeSeries_DateLocator ,
15+ from pandas .tseries .converter import (TimeSeries_DateLocator ,
1916 TimeSeries_DateFormatter )
2017
2118#----------------------------------------------------------------------
2219# Plotting functions and monkey patches
2320
2421
25- def tsplot (series , plotf , ** kwargs ):
22+ def tsplot (series , plotf , ax = None , ** kwargs ):
2623 """
2724 Plots a Series on the given Matplotlib axes or the current axes
2825
@@ -36,36 +33,21 @@ def tsplot(series, plotf, **kwargs):
3633 Supports same kwargs as Axes.plot
3734
3835 """
39- # Used inferred freq is possible, need a test case for inferred
40- if 'ax' in kwargs :
41- ax = kwargs .pop ('ax' )
42- else :
43- import matplotlib .pyplot as plt
44- ax = plt .gca ()
45-
46- freq = _get_freq (ax , series )
47- # resample against axes freq if necessary
48- if freq is None : # pragma: no cover
49- raise ValueError ('Cannot use dynamic axis without frequency info' )
50- else :
51- # Convert DatetimeIndex to PeriodIndex
52- if isinstance (series .index , DatetimeIndex ):
53- series = series .to_period (freq = freq )
54- freq , ax_freq , series = _maybe_resample (series , ax , freq , plotf ,
55- kwargs )
56-
36+ if ax is None :
37+ raise ValueError ('ax keyword must be passed' )
38+ if not isinstance (series .index , PeriodIndex ):
39+ raise ValueError ('Passed data must have PeriodIndex' )
5740 # Set ax with freq info
58- _decorate_axes (ax , freq , kwargs )
41+ _decorate_axes (ax , series . index . freq )
5942
6043 # how to make sure ax.clear() flows through?
61- if not hasattr (ax , '_plot_data' ) :
44+ if getattr (ax , '_plot_data' , None ) is None :
6245 ax ._plot_data = []
6346 ax ._plot_data .append ((series , plotf , kwargs ))
6447 lines = plotf (ax , series .index ._mpl_repr (), series .values , ** kwargs )
6548
6649 # set date formatter, locators and rescale limits
6750 format_dateaxis (ax , ax .freq )
68-
6951 # x and y coord info
7052 ax .format_coord = lambda t , y : ("t = {0} "
7153 "y = {1:8f}" .format (Period (ordinal = int (t ),
@@ -75,24 +57,24 @@ def tsplot(series, plotf, **kwargs):
7557 return lines
7658
7759
78- def _maybe_resample (series , ax , freq , plotf , kwargs ):
60+ def _maybe_resample (data , ax , freq , kwargs ):
7961 ax_freq = _get_ax_freq (ax )
8062 if ax_freq is not None and freq != ax_freq :
8163 if frequencies .is_superperiod (freq , ax_freq ): # upsample input
82- series = series .copy ()
83- series .index = series .index .asfreq (ax_freq , how = 's' )
64+ data = data .copy ()
65+ data .index = data .index .asfreq (ax_freq , how = 's' )
8466 freq = ax_freq
8567 elif _is_sup (freq , ax_freq ): # one is weekly
8668 how = kwargs .pop ('how' , 'last' )
87- series = series .resample ('D' , how = how ).dropna ()
88- series = series .resample (ax_freq , how = how ).dropna ()
69+ data = data .resample ('D' , how = how ).dropna ()
70+ data = data .resample (ax_freq , how = how ).dropna ()
8971 freq = ax_freq
9072 elif frequencies .is_subperiod (freq , ax_freq ) or _is_sub (freq , ax_freq ):
91- _upsample_others (ax , freq , plotf , kwargs )
73+ _upsample_others (ax , freq )
9274 ax_freq = freq
9375 else : # pragma: no cover
9476 raise ValueError ('Incompatible frequency conversion' )
95- return freq , ax_freq , series
77+ return data
9678
9779
9880def _get_ax_freq (ax ):
@@ -115,67 +97,91 @@ def _is_sup(f1, f2):
11597 (f2 .startswith ('W' ) and frequencies .is_superperiod (f1 , 'D' )))
11698
11799
118- def _upsample_others (ax , freq , plotf , kwargs ):
119- legend = ax .get_legend ()
120- lines , labels = _replot_ax (ax , freq , kwargs )
100+ def _upsample_others (ax , freq ):
101+
102+ def _replot (ax ):
103+ data = getattr (ax , '_plot_data' , None )
104+ if data is None :
105+ return
106+
107+ # preserve legend
108+ leg = ax .get_legend ()
109+ handles , labels = ax .get_legend_handles_labels ()
110+
111+ ax ._plot_data = []
112+ ax .clear ()
113+ _decorate_axes (ax , freq )
121114
122- other_ax = None
123- if hasattr (ax , 'left_ax' ):
124- other_ax = ax .left_ax
125- if hasattr (ax , 'right_ax' ):
126- other_ax = ax .right_ax
127-
128- if other_ax is not None :
129- rlines , rlabels = _replot_ax (other_ax , freq , kwargs )
130- lines .extend (rlines )
131- labels .extend (rlabels )
132-
133- if (legend is not None and kwargs .get ('legend' , True ) and
134- len (lines ) > 0 ):
135- title = legend .get_title ().get_text ()
136- if title == 'None' :
137- title = None
138- ax .legend (lines , labels , loc = 'best' , title = title )
139-
140-
141- def _replot_ax (ax , freq , kwargs ):
142- data = getattr (ax , '_plot_data' , None )
143- ax ._plot_data = []
144- ax .clear ()
145- _decorate_axes (ax , freq , kwargs )
146-
147- lines = []
148- labels = []
149- if data is not None :
150115 for series , plotf , kwds in data :
151116 series = series .copy ()
152117 idx = series .index .asfreq (freq , how = 'S' )
153118 series .index = idx
154- ax ._plot_data .append (series )
155- lines .append (plotf (ax , series .index ._mpl_repr (), series .values , ** kwds )[0 ])
156- labels .append (com .pprint_thing (series .name ))
119+ ax ._plot_data .append ((series , plotf , kwds ))
120+ plotf (ax , series .index ._mpl_repr (), series , ** kwds )
121+
122+ if leg is not None :
123+ ax .legend (handles , labels , title = leg .get_title ().get_text ())
124+
125+ _replot (ax )
126+ if hasattr (ax , 'left_ax' ):
127+ _replot (ax .left_ax )
128+ elif hasattr (ax , 'right_ax' ):
129+ _replot (ax .right_ax )
130+
131+
132+ def _replot_x_compat (ax ):
133+
134+ def _replot (ax ):
135+ data = getattr (ax , '_plot_data' , None )
136+ if data is None :
137+ return
138+
139+ # preserve legend
140+ leg = ax .get_legend ()
141+ handles , labels = ax .get_legend_handles_labels ()
142+
143+ ax ._plot_data = None
144+ ax .clear ()
145+
146+ _decorate_axes (ax , None )
147+
148+ for series , plotf , kwds in data :
149+ idx = series .index .to_timestamp (how = 'e' )
150+ series .index = idx
151+ plotf (ax , series .index_mpl_repr (), series , ** kwds )
157152
158- return lines , labels
153+ if leg is not None :
154+ ax .legend (handles , labels , title = leg .get_title ().get_text ())
155+
156+ _replot (ax )
157+ if hasattr (ax , 'left_ax' ):
158+ _replot (ax .left_ax )
159+ elif hasattr (ax , 'right_ax' ):
160+ _replot (ax .right_ax )
159161
160162
161- def _decorate_axes (ax , freq , kwargs ):
163+ def _decorate_axes (ax , freq ):
162164 ax .freq = freq
163165 xaxis = ax .get_xaxis ()
164166 xaxis .freq = freq
165- if not hasattr (ax , 'legendlabels' ):
166- ax .legendlabels = [kwargs .get ('label' , None )]
167- else :
168- ax .legendlabels .append (kwargs .get ('label' , None ))
169167 ax .view_interval = None
170168 ax .date_axis_info = None
171169
172170
173- def _get_freq (ax , series ):
174- # get frequency from data
175- freq = getattr (series .index , 'freq' , None )
171+ def _get_index_freq (data ):
172+ freq = getattr (data .index , 'freq' , None )
176173 if freq is None :
177- freq = getattr (series .index , 'inferred_freq' , None )
174+ freq = getattr (data .index , 'inferred_freq' , None )
175+ if freq == 'B' :
176+ weekdays = np .unique (data .index .dayofweek )
177+ if (5 in weekdays ) or (6 in weekdays ):
178+ freq = None
179+ return freq
180+
178181
182+ def _get_freq (ax , data ):
183+ # get frequency from data
184+ freq = _get_index_freq (data )
179185 ax_freq = getattr (ax , 'freq' , None )
180186
181187 # use axes freq if no data freq
0 commit comments