def cube(axes, values=None, broadcast=True, dtype=None): """Create a cube object. axes: list of axis of the cube values: optional, list of values of the cube. Can be other cubes for build a report. Ex. cp.cube([time]) cp.cube([time,product]) cp.cube([time,product],[10,20,30,40,50,60,70,80]) cp.cube([time,product],cp.random) cp.cube([index_reports],[report_1,report_2]) """ if values is None: if not dtype is None: if dtype is str: return cubepy.Cube.full(axes, '', dtype='U25') elif kindToString(np.dtype(dtype).kind) == "string": return cubepy.Cube.full(axes, '', dtype=dtype) return cubepy.Cube.zeros(axes) else: if isinstance(values, list) or isinstance(values, np.ndarray): if len(values) > 0: if isinstance(values[0], cubepy.Cube): #use stack if isinstance(axes, list): axes = axes[0] return cubepy.stack(values, axes, broadcast) return cubepy.Cube(axes, values, fillValues=True, dtype=dtype) elif isinstance(values, numbers.Number) and values == random: theSize = [len(x) for x in axes] return cube(axes, np.random.randint(100, size=theSize), dtype=dtype) else: return cubepy.Cube.full(axes, values, dtype=dtype)
def aggregate(cube, mapCube, indexToRemove, targetIndex): """ Aggregates the values in Cube to generate the result indexed by targetIndex. Map gives the value of targetIndex for each element of indexToRemove Example for aggregating time information into annual index the syntax is: cp.aggregate(cube, map, time, years ) """ grouping_index_mat = cubepy.Cube([targetIndex], targetIndex.values) mat_allocation = mapCube == grouping_index_mat return (cube * mat_allocation).sum(indexToRemove)
def hierarchize(cube, levels, maps): mapArray = nodeDic[maps[0]].result coordValues = mapArray.values.copy() targetIndexId = nodeDic[levels[1]].result.name for pos, level in enumerate(levels): if pos > 0: if not maps[pos] is None: mapArrayLevel = nodeDic[maps[pos]].result for ii in range(len(coordValues)): if not coordValues[ii] is None: try: newVal = mapArrayLevel.filter( mapArrayLevel.dims[0], coordValues[ii]).values.item(0) coordValues[ii] = newVal except Exception as ex: coordValues[ii] = None #raise ValueError("Hierarchy not found. Level: " + targetIndexId + ", value: " + coordValues[ii]) pass # convert to dataarray _coords = [] for _axis in cube.axes: _coord = pd.Index(_axis.values, name=_axis.name) _coords.append(_coord) dataArray = xr.DataArray(cube.values, _coords) # perform aggregate dataArray.coords[levels[0]].values = coordValues _df = dataArray.to_series() _df = _df.groupby(list(dataArray.dims), sort=False).agg(sby) _da = _df.to_xarray() reindex_dic = dict() for dimension in _da.dims: if dimension == levels[0]: reindex_dic[dimension] = nodeDic[levels[-1:] [0]].result.values elif dimension in nodeDic and isinstance( nodeDic[dimension].result, cubepy.Index): reindex_dic[dimension] = nodeDic[dimension].result.values _db = _da.reindex(reindex_dic) # convert to cube _indexes = [] for _dim in _db.dims: _index = cubepy.Index(_dim, _db.coords[_dim].values) _indexes.append(_index) _cube = cubepy.Cube(_indexes, _db.values) return _cube
def find(param1, param2, compareType=1, caseSensitive=True): """ param1: value or indexarray for compare param2: index compare to compareType: cp.exact=1, cp.start_with=2, cp.end_with=3, cp.contain=4 caseSensitive: able to differentiate between uppercase and lowercase (by default True) If param1 is a scalar (numeric or str) and param2 is an index: return cube indexed by param2 with True on ocurrences of param2 Ex. result = cp.apply("te", region, cp.end_with) If param1 is an index and param2 is an index too: return cube indexed by param1 and param2 with True on ocurrences of param1 on param2 Ex. result = cp.apply(subregion, region, cp.contain) """ def _fn(item, value): if isinstance(item, str) == False: item = str(item) if isinstance(value, str) == False: value = str(value) if compareType == 1: if caseSensitive: return item == value else: return item.lower() == value.lower() elif compareType == 2: if caseSensitive: return item[:len(value)] == value else: return item[:len(value)].lower() == value.lower() elif compareType == 3: if caseSensitive: return item[-len(value):] == value else: return item[-len(value):].lower() == value.lower() elif compareType == 4: if caseSensitive: return value in item else: return value.lower() in item.lower() if (isinstance(param1, str) or str(param1).isnumeric()) and isinstance( param2, cubepy.Index): vfn = np.vectorize(_fn) return cubepy.Cube([param2], vfn(param2.values, param1)) if isinstance(param1, cubepy.Index) and isinstance(param2, cubepy.Index): _res = cubepy.Cube.full([param1, param2], False) rr = 0 for row in param1.values: cc = 0 for col in param2.values: _res.values[rr, cc] = _fn(col, row) cc += 1 rr += 1 return _res
def apply(fn, param1, param2=None, start=None): """ Apply functions to index and cubes. Multiple results can be obtained fn: function to apply param1: index or cube param2: index or cube start: scalar or cube Ex. cp.apply(lambda x: x[:2] ,indexRegion): return new cube indexed by "indexRegion" and apply fn on each item cp.apply(lambda x: x*5 ,cubeSales): return new cube result of apply fn on all values of the cubeSales cp.apply( cp.addPeriods, start_proj , end_proj): Return new cube result of apply fn on "start_proj" with "end_proj" cp.apply(lambda x: x+1, indexYear, start=10) : Return new cube indexed by "indexYear", result of apply fn starting with scalar value "10" cp.apply(lambda x: x+1, indexYear, start=prices) : Return new cube indexed by "indexYear", result of apply fn starting with cube "prices" """ if callable(fn): vfn = np.vectorize(fn) if param2 is None: if isinstance(param1, cubepy.Index): if start is None: return cubepy.Cube([param1], vfn(param1.values)) elif isinstance(start, cubepy.Cube): values = [start.values] numEls = len(param1) for nn in range(numEls - 1): values.append(fn(values[nn])) new_axes = start._axes.insert(param1, 0) return cubepy.Cube(new_axes, values) else: values = [start] numEls = len(param1) for nn in range(numEls - 1): values.append(fn(values[nn])) return cubepy.Cube(param1, values) if isinstance(param1, cubepy.Cube): return param1.apply(fn) elif isinstance(param1, cubepy.Cube) and isinstance( param2, cubepy.Cube): return apply_op(param1, param2, vfn) return None
def createCube(self, nodeId, npArray): _dimsNames = [ self.AXISNAME + str(x) + "." + nodeId for x in range(npArray.ndim) ] _dimsValues = [ list(x) for x in (range(npArray.shape[y]) for y in range(npArray.ndim)) ] _indexes = [ cubepy.Index(_dimsNames[x], _dimsValues[x]) for x in range(len(_dimsNames)) ] _cube = cubepy.Cube(_indexes, npArray) return _cube
def cubeEvaluate(self, result, nodeDic, nodeId, dims=None, rows=None, columns=None, summaryBy="sum", bottomTotal=False, rightTotal=False, fromRow=0, toRow=0): sby = safesum if summaryBy == 'avg': sby = safemean elif summaryBy == 'max': sby = safemax elif summaryBy == 'min': sby = safemin if (fromRow is None) or int(fromRow) <= 0: fromRow = 1 if (toRow is None) or int(toRow) < 1: toRow = 100 fromRow = int(fromRow) toRow = int(toRow) result = self.applyHierarchy(result, nodeDic, nodeId, dims, rows, columns, sby) _filters = [] _rows = [] _columns = [] if not rows is None: for row in rows: if self.hasDim(result, str(row["field"])): _rows.append(str(row["field"])) self.addToFilter(nodeDic, row, _filters) if not columns is None: for column in columns: if self.hasDim(result, str(column["field"])): _columns.append(str(column["field"])) self.addToFilter(nodeDic, column, _filters) if not dims is None: for dim in dims: if self.hasDim(result, str(dim["field"])): self.addToFilter(nodeDic, dim, _filters) tmp = None if len(_rows) == 0 and len(_columns) == 0 and result.ndim > 0: #_rows.append( result.dims[0] ) tmp = cubepy.Cube([], result.filter(_filters).reduce(sby)) else: tmp = result.filter(_filters).reduce( sby, keep=(_rows + _columns)).transpose(_rows + _columns) finalValues = tmp.values finalIndexes = [] if tmp.ndim > 0: finalIndexes = tmp.axes[0].values finalColumns = ["Total"] if tmp.ndim == 2: finalColumns = tmp.axes[1].values # Add totales _totalRow = None if bottomTotal and len(_rows) > 0: # add total row #finalIndexes = np.append(finalIndexes,"Total") if tmp.ndim == 1: _totalRow = finalValues.sum(axis=0).reshape(1) #finalValues = np.append( finalValues, finalValues.sum(axis=0).reshape(1), axis=0) else: _totalRow = finalValues.sum(axis=0).reshape( 1, len(finalValues[0])) _totalRow = _totalRow[0] if rightTotal: _totalRow = np.append(_totalRow, finalValues.sum()) if rightTotal and len(_columns) > 0: # add total column if tmp.ndim == 1: finalIndexes = np.append(finalIndexes, "Total") finalValues = np.append(finalValues, finalValues.sum(axis=0).reshape(1), axis=0) else: finalColumns = np.append(finalColumns, "Total") finalValues = np.append(finalValues, finalValues.sum(axis=1).reshape( len(finalValues), 1), axis=1) # con una sola dimension # chek inf if kindToString(finalValues.dtype.kind) == "numeric": if np.isinf(finalValues).any(): finalValues[np.isinf(finalValues)] = None # chec if haver nan values # if np.isnan(finalValues).any(): if pd.isnull(finalValues).any(): try: finalValues = np.where(np.isnan(finalValues), None, finalValues) except: finalValues[pd.isnull(finalValues)] = None res = {} pageInfo = None onRow = None onColumn = None if len(_rows) == 0 and len(_columns) == 0: res = { "columns": [], "index": ["Total"], "data": [[finalValues.tolist()]] } elif len(_rows) == 0: onColumn = _columns[0] res = { "columns": finalIndexes[:300].tolist(), "index": finalColumns, "data": [finalValues[:300].tolist()] } elif len(_columns) == 0: if (len(finalIndexes) > self.PAGESIZE): pageInfo = { "fromRow": int(fromRow), "toRow": int(toRow), "totalRows": len(finalIndexes) } onRow = _rows[0] res = { "columns": finalColumns, "index": finalIndexes[fromRow - 1:toRow].tolist(), "data": [[x] for x in finalValues[fromRow - 1:toRow].tolist()] } # add total rows if not _totalRow is None: res["index"].append("Total") res["data"].append(_totalRow.tolist()) else: onColumn = _columns[0] onRow = _rows[0] if (len(finalIndexes) > self.PAGESIZE): pageInfo = { "fromRow": int(fromRow), "toRow": int(toRow), "totalRows": len(finalIndexes) } res = { "columns": finalColumns[:300].tolist(), "index": finalIndexes[fromRow - 1:toRow].tolist(), "data": finalValues[fromRow - 1:toRow, :300].tolist() } # add total rows if not _totalRow is None: res["index"].append("Total") res["data"].append(_totalRow[:300].tolist()) return self.createResult(res, type(tmp), onRow=onRow, onColumn=onColumn, node=nodeDic[nodeId], pageInfo=pageInfo)