Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/non decorator transformations #107

Merged
merged 7 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions polytope/datacube/backends/datacube.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import importlib
import logging
import math
from abc import ABC, abstractmethod
Expand Down Expand Up @@ -53,9 +52,7 @@ def _create_axes(self, name, values, transformation_type_key, transformation_opt
# factory inside datacube_transformations to set the has_transform, is_cyclic etc axis properties
# add the specific transformation handled here to the relevant axes
# Modify the axis to update with the tag
decorator_module = importlib.import_module("polytope.datacube.datacube_axis")
decorator = getattr(decorator_module, transformation_type_key)
decorator(self._axes[axis_name])

if transformation not in self._axes[axis_name].transformations: # Avoids duplicates being stored
self._axes[axis_name].transformations.append(transformation)

Expand Down
2 changes: 1 addition & 1 deletion polytope/datacube/backends/fdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def sort_fdb_request_ranges(self, range_lengths, current_start_idx, lat_length):
return (original_indices, sorted_request_ranges)

def datacube_natural_indexes(self, axis, subarray):
indexes = subarray[axis.name]
indexes = subarray.get(axis.name, None)
return indexes

def select(self, path, unmapped_path):
Expand Down
29 changes: 17 additions & 12 deletions polytope/datacube/backends/xarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,7 @@ def get(self, requests: IndexTree):
path.update(unmapped_path)

unmapped_path = {}
for key in path.keys():
if key not in self.dataarray.dims:
path.pop(key)
if key not in self.dataarray.coords.dtypes:
unmapped_path.update({key: path[key]})
path.pop(key)
for key in self.dataarray.coords.dtypes:
key_dtype = self.dataarray.coords.dtypes[key]
if key_dtype.type is np.str_ and key in path.keys():
unmapped_path.update({key: path[key]})
path.pop(key)
self.refit_path(path, unmapped_path, path)

subxarray = self.dataarray.sel(path, method="nearest")
subxarray = subxarray.sel(unmapped_path)
Expand All @@ -97,8 +87,23 @@ def datacube_natural_indexes(self, axis, subarray):
indexes = subarray[axis.name].values
return indexes

def refit_path(self, path_copy, unmapped_path, path):
for key in path.keys():
if key not in self.dataarray.dims:
path_copy.pop(key)
if key not in self.dataarray.coords.dtypes:
unmapped_path.update({key: path[key]})
path_copy.pop(key)
for key in self.dataarray.coords.dtypes:
key_dtype = self.dataarray.coords.dtypes[key]
if key_dtype.type is np.str_ and key in path.keys():
unmapped_path.update({key: path[key]})
path_copy.pop(key, None)

def select(self, path, unmapped_path):
subarray = self.dataarray.sel(path, method="nearest")
path_copy = deepcopy(path)
self.refit_path(path_copy, unmapped_path, path)
subarray = self.dataarray.sel(path_copy, method="nearest")
subarray = subarray.sel(unmapped_path)
return subarray

Expand Down
82 changes: 57 additions & 25 deletions polytope/datacube/datacube_axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import numpy as np
import pandas as pd

from .transformations.datacube_cyclic.cyclic_axis_decorator import cyclic
from .transformations.datacube_mappers.mapper_axis_decorator import mapper
from .transformations.datacube_merger.merger_axis_decorator import merge
from .transformations.datacube_reverse.reverse_axis_decorator import reverse
from .transformations.datacube_type_change.type_change_axis_decorator import type_change
from .transformations.datacube_cyclic.datacube_cyclic import DatacubeAxisCyclic
from .transformations.datacube_mappers.datacube_mappers import DatacubeMapper
from .transformations.datacube_merger.datacube_merger import DatacubeAxisMerger
from .transformations.datacube_reverse.datacube_reverse import DatacubeAxisReverse
from .transformations.datacube_type_change.datacube_type_change import (
DatacubeAxisTypeChange,
)


class DatacubeAxis(ABC):
Expand All @@ -20,10 +22,12 @@ class DatacubeAxis(ABC):
reorder = False
type_change = False

def update_axis(self):
if self.is_cyclic:
self = cyclic(self)
return self
def order_tranformations(self):
self.transformations = sorted(self.transformations, key=lambda x: transformations_order[type(x)])

def give_transformations_parents(self):
for i, transform in enumerate(self.transformations[1:]):
transform.parent = self.transformations[i - 1]

# Convert from user-provided value to CONTINUOUS type (e.g. float, pd.timestamp)
@abstractmethod
Expand All @@ -44,15 +48,21 @@ def serialize(self, value: Any) -> Any:
pass

def to_intervals(self, range):
return [range]
intervals = [range]
for transformation in self.transformations[::-1]:
intervals = transformation.to_intervals(range, intervals, self)
return intervals

def remap(self, range: List) -> Any:
return [range]
ranges = [range]
for transformation in self.transformations[::-1]:
ranges = transformation.remap(range, ranges, self)
return ranges

def unmap_to_datacube(self, path, unmapped_path):
return (path, unmapped_path)

def find_indexes(self, path, datacube):
def find_standard_indexes(self, path, datacube):
unmapped_path = {}
path_copy = deepcopy(path)
for key in path_copy:
Expand All @@ -61,16 +71,31 @@ def find_indexes(self, path, datacube):
subarray = datacube.select(path, unmapped_path)
return datacube.datacube_natural_indexes(self, subarray)

def find_indexes(self, path, datacube):
indexes = self.find_standard_indexes(path, datacube)
for transformation in self.transformations[::-1]:
indexes = transformation.find_modified_indexes(indexes, path, datacube, self)
return indexes

def offset(self, value):
return 0
offset = 0
for transformation in self.transformations[::-1]:
offset = transformation.offset(value, self, offset)
return offset

def unmap_path_key(self, key_value_path, leaf_path, unwanted_path):
for transformation in self.transformations[::-1]:
(key_value_path, leaf_path, unwanted_path) = transformation.unmap_path_key(
key_value_path, leaf_path, unwanted_path, self
)
return (key_value_path, leaf_path, unwanted_path)

def _remap_val_to_axis_range(self, value):
for transformation in self.transformations[::-1]:
value = transformation._remap_val_to_axis_range(value, self)
return value

def find_indices_between(self, index_ranges, low, up, datacube, method=None):
def find_standard_indices_between(self, index_ranges, low, up, datacube, method=None):
indexes_between_ranges = []
for indexes in index_ranges:
if self.name in datacube.complete_axes and self.name not in datacube.transformed_axes:
Expand Down Expand Up @@ -104,6 +129,14 @@ def find_indices_between(self, index_ranges, low, up, datacube, method=None):
indexes_between_ranges.append(indexes_between)
return indexes_between_ranges

def find_indices_between(self, indexes_ranges, low, up, datacube, method=None):
indexes_between_ranges = self.find_standard_indices_between(indexes_ranges, low, up, datacube, method)
for transformation in self.transformations[::-1]:
indexes_between_ranges = transformation.find_indices_between(
indexes_ranges, low, up, datacube, method, indexes_between_ranges, self
)
return indexes_between_ranges

@staticmethod
def create_standard(name, values, datacube):
values = np.array(values)
Expand All @@ -122,10 +155,16 @@ def check_axis_type(name, values):
raise ValueError(f"Could not create a mapper for index type {values.dtype.type} for axis {name}")


@reverse
@cyclic
@mapper
@type_change
transformations_order = [
DatacubeAxisMerger,
DatacubeAxisReverse,
DatacubeAxisCyclic,
DatacubeMapper,
DatacubeAxisTypeChange,
]
transformations_order = {key: i for i, key in enumerate(transformations_order)}


class IntDatacubeAxis(DatacubeAxis):
def __init__(self):
self.name = None
Expand All @@ -148,10 +187,6 @@ def serialize(self, value):
return value


@reverse
@cyclic
@mapper
@type_change
class FloatDatacubeAxis(DatacubeAxis):
def __init__(self):
self.name = None
Expand All @@ -173,7 +208,6 @@ def serialize(self, value):
return value


@merge
class PandasTimestampDatacubeAxis(DatacubeAxis):
def __init__(self):
self.name = None
Expand Down Expand Up @@ -203,7 +237,6 @@ def offset(self, value):
return None


@merge
class PandasTimedeltaDatacubeAxis(DatacubeAxis):
def __init__(self):
self.name = None
Expand Down Expand Up @@ -233,7 +266,6 @@ def offset(self, value):
return None


@type_change
class UnsliceableDatacubeAxis(DatacubeAxis):
def __init__(self):
self.name = None
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from .cyclic_axis_decorator import *
from .datacube_cyclic import *

This file was deleted.

Loading
Loading