@@ -111,7 +111,7 @@ def clean_interp_method(method, **kwargs):
111111
112112
113113def interpolate_1d (xvalues , yvalues , method = 'linear' , limit = None ,
114- limit_direction = 'forward' , fill_value = None ,
114+ limit_direction = 'forward' , limit_area = None , fill_value = None ,
115115 bounds_error = False , order = None , ** kwargs ):
116116 """
117117 Logic for the 1-d interpolation. The result should be 1-d, inputs
@@ -155,28 +155,12 @@ def _interp_limit(invalid, fw_limit, bw_limit):
155155 raise ValueError ('Invalid limit_direction: expecting one of %r, got '
156156 '%r.' % (valid_limit_directions , limit_direction ))
157157
158- from pandas import Series
159- ys = Series (yvalues )
160- start_nans = set (range (ys .first_valid_index ()))
161- end_nans = set (range (1 + ys .last_valid_index (), len (valid )))
162-
163- # violate_limit is a list of the indexes in the series whose yvalue is
164- # currently NaN, and should still be NaN after the interpolation.
165- # Specifically:
166- #
167- # If limit_direction='forward' or None then the list will contain NaNs at
168- # the beginning of the series, and NaNs that are more than 'limit' away
169- # from the prior non-NaN.
170- #
171- # If limit_direction='backward' then the list will contain NaNs at
172- # the end of the series, and NaNs that are more than 'limit' away
173- # from the subsequent non-NaN.
174- #
175- # If limit_direction='both' then the list will contain NaNs that
176- # are more than 'limit' away from any non-NaN.
177- #
178- # If limit=None, then use default behavior of filling an unlimited number
179- # of NaNs in the direction specified by limit_direction
158+ if not limit_area is None :
159+ valid_limit_areas = ['inside' , 'outside' ]
160+ limit_area = limit_area .lower ()
161+ if limit_area not in valid_limit_areas :
162+ raise ValueError ('Invalid limit_area: expecting one of %r, got %r.'
163+ % (valid_limit_areas , limit_area ))
180164
181165 # default limit is unlimited GH #16282
182166 if limit is None :
@@ -186,15 +170,43 @@ def _interp_limit(invalid, fw_limit, bw_limit):
186170 elif limit < 1 :
187171 raise ValueError ('Limit must be greater than 0' )
188172
189- # each possible limit_direction
173+ from pandas import Series
174+ ys = Series (yvalues )
175+
176+ # These are sets of index pointers to invalid values... i.e. {0, 1, etc...
177+ all_nans = set (np .flatnonzero (invalid ))
178+ start_nans = set (range (ys .first_valid_index ()))
179+ end_nans = set (range (1 + ys .last_valid_index (), len (valid )))
180+ mid_nans = all_nans - start_nans - end_nans
181+
182+ # Like the sets above, preserve_nans contains indices of invalid values,
183+ # but in this case, it is the final set of indices that need to be
184+ # preserved as NaN after the interpolation.
185+
186+ # For example if limit_direction='forward' then preserve_nans will
187+ # contain indices of NaNs at the beginning of the series, and NaNs that
188+ # are more than'limit' away from the prior non-NaN.
189+
190+ # set preserve_nans based on direction using _interp_limit
190191 if limit_direction == 'forward' :
191- violate_limit = sorted (start_nans |
192- set (_interp_limit (invalid , limit , 0 )))
192+ preserve_nans = start_nans | set (_interp_limit (invalid , limit , 0 ))
193193 elif limit_direction == 'backward' :
194- violate_limit = sorted (end_nans |
195- set (_interp_limit (invalid , 0 , limit )))
196- elif limit_direction == 'both' :
197- violate_limit = sorted (_interp_limit (invalid , limit , limit ))
194+ preserve_nans = end_nans | set (_interp_limit (invalid , 0 , limit ))
195+ else :
196+ # both directions... just use _interp_limit
197+ preserve_nans = set (_interp_limit (invalid , limit , limit ))
198+
199+ # if limit_area is set, add either mid or outside indices
200+ # to preserve_nans GH #16284
201+ if limit_area == 'inside' :
202+ # preserve NaNs on the outside
203+ preserve_nans |= start_nans | end_nans
204+ elif limit_area == 'outside' :
205+ # preserve NaNs on the inside
206+ preserve_nans |= mid_nans
207+
208+ # sort preserve_nans and covert to list
209+ preserve_nans = sorted (preserve_nans )
198210
199211 xvalues = getattr (xvalues , 'values' , xvalues )
200212 yvalues = getattr (yvalues , 'values' , yvalues )
@@ -211,7 +223,7 @@ def _interp_limit(invalid, fw_limit, bw_limit):
211223 else :
212224 inds = xvalues
213225 result [invalid ] = np .interp (inds [invalid ], inds [valid ], yvalues [valid ])
214- result [violate_limit ] = np .nan
226+ result [preserve_nans ] = np .nan
215227 return result
216228
217229 sp_methods = ['nearest' , 'zero' , 'slinear' , 'quadratic' , 'cubic' ,
@@ -230,7 +242,7 @@ def _interp_limit(invalid, fw_limit, bw_limit):
230242 fill_value = fill_value ,
231243 bounds_error = bounds_error ,
232244 order = order , ** kwargs )
233- result [violate_limit ] = np .nan
245+ result [preserve_nans ] = np .nan
234246 return result
235247
236248
0 commit comments