def item_get_elements(self, s, type, name, filters=None): if filters: # Convert filter elements to strings filters = {dim: as_str_list(ele) for dim, ele in filters.items()} try: # Retrieve the cached value with this exact set of filters return self.cache_get(s, type, name, filters) except KeyError: pass # Cache miss try: # Retrieve a cached, unfiltered value of the same item unfiltered = self.cache_get(s, type, name, None) except KeyError: pass # Cache miss else: # Success; filter and return return filtered(unfiltered, filters) # Failed to load item from cache # Retrieve the item item = self._get_item(s, type, name, load=True) idx_names = list(item.getIdxNames()) idx_sets = list(item.getIdxSets()) # Get list of elements, using filters if provided if filters is not None: jFilter = java.HashMap() for idx_name, values in filters.items(): # Retrieve the elements of the index set as a list idx_set = idx_sets[idx_names.index(idx_name)] elements = self.item_get_elements(s, 'set', idx_set).tolist() # Filter for only included values and store filtered_elements = filter(lambda e: e in values, elements) jFilter.put(idx_name, to_jlist(filtered_elements)) jList = item.getElements(jFilter) else: jList = item.getElements() if item.getDim() > 0: # Mapping set or multi-dimensional equation, parameter, or variable columns = copy(idx_names) # Prepare dtypes for index columns dtypes = {} for idx_name, idx_set in zip(columns, idx_sets): # NB using categoricals could be more memory-efficient, but # requires adjustment of tests/documentation. See # https://github.com/iiasa/ixmp/issues/228 # dtypes[idx_name] = CategoricalDtype( # self.item_get_elements(s, 'set', idx_set)) dtypes[idx_name] = str # Prepare dtypes for additional columns if type == 'par': columns.extend(['value', 'unit']) dtypes['value'] = float # Same as above # dtypes['unit'] = CategoricalDtype(self.jobj.getUnitList()) dtypes['unit'] = str elif type in ('equ', 'var'): columns.extend(['lvl', 'mrg']) dtypes.update({'lvl': float, 'mrg': float}) # Prepare empty DataFrame result = pd.DataFrame(index=pd.RangeIndex(len(jList)), columns=columns) # Copy vectors from Java into DataFrame columns # NB [:] causes JPype to use a faster code path for i in range(len(idx_sets)): result.iloc[:, i] = item.getCol(i, jList)[:] if type == 'par': result.loc[:, 'value'] = item.getValues(jList)[:] result.loc[:, 'unit'] = item.getUnits(jList)[:] elif type in ('equ', 'var'): result.loc[:, 'lvl'] = item.getLevels(jList)[:] result.loc[:, 'mrg'] = item.getMarginals(jList)[:] # .loc assignment above modifies dtypes; set afterwards result = result.astype(dtypes) elif type == 'set': # Index sets # dtype=object is to silence a warning in pandas 1.0 result = pd.Series(item.getCol(0, jList), dtype=object) elif type == 'par': # Scalar parameters result = dict(value=item.getScalarValue().floatValue(), unit=str(item.getScalarUnit())) elif type in ('equ', 'var'): # Scalar equations and variables result = dict(lvl=item.getScalarLevel().floatValue(), mrg=item.getScalarMarginal().floatValue()) # Store cache self.cache(s, type, name, filters, result) return result
def test_filtered(): df = pd.DataFrame() assert df is utils.filtered(df, filters=None)