From 3040cfeebaadfebfba6e3e0c44da4ce142b7ec37 Mon Sep 17 00:00:00 2001 From: Paz Barda Date: Mon, 12 Feb 2024 13:42:14 +0200 Subject: [PATCH 1/3] added Simple HTML Exporter plugin Signed-off-by: Paz Barda --- package.json | 2 +- src/lib/index.ts | 1 + .../helpers/TimeSeriesDataExtractor.ts | 18 +++ .../html-export-template.html | 108 ++++++++++++++++++ src/lib/simple-html-exporter/index.ts | 64 +++++++++++ 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 src/lib/simple-html-exporter/helpers/TimeSeriesDataExtractor.ts create mode 100644 src/lib/simple-html-exporter/html-export-template.html create mode 100644 src/lib/simple-html-exporter/index.ts diff --git a/package.json b/package.json index 5ffe038..f947199 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "scripts": { "build": "npm run clean && tsc --project tsconfig.build.json && npm run copy-files", "clean": "rimraf build/", - "copy-files": "copyfiles -u 1 src/**/*.csv build", + "copy-files": "copyfiles -u 1 src/**/*.csv build && copyfiles -u 1 src/lib/simple-html-exporter/html-export-template.html build/lib/simple-html-exporter/html-export-template.html", "coverage": "jest --verbose --coverage", "fix": "gts fix", "fix:package": "fixpack", diff --git a/src/lib/index.ts b/src/lib/index.ts index 553a286..a0124bf 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -8,3 +8,4 @@ export * from './sci-o'; export * from './shell'; export * from './tdp-finder'; export * from './mock-observations'; +export * from './simple-html-exporter'; diff --git a/src/lib/simple-html-exporter/helpers/TimeSeriesDataExtractor.ts b/src/lib/simple-html-exporter/helpers/TimeSeriesDataExtractor.ts new file mode 100644 index 0000000..d1efd0a --- /dev/null +++ b/src/lib/simple-html-exporter/helpers/TimeSeriesDataExtractor.ts @@ -0,0 +1,18 @@ +import {ModelParams} from '../../../types/common'; + +export class TimeSeriesDataExtractor { + extract(inputs: ModelParams[]): [string[], number[], number[]] { + const timestamps: string[] = []; + const energyValues: number[] = []; + const carbonValues: number[] = []; + inputs.forEach(input => { + const timestamp = input['timestamp']; + const energy = input['energy']; + const carbon = input['carbon']; + timestamps.push(timestamp); + energyValues.push(energy); + carbonValues.push(carbon); + }); + return [timestamps, energyValues, carbonValues]; + } +} diff --git a/src/lib/simple-html-exporter/html-export-template.html b/src/lib/simple-html-exporter/html-export-template.html new file mode 100644 index 0000000..1b53498 --- /dev/null +++ b/src/lib/simple-html-exporter/html-export-template.html @@ -0,0 +1,108 @@ + + + + + + Time Series Chart + + + + + + + + + + + + + + + + + diff --git a/src/lib/simple-html-exporter/index.ts b/src/lib/simple-html-exporter/index.ts new file mode 100644 index 0000000..470d20b --- /dev/null +++ b/src/lib/simple-html-exporter/index.ts @@ -0,0 +1,64 @@ +import {ModelPluginInterface} from '../../interfaces'; +import {ModelParams} from '../../types/common'; +import {TimeSeriesDataExtractor} from './helpers/TimeSeriesDataExtractor'; +import {ERRORS} from '../../util/errors'; +const {InputValidationError} = ERRORS; +import {buildErrorMessage} from '../../util/helpers'; +import * as fs from 'fs'; +import path = require('path'); + +export class SimpleHtmlExporter implements ModelPluginInterface { + private static INPUT_HTML_NAME: string = 'html-export-template.html'; + private outputHtmlPath: string = ''; + errorBuilder = buildErrorMessage('SimpleHtmlExporter'); + + async configure( + staticParams: object | undefined = undefined + ): Promise { + if (staticParams === undefined) { + throw new InputValidationError( + this.errorBuilder({message: 'Input data is missing'}) + ); + } + if ('html-path' in staticParams) { + const htmlPath = staticParams['html-path'] as string; + if (htmlPath !== undefined) { + this.outputHtmlPath = htmlPath; + } + } else { + throw new InputValidationError( + this.errorBuilder({message: 'Output HTML is missing'}) + ); + } + return this; + } + + async execute(inputs: ModelParams[]): Promise { + const [timestamps, energyValues, carbonValues] = + new TimeSeriesDataExtractor().extract(inputs); + + const directoryPath = __dirname; + const templateHtmlPath = path.join( + directoryPath, + SimpleHtmlExporter.INPUT_HTML_NAME + ); + const htmlContent = fs.readFileSync(templateHtmlPath, 'utf8'); + + const updatedHtmlContent = htmlContent + .replace( + /var timestamps = \[.*?\]/s, + `var timestamps = ${JSON.stringify(timestamps)}` + ) + .replace( + /var energyValues = \[.*?\]/s, + `var energyValues = ${JSON.stringify(energyValues)}` + ) + .replace( + /var carbonValues = \[.*?\]/s, + `var carbonValues = ${JSON.stringify(carbonValues)}` + ); + fs.writeFileSync(this.outputHtmlPath, updatedHtmlContent, 'utf8'); + + return inputs; + } +} From c049946870f5c38e9380795a69d50e77108e3924 Mon Sep 17 00:00:00 2001 From: Narek Hovhannisyan Date: Tue, 13 Feb 2024 09:48:33 +0400 Subject: [PATCH 2/3] fix(lib): end of line sequence --- .../helpers/TimeSeriesDataExtractor.ts | 36 ++--- src/lib/simple-html-exporter/index.ts | 128 +++++++++--------- 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/lib/simple-html-exporter/helpers/TimeSeriesDataExtractor.ts b/src/lib/simple-html-exporter/helpers/TimeSeriesDataExtractor.ts index d1efd0a..66b42e4 100644 --- a/src/lib/simple-html-exporter/helpers/TimeSeriesDataExtractor.ts +++ b/src/lib/simple-html-exporter/helpers/TimeSeriesDataExtractor.ts @@ -1,18 +1,18 @@ -import {ModelParams} from '../../../types/common'; - -export class TimeSeriesDataExtractor { - extract(inputs: ModelParams[]): [string[], number[], number[]] { - const timestamps: string[] = []; - const energyValues: number[] = []; - const carbonValues: number[] = []; - inputs.forEach(input => { - const timestamp = input['timestamp']; - const energy = input['energy']; - const carbon = input['carbon']; - timestamps.push(timestamp); - energyValues.push(energy); - carbonValues.push(carbon); - }); - return [timestamps, energyValues, carbonValues]; - } -} +import {ModelParams} from '../../../types/common'; + +export class TimeSeriesDataExtractor { + extract(inputs: ModelParams[]): [string[], number[], number[]] { + const timestamps: string[] = []; + const energyValues: number[] = []; + const carbonValues: number[] = []; + inputs.forEach(input => { + const timestamp = input['timestamp']; + const energy = input['energy']; + const carbon = input['carbon']; + timestamps.push(timestamp); + energyValues.push(energy); + carbonValues.push(carbon); + }); + return [timestamps, energyValues, carbonValues]; + } +} diff --git a/src/lib/simple-html-exporter/index.ts b/src/lib/simple-html-exporter/index.ts index 470d20b..85ce4cf 100644 --- a/src/lib/simple-html-exporter/index.ts +++ b/src/lib/simple-html-exporter/index.ts @@ -1,64 +1,64 @@ -import {ModelPluginInterface} from '../../interfaces'; -import {ModelParams} from '../../types/common'; -import {TimeSeriesDataExtractor} from './helpers/TimeSeriesDataExtractor'; -import {ERRORS} from '../../util/errors'; -const {InputValidationError} = ERRORS; -import {buildErrorMessage} from '../../util/helpers'; -import * as fs from 'fs'; -import path = require('path'); - -export class SimpleHtmlExporter implements ModelPluginInterface { - private static INPUT_HTML_NAME: string = 'html-export-template.html'; - private outputHtmlPath: string = ''; - errorBuilder = buildErrorMessage('SimpleHtmlExporter'); - - async configure( - staticParams: object | undefined = undefined - ): Promise { - if (staticParams === undefined) { - throw new InputValidationError( - this.errorBuilder({message: 'Input data is missing'}) - ); - } - if ('html-path' in staticParams) { - const htmlPath = staticParams['html-path'] as string; - if (htmlPath !== undefined) { - this.outputHtmlPath = htmlPath; - } - } else { - throw new InputValidationError( - this.errorBuilder({message: 'Output HTML is missing'}) - ); - } - return this; - } - - async execute(inputs: ModelParams[]): Promise { - const [timestamps, energyValues, carbonValues] = - new TimeSeriesDataExtractor().extract(inputs); - - const directoryPath = __dirname; - const templateHtmlPath = path.join( - directoryPath, - SimpleHtmlExporter.INPUT_HTML_NAME - ); - const htmlContent = fs.readFileSync(templateHtmlPath, 'utf8'); - - const updatedHtmlContent = htmlContent - .replace( - /var timestamps = \[.*?\]/s, - `var timestamps = ${JSON.stringify(timestamps)}` - ) - .replace( - /var energyValues = \[.*?\]/s, - `var energyValues = ${JSON.stringify(energyValues)}` - ) - .replace( - /var carbonValues = \[.*?\]/s, - `var carbonValues = ${JSON.stringify(carbonValues)}` - ); - fs.writeFileSync(this.outputHtmlPath, updatedHtmlContent, 'utf8'); - - return inputs; - } -} +import {ModelPluginInterface} from '../../interfaces'; +import {ModelParams} from '../../types/common'; +import {TimeSeriesDataExtractor} from './helpers/TimeSeriesDataExtractor'; +import {ERRORS} from '../../util/errors'; +const {InputValidationError} = ERRORS; +import {buildErrorMessage} from '../../util/helpers'; +import * as fs from 'fs'; +import path = require('path'); + +export class SimpleHtmlExporter implements ModelPluginInterface { + private static INPUT_HTML_NAME = 'html-export-template.html'; + private outputHtmlPath = ''; + errorBuilder = buildErrorMessage('SimpleHtmlExporter'); + + async configure( + staticParams: object | undefined = undefined + ): Promise { + if (staticParams === undefined) { + throw new InputValidationError( + this.errorBuilder({message: 'Input data is missing'}) + ); + } + if ('html-path' in staticParams) { + const htmlPath = staticParams['html-path'] as string; + if (htmlPath !== undefined) { + this.outputHtmlPath = htmlPath; + } + } else { + throw new InputValidationError( + this.errorBuilder({message: 'Output HTML is missing'}) + ); + } + return this; + } + + async execute(inputs: ModelParams[]): Promise { + const [timestamps, energyValues, carbonValues] = + new TimeSeriesDataExtractor().extract(inputs); + + const directoryPath = __dirname; + const templateHtmlPath = path.join( + directoryPath, + SimpleHtmlExporter.INPUT_HTML_NAME + ); + const htmlContent = fs.readFileSync(templateHtmlPath, 'utf8'); + + const updatedHtmlContent = htmlContent + .replace( + /var timestamps = \[.*?\]/s, + `var timestamps = ${JSON.stringify(timestamps)}` + ) + .replace( + /var energyValues = \[.*?\]/s, + `var energyValues = ${JSON.stringify(energyValues)}` + ) + .replace( + /var carbonValues = \[.*?\]/s, + `var carbonValues = ${JSON.stringify(carbonValues)}` + ); + fs.writeFileSync(this.outputHtmlPath, updatedHtmlContent, 'utf8'); + + return inputs; + } +} From 5b7d91d8c53c879c8a084e0f73614b097956c60a Mon Sep 17 00:00:00 2001 From: Paz Barda Date: Tue, 13 Feb 2024 11:42:37 +0200 Subject: [PATCH 3/3] HTML template tweaks, README Signed-off-by: Paz Barda --- src/lib/simple-html-exporter/README.md | 71 +++++++++++++++++++ .../html-export-template.html | 4 +- 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/lib/simple-html-exporter/README.md diff --git a/src/lib/simple-html-exporter/README.md b/src/lib/simple-html-exporter/README.md new file mode 100644 index 0000000..310a092 --- /dev/null +++ b/src/lib/simple-html-exporter/README.md @@ -0,0 +1,71 @@ +# Simple HTML exporter + +The `Simple HTML exporter` aims at providing basic (simple) visualization of overall energy and carbon results. +It it includes a template HTML file that renders into 2 charts: `Energy` and `Carbon` over `time`. +Every time the plugin is executed an HTML file is generated based on the template HTML and the `Energy` and `Carbon` values in the input + +## Parameters + +### Model config + +The model should be initialized as follows: + +- `html-path`: the path to output (updated) HTML file. If the file already exists it would be overwritten. + +### inputs + +`energy`[kWh], `carbon`[gCO2] and `timestamp` should be included in the input array items. + +## Returns + +This plugin acts as a relay, returning the input as-is, with the generated HTML acting as a "side effect". + +## Implementation + +To run the model, you must first create an instance of `SimpleHtmlExporter` and call its `configure()` method. Then, you can call `execute()` with the proper inputs to generate the HTML. + +```typescript +import {SimpleHtmlExporter} from '@grnsft/if-models'; +const outputModel = new SimpleHtmlExporter(); +await outputModel.configure(); +const result = await outputModel.execute([ + { + ... + timestamp: '2021-01-01T00:00:00Z', + energy: 0.00001841, + carbon: 0.0104062, + ... + }, +]); +``` +## Example impl + +```yaml +name: simple-html-exporter-demo +description: +tags: +initialize: + models: + - name: simple-html-exporter + model: SimpleHtmlExporter + path: "@grnsft/if-models" +graph: + children: + child: + pipeline: + - simple-html-exporter + config: + simple-html-exporter: + html-path: /usr/local/data/html-export.html + inputs: + - timestamp: '2021-01-01T00:00:00Z', + energy: 0.00001841, + carbon: 0.0104062, +``` + + +```sh +npm i -g @grnsft/if +npm i -g @grnsft/if-models +impact-engine --impl ./examples/impls/test/simple-html-exporter.yml --ompl ./examples/ompls/simple-html-exporter.yml +``` diff --git a/src/lib/simple-html-exporter/html-export-template.html b/src/lib/simple-html-exporter/html-export-template.html index 1b53498..497aa4a 100644 --- a/src/lib/simple-html-exporter/html-export-template.html +++ b/src/lib/simple-html-exporter/html-export-template.html @@ -21,8 +21,8 @@