Skip to content

Commit

Permalink
feat: add aggregates to raw data and update Hydro matrices
Browse files Browse the repository at this point in the history
  • Loading branch information
hdinia committed Sep 16, 2024
1 parent 182e984 commit 4d88eb6
Show file tree
Hide file tree
Showing 14 changed files with 197 additions and 74 deletions.
14 changes: 14 additions & 0 deletions antarest/study/web/raw_studies_blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import typing as t
from pathlib import Path, PurePosixPath

import numpy as np
from fastapi import APIRouter, Body, Depends, File, HTTPException
from fastapi.params import Param, Query
from starlette.responses import FileResponse, JSONResponse, PlainTextResponse, Response, StreamingResponse
Expand Down Expand Up @@ -114,6 +115,7 @@ def get_study(
path: str = Param("/", examples=get_path_examples()), # type: ignore
depth: int = 3,
formatted: bool = True,
aggregates: bool = Query(default=False, description="Whether to calculate aggregates for 2D matrices"),
current_user: JWTUser = Depends(auth.get_current_user),
) -> t.Any:
"""
Expand All @@ -136,6 +138,17 @@ def get_study(
parameters = RequestParameters(user=current_user)
output = study_service.get(uuid, path, depth=depth, formatted=formatted, params=parameters)

# Temporary workaround to calculate aggregates for 2D matrices
if aggregates and isinstance(output, dict) and "data" in output:
matrix = np.asarray(output["data"])
if matrix.ndim == 2:
aggregate_values = {
"min": np.nanmin(matrix, axis=1).tolist(),
"max": np.nanmax(matrix, axis=1).tolist(),
"avg": np.nanmean(matrix, axis=1).tolist(),
}
output["aggregates"] = aggregate_values

if isinstance(output, bytes):
# Guess the suffix form the target data
resource_path = PurePosixPath(path)
Expand Down Expand Up @@ -189,6 +202,7 @@ def get_study(
indent=None,
separators=(",", ":"),
).encode("utf-8")

return Response(content=json_response, media_type="application/json")

@bp.get(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import {
StudyMetadata,
Area,
MatrixType,
} from "../../../../../../../../common/types";
import { StudyMetadata, Area } from "../../../../../../../../common/types";
import client from "../../../../../../../../services/api/client";
import { MatrixDataDTO } from "../../../../../../../common/MatrixGrid/types";
import { AreaCoefficientItem } from "../utils";

////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -44,7 +41,7 @@ export async function setAllocationFormFields(

export const getAllocationMatrix = async (
studyId: StudyMetadata["id"],
): Promise<MatrixType> => {
): Promise<MatrixDataDTO> => {
const res = await client.get(
`v1/studies/${studyId}/areas/hydro/allocation/matrix`,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import {
StudyMetadata,
Area,
MatrixType,
} from "../../../../../../../../common/types";
import { StudyMetadata, Area } from "../../../../../../../../common/types";
import client from "../../../../../../../../services/api/client";
import { MatrixDataDTO } from "../../../../../../../common/MatrixGrid/types";
import { AreaCoefficientItem } from "../utils";

////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -44,7 +41,7 @@ export async function setCorrelationFormFields(

export async function getCorrelationMatrix(
studyId: StudyMetadata["id"],
): Promise<MatrixType> {
): Promise<MatrixDataDTO> {
const res = await client.get(
`v1/studies/${studyId}/areas/hydro/correlation/matrix`,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import useAppSelector from "../../../../../../../redux/hooks/useAppSelector";
import { getCurrentAreaId } from "../../../../../../../redux/selectors";
import { MATRICES, HydroMatrixType } from "./utils";
import Matrix from "../../../../../../common/MatrixGrid/Matrix";
import { Box } from "@mui/material";

interface Props {
type: HydroMatrixType;
Expand All @@ -17,14 +18,18 @@ function HydroMatrix({ type }: Props) {
////////////////////////////////////////////////////////////////

return (
<Matrix
title={hydroMatrix.title}
url={hydroMatrix.url.replace("{areaId}", areaId)}
customColumns={hydroMatrix.columns}
rowHeaders={hydroMatrix.rowHeaders}
enableReadOnly={hydroMatrix.enableReadOnly}
enablePercentDisplay={hydroMatrix.enablePercentDisplay}
/>
<Box sx={{ width: 1, height: 1, p: 2 }}>
<Matrix
title={hydroMatrix.title}
url={hydroMatrix.url.replace("{areaId}", areaId)}
customColumns={hydroMatrix.columns}
customRowHeaders={hydroMatrix.rowHeaders}
enableDateTimeColumn={hydroMatrix.enableDateTimeColumn}
enableReadOnly={hydroMatrix.enableReadOnly}
enablePercentDisplay={hydroMatrix.enablePercentDisplay}
fetchMatrixData={hydroMatrix.fetchFn}
/>
</Box>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ function Hydro() {
// JSX
////////////////////////////////////////////////////////////////

return <TabWrapper study={study} tabList={tabList} />;
return (
<TabWrapper study={study} tabList={tabList} tabStyle="withoutBorder" />
);
}

export default Hydro;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MatrixType } from "../../../../../../../common/types";
import { MatrixDataDTO } from "../../../../../../common/MatrixGrid/types";
import { SplitViewProps } from "../../../../../../common/SplitView";
import { getAllocationMatrix } from "./Allocation/utils";
import { getCorrelationMatrix } from "./Correlation/utils";
Expand Down Expand Up @@ -26,7 +26,7 @@ export const HydroMatrix = {
// Types
////////////////////////////////////////////////////////////////

export type fetchMatrixFn = (studyId: string) => Promise<MatrixType>;
export type fetchMatrixFn = (studyId: string) => Promise<MatrixDataDTO>;
export type HydroMatrixType = (typeof HydroMatrix)[keyof typeof HydroMatrix];

export interface HydroMatrixProps {
Expand All @@ -35,6 +35,7 @@ export interface HydroMatrixProps {
columns?: string[];
rowHeaders?: string[];
fetchFn?: fetchMatrixFn;
enableDateTimeColumn?: boolean;
enableReadOnly?: boolean;
enablePercentDisplay?: boolean;
}
Expand Down Expand Up @@ -112,6 +113,7 @@ export const MATRICES: Matrices = {
url: "input/hydro/common/capacity/creditmodulations_{areaId}",
columns: generateColumns("%"),
rowHeaders: ["Generating Power", "Pumping Power"],
enableDateTimeColumn: false,
enablePercentDisplay: true,
},
[HydroMatrix.EnergyCredits]: {
Expand All @@ -133,7 +135,7 @@ export const MATRICES: Matrices = {
[HydroMatrix.WaterValues]: {
title: "Water Values",
url: "input/hydro/common/capacity/waterValues_{areaId}",
// columns: generateColumns("%"), // TODO this causes the data is undefined error
// columns: generateColumns("%"), // TODO this causes Runtime error to be fixed
},
[HydroMatrix.HydroStorage]: {
title: "Hydro Storage",
Expand Down Expand Up @@ -181,13 +183,15 @@ export const MATRICES: Matrices = {
title: "Allocation",
url: "",
fetchFn: getAllocationMatrix,
enableDateTimeColumn: false,
enableReadOnly: true,
enablePercentDisplay: true,
},
[HydroMatrix.Correlation]: {
title: "Correlation",
url: "",
fetchFn: getCorrelationMatrix,
enableDateTimeColumn: false,
enableReadOnly: true,
enablePercentDisplay: true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function Load() {
// JSX
////////////////////////////////////////////////////////////////

return <Matrix url={url} />;
return <Matrix url={url} enableAggregateColumns />;
}

export default Load;
17 changes: 13 additions & 4 deletions webapp/src/components/common/MatrixGrid/Matrix.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,44 @@ import { StudyMetadata } from "../../../common/types";
import { MatrixContainer, MatrixHeader, MatrixTitle } from "./style";
import MatrixActions from "./MatrixActions";
import EmptyView from "../page/SimpleContent";
import { fetchMatrixFn } from "../../App/Singlestudy/explore/Modelization/Areas/Hydro/utils";

interface MatrixProps {
url: string;
title?: string;
rowHeaders?: string[];
customRowHeaders?: string[];
enableDateTimeColumn?: boolean;
enableTimeSeriesColumns?: boolean;
enableAggregateColumns?: boolean;
enableRowHeaders?: boolean;
enablePercentDisplay?: boolean;
enableReadOnly?: boolean;
customColumns?: string[] | readonly string[];
colWidth?: number;
fetchMatrixData?: fetchMatrixFn;
}

function Matrix({
url,
title = "global.timeSeries",
rowHeaders = [],
customRowHeaders = [],
enableDateTimeColumn = true,
enableTimeSeriesColumns = true,
enableAggregateColumns = false,
enableRowHeaders = rowHeaders.length > 0,
enableRowHeaders = customRowHeaders.length > 0,
enablePercentDisplay = false,
enableReadOnly = false,
customColumns,
colWidth,
fetchMatrixData,
}: MatrixProps) {
const { t } = useTranslation();
const { study } = useOutletContext<{ study: StudyMetadata }>();
const [openImportDialog, setOpenImportDialog] = useState(false);

const {
data,
aggregates,
error,
isLoading,
isSubmitting,
Expand All @@ -58,11 +64,13 @@ function Matrix({
} = useMatrix(
study.id,
url,
enableDateTimeColumn,
enableTimeSeriesColumns,
enableAggregateColumns,
enableRowHeaders,
customColumns,
colWidth,
fetchMatrixData,
);

////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -102,9 +110,10 @@ function Matrix({
<Divider sx={{ width: 1, mt: 1, mb: 2 }} />
<MatrixGrid
data={data}
aggregates={aggregates}
columns={columns}
rows={data.length}
rowHeaders={rowHeaders}
rowHeaders={customRowHeaders}
dateTime={dateTime}
onCellEdit={handleCellEdit}
onMultipleCellsEdit={handleMultipleCellsEdit}
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/components/common/MatrixGrid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import DataEditor, {
} from "@glideapps/glide-data-grid";
import { useGridCellContent } from "./useGridCellContent";
import { useMemo, useState } from "react";
import { EnhancedGridColumn, GridUpdate } from "./types";
import { EnhancedGridColumn, GridUpdate, MatrixAggregates } from "./types";
import { darkTheme, readOnlyDarkTheme } from "./utils";
import { useColumnMapping } from "./useColumnMapping";

Expand All @@ -18,7 +18,7 @@ export interface MatrixGridProps {
rows: number;
columns: EnhancedGridColumn[];
dateTime?: string[];
aggregates?: Record<string, number[]>;
aggregates?: MatrixAggregates;
rowHeaders?: string[];
width?: string;
height?: string;
Expand Down
8 changes: 8 additions & 0 deletions webapp/src/components/common/MatrixGrid/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,19 @@ export interface EnhancedGridColumn extends BaseGridColumn {
type: ColumnType;
editable: boolean;
}

export interface MatrixAggregates {
min: number[];
max: number[];
avg: number[];
}

// Represents data coming from the API
export interface MatrixDataDTO {
data: number[][];
columns: number[];
index: number[];
aggregates?: MatrixAggregates;
}

export type Coordinates = [number, number];
Expand Down
29 changes: 18 additions & 11 deletions webapp/src/components/common/MatrixGrid/useGridCellContent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { useCallback, useMemo } from "react";
import { GridCell, GridCellKind, Item } from "@glideapps/glide-data-grid";
import { type EnhancedGridColumn, type ColumnType, ColumnTypes } from "./types";
import {
type EnhancedGridColumn,
type ColumnType,
ColumnTypes,
MatrixAggregates,
} from "./types";
import { formatDateTime } from "./utils";

type CellContentGenerator = (
Expand All @@ -9,7 +14,7 @@ type CellContentGenerator = (
column: EnhancedGridColumn,
data: number[][],
dateTime?: string[],
aggregates?: Record<string, number[]>,
aggregates?: MatrixAggregates,
rowHeaders?: string[],
) => GridCell;

Expand Down Expand Up @@ -52,14 +57,14 @@ const cellContentGenerators: Record<ColumnType, CellContentGenerator> = {
};
},
[ColumnTypes.Aggregate]: (row, col, column, data, dateTime, aggregates) => {
const value = aggregates?.[column.id]?.[row];
const value = aggregates?.[column.id as keyof MatrixAggregates]?.[row];

return {
kind: GridCellKind.Number,
data: value,
displayData: value?.toString() ?? "",
readonly: !column.editable,
allowOverlay: false,
allowOverlay: true,
};
},
};
Expand Down Expand Up @@ -95,7 +100,7 @@ export function useGridCellContent(
columns: EnhancedGridColumn[],
gridToData: (cell: Item) => Item | null,
dateTime?: string[],
aggregates?: Record<string, number[]>,
aggregates?: MatrixAggregates,
rowHeaders?: string[],
isReadOnlyEnabled = false,
isPercentDisplayEnabled = false,
Expand Down Expand Up @@ -156,19 +161,21 @@ export function useGridCellContent(
rowHeaders,
);

// Prevent updates for read-only grids
if (isReadOnlyEnabled) {
// Display number values as percentages if enabled
if (isPercentDisplayEnabled && gridCell.kind === GridCellKind.Number) {
return {
...gridCell,
allowOverlay: false,
displayData: `${gridCell.data}%`,
// If ReadOnly is enabled, we don't want to allow overlay
allowOverlay: !isReadOnlyEnabled,
};
}

// Display number values as percentages if enabled
if (isPercentDisplayEnabled && gridCell.kind === GridCellKind.Number) {
// Prevent updates for read-only grids
if (isReadOnlyEnabled) {
return {
...gridCell,
displayData: `${gridCell.data}%`,
allowOverlay: false,
};
}

Expand Down
Loading

0 comments on commit 4d88eb6

Please sign in to comment.