Xarray and PythonCall.jl
In the Python ecosystem Xarray is by far the most popular package for working with multidimensional labelled arrays. The main data structures it provides are:
DimensionalData integrates with PythonCall.jl to allow converting these Xarray types to their DimensionalData equivalent:
import PythonCall: pyconvert
# By default this will share the underlying array
my_dimarray = pyconvert(DimArray, my_dataarray)
my_dimstack = pyconvert(DimStack, my_dataset)DimensionalData also defines Py() conversion methods for DimArray and DimStack to convert them to a DataArray and Dataset respectively. These are opt-in because they require Xarray to be installed, so they must be enabled first:
DimensionalData.set_xarray_convert!(true)We recommend restarting Julia after changing the preference. Once it's enabled, passing a DimArray or DimStack to a Python function will automatically convert it. Otherwise they will be passed as opaque Julia objects, though a DimArray will still support the array interface in Python so it can be used with e.g. numpy.
The preference can be overridden for a single conversion with the xarray argument, which is useful if you only occasionally want an Xarray type:
Py(my_dimarray; xarray=true) # Always a DataArray
Py(my_dimstack; xarray=false) # Never a DatasetDimensionalData.set_xarray_convert! Function
set_xarray_convert!(x::Bool)Set whether converting an AbstractDimArray/AbstractDimStack to Python with PythonCall.Py() should create an xarray.DataArray/xarray.Dataset.
Defaults to false, in which case both are passed through as opaque Julia objects (an AbstractDimArray still supports the array interface in Python). Note that enabling it means that any conversion to Python will import xarray, so it must be installed.
The preference is set for the active project, and restarting Julia afterwards is recommended.
sourceHere are some things to keep in mind when converting:
pyconvert(DimArray, x)is zero-copy by default, i.e. it will share the underlying array with Python and register itself with Pythons GC to ensure that the memory isn't garbage-collected prematurely. If you want to make a copy you can call it likepyconvert(DimArray, x; copy=true). The same is true forPy(x), it's zero-copy by default and you can passcopy=trueto make it copy. An exception to the above is when convertingxtox_jl, andxcontainsmissingvalues. These cannot be represented in Python so in such cases a copy will always be made and themissingvalues will be converted to NaNs when possible. When conversion is not possible (e.g. because the array holds integers rather floats) an exception will be thrown.When doing a zero-copy conversion from
xtox_jl,parent(x_jl)will be a PyArray. In most situations there should be no overhead from this but note that aPyArrayis not aDenseArrayso some operations that dispatch onDenseArraymay not be performant, e.g. BLAS calls. See these issues for more information:When
copy=true,parent(x_jl)will always be a standardArray. However, we do not consider the type of parent array covered by semver so this may change in the future.Python stores arrays in row-major order whereas Julia stores them in column-major order, hence the dimensions on a converted
DimArraywill be in reverse order from the originalDataArray(and vice versa). This is done to ensure that the 'fast axis' to iterate over is the same dimension in both Julia and Python.Only the metadata of the array/stack itself is converted to
attrs. Any metadata attached to lookups (e.g. units) is not passed to the coordinates when converting to Python, and likewise coordinateattrsare not converted to lookup metadata when converting to Julia.