From a9f0bb12e663f306126ea007027723216b7d1286 Mon Sep 17 00:00:00 2001 From: Philipp Kraft Date: Fri, 26 Jul 2024 10:24:22 +0200 Subject: [PATCH 1/3] Added autoreload feature to plot --- odmf/static/media/js/plot.js | 27 ++++++++++++++++++++++----- odmf/static/templates/plot.html | 20 ++++++++++++++++++-- odmf/webpage/plot.py | 5 +++-- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/odmf/static/media/js/plot.js b/odmf/static/media/js/plot.js index 3703b71d..e3a8f1f0 100644 --- a/odmf/static/media/js/plot.js +++ b/odmf/static/media/js/plot.js @@ -147,8 +147,9 @@ class Plot { this.apply() return this } - render() { + render(do_apply=true) { $('#plot').html('Loading image...'); + let startTime = Date.now() $.ajax({ method: 'POST', url: odmf_ref('/plot/figure'), @@ -162,9 +163,19 @@ class Plot { $('#plot-reload-button').addClass('d-none') $('#plot').removeClass('semitransparent') $('#error-row').addClass('d-none') + let renderTime = Date.now() - startTime + $('#rendertime').html(renderTime.toString() + ' ms') + if (renderTime > 1000) { + $('#autoreload_switch').prop('checked', false) + } }) .fail(seterror); - return this.apply() + if (do_apply) { + return this.apply() + } else { + return this + } + } addsubplot() { @@ -184,6 +195,7 @@ class Plot { let txt_plot = JSON.stringify(this, null, 4); $('#plot-name').html(this.name) $('#content-tree .subplot').remove(); + let autoreload = $('#autoreload_switch').prop('checked'); this.subplots.forEach((subplot, index) => { let txt = $('#subplot-template').html() .replace(/§position§/g, index) @@ -203,10 +215,15 @@ class Plot { }) sessionStorage.setItem('plot', txt_plot); $('#json-row pre').html(txt_plot); - $('#plot-reload-button').css('top',this.height / 2).css('left', this.width / 3).removeClass('d-none') - $('#plot').addClass('semitransparent') set_content_tree_handlers(); - return this + if (autoreload) { + return this.render(false); + } else { + $('#plot-reload-button').css('top',this.height / 2).css('left', this.width / 3).removeClass('d-none') + $('#plot').addClass('semitransparent') + return this + } + } removesubplot(id) { this.subplots.splice(id, 1); diff --git a/odmf/static/templates/plot.html b/odmf/static/templates/plot.html index a694ed47..b19a4305 100644 --- a/odmf/static/templates/plot.html +++ b/odmf/static/templates/plot.html @@ -120,7 +120,6 @@
plot §position§
-
-

name...

+
+

name...

+
+
+ + +
+
+
+
+ + + +ODMFODMF diff --git a/odmf/static/media/images/odmf.svg b/odmf/static/media/images/odmf.svg new file mode 100644 index 00000000..944a7ecf --- /dev/null +++ b/odmf/static/media/images/odmf.svg @@ -0,0 +1,125 @@ + + + +ODMFODMFobservatorydata managementframework diff --git a/odmf/static/media/js/plot.js b/odmf/static/media/js/plot.js index e3a8f1f0..3fbf72c5 100644 --- a/odmf/static/media/js/plot.js +++ b/odmf/static/media/js/plot.js @@ -6,13 +6,17 @@ function seterror(jqhxr ,textStatus, errorThrown) { - set_error(textStatus) + set_error(jqhxr.responseText) } function gettime(startOrEnd) { + let timespan = $('#timeselect').val() + if (timespan < 0) { + return timespan * 1; + } let res = $('#'+ startOrEnd + 'date').val(); if (res) { - res += ' ' + ($('#'+ startOrEnd + 'time').val() || '00:00'); + res += ' ' + ($('#'+ startOrEnd + 'time').val() || '00:00:00'); } else { let today = new Date(); if (startOrEnd == 'start') { @@ -123,18 +127,14 @@ class Plot { this.subplots = saved_plot.subplots || [] } else { - this.name = '' + this.name = 'Unnamed plot' this.start = gettime('start') this.end = gettime('end') this.columns = 1 this.aggregate = '' this.height = 640 this.width = 480 - this.subplots = [{ - lines: [], - ylim: null, - logsite: null, - }] + this.subplots = [] } } @@ -162,7 +162,7 @@ class Plot { $('#plot').html(result); $('#plot-reload-button').addClass('d-none') $('#plot').removeClass('semitransparent') - $('#error-row').addClass('d-none') + set_error('') let renderTime = Date.now() - startTime $('#rendertime').html(renderTime.toString() + ' ms') if (renderTime > 1000) { diff --git a/odmf/static/templates/plot.html b/odmf/static/templates/plot.html index b19a4305..56de96bd 100644 --- a/odmf/static/templates/plot.html +++ b/odmf/static/templates/plot.html @@ -24,7 +24,7 @@
plot §position§ class="sp-remove-button btn btn-sm btn-danger py-0" data-toggle="tooltip" title="remove subplot §position§ from figure" > - +
- -
+ + + +
+ + diff --git a/odmf/webpage/plot.py b/odmf/webpage/plot.py index 5b915481..d73ea98a 100644 --- a/odmf/webpage/plot.py +++ b/odmf/webpage/plot.py @@ -15,12 +15,12 @@ from cherrypy.lib.static import serve_fileobj from logging import getLogger -from datetime import datetime +from datetime import datetime, timedelta import io import json from ..tools import Path as OPath from ..config import conf -from ..plot import Plot +from ..plot import Plot, NoDataError from .markdown import MarkDown from .. import db from . import lib as web @@ -42,6 +42,24 @@ markdown = MarkDown() +def to_datetime(start, end): + if isinstance(start, str): + if start[0] == '-': + start = datetime.today() + timedelta(days=int(start)) + else: + start = pd.to_datetime(start).to_pydatetime() + if isinstance(start, int): + start = datetime.today() + timedelta(days=int(start)) + if isinstance(end, str): + if end[0] == '-': + end = datetime.today() + else: + end = pd.to_datetime(start).to_pydatetime() + if isinstance(end, int): + end = datetime.today() + return start, end + + class PlotError(web.HTTPError): def __init__(self, message: str): @@ -197,8 +215,9 @@ def export(self, plot, fileformat, timeindex, tolerance, grid, interpolation_met raise web.HTTPError(500, 'Unknown fileformat: ' + fileformat) plot_dict = web.json.loads(plot) plot: Plot = Plot(**plot_dict) + start, end = plot.get_time_span() lines = [line for lines in plot.subplots for line in lines] - series = [line.load(plot.start, plot.end) for line in lines] + series = [line.load(start, end) for line in lines] # Convert timeindex to int if possible timeindex = web.conv(int, timeindex, timeindex) # If timeindex is 'regular', replace with time grid @@ -233,8 +252,10 @@ def figure(self, **kwargs): try: plot = Plot(**plot_data) if not plot.subplots: - raise IndexError('Nothing to plot, add a subplot') + raise NoDataError('Nothing to plot, add a subplot') svg = plot_backend.to_html(plot) + except NoDataError as e: + raise web.AJAXError(400, str(e)) from e except Exception as e: if users.current.is_member('admin'): msg = str(e) + '\n\n```\n' + traceback() + '\n```\n' @@ -256,14 +277,12 @@ def image(self, format, plot): @expose_for(plotgroup) @web.mime.json def linedatasets_json(self,valuetype, site, instrument, level, start, end): - from pandas import to_datetime with db.session_scope() as session: valuetype = web.conv(int, valuetype) site = web.conv(int, site) level = web.conv(float, level) instrument = web.conv(int, instrument) - start = to_datetime(start) - end = to_datetime(end) + start, end = to_datetime(start, end) me = users.current datasets = session.query(db.Dataset).filter( db.Dataset._valuetype == valuetype, @@ -271,9 +290,9 @@ def linedatasets_json(self,valuetype, site, instrument, level, start, end): db.Dataset.start <= end, db.Dataset.end >= start ) - if instrument: + if not pd.isnull(instrument): datasets = datasets.filter(db.Dataset._source == instrument) - if level is not None: + if not pd.isnull(level): datasets = datasets.filter(db.Dataset.level == level) datasets = [ ds for ds in datasets.order_by(db.Dataset.start) From e6d0927ebcf182208757ee2ec9912303b528ebdc Mon Sep 17 00:00:00 2001 From: Philipp Kraft Date: Mon, 29 Jul 2024 17:28:37 +0200 Subject: [PATCH 3/3] Fixed regression with plot from last commit --- odmf/plot/plot.py | 4 +-- odmf/static/media/js/plot.js | 14 +++++++++- odmf/static/templates/plot.html | 46 ++++++++++++++++++++------------- odmf/webpage/plot.py | 5 +--- 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/odmf/plot/plot.py b/odmf/plot/plot.py index 4bf0a172..65b69818 100644 --- a/odmf/plot/plot.py +++ b/odmf/plot/plot.py @@ -109,7 +109,7 @@ def load(self, start=None, end=None): else: series = pd.Series([]) - if self.subplot.plot.aggregate: + if self.subplot.plot.aggregate and not series.empty: if self.subplot.plot.aggregate == 'decade': from ..tools.exportdatasets import DecadeMonthStart sampler = series.resample(DecadeMonthStart()) @@ -236,7 +236,7 @@ def __init__(self, height=None, width=None, columns=None, start=None, end=None, if end[0] == '-': end = int(end) else: - end = pd.to_datetime(start).to_pydatetime() + end = pd.to_datetime(end).to_pydatetime() self.start = start or -90 self.end = end or -90 self.size = (width or 640, height or 480) diff --git a/odmf/static/media/js/plot.js b/odmf/static/media/js/plot.js index 3fbf72c5..4727bebd 100644 --- a/odmf/static/media/js/plot.js +++ b/odmf/static/media/js/plot.js @@ -214,6 +214,7 @@ class Plot { $('#ct-new-subplot').before(obj); }) sessionStorage.setItem('plot', txt_plot); + $('#property-summary').html(plot.toString()) $('#json-row pre').html(txt_plot); set_content_tree_handlers(); if (autoreload) { @@ -258,6 +259,13 @@ class Plot { sp.lines.splice(line, 1); return this } + + toString() { + if (this.start < 0) { + return 'last ' + (this.start*-1) + ' days, aggregate: ' + this.aggregate + } + return this.start.toString().slice(0,10) + ' - ' + this.end.toString().slice(0,10) + ', aggregate: ' + this.aggregate + } } function line_from_dialog() { @@ -494,7 +502,7 @@ $(() => { set_line_dialog_handlers() - $('#reload_plot').on('click', () => { + $('.do-reload').on('click', () => { window.plot.render() }); @@ -520,6 +528,10 @@ $(() => { if (confirm('Do you really want to delete your plot "' + fn + '" from the server')) $.post('deleteplotfile',{filename:fn},seterror); }); + $('#autoreload_div').on('click', event => { + alert('hä?') + window.plot.render() + }) }); diff --git a/odmf/static/templates/plot.html b/odmf/static/templates/plot.html index 56de96bd..c34113d9 100644 --- a/odmf/static/templates/plot.html +++ b/odmf/static/templates/plot.html @@ -135,7 +135,7 @@
plot §position§ load / save plot... @@ -150,28 +150,37 @@
plot §position§ -
-
-

name...

-
-
- - -
-
+
+

name...

+
+ +
+
+
+ +
+
+
+
+
+ properties +
+
+ Subplots + -->
@@ -195,7 +204,7 @@

name...

PLOT
-
@@ -354,6 +363,7 @@ +
diff --git a/odmf/webpage/plot.py b/odmf/webpage/plot.py index d73ea98a..bbf6a3a8 100644 --- a/odmf/webpage/plot.py +++ b/odmf/webpage/plot.py @@ -12,11 +12,10 @@ from traceback import format_exc as traceback -from cherrypy.lib.static import serve_fileobj from logging import getLogger from datetime import datetime, timedelta -import io + import json from ..tools import Path as OPath from ..config import conf @@ -197,8 +196,6 @@ def property(self): @web.method.post def export(self, plot, fileformat, timeindex, tolerance, grid, interpolation_method, interpolation_limit): """ - TODO: Compare to exportall_csv and RegularExport - Parameters ---------- plot: The plot as JSON