Skip to content
forked from pydata/xarray

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into fix/2932
Browse files Browse the repository at this point in the history
* upstream/master:
  [WIP] Custom fill value for reindex, align, and merge operations (pydata#2920)
  Attempt to fix py35 build on Travis (pydata#2925)
  List formatting in docs (pydata#2939)
  DOC: Avoid downloading .tif file (pydata#2919)
  • Loading branch information
dcherian committed May 6, 2019
2 parents 2fca3b4 + 5aaa654 commit 106034d
Show file tree
Hide file tree
Showing 22 changed files with 183 additions and 112 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ matrix:
fast_finish: true
include:
- env: CONDA_ENV=py35-min
- env: CONDA_ENV=py35
- env: CONDA_ENV=py36
- env: CONDA_ENV=py37
- env:
Expand Down
23 changes: 0 additions & 23 deletions ci/requirements-py35.yml

This file was deleted.

4 changes: 2 additions & 2 deletions ci/requirements-py36-dask-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ dependencies:
- pytest-env
- coveralls
- flake8
- numpy
- pandas
- numpy>=1.12
- pandas>=0.19
- scipy
- seaborn
- toolz
Expand Down
4 changes: 2 additions & 2 deletions ci/requirements-py36-hypothesis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ dependencies:
- coveralls
- hypothesis
- flake8
- numpy
- pandas
- numpy>=1.12
- pandas>=0.19
- scipy
- seaborn
- toolz
Expand Down
2 changes: 1 addition & 1 deletion ci/requirements-py36-pandas-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies:
- pytest-env
- coveralls
- flake8
- numpy
- numpy>=1.12
- scipy
- toolz
- pip:
Expand Down
4 changes: 2 additions & 2 deletions ci/requirements-py36-rasterio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ dependencies:
- pytest-cov
- pytest-env
- coveralls
- numpy
- pandas
- numpy>=1.12
- pandas>=0.19
- scipy
- seaborn
- toolz
Expand Down
5 changes: 2 additions & 3 deletions ci/requirements-py36-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ dependencies:
- netcdf4
- pytest
- pytest-env
- numpy
- pandas
- numpy>=1.12
- pandas>=0.19
- scipy
- seaborn
- toolz
- rasterio
- zarr

4 changes: 2 additions & 2 deletions ci/requirements-py36-zarr-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ dependencies:
- pytest-env
- coveralls
- flake8
- numpy
- pandas
- numpy>=1.12
- pandas>=0.19
- scipy
- seaborn
- toolz
Expand Down
4 changes: 2 additions & 2 deletions ci/requirements-py36.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ dependencies:
- pytest-env
- coveralls
- pycodestyle
- numpy
- pandas
- numpy>=1.12
- pandas>=0.19
- scipy
- seaborn
- toolz
Expand Down
4 changes: 2 additions & 2 deletions ci/requirements-py37-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ dependencies:
- netcdf4
- pytest
- pytest-env
- numpy
- pandas
- numpy>=1.12
- pandas>=0.19
- scipy
- seaborn
- toolz
Expand Down
4 changes: 2 additions & 2 deletions ci/requirements-py37.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ dependencies:
- pytest-env
- coveralls
- pycodestyle
- numpy
- pandas
- numpy>=1.12
- pandas>=0.19
- scipy
- seaborn
- toolz
Expand Down
13 changes: 2 additions & 11 deletions doc/gallery/plot_rasterio.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,16 @@
original map projection (see :ref:`recipes.rasterio_rgb`).
"""

import os
import urllib.request

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np
from rasterio.warp import transform

import xarray as xr

# Download the file from rasterio's repository
url = 'https://github.com/mapbox/rasterio/raw/master/tests/data/RGB.byte.tif'
urllib.request.urlretrieve(url, 'RGB.byte.tif')

# Read the data
da = xr.open_rasterio('RGB.byte.tif')
url = 'https://github.com/mapbox/rasterio/raw/master/tests/data/RGB.byte.tif'
da = xr.open_rasterio(url)

# Compute the lon/lat coordinates with rasterio.warp.transform
ny, nx = len(da['y']), len(da['x'])
Expand All @@ -54,6 +48,3 @@
cmap='Greys_r', add_colorbar=False)
ax.coastlines('10m', color='r')
plt.show()

# Delete the file
os.remove('RGB.byte.tif')
13 changes: 2 additions & 11 deletions doc/gallery/plot_rasterio_rgb.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,14 @@
transformation.
"""

import os
import urllib.request

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

import xarray as xr

# Download the file from rasterio's repository
url = 'https://github.com/mapbox/rasterio/raw/master/tests/data/RGB.byte.tif'
urllib.request.urlretrieve(url, 'RGB.byte.tif')

# Read the data
da = xr.open_rasterio('RGB.byte.tif')
url = 'https://github.com/mapbox/rasterio/raw/master/tests/data/RGB.byte.tif'
da = xr.open_rasterio(url)

# The data is in UTM projection. We have to set it manually until
# https://github.com/SciTools/cartopy/issues/813 is implemented
Expand All @@ -37,6 +31,3 @@
da.plot.imshow(ax=ax, rgb='band', transform=crs)
ax.coastlines('10m', color='r')
plt.show()

# Delete the file
os.remove('RGB.byte.tif')
3 changes: 3 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ v0.12.2 (unreleased)
Enhancements
~~~~~~~~~~~~

- Add ``fill_value`` argument for reindex, align, and merge operations
to enable custom fill values. (:issue:`2876`)
By `Zach Griffith <https://github.com/zdgriffith>`_.
- Character arrays' character dimension name decoding and encoding handled by
``var.encoding['char_dim_name']`` (:issue:`2895`)
By `James McCreight <https://github.com/jmccreight>`_.
Expand Down
41 changes: 19 additions & 22 deletions xarray/core/alignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import numpy as np
import pandas as pd

from . import utils
from . import utils, dtypes
from .indexing import get_indexer_nd
from .utils import is_dict_like, is_full_slice
from .variable import IndexVariable, Variable
Expand All @@ -31,20 +31,17 @@ def _get_joiner(join):
raise ValueError('invalid value for join: %s' % join)


_DEFAULT_EXCLUDE = frozenset() # type: frozenset


def align(*objects, **kwargs):
"""align(*objects, join='inner', copy=True, indexes=None,
exclude=frozenset())
def align(*objects, join='inner', copy=True, indexes=None, exclude=frozenset(),
fill_value=dtypes.NA):
"""
Given any number of Dataset and/or DataArray objects, returns new
objects with aligned indexes and dimension sizes.
Array from the aligned objects are suitable as input to mathematical
operators, because along each dimension they have the same index and size.
Missing values (if ``join != 'inner'``) are filled with NaN.
Missing values (if ``join != 'inner'``) are filled with ``fill_value``.
The default fill value is NaN.
Parameters
----------
Expand All @@ -65,11 +62,13 @@ def align(*objects, **kwargs):
``copy=False`` and reindexing is unnecessary, or can be performed with
only slice operations, then the output may share memory with the input.
In either case, new xarray objects are always returned.
exclude : sequence of str, optional
Dimensions that must be excluded from alignment
indexes : dict-like, optional
Any indexes explicitly provided with the `indexes` argument should be
used in preference to the aligned indexes.
exclude : sequence of str, optional
Dimensions that must be excluded from alignment
fill_value : scalar, optional
Value to use for newly missing values
Returns
-------
Expand All @@ -82,15 +81,8 @@ def align(*objects, **kwargs):
If any dimensions without labels on the arguments have different sizes,
or a different size than the size of the aligned dimension labels.
"""
join = kwargs.pop('join', 'inner')
copy = kwargs.pop('copy', True)
indexes = kwargs.pop('indexes', None)
exclude = kwargs.pop('exclude', _DEFAULT_EXCLUDE)
if indexes is None:
indexes = {}
if kwargs:
raise TypeError('align() got unexpected keyword arguments: %s'
% list(kwargs))

if not indexes and len(objects) == 1:
# fast path for the trivial case
Expand Down Expand Up @@ -162,15 +154,17 @@ def align(*objects, **kwargs):
# fast path for no reindexing necessary
new_obj = obj.copy(deep=copy)
else:
new_obj = obj.reindex(copy=copy, **valid_indexers)
new_obj = obj.reindex(copy=copy, fill_value=fill_value,
**valid_indexers)
new_obj.encoding = obj.encoding
result.append(new_obj)

return tuple(result)


def deep_align(objects, join='inner', copy=True, indexes=None,
exclude=frozenset(), raise_on_invalid=True):
exclude=frozenset(), raise_on_invalid=True,
fill_value=dtypes.NA):
"""Align objects for merging, recursing into dictionary values.
This function is not public API.
Expand Down Expand Up @@ -214,7 +208,7 @@ def is_alignable(obj):
out.append(variables)

aligned = align(*targets, join=join, copy=copy, indexes=indexes,
exclude=exclude)
exclude=exclude, fill_value=fill_value)

for position, key, aligned_obj in zip(positions, keys, aligned):
if key is no_key:
Expand Down Expand Up @@ -270,6 +264,7 @@ def reindex_variables(
method: Optional[str] = None,
tolerance: Any = None,
copy: bool = True,
fill_value: Optional[Any] = dtypes.NA,
) -> 'Tuple[OrderedDict[Any, Variable], OrderedDict[Any, pd.Index]]':
"""Conform a dictionary of aligned variables onto a new set of variables,
filling in missing values with NaN.
Expand Down Expand Up @@ -305,6 +300,8 @@ def reindex_variables(
``copy=False`` and reindexing is unnecessary, or can be performed
with only slice operations, then the output may share memory with
the input. In either case, new xarray objects are always returned.
fill_value : scalar, optional
Value to use for newly missing values
Returns
-------
Expand Down Expand Up @@ -380,7 +377,7 @@ def reindex_variables(
needs_masking = any(d in masked_dims for d in var.dims)

if needs_masking:
new_var = var._getitem_with_mask(key)
new_var = var._getitem_with_mask(key, fill_value=fill_value)
elif all(is_full_slice(k) for k in key):
# no reindexing necessary
# here we need to manually deal with copying data, since
Expand Down
22 changes: 14 additions & 8 deletions xarray/core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,9 +879,10 @@ def sel_points(self, dim='points', method=None, tolerance=None,
dim=dim, method=method, tolerance=tolerance, **indexers)
return self._from_temp_dataset(ds)

def reindex_like(self, other, method=None, tolerance=None, copy=True):
"""Conform this object onto the indexes of another object, filling
in missing values with NaN.
def reindex_like(self, other, method=None, tolerance=None, copy=True,
fill_value=dtypes.NA):
"""Conform this object onto the indexes of another object, filling in
missing values with ``fill_value``. The default fill value is NaN.
Parameters
----------
Expand Down Expand Up @@ -910,6 +911,8 @@ def reindex_like(self, other, method=None, tolerance=None, copy=True):
``copy=False`` and reindexing is unnecessary, or can be performed
with only slice operations, then the output may share memory with
the input. In either case, a new xarray object is always returned.
fill_value : scalar, optional
Value to use for newly missing values
Returns
-------
Expand All @@ -924,12 +927,12 @@ def reindex_like(self, other, method=None, tolerance=None, copy=True):
"""
indexers = reindex_like_indexers(self, other)
return self.reindex(method=method, tolerance=tolerance, copy=copy,
**indexers)
fill_value=fill_value, **indexers)

def reindex(self, indexers=None, method=None, tolerance=None, copy=True,
**indexers_kwargs):
"""Conform this object onto a new set of indexes, filling in
missing values with NaN.
fill_value=dtypes.NA, **indexers_kwargs):
"""Conform this object onto the indexes of another object, filling in
missing values with ``fill_value``. The default fill value is NaN.
Parameters
----------
Expand All @@ -956,6 +959,8 @@ def reindex(self, indexers=None, method=None, tolerance=None, copy=True,
Maximum distance between original and new labels for inexact
matches. The values of the index at the matching locations must
satisfy the equation ``abs(index[indexer] - target) <= tolerance``.
fill_value : scalar, optional
Value to use for newly missing values
**indexers_kwarg : {dim: indexer, ...}, optional
The keyword arguments form of ``indexers``.
One of indexers or indexers_kwargs must be provided.
Expand All @@ -974,7 +979,8 @@ def reindex(self, indexers=None, method=None, tolerance=None, copy=True,
indexers = either_dict_or_kwargs(
indexers, indexers_kwargs, 'reindex')
ds = self._to_temp_dataset().reindex(
indexers=indexers, method=method, tolerance=tolerance, copy=copy)
indexers=indexers, method=method, tolerance=tolerance, copy=copy,
fill_value=fill_value)
return self._from_temp_dataset(ds)

def interp(self, coords=None, method='linear', assume_sorted=False,
Expand Down
Loading

0 comments on commit 106034d

Please sign in to comment.