Dashboard: fix plots
This commit is contained in:
parent
5434c7d6ef
commit
c8ca68e1a4
3 changed files with 28 additions and 20 deletions
|
@ -1,7 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from json import dumps
|
|
||||||
from typing import Annotated
|
|
||||||
|
|
||||||
from fastapi import Depends, APIRouter, HTTPException, status, responses
|
from fastapi import Depends, APIRouter, HTTPException, status, responses
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
|
@ -10,7 +8,7 @@ import pandas as pd
|
||||||
import geopandas as gpd
|
import geopandas as gpd
|
||||||
|
|
||||||
from gisaf.config import conf
|
from gisaf.config import conf
|
||||||
from gisaf.utils import NumpyEncoder
|
from gisaf.utils import dict_array_to_list
|
||||||
from gisaf.database import fastapi_db_session as db_session
|
from gisaf.database import fastapi_db_session as db_session
|
||||||
from gisaf.models.authentication import User
|
from gisaf.models.authentication import User
|
||||||
from gisaf.models.dashboard import (
|
from gisaf.models.dashboard import (
|
||||||
|
@ -138,16 +136,8 @@ async def get_dashboard_page(group: str, name: str,
|
||||||
'see debug message')
|
'see debug message')
|
||||||
logger.exception(err)
|
logger.exception(err)
|
||||||
if page.plot:
|
if page.plot:
|
||||||
try:
|
|
||||||
plot = page.get_plot()
|
plot = page.get_plot()
|
||||||
plotData = {
|
## Convert manually numpy arrays to lists
|
||||||
'data': [d.to_plotly_json() for d in plot.data],
|
dp.plotData = [dict_array_to_list(d.to_plotly_json()) for d in plot.data]
|
||||||
'layout': plot.layout.to_plotly_json(),
|
dp.plotLayout = plot.layout.to_plotly_json()
|
||||||
}
|
|
||||||
except Exception as err:
|
|
||||||
logger.warning(f'Dashboard: cannot add plot for page {page.name}, '
|
|
||||||
'see debug message')
|
|
||||||
logger.exception(err)
|
|
||||||
else:
|
|
||||||
dp.plotData = dumps(plotData, cls=NumpyEncoder)
|
|
||||||
return dp
|
return dp
|
|
@ -3,9 +3,11 @@ from pickle import loads
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
# from typing import Any
|
# from typing import Any
|
||||||
|
|
||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
|
from plotly.graph_objs._figure import Figure as PlotlyFigure
|
||||||
from sqlmodel import Field, Relationship, String, JSON
|
from sqlmodel import Field, Relationship, String, JSON
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
@ -110,18 +112,22 @@ class DashboardPageCommon:
|
||||||
#f'in {self.get_attachment_file_name()}')
|
#f'in {self.get_attachment_file_name()}')
|
||||||
return self.attachment
|
return self.attachment
|
||||||
|
|
||||||
def get_page_df(self):
|
def get_page_df(self) -> pd.DataFrame | None:
|
||||||
"""
|
"""
|
||||||
Get the dataframe of the page
|
Get the dataframe of the page
|
||||||
"""
|
"""
|
||||||
if not self.df:
|
if not self.df:
|
||||||
return
|
return None
|
||||||
try:
|
try:
|
||||||
return pd.read_pickle(BytesIO(self.df), compression=None)
|
df = pd.read_pickle(BytesIO(self.df), compression=None)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise NotADataframeError()
|
raise NotADataframeError()
|
||||||
|
if isinstance(df, dict):
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return df
|
||||||
|
|
||||||
def get_plot(self):
|
def get_plot(self) -> PlotlyFigure | None:
|
||||||
if self.plot is not None:
|
if self.plot is not None:
|
||||||
return loads(self.plot)
|
return loads(self.plot)
|
||||||
|
|
||||||
|
@ -293,7 +299,8 @@ class Dashboard(BaseModel):
|
||||||
html: str | None = None
|
html: str | None = None
|
||||||
attachment: str | None = None
|
attachment: str | None = None
|
||||||
dfData: list = []
|
dfData: list = []
|
||||||
plotData: str | None = None
|
plotData: list[dict] | None = None
|
||||||
|
plotLayout: dict[str, Any] | None = None
|
||||||
notebook: str | None = None
|
notebook: str | None = None
|
||||||
expandedPanes: list[str] | None = None
|
expandedPanes: list[str] | None = None
|
||||||
sections: list[DashboardSection] | None = None
|
sections: list[DashboardSection] | None = None
|
||||||
|
|
|
@ -83,6 +83,17 @@ gisTypeSymbolMap = {
|
||||||
# ).transform
|
# ).transform
|
||||||
|
|
||||||
|
|
||||||
|
def dict_array_to_list(d: dict) -> dict:
|
||||||
|
'''Convert any ndarray a dict to plain python list.
|
||||||
|
Useful for transforming a Dataframe to a serializable object'''
|
||||||
|
for k, v in d.items():
|
||||||
|
if isinstance(v, dict):
|
||||||
|
dict_array_to_list(v)
|
||||||
|
else:
|
||||||
|
if isinstance(v, ndarray):
|
||||||
|
d[k] = v.tolist()
|
||||||
|
return d
|
||||||
|
|
||||||
class NumpyEncoder(JSONEncoder):
|
class NumpyEncoder(JSONEncoder):
|
||||||
"""
|
"""
|
||||||
Encoder that can serialize numpy arrays and datetime objects
|
Encoder that can serialize numpy arrays and datetime objects
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue