Multiple improvements on syntax

Syntax has been simplified
Removed extra initial states
Removed unused groups
Nodes can be wrapped in double qotes
Updated demo page
This commit is contained in:
Nikolay Rozhkov 2023-06-19 03:45:24 +03:00
parent 726efdad53
commit 6722ac7540
5 changed files with 214 additions and 56 deletions

View File

@ -16,16 +16,93 @@
<body>
<h1>Sankey diagram demos</h1>
<h2>Simple flow</h2>
<h2>Simple example</h2>
<pre class="mermaid">
sankey
a->28->b->10->c
a->11->b
k->18->b->35->d->13->e->43->dd11
d->5->e
d->10->c
k->25->e
</pre>
sankey
node[title="hello, how are you?"]
node[title="hello, mister Sankey"]
First -> 30 -> Second
First -> 10 -> Third
Second -> 20 -> Third
</pre>
<!-- node[title="hello, mister "sankey", backslash for you "] -->
<h2>Energy flow</h2>
<pre class="mermaid">
sankey
"Agricultural 'waste'" -> 124.729 -> "Bio-conversion"
"Bio-conversion" -> 0.597 -> "Liquid"
"Bio-conversion" -> 26.862 -> "Losses"
"Bio-conversion" -> 280.322 -> "Solid"
"Bio-conversion" -> 81.144 -> "Gas"
"Biofuel imports" -> 35 -> "Liquid"
"Biomass imports" -> 35 -> "Solid"
"Coal imports" -> 11.606 -> "Coal"
"Coal reserves" -> 63.965 -> "Coal"
"Coal" -> 75.571 -> "Solid"
"District heating" -> 10.639 -> "Industry"
"District heating" -> 22.505 -> "Heating and cooling - commercial"
"District heating" -> 46.184 -> "Heating and cooling - homes"
"Electricity grid" -> 104.453 -> "Over generation / exports"
"Electricity grid" -> 113.726 -> "Heating and cooling - homes"
"Electricity grid" -> 27.14 -> "H2 conversion"
"Electricity grid" -> 342.165 -> "Industry"
"Electricity grid" -> 37.797 -> "Road transport"
"Electricity grid" -> 4.412 -> "Agriculture"
"Electricity grid" -> 40.858 -> "Heating and cooling - commercial"
"Electricity grid" -> 56.691 -> "Losses"
"Electricity grid" -> 7.863 -> "Rail transport"
"Electricity grid" -> 90.008 -> "Lighting & appliances - commercial"
"Electricity grid" -> 93.494 -> "Lighting & appliances - homes"
"Gas imports" -> 40.719 -> "Ngas"
"Gas reserves" -> 82.233 -> "Ngas"
"Gas" -> 0.129 -> "Heating and cooling - commercial"
"Gas" -> 1.401 -> "Losses"
"Gas" -> 151.891 -> "Thermal generation"
"Gas" -> 2.096 -> "Agriculture"
"Gas" -> 48.58 -> "Industry"
"Geothermal" -> 7.013 -> "Electricity grid"
"H2 conversion" -> 20.897 -> "H2"
"H2 conversion" -> 6.242 -> "Losses"
"H2" -> 20.897 -> "Road transport"
"Hydro" -> 6.995 -> "Electricity grid"
"Liquid" -> 121.066 -> "Industry"
"Liquid" -> 128.69 -> "International shipping"
"Liquid" -> 135.835 -> "Road transport"
"Liquid" -> 14.458 -> "Domestic aviation"
"Liquid" -> 206.267 -> "International aviation"
"Liquid" -> 3.64 -> "Agriculture"
"Liquid" -> 33.218 -> "National navigation"
"Liquid" -> 4.413 -> "Rail transport"
"Marine algae" -> 4.375 -> "Bio-conversion"
"Ngas" -> 122.952 -> "Gas"
"Nuclear" -> 839.978 -> "Thermal generation"
"Oil imports" -> 504.287 -> "Oil"
"Oil reserves" -> 107.703 -> "Oil"
"Oil" -> 611.99 -> "Liquid"
"Other waste" -> 56.587 -> "Solid"
"Other waste" -> 77.81 -> "Bio-conversion"
"Pumped heat" -> 193.026 -> "Heating and cooling - homes"
"Pumped heat" -> 70.672 -> "Heating and cooling - commercial"
"Solar PV" -> 59.901 -> "Electricity grid"
"Solar Thermal" -> 19.263 -> "Heating and cooling - homes"
"Solar" -> 19.263 -> "Solar Thermal"
"Solar" -> 59.901 -> "Solar PV"
"Solid" -> 0.882 -> "Agriculture"
"Solid" -> 400.12 -> "Thermal generation"
"Solid" -> 46.477 -> "Industry"
"Thermal generation" -> 525.531 -> "Electricity grid"
"Thermal generation" -> 787.129 -> "Losses"
"Thermal generation" -> 79.329 -> "District heating"
"Tidal" -> 9.452 -> "Electricity grid"
"UK land based bioenergy" -> 182.01 -> "Bio-conversion"
"Wave" -> 19.013 -> "Electricity grid"
"Wind" -> 289.366 -> "Electricity grid"
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({

View File

@ -4,38 +4,36 @@
%options case-insensitive
%options easy_keyword_rules
%s group
// when we are inside [] section we are defining attrubutes
%x attributes
// after attr= we are expecting a value without quotes
%x value
// or if we use "" we are expecting a string containing value
%x string
%x string
%x value
%%
"sankey" { return 'SANKEY'; }
\d+ { return 'AMOUNT'; }
"->" { return 'ARROW'; }
\w+ { return 'NODE'; }
(?:<<EOF>>|[\n;])+ { return 'EOS'; } // end of statement is ; \n or end of file
\s+ // skip all whitespace
"{" { this.pushState('group'); return 'OPEN_GROUP'; }
<group>"}" { this.popState(); return 'CLOSE_GROUP'; }
"[" { this.pushState('attributes'); return 'OPEN_ATTRIBUTES'; }
<attributes>"]" { this.popState(); return 'CLOSE_ATTRIBUTES'; }
<attributes>\w+ { return 'ATTRIBUTE'; }
<attributes>(?=\=s*)[\s\w] { return 'VALUE';}
<attributes>\= { this.pushState('value'); return 'EQUAL'; }
<attributes>\s+ // skip all whitespace
<value>[\w]+ { this.popState(); return 'VALUE';}
<value>\s+ //skip
<value>\" { this.pushState('string'); return 'OPEN_STRING'; }
<string>(?!\\)\" {
if(this.topState()==='string') this.popState();
if(this.topState()==='value') this.popState();
return 'CLOSE_STRING';
}
<string>([^"\\]|\\\")+ { return 'STRING'; }
// skip all whitespace EXCEPT newlines, but not within a string
<INITIAL,attributes,value>[^\S\r\n]+ {}
// main
"sankey" { return 'SANKEY'; }
\d+(.\d+)? { return 'AMOUNT'; }
"->" { return 'ARROW'; }
\w+ { return 'NODE'; }
(?:<<EOF>>|[\n;])+ { return 'EOS'; } // end of statement is semicolon ; new line \n or end of file
// attributes
"[" { this.pushState('attributes'); return 'OPEN_ATTRIBUTES'; }
<attributes>"]" { this.popState(); return 'CLOSE_ATTRIBUTES'; }
<attributes>\w+ { return 'ATTRIBUTE'; }
<attributes>\= { this.pushState('value'); return 'EQUAL'; }
<value>\w+ { this.popState(); return 'VALUE'; }
// strings
<INITIAL,attributes,value>\" { this.pushState('string'); return 'OPEN_STRING'; }
<string>(?!\\)\" {
if(this.topState()==='string') this.popState();
if(this.topState()==='value') this.popState();
return 'CLOSE_STRING';
}
<string>([^"\\]|\\\"|\\\\)+ { return 'STRING'; }
/lex
@ -79,14 +77,8 @@ tail
| node { $$ = $node; }
;
node: NODE { $$ = yy.addNode($NODE); };
node
: NODE { $$ = yy.addNode($NODE); }
| OPEN_STRING STRING[title] CLOSE_STRING { $$ = yy.addNode($title); /* TODO: add title and id separately?*/ }
;
// : NODE exhaust intake exhaust_chain optional_attributes EOS
// exhaust_chain: ARROW AMOUNT intake_chain | ;
// intake_chain: ARROW NODE exhaust_chain | ;
// exhaust: ARROW AMOUNT;
// intake: ARROW NODE;
// node_chain_amount: NODE ARROW amount_node_chain | NODE;
// amount_node_chain: AMOUNT ARROW node_chain_amount | AMOUNT;

View File

@ -38,11 +38,23 @@ describe('Sankey diagram', function () {
parser.parse(str);
});
it('parses node as a string', () => {
const str = `
sankey
"node a" -> 30 -> "node b" -> 12 -> "node e"
"node c" -> 30 -> "node d" -> 12 -> "node e"
"node c" -> 40 -> "node e" -> 12 -> "node q"
`;
parser.parse(str);
});
describe('while attributes parsing', () => {
it('parses different quotless variations', () => {
const str = `
sankey
node[]
node[attr=1]
node_a -> 30 -> node_b
node[attrWithoutValue]
@ -57,12 +69,89 @@ describe('Sankey diagram', function () {
it('parses strings as values', () => {
const str = `
sankey
node[attr="hello, how are you?"]
node[attr="hello\\"afaasd"]
node[title="hello, how are you?"]
node[title="hello, mister \\"sankey\\", backslash for you \\\\"]
`;
parser.parse(str);
});
it('parses truly complex example', () => {
const str = `
sankey
"Agricultural 'waste'" -> 124.729 -> "Bio-conversion"
"Bio-conversion" -> 0.597 -> "Liquid"
"Bio-conversion" -> 26.862 -> "Losses"
"Bio-conversion" -> 280.322 -> "Solid"
"Bio-conversion" -> 81.144 -> "Gas"
"Biofuel imports" -> 35 -> "Liquid"
"Biomass imports" -> 35 -> "Solid"
"Coal imports" -> 11.606 -> "Coal"
"Coal reserves" -> 63.965 -> "Coal"
"Coal" -> 75.571 -> "Solid"
"District heating" -> 10.639 -> "Industry"
"District heating" -> 22.505 -> "Heating and cooling - commercial"
"District heating" -> 46.184 -> "Heating and cooling - homes"
"Electricity grid" -> 104.453 -> "Over generation / exports"
"Electricity grid" -> 113.726 -> "Heating and cooling - homes"
"Electricity grid" -> 27.14 -> "H2 conversion"
"Electricity grid" -> 342.165 -> "Industry"
"Electricity grid" -> 37.797 -> "Road transport"
"Electricity grid" -> 4.412 -> "Agriculture"
"Electricity grid" -> 40.858 -> "Heating and cooling - commercial"
"Electricity grid" -> 56.691 -> "Losses"
"Electricity grid" -> 7.863 -> "Rail transport"
"Electricity grid" -> 90.008 -> "Lighting & appliances - commercial"
"Electricity grid" -> 93.494 -> "Lighting & appliances - homes"
"Gas imports" -> 40.719 -> "Ngas"
"Gas reserves" -> 82.233 -> "Ngas"
"Gas" -> 0.129 -> "Heating and cooling - commercial"
"Gas" -> 1.401 -> "Losses"
"Gas" -> 151.891 -> "Thermal generation"
"Gas" -> 2.096 -> "Agriculture"
"Gas" -> 48.58 -> "Industry"
"Geothermal" -> 7.013 -> "Electricity grid"
"H2 conversion" -> 20.897 -> "H2"
"H2 conversion" -> 6.242 -> "Losses"
"H2" -> 20.897 -> "Road transport"
"Hydro" -> 6.995 -> "Electricity grid"
"Liquid" -> 121.066 -> "Industry"
"Liquid" -> 128.69 -> "International shipping"
"Liquid" -> 135.835 -> "Road transport"
"Liquid" -> 14.458 -> "Domestic aviation"
"Liquid" -> 206.267 -> "International aviation"
"Liquid" -> 3.64 -> "Agriculture"
"Liquid" -> 33.218 -> "National navigation"
"Liquid" -> 4.413 -> "Rail transport"
"Marine algae" -> 4.375 -> "Bio-conversion"
"Ngas" -> 122.952 -> "Gas"
"Nuclear" -> 839.978 -> "Thermal generation"
"Oil imports" -> 504.287 -> "Oil"
"Oil reserves" -> 107.703 -> "Oil"
"Oil" -> 611.99 -> "Liquid"
"Other waste" -> 56.587 -> "Solid"
"Other waste" -> 77.81 -> "Bio-conversion"
"Pumped heat" -> 193.026 -> "Heating and cooling - homes"
"Pumped heat" -> 70.672 -> "Heating and cooling - commercial"
"Solar PV" -> 59.901 -> "Electricity grid"
"Solar Thermal" -> 19.263 -> "Heating and cooling - homes"
"Solar" -> 19.263 -> "Solar Thermal"
"Solar" -> 59.901 -> "Solar PV"
"Solid" -> 0.882 -> "Agriculture"
"Solid" -> 400.12 -> "Thermal generation"
"Solid" -> 46.477 -> "Industry"
"Thermal generation" -> 525.531 -> "Electricity grid"
"Thermal generation" -> 787.129 -> "Losses"
"Thermal generation" -> 79.329 -> "District heating"
"Tidal" -> 9.452 -> "Electricity grid"
"UK land based bioenergy" -> 182.01 -> "Bio-conversion"
"Wave" -> 19.013 -> "Electricity grid"
"Wind" -> 289.366 -> "Electricity grid"
`
parser.parse(str);
})
});
});
});

View File

@ -79,9 +79,9 @@ const addLink = function(source?: Node, target?: Node, value?: number): Link {
class Node {
ID: string;
title: string;
constructor(ID: string) {
constructor(ID: string, title: string = ID) {
this.ID = ID;
this.title = ID;
this.title = title;
}
}

View File

@ -1,6 +1,6 @@
// @ts-nocheck TODO: fix file
import { Diagram } from '../../Diagram.js';
import { log } from '../../logger.js';
// import { log } from '../../logger.js';
import * as configApi from '../../config.js';
import {
select as d3select,
@ -43,7 +43,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb
// Launch parsing
diagObj.parser.parse(text);
// debugger;
log.debug('Parsed sankey diagram');
// log.debug('Parsed sankey diagram');
// Figure out what is happening there
// The main thing is svg object that is a d3 wrapper for svg operations
@ -64,7 +64,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb
//
const elem = doc.getElementById(id);
const width = elem.parentElement.offsetWidth;
const height = 300; // TODO calculate height?
const height = 600; // TODO calculate height?
// FIX: using max width prevents height from being set
configureSvgSize(svg, height, width, true);
@ -92,7 +92,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb
}
diagObj.db.getNodes().forEach(node => {
graph.nodes.push({ id: node.ID });
graph.nodes.push({ id: node.ID, title: node.title });
});
diagObj.db.getLinks().forEach(link => {
@ -158,7 +158,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb
.attr('x', (d) => d.x0)
.attr('y', (d) => d.y0)
.append('rect')
.attr('height', (d) => { console.log(d); return (d.y1 - d.y0); })
.attr('height', (d) => { return (d.y1 - d.y0); })
.attr('width', (d) => d.x1 - d.x0)
.attr('fill', (d) => color(d.id));
@ -175,7 +175,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb
.attr("y", d => (d.y1 + d.y0) / 2)
.attr("dy", "0.35em")
.attr("text-anchor", d => d.x0 < width / 2 ? "start" : "end")
.text(d => d.id)
.text(d => d.title)
// Creates the paths that represent the links.
const link_g = svg.append("g")