Mercurial > gemma
changeset 2751:5da81634bdc4
client: waterlevel diagram: implemented nash-sutcliffe
Since there is no real data available currently, I left a commented block of demo data in
client/src/store/gauges.js:L139. Uncomment that block to see the coefficients in the diagram.
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Thu, 21 Mar 2019 12:33:43 +0100 |
parents | 6446bf6d2a89 |
children | 018f979f9e23 |
files | client/src/components/gauge/Gauges.vue client/src/components/gauge/Waterlevel.vue client/src/store/gauges.js |
diffstat | 3 files changed, 204 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/gauge/Gauges.vue Thu Mar 21 12:23:52 2019 +0100 +++ b/client/src/components/gauge/Gauges.vue Thu Mar 21 12:33:43 2019 +0100 @@ -192,8 +192,11 @@ this.$store.commit("application/splitscreenLoading", true); this.loading = true; this.$store.commit("application/showSplitscreen", true); - this.$store - .dispatch("gauges/loadWaterlevels") + + Promise.all([ + this.$store.dispatch("gauges/loadWaterlevels"), + this.$store.dispatch("gauges/loadNashSutcliffe") + ]) .catch(error => { const { status, data } = error.response; displayError({
--- a/client/src/components/gauge/Waterlevel.vue Thu Mar 21 12:23:52 2019 +0100 +++ b/client/src/components/gauge/Waterlevel.vue Thu Mar 21 12:33:43 2019 +0100 @@ -18,14 +18,14 @@ .line stroke: steelblue stroke-width: 2 - fill: transparent + fill: none clip-path: url(#clip) .hdc-line, .ldc-line, .mw-line stroke-width: 1 - fill: transparent + fill: none clip-path: url(#clip) .hdc-line stroke: red @@ -39,6 +39,20 @@ .hdc-ldc-area fill: rgba(0, 255, 0, 0.15) + path.nash-sutcliffe + fill: none + stroke: black + stroke-width: 1 + clip-path: url(#clip) + &.ns72 + fill: rgba(0, 0, 0, 0.05) + text.nash-sutcliffe + font-size: 10px + clip-path: url(#clip) + tspan:last-child + font-size: 9px + fill: #777 + .tick line stroke-dasharray: 5 @@ -50,7 +64,7 @@ pointer-events: all .brush .selection - stroke: transparent + stroke: none fill-opacity: 0.2 .handle stroke: rgba($color-info, 0.5) @@ -73,6 +87,8 @@ text fill: #666 font-size: 12px + tspan:last-child + font-weight: bold </style> <script> @@ -101,7 +117,12 @@ export default { computed: { - ...mapState("gauges", ["waterlevels", "dateFrom", "dateTo"]), + ...mapState("gauges", [ + "waterlevels", + "dateFrom", + "dateTo", + "nashSutcliffe" + ]), ...mapGetters("gauges", ["selectedGauge"]) }, watch: { @@ -111,6 +132,9 @@ }, methods: { drawDiagram() { + // TODO: Optimize code. I'm pretty sure all of this can be done in a much + // more elegant way and with less lines of code. + // remove old diagram d3.select(".diagram-container svg").remove(); @@ -161,7 +185,7 @@ { waterlevel: Math.max( refWaterLevels.LDC - - (refWaterLevels.HDC - refWaterLevels.LDC) / 8, + (refWaterLevels.HDC - refWaterLevels.LDC) / 4, 0 ) } @@ -325,7 +349,7 @@ .attr("class", "nav") .attr("transform", `translate(${navMargin.left}, ${navMargin.top})`); - // axis (nav chart only has y-axis) + // axis (nav chart only has x-axis) navChart .append("g") .attr("class", "axis axis--x") @@ -339,6 +363,98 @@ .attr("class", "line") .attr("d", navLineChart); + // NASH SUTCLIFFE + + let nashSut24 = this.nashSutcliffe.coeffs.find(c => c.hours === 24); + let nashSut48 = this.nashSutcliffe.coeffs.find(c => c.hours === 48); + let nashSut72 = this.nashSutcliffe.coeffs.find(c => c.hours === 72); + + let nashSutDateNow = new Date(this.nashSutcliffe.when); + let nashSutDate24 = new Date(this.nashSutcliffe.when); + let nashSutDate48 = new Date(this.nashSutcliffe.when); + let nashSutDate72 = new Date(this.nashSutcliffe.when); + nashSutDate24.setDate(nashSutDate24.getDate() - 1); + nashSutDate48.setDate(nashSutDate48.getDate() - 2); + nashSutDate72.setDate(nashSutDate72.getDate() - 3); + + const nashSutcliffeBox = hours => { + return d3 + .area() + .x(d => x(d)) + .y0(() => mainHeight + 0.5) + .y1(() => mainHeight - 15 * (hours / 24)); + }; + + const nashSutcliffeLabel = (label, date, hours) => { + let days = hours / 24; + label + .attr("x", x(date) + 3) + .attr("y", mainHeight - (15 * days + 0.5) + 12); + }; + + // Show nash-sutcliffe only when x-axis extent is smaller than 31 days + // (2678400000 ms). Since it shows squares representing 1, 2 and 3 days + // it does not make sense to show them on a x-axis with hundres of days. + if (this.nashSutcliffe && x.domain()[1] - x.domain()[0] < 2678400000) { + if (nashSut24.samples) { + mainChart + .append("path") + .datum([nashSutDate24, nashSutDateNow]) + .attr("class", "nash-sutcliffe ns24") + .attr("d", nashSutcliffeBox(24)); + mainChart + .append("text") + .attr("class", "nash-sutcliffe ns24") + .call(nashSutcliffeLabel, nashSutDate24, 24) + .append("tspan") + .text(nashSut24.value.toFixed(2)) + .select(function() { + return this.parentNode; + }) + .append("tspan") + .text(` (${nashSut24.samples})`) + .attr("dy", -1); + } + if (nashSut48.samples) { + mainChart + .append("path") + .datum([nashSutDate48, nashSutDateNow]) + .attr("class", "nash-sutcliffe ns48") + .attr("d", nashSutcliffeBox(48)); + mainChart + .append("text") + .attr("class", "nash-sutcliffe ns48") + .call(nashSutcliffeLabel, nashSutDate48, 48) + .append("tspan") + .text(nashSut48.value.toFixed(2)) + .select(function() { + return this.parentNode; + }) + .append("tspan") + .text(` (${nashSut48.samples})`) + .attr("dy", -1); + } + if (nashSut72.samples) { + mainChart + .append("path") + .datum([nashSutDate72, nashSutDateNow]) + .attr("class", "nash-sutcliffe ns72") + .attr("d", nashSutcliffeBox(72)); + mainChart + .append("text") + .attr("class", "nash-sutcliffe ns72") + .call(nashSutcliffeLabel, nashSutDate72, 72) + .append("tspan") + .text(nashSut72.value.toFixed(2)) + .select(function() { + return this.parentNode; + }) + .append("tspan") + .text(` (${nashSut72.samples})`) + .attr("dy", -1); + } + } + // INTERACTIVITY // selecting time period in nav chart @@ -353,6 +469,24 @@ x.domain(s.map(x2.invert, x2)); mainChart.select(".line").call(mainLineChart); mainChart + .select("path.nash-sutcliffe.ns24") + .attr("d", nashSutcliffeBox(24)); + mainChart + .select("text.nash-sutcliffe.ns24") + .call(nashSutcliffeLabel, nashSutDate24, 24); + mainChart + .select("path.nash-sutcliffe.ns48") + .attr("d", nashSutcliffeBox(48)); + mainChart + .select("text.nash-sutcliffe.ns48") + .call(nashSutcliffeLabel, nashSutDate48, 48); + mainChart + .select("path.nash-sutcliffe.ns72") + .attr("d", nashSutcliffeBox(72)); + mainChart + .select("text.nash-sutcliffe.ns72") + .call(nashSutcliffeLabel, nashSutDate72, 72); + mainChart .select(".axis--x") .call(xAxis) .selectAll(".tick text") @@ -378,6 +512,24 @@ x.domain(t.rescaleX(x2).domain()); mainChart.select(".line").call(mainLineChart); mainChart + .select("path.nash-sutcliffe.ns24") + .attr("d", nashSutcliffeBox(24)); + mainChart + .select("text.nash-sutcliffe.ns24") + .call(nashSutcliffeLabel, nashSutDate24, 24); + mainChart + .select("path.nash-sutcliffe.ns48") + .attr("d", nashSutcliffeBox(48)); + mainChart + .select("text.nash-sutcliffe.ns48") + .call(nashSutcliffeLabel, nashSutDate48, 48); + mainChart + .select("path.nash-sutcliffe.ns72") + .attr("d", nashSutcliffeBox(72)); + mainChart + .select("text.nash-sutcliffe.ns72") + .call(nashSutcliffeLabel, nashSutDate72, 72); + mainChart .select(".axis--x") .call(xAxis) .selectAll(".tick text") @@ -429,8 +581,7 @@ tooltipText .append("tspan") .attr("x", 8) - .attr("y", 8) - .style("font-weight", "bold"); + .attr("y", 8); let bisectDate = d3.bisector(d => d.date).left; zoomRect
--- a/client/src/store/gauges.js Thu Mar 21 12:23:52 2019 +0100 +++ b/client/src/store/gauges.js Thu Mar 21 12:33:43 2019 +0100 @@ -22,6 +22,7 @@ gauges: [], selectedGaugeISRS: null, waterlevels: [], + nashSutcliffe: null, dateFrom: dateFrom, dateTo: new Date() }; @@ -48,6 +49,9 @@ waterlevels: (state, data) => { state.waterlevels = data; }, + nashSutcliffe: (state, data) => { + state.nashSutcliffe = data; + }, dateFrom: (state, dateFrom) => { state.dateFrom = dateFrom; }, @@ -124,6 +128,42 @@ reject(error); }); }); + }, + loadNashSutcliffe({ state, commit }) { + return new Promise((resolve, reject) => { + HTTP.get(`/data/nash-sutcliffe/${state.selectedGaugeISRS}`, { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } + }) + .then(response => { + commit("nashSutcliffe", response.data); + // dest data + // commit("nashSutcliffe", { + // when: "2019-03-20T10:38:05.687", + // coeffs: [ + // { + // value: 0.814, + // samples: 18, + // hours: 24 + // }, + // { + // value: 0.319, + // samples: 36, + // hours: 48 + // }, + // { + // value: -0.20546757, + // samples: 54, + // hours: 72 + // } + // ] + // }); + resolve(response.data); + }) + .catch(error => { + commit("nashSutcliffe", null); + reject(error); + }); + }); } } };