Mod: refactoring gui

This commit is contained in:
L-Nafaryus 2022-02-12 13:58:24 +05:00
parent 13e02b57a4
commit fea53d0db7
No known key found for this signature in database
GPG Key ID: C76D8DCD2727DBB7
9 changed files with 186 additions and 126 deletions

View File

@ -34,7 +34,7 @@ def init(path, verbose):
core_utils.setupLogger(utils.verbose_level(verbose))
logger = logging.getLogger(__name__)
config = config.default_config()
config = core_config.default_config()
filepath = os.path.abspath(os.path.join(path, "anisotropy.toml"))
logger.info(f"Saving file at { filepath }")
@ -165,7 +165,7 @@ def compute(path, configFile, nprocs, stage, overwrite, params, verbose, executi
def gui(path, verbose):
import anisotropy
from anisotropy.core import utils as core_utils
from anisotropy.gui import app
from anisotropy import gui
anisotropy.loadEnv()
@ -178,4 +178,4 @@ def gui(path, verbose):
core_utils.setupLogger(utils.verbose_level(verbose))
# logger = logging.getLogger(__name__)
app.run_server(debug = True)
gui.run(debug = True)

View File

@ -1,7 +1,15 @@
# -*- coding: utf-8 -*-
from .layouts.main import app
from . import layouts
from .layouts import app
app.layout = layouts.base
def run(*args, **kwargs):
app.run_server(*args, **kwargs)
if __name__ == "__main__":
app.run_server(debug = True)
run(debug = True)

View File

@ -4,7 +4,5 @@ import dash
import dash_bootstrap_components as dbc
app = dash.Dash(__name__, external_stylesheets = [ dbc.themes.LUX ])
app.title = "anisotropy"
app.config.update(
update_title = None
)
app.title = "Anisotropy"
app.config["update_title"] = None

View File

@ -1 +1,29 @@
# -*- coding: utf-8 -*-
from . import (
runner,
settings,
database,
visualization,
about,
base
)
from .base import app
runner = runner.layout
settings = settings.layout
database = database.layout
visualization = visualization.layout
about = about.layout
base = base.layout
__all__ = [
"runner",
"settings",
"database",
"visualization",
"about",
"base",
"app"
]

View File

@ -2,7 +2,7 @@
from dash import html
from dash import dcc
from dash.dependencies import Input, Output, State
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
from . import (
@ -13,31 +13,32 @@ from . import (
about
)
from ..app import app
from ..styles import *
from .. import styles
import anisotropy
###
# Layout
##
app.layout = html.Div([
layout = html.Div([
# Location
dcc.Location(id = "url", refresh = False),
# Sidebar
html.Div([
# Sidebar
html.H2([html.Img(src = "/assets/simple.png", height = "150px")], style = logo),
html.H2([html.Img(src = "/assets/simple.png", height = "150px")], style = styles.logo),
html.Hr(style = { "color": "#ffffff" }),
dbc.Nav([
dbc.NavLink("Runner", href = "/", active = "exact", style = white),
dbc.NavLink("Settings", href = "/settings", active = "exact", style = white),
dbc.NavLink("Database", href = "/database", active = "exact", style = white),
dbc.NavLink("Visualization", href = "/visualization", active = "exact", style = white),
dbc.NavLink("About", href = "/about", active = "exact", style = white),
dbc.NavLink("Runner", href = "/", active = "exact", style = styles.white),
dbc.NavLink("Settings", href = "/settings", active = "exact", style = styles.white),
dbc.NavLink("Database", href = "/database", active = "exact", style = styles.white),
dbc.NavLink("Visualization", href = "/visualization", active = "exact", style = styles.white),
dbc.NavLink("About", href = "/about", active = "exact", style = styles.white),
], vertical = True, pills = True),
# Misc
html.Hr(style = white),
html.Hr(style = styles.white),
dbc.Container([
dbc.Row([
dbc.Col("v1.2.0"),
@ -48,12 +49,12 @@ app.layout = html.Div([
)
)
])
], style = misc)
], style = sidebar),
], style = styles.misc)
], style = styles.sidebar),
# Content
html.Div(id = "page-content", style = page),
], style = content)
html.Div(id = "page-content", style = styles.page),
], style = styles.content)
###
@ -78,4 +79,3 @@ def displayPage(pathname):
else:
return runner.layout

View File

@ -6,10 +6,11 @@ from dash import dcc
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import os
import pathlib
from os import environ
from ..app import app
from ..styles import *
from .. import styles
###
@ -22,9 +23,9 @@ layout = html.Div([
duration = 10000,
dismissable = True,
is_open = False,
style = message
style = styles.message
),
#dcc.Interval(id = "interval", interval = 1000, n_intervals = 0),
# dcc.Interval(id = "interval", interval = 1000, n_intervals = 0),
# Query
html.H2("Database"),
@ -32,20 +33,26 @@ layout = html.Div([
html.P("Query"),
dcc.Textarea(id = "db_input", style = { "min-width": "100%"}),
html.Br(),
dbc.Button("Query", id = "query", style = minWidth),
dbc.Button("Query", id = "query", style = styles.minWidth),
# Output
html.Hr(),
html.P("Output"),
DataTable(id = "db_output", columns = [], data = [], style_table = { "overflow": "scroll"}, style_cell={
'textAlign': 'left',
'width': '150px',
'minWidth': '180px',
'maxWidth': '180px',
'whiteSpace': 'no-wrap',
'overflow': 'hidden',
'textOverflow': 'ellipsis',
}),
DataTable(
id = "db_output",
columns = [],
data = [],
style_table = { "overflow": "scroll"},
style_cell = {
'textAlign': 'left',
'width': '150px',
'minWidth': '180px',
'maxWidth': '180px',
'whiteSpace': 'no-wrap',
'overflow': 'hidden',
'textOverflow': 'ellipsis',
}
),
])
@ -63,17 +70,17 @@ layout = html.Div([
prevent_initial_call = True
)
def db_query(clicks, db_input):
from anisotropy.database import Database
from peewee import OperationalError
from anisotropy import database
import peewee as pw
dbpath = os.path.join(os.environ["ANISOTROPY_CWD"], os.environ["ANISOTROPY_DB_FILE"])
db = Database(path = dbpath)
path = pathlib.Path(environ["AP_CWD"], environ["AP_DB_FILE"])
db = database.Database(path)
try:
db.connect()
cursor = db.execute_sql(db_input)
except OperationalError as e:
except pw.OperationalError as e:
db.close()
return None, None, str(e), True, "danger"
@ -91,4 +98,4 @@ def db_query(clicks, db_input):
db.close()
return columns, data, "", False, "success"
return columns, data, "", False, "success"

View File

@ -6,11 +6,13 @@ from dash import dcc
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import pathlib
import os
from os import environ
from ..app import app
from ..styles import *
from ..utils import getSize
from .. import styles
from .. import utils
###
@ -23,7 +25,7 @@ layout = html.Div([
duration = 10000,
dismissable = True,
is_open = False,
style = message
style = styles.message
),
dcc.Interval(id = "interval", interval = 1000, n_intervals = 0),
@ -31,22 +33,22 @@ layout = html.Div([
html.H2("Runner"),
html.Hr(),
html.P("Execution (leave zero for the latest)"),
dcc.Input(id = "execution", type = "number", value = 0, min = 0, style = minWidth),
dcc.Input(id = "execution", type = "number", value = 0, min = 0, style = styles.minWidth),
html.Br(),
dbc.Button("Start", id = "start", color = "success", style = minWidth),
dbc.Button("Stop", id = "stop", color = "danger", disabled = True, style = minWidth),
dbc.Button("Start", id = "start", color = "success", style = styles.minWidth),
dbc.Button("Stop", id = "stop", color = "danger", disabled = True, style = styles.minWidth),
# Monitor
html.H2("Monitor"),
html.Hr(),
html.P(id = "runner-status"),
DataTable(id = "monitor", columns = [], data = [], style_table = table),
DataTable(id = "monitor", columns = [], data = [], style_table = styles.table),
# Log
html.H2("Log"),
html.Hr(),
dbc.Button("Delete", id = "delete", style = minWidth),
dcc.Textarea(id = "logger", disabled = True, style = bigText)
dbc.Button("Delete", id = "delete", style = styles.minWidth),
dcc.Textarea(id = "logger", disabled = True, style = styles.bigText)
])
@ -67,10 +69,10 @@ def runnerStart(clicks, execution):
"anisotropy",
"compute",
"-v",
"--path", os.environ["ANISOTROPY_CWD"],
"--conf", os.environ["ANISOTROPY_CONF_FILE"],
"--path", environ["AP_CWD"],
"--conf", environ["AP_CONF_FILE"],
"--pid", "anisotropy.pid",
"--logfile", os.environ["ANISOTROPY_LOG_FILE"],
"--logfile", environ["AP_LOG_FILE"],
]
if execution > 0:
@ -83,6 +85,7 @@ def runnerStart(clicks, execution):
return True
@app.callback(
Output("stop", "active"),
[ Input("stop", "n_clicks") ],
@ -92,7 +95,7 @@ def runnerStop(clicks):
import psutil
import signal
pidpath = os.path.join(os.environ["ANISOTROPY_CWD"], "anisotropy.pid")
pidpath = pathlib.Path(environ["AP_CWD"], "anisotropy.pid")
try:
pid = int(open(pidpath, "r").read())
@ -107,7 +110,6 @@ def runnerStop(clicks):
return True
@app.callback(
Output("monitor", "columns"),
Output("monitor", "data"),
@ -120,14 +122,14 @@ def runnerStop(clicks):
def monitorUpdate(intervals):
import psutil
pidpath = os.path.join(os.environ["ANISOTROPY_CWD"], "anisotropy.pid")
pidpath = pathlib.Path(environ["AP_CWD"], "anisotropy.pid")
processes = []
try:
pid = int(open(pidpath, "r").read())
master = psutil.Process(pid)
except (FileNotFoundError, psutil.NoSuchProcess) as e:
except (FileNotFoundError, psutil.NoSuchProcess):
return [], [], "Status: not running", False, True, False
else:
@ -137,7 +139,7 @@ def monitorUpdate(intervals):
"name": process.name(),
"pid": process.pid,
"status": process.status(),
"memory": getSize(process.memory_full_info().uss),
"memory": utils.getSize(process.memory_full_info().uss),
"threads": process.num_threads(),
"created": "{}:{}:{}".format(created.tm_hour, created.tm_min, created.tm_sec)
})
@ -146,12 +148,13 @@ def monitorUpdate(intervals):
return columns, processes, "Status: running", True, False, True
@app.callback(
Output("logger", "value"),
[ Input("interval", "n_intervals") ]
)
def logUpdate(intervals):
logpath = os.path.join(os.environ["ANISOTROPY_CWD"], "anisotropy.log")
logpath = pathlib.Path(environ["AP_CWD"], "anisotropy.log")
if os.path.exists(logpath):
with open(logpath, "r") as io:
@ -169,9 +172,9 @@ def logUpdate(intervals):
prevent_initial_call = True
)
def logDelete(clicks):
logpath = os.path.join(os.environ["ANISOTROPY_CWD"], "anisotropy.log")
logpath = pathlib.Path(environ["AP_CWD"], "anisotropy.log")
if os.path.exists(logpath):
os.remove(logpath)
return True
return True

View File

@ -5,9 +5,11 @@ from dash import dcc
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import os
import pathlib
from os import environ
from ..app import app
from ..styles import *
from .. import styles
###
@ -20,14 +22,14 @@ layout = html.Div([
duration = 10000,
dismissable = True,
is_open = False,
style = message
style = styles.message
),
dbc.Alert(
id = "general-status",
duration = 10000,
dismissable = True,
is_open = False,
style = message
style = styles.message
),
# General
html.H2("General"),
@ -35,25 +37,25 @@ layout = html.Div([
html.P("Path"),
dcc.Input(id = "cwd", style = { "min-width": "500px" }),
html.Br(),
dbc.Button("Save general", id = "general-save", style = minWidth),
dbc.Button("Save general", id = "general-save", style = styles.minWidth),
# Options
html.H2("Options"),
html.Hr(),
html.P("Nprocs"),
dcc.Input(id = "nprocs", type = "number", style = minWidth),
dcc.Input(id = "nprocs", type = "number", style = styles.minWidth),
html.P("Stage"),
dcc.Dropdown(
id = "stage",
options = [ { "label": k, "value": k } for k in ["all", "shape", "mesh", "flow", "postProcess"] ],
style = minWidth
style = styles.minWidth
),
dbc.Button("Save", id = "submit", style = minWidth),
dbc.Button("Save", id = "submit", style = styles.minWidth),
# Cases
html.H2("Cases"),
html.Hr(),
dcc.Textarea(id = "cases", style = bigText),
dcc.Textarea(id = "cases", style = styles.bigText),
])
@ -71,13 +73,12 @@ layout = html.Div([
prevent_initial_call = True
)
def generalSave(clicks, cwd):
if not os.path.abspath(cwd):
path = pathlib.Path(cwd)
if not path.is_absolute():
return "Cwd path must be absolute", True, "danger"
if cwd[-1] == "/":
cwd = cwd[ :-1]
os.environ["ANISOTROPY_CWD"] = cwd
environ["AP_CWD"] = str(path)
return "General settings saved", True, "success"
@ -93,13 +94,13 @@ def settingsLoad(pathname):
from anisotropy.core import config as core_config
import toml
filepath = os.path.join(os.environ["ANISOTROPY_CWD"], os.environ["ANISOTROPY_CONF_FILE"])
path = pathlib.Path(environ["AP_CWD"], environ["AP_CONF_FILE"])
config = core_config.default_config()
if os.path.exists(filepath):
config.load(filepath)
if path.exists():
config.load(path)
return os.environ["ANISOTROPY_CWD"], config["nprocs"], config["stage"], toml.dumps(config.content)
return environ["AP_CWD"], config["nprocs"], config["stage"], toml.dumps(config.content)
@app.callback(
@ -118,11 +119,11 @@ def settingsSave(nclick, nprocs, stage, cases):
from anisotropy.core import config as core_config
import toml
filepath = os.path.join(os.environ["ANISOTROPY_CWD"], os.environ["ANISOTROPY_CONF_FILE"])
path = pathlib.Path(environ["AP_CWD"], environ["AP_CONF_FILE"])
config = core_config.default_config()
if os.path.exists(filepath):
config.load(filepath)
if path.exists():
config.load(path)
config.update(
nprocs = nprocs,
@ -131,10 +132,10 @@ def settingsSave(nclick, nprocs, stage, cases):
try:
config.content = toml.loads(cases)
config.dump(filepath)
config.dump(path)
except Exception as e:
return str(e), True, "danger"
else:
return f"Saved to { filepath }", True, "success"
return f"Saved to { path }", True, "success"

View File

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from dash.dash_table import DataTable
from dash import html
from dash import dcc
import dash_bootstrap_components as dbc
@ -8,7 +7,9 @@ from dash.dependencies import Input, Output, State
import dash_vtk
import dash_vtk.utils
import vtk
import os
import pathlib
from os import environ
from ..app import app
from .. import styles
@ -149,7 +150,10 @@ plotcontrols = html.Div([
html.P("Structure"),
dcc.Dropdown(
id = "plot-structure",
options = [ { "label": v, "value": v } for v in [ "simple", "bodyCentered", "faceCentered" ] ],
options = [
{ "label": v, "value": v }
for v in [ "simple", "bodyCentered", "faceCentered" ]
],
value = "simple"
),
html.Br(),
@ -157,7 +161,10 @@ plotcontrols = html.Div([
html.P("Direction"),
dcc.Dropdown(
id = "plot-direction",
options = [ { "label": str(v), "value": str(v)} for v in [ [1., 0., 0.], [0., 0., 1.], [1., 1., 1.], "all" ] ],
options = [
{ "label": str(v), "value": str(v)}
for v in [ [1., 0., 0.], [0., 0., 1.], [1., 1., 1.], "all" ]
],
value = str([1., 0., 0.]),
),
html.Br(),
@ -185,10 +192,11 @@ layout = html.Div([
width = 8,
children = [
html.Div(id = "plot-output", style = { "width": "100%", "min-width": "800px" })
]
, style = { "min-width": "800px" }),
],
style = { "min-width": "800px" }
),
], style = { "height": "100%"}),
]),
]),
html.Br(),
html.H2("Mesh"),
@ -201,11 +209,14 @@ layout = html.Div([
dbc.Col(
width = 8,
children = [
html.Div(id = "vtk-output", style = { "height": "800px", "width": "100%", "min-width": "800px" })
]
, style = { "min-width": "800px" }),
html.Div(
id = "vtk-output",
style = { "height": "800px", "width": "100%", "min-width": "800px" }
)
],
style = { "min-width": "800px" }),
], style = { "height": "100%"}),
])
])
])
@ -220,19 +231,18 @@ layout = html.Div([
]
)
def plotDraw(clicks, execution, structure, direction, data):
from os import path
from peewee import JOIN
from anisotropy.database import Database, models
from anisotropy.database import Database, tables
import json
from pandas import DataFrame
import plotly.express as px
dbpath = path.join(os.environ["ANISOTROPY_CWD"], os.environ["ANISOTROPY_DB_FILE"])
path = pathlib.Path(environ["AP_CWD"], environ["AP_DB_FILE"])
if not path.isfile(dbpath):
if not path.is_file():
return [ "Database not found" ]
db = Database(path = dbpath)
db = Database(path)
if not db.getExecution(execution):
return [ "Execution not found" ]
@ -241,33 +251,35 @@ def plotDraw(clicks, execution, structure, direction, data):
try:
column = getattr(model, data)
except AttributeError as e:
except AttributeError:
pass
else:
break
if direction == "all":
select = (models.Shape.alpha, column, models.Shape.direction)
select = (tables.Shape.alpha, column, tables.Shape.direction)
else:
select = (models.Shape.alpha, column)
select = (tables.Shape.alpha, column)
query = (
models.Shape
tables.Shape
.select(*select)
.join(models.Execution, JOIN.LEFT_OUTER)
.switch(models.Shape)
.join(models.Mesh, JOIN.LEFT_OUTER)
.switch(models.Shape)
.join(tables.Execution, JOIN.LEFT_OUTER)
.switch(tables.Shape)
.join(tables.Mesh, JOIN.LEFT_OUTER)
.switch(tables.Shape)
# .join(tables.FlowOnephase, JOIN.LEFT_OUTER)
# .switch(tables.Shape)
.where(
models.Shape.exec_id == execution,
models.Shape.label == structure,
tables.Shape.exec_id == execution,
tables.Shape.label == structure,
)
)
if not direction == "all":
query = query.where(models.Shape.direction == json.loads(direction))
query = query.where(tables.Shape.direction == json.loads(direction))
with db:
if query.exists():
@ -305,8 +317,8 @@ def plotDraw(clicks, execution, structure, direction, data):
)
fig.layout.template = "custom_dark"
fig.update_xaxes(showline=True, linewidth=1, linecolor='#4f687d', mirror=True)
fig.update_yaxes(showline=True, linewidth=1, linecolor='#4f687d', mirror=True)
fig.update_xaxes(showline = True, linewidth = 1, linecolor = '#4f687d', mirror = True)
fig.update_yaxes(showline = True, linewidth = 1, linecolor = '#4f687d', mirror = True)
plot = dcc.Graph(
figure = fig
@ -315,7 +327,6 @@ def plotDraw(clicks, execution, structure, direction, data):
return [ plot ]
@app.callback(
[ Output("alpha", "min"), Output("alpha", "max") ],
[ Input("structure", "value") ]
@ -330,6 +341,7 @@ def alphaLimits(label):
elif label == "faceCentered":
return 0.01, 0.13
@app.callback(
[ Output("vtk-output", "children") ],
[ Input("draw", "n_clicks") ],
@ -351,19 +363,22 @@ def alphaLimits(label):
prevent_initial_call = True
)
def meshDraw(clicks, execution, structure, direction, alpha, clip, crinkle, wireframe, normal_x, normal_y, normal_z, origin_x, origin_y, origin_z):
from os import path
import meshio
path = pathlib.Path(environ["AP_CWD"], environ["AP_BUILD_DIR"])
path /= "execution-{}".format(execution)
path /= "{}-{}-{}".format(
structure,
direction.replace(" ", ""),
alpha
)
basemeshpath = path / "mesh.msh"
meshpath = path / "mesh.vtu"
execution = "execution-{}".format(execution)
case = "{}-{}-{}".format(structure, direction.replace(" ", ""), alpha)
casepath = path.join(os.environ["ANISOTROPY_CWD"], os.environ["ANISOTROPY_BUILD_DIR"], execution, case)
basemeshpath = path.join(casepath, "mesh.msh")
meshpath = path.join(casepath, "mesh.vtu")
if not path.exists(basemeshpath):
if not basemeshpath.exists():
return [ "Mesh not found" ]
if not path.exists(meshpath) or not path.isfile(meshpath):
if not meshpath.exists() or not meshpath.is_file():
meshold = meshio.read(basemeshpath)
meshold.write(meshpath)