def __getitem__(self, key, key_id=None, key_var=None): """ Returns a specific value by asking the table for the value. The numerical key_id or Variable key_var can be given explicitly. This prevents dictionary lookups below. Just 'key' is either a key_id or a key_var. TODO: - Pull from self.table instead of from self.table.widget_origin? """ # Convert from 'key' to the numerical 'key_id' if key_id is None: if not isinstance(key, Integral): key_id = self._domain.index(key) else: key_id = key # Get key_var for the Variable itself. if key_var is None: key_var = self.table.domain[key_id] # Get the value cached in memory. #value = self._values[keyid] # ._value has been removed in Orange 3.2 value = RowInstance.__getitem__(self, key=key, key_id=key_id, key_var=key_var) # A nan means the value is not yet available. if numpy.isnan(value): # Pull and cache the value. # TODO: Pull from self.table.widget_origin? if self.table.widget_origin is not None: value = self.table.widget_origin.pull_cell(self.row_index_full, key_var) elif self.table.table_origin is not None: value = self.table.table_origin[self.row_index_full][key_var] # TODO: Is this necessary? Where does the 'int' come from? if isinstance(value, (int, numpy.float)): value = float(value) # Cache the value both in this RowInstance as well as in # the original table. # TODO: Can we do everything with only self.table.X? #self._values[keyid] = value # ._values is removed in Orange 3.2 RowInstance.__setitem__(self, key_var, value) # Only cache in self.table if there is a corresponding row there. # TODO: Should we do this caching here at all? Probably better # to do this in the LazyTable itself? E.g. preventing this # pylint warning: # pylint: disable=protected-access if self.row_index_materialized is not None: if 0 <= key_id < len(self._domain.attributes): self.table.X[self.row_index_materialized][key_id] = value elif key_id >= len(self._domain.attributes): self.table._Y[self.row_index_materialized][key_id - len(self.domain.attributes)] = value else: self.table._metas = self._metas[-1 - key_id] val = Value(self._domain[key_id], value) return val
def __init__(self, table, row_index, region_of_interest_only=False): """ Construct a data instance representing the given row of the table. row_index is the real row of the data set, which might not be the materialized row. When region_of_interest_only is set, then the row is only stored in the table if it's in the region_of_interest. It should only be necessary to set this flag internally. TODO: - Ensure that rows that are not in the region of interest are removed from memory because saving memory is the reason they are not appended to the table. - Perhaps cache whether an instance is in the region of interest so they can be skipped later. """ # The table that this row belongs to, should be a LazyTable instance. self.table = table # row_index_full is enough to get the attribute values of this row. self.row_index_full = row_index # TODO: A None for row_index_materialized should not happen anymore # because this is now checked in LazyTable.__getitem__(). However # this does mean that the in_roi code is not functional anymore. # Replace all the RoI code with Filters? # row_index_materialized is used to cache the attribute values in # memory in self.table.X, Y and metas. It is set to None if there is # no corresponding row in self.table. self.row_index_materialized = table.row_mapping.get(self.row_index_full, None) if self.row_index_materialized is None: # The row has not yet been stored in the table. We instantiate # Instance (super of RowInstance) instead of RowInstance because # there is no corresponding row in memory yet. # pylint: disable=non-parent-init-called Instance.__init__(self, table.domain) # Nevertheless, from this moment on, we can use this # LazyRowInstance because all attribute values can be retrieved # on the fly. if self.in_filters(): # The row is new and within the filter. # Therefore needs to be added to be appended to self.table # if it is within the region_of_interest as well. self_in_region_of_interest = self.in_region_of_interest() if not region_of_interest_only or self_in_region_of_interest: # TODO: Replace the region_of_interest with Filters. # The new row_index_materialized # will be set to the current length of the table in memory. # This ensures that the row is inserted at the right place # (that is, at the end) when appending. self.row_index_materialized = table.len_instantiated_data() self.row_index = self.row_index_materialized self.table.append(self) self.table.row_mapping[self.row_index_full] = self.row_index_materialized # A full RowInstance can now be initialized because the row # is indeed available in the table. RowInstance.__init__(self, table, self.row_index_materialized) else: # This new row is not available in the table, and we'd like # to keep it this way to conserve memory. self.row_index_materialized = None self.row_index = self.row_index_materialized else: # This new row is not available in the table, and we'd like # to keep it this way to conserve memory. self.row_index_materialized = None self.row_index = self.row_index_materialized else: # The row is already available in the table. RowInstance.__init__(self, table, self.row_index_materialized)