@@ -111,7 +111,7 @@ def clean_interp_method(method, **kwargs):
111
111
112
112
113
113
def 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 ,
115
115
bounds_error = False , order = None , ** kwargs ):
116
116
"""
117
117
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):
155
155
raise ValueError ('Invalid limit_direction: expecting one of %r, got '
156
156
'%r.' % (valid_limit_directions , limit_direction ))
157
157
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 ))
180
164
181
165
# default limit is unlimited GH #16282
182
166
if limit is None :
@@ -186,15 +170,43 @@ def _interp_limit(invalid, fw_limit, bw_limit):
186
170
elif limit < 1 :
187
171
raise ValueError ('Limit must be greater than 0' )
188
172
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
190
191
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 ))
193
193
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 )
198
210
199
211
xvalues = getattr (xvalues , 'values' , xvalues )
200
212
yvalues = getattr (yvalues , 'values' , yvalues )
@@ -211,7 +223,7 @@ def _interp_limit(invalid, fw_limit, bw_limit):
211
223
else :
212
224
inds = xvalues
213
225
result [invalid ] = np .interp (inds [invalid ], inds [valid ], yvalues [valid ])
214
- result [violate_limit ] = np .nan
226
+ result [preserve_nans ] = np .nan
215
227
return result
216
228
217
229
sp_methods = ['nearest' , 'zero' , 'slinear' , 'quadratic' , 'cubic' ,
@@ -230,7 +242,7 @@ def _interp_limit(invalid, fw_limit, bw_limit):
230
242
fill_value = fill_value ,
231
243
bounds_error = bounds_error ,
232
244
order = order , ** kwargs )
233
- result [violate_limit ] = np .nan
245
+ result [preserve_nans ] = np .nan
234
246
return result
235
247
236
248
0 commit comments