2021-09-04 19:13:57 +02:00
|
|
|
|
<template>
|
|
|
|
|
|
<v-card style="min-height:400px;">
|
|
|
|
|
|
<v-card-title class="headline">
|
|
|
|
|
|
Gun pressures
|
|
|
|
|
|
<v-spacer></v-spacer>
|
|
|
|
|
|
<v-switch v-model="shotpoint" label="Shotpoint"></v-switch>
|
|
|
|
|
|
<v-switch class="ml-4" v-model="violinplot" label="Violin plot"></v-switch>
|
|
|
|
|
|
</v-card-title>
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
<v-container fluid fill-height>
|
|
|
|
|
|
<v-row>
|
|
|
|
|
|
<v-col>
|
|
|
|
|
|
<div class="graph-container" ref="graphSeries"></div>
|
|
|
|
|
|
</v-col>
|
|
|
|
|
|
</v-row>
|
|
|
|
|
|
<v-row v-show="shotpoint">
|
|
|
|
|
|
<v-col>
|
|
|
|
|
|
<div class="graph-container" ref="graphBar"></div>
|
|
|
|
|
|
</v-col>
|
|
|
|
|
|
</v-row>
|
|
|
|
|
|
<v-row v-show="violinplot">
|
|
|
|
|
|
<v-col>
|
|
|
|
|
|
<div class="graph-container" ref="graphViolin"></div>
|
|
|
|
|
|
</v-col>
|
|
|
|
|
|
</v-row>
|
|
|
|
|
|
</v-container>
|
|
|
|
|
|
|
|
|
|
|
|
<v-overlay :value="busy" absolute z-index="1">
|
|
|
|
|
|
<v-progress-circular indeterminate></v-progress-circular>
|
|
|
|
|
|
</v-overlay>
|
|
|
|
|
|
</v-card>
|
|
|
|
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.graph-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
|
|
|
|
|
|
import * as d3a from 'd3-array';
|
|
|
|
|
|
import Plotly from 'plotly.js-dist';
|
|
|
|
|
|
import { mapActions, mapGetters } from 'vuex';
|
|
|
|
|
|
import unpack from '@/lib/unpack.js';
|
|
|
|
|
|
import * as aes from '@/lib/graphs/aesthetics.js';
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'DougalGraphGunsPressure',
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-28 18:12:37 +02:00
|
|
|
|
props: [ "data", "settings" ],
|
2021-09-04 19:13:57 +02:00
|
|
|
|
|
|
|
|
|
|
data () {
|
|
|
|
|
|
return {
|
|
|
|
|
|
graph: null,
|
|
|
|
|
|
graphHover: null,
|
|
|
|
|
|
busy: false,
|
|
|
|
|
|
resizeObserver: null,
|
|
|
|
|
|
shotpoint: true,
|
|
|
|
|
|
violinplot: false
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
computed: {
|
|
|
|
|
|
//...mapGetters(['apiUrl'])
|
|
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
watch: {
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
data (newVal, oldVal) {
|
|
|
|
|
|
console.log("data changed");
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
if (newVal === null) {
|
|
|
|
|
|
this.busy = true;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.busy = false;
|
|
|
|
|
|
this.plot();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-28 18:12:37 +02:00
|
|
|
|
settings () {
|
|
|
|
|
|
for (const key in this.settings) {
|
|
|
|
|
|
this[key] = this.settings[key];
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-28 18:12:37 +02:00
|
|
|
|
shotpoint () {
|
|
|
|
|
|
if (this.shotpoint) {
|
|
|
|
|
|
this.replot();
|
|
|
|
|
|
}
|
|
|
|
|
|
this.$emit("update:settings", {[`${this.$options.name}.shotpoint`]: this.shotpoint});
|
|
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
violinplot () {
|
|
|
|
|
|
if (this.violinplot) {
|
|
|
|
|
|
this.plotViolin();
|
|
|
|
|
|
}
|
2021-09-28 18:12:37 +02:00
|
|
|
|
this.$emit("update:settings", {[`${this.$options.name}.violinplot`]: this.violinplot});
|
2021-09-04 19:13:57 +02:00
|
|
|
|
}
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
methods: {
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
plot () {
|
|
|
|
|
|
this.plotSeries();
|
|
|
|
|
|
if (this.violinplot) {
|
|
|
|
|
|
this.plotViolin();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
async plotSeries () {
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
function transformSeries (d, src_number, otherParams={}) {
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const meta = src_number
|
|
|
|
|
|
? unpack(d, "meta").filter( s => s.src_number == src_number )
|
|
|
|
|
|
: unpack(d, "meta");
|
|
|
|
|
|
const guns = unpack(meta, "guns").map(s => s.filter(g => g[2] == src_number));;
|
|
|
|
|
|
const gunPressures = guns.map(s => s.map(g => g[11]));
|
|
|
|
|
|
const gunPressuresSorted = gunPressures.map(s => d3a.sort(s));
|
|
|
|
|
|
const gunVolumes = guns.map(s => s.map(g => g[12]));
|
|
|
|
|
|
const gunPressureWeights = gunVolumes.map( (s, sidx) => s.map( v => v/meta[sidx].volume ));
|
|
|
|
|
|
const gunsWeightedAvgPressure = gunPressures.map( (s, sidx) =>
|
|
|
|
|
|
d3a.sum(s.map( (pressure, gidx) => pressure * gunPressureWeights[sidx][gidx] )) / d3a.sum(gunPressureWeights[sidx])
|
|
|
|
|
|
);
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const manifold = unpack(meta, "manifold");
|
|
|
|
|
|
const x = src_number
|
|
|
|
|
|
? unpack(d.filter(s => s.meta.src_number == src_number), "point")
|
|
|
|
|
|
: unpack(d, "point");
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const traceManifold = {
|
|
|
|
|
|
name: "Manifold",
|
|
|
|
|
|
type: "scatter",
|
|
|
|
|
|
mode: "lines",
|
|
|
|
|
|
line: { ...aes.gunArrays[src_number || 1].avg.line, dash: "dot", width: 1 },
|
|
|
|
|
|
x,
|
|
|
|
|
|
y: manifold,
|
|
|
|
|
|
};
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const tracesGunPressures = [{
|
|
|
|
|
|
type: "scatter",
|
|
|
|
|
|
mode: "lines",
|
|
|
|
|
|
x,
|
|
|
|
|
|
y: gunPressuresSorted.map(s => d3a.quantileSorted(s, 0.25)),
|
|
|
|
|
|
...aes.gunArrays[src_number || 1].min
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
type: "scatter",
|
|
|
|
|
|
mode: "lines",
|
|
|
|
|
|
fill: "tonexty",
|
|
|
|
|
|
x,
|
|
|
|
|
|
y: gunsWeightedAvgPressure,
|
|
|
|
|
|
...aes.gunArrays[src_number || 1].avg
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
type: "scatter",
|
|
|
|
|
|
mode: "lines",
|
|
|
|
|
|
fill: "tonexty",
|
|
|
|
|
|
x,
|
|
|
|
|
|
y: gunPressuresSorted.map(s => d3a.quantileSorted(s, 0.75)),
|
|
|
|
|
|
...aes.gunArrays[src_number || 1].max
|
|
|
|
|
|
}];
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const tracesGunsPressuresIndividual = {
|
2021-09-11 17:26:50 +02:00
|
|
|
|
//name: `Array ${src_number} outliers`,
|
2021-09-04 19:13:57 +02:00
|
|
|
|
type: "scatter",
|
|
|
|
|
|
mode: "markers",
|
|
|
|
|
|
marker: {size: 2 },
|
|
|
|
|
|
hoverinfo: "skip",
|
|
|
|
|
|
x: gunPressuresSorted.map( (s, idx) =>
|
|
|
|
|
|
s.filter( g => g < d3a.quantileSorted(s, 0.05) || g > d3a.quantileSorted(s, 0.95))
|
|
|
|
|
|
.map( f => Array(f.length).fill(x[idx]) ).flat()
|
|
|
|
|
|
).flat(),
|
|
|
|
|
|
y: gunPressuresSorted.map( (s, idx) =>
|
|
|
|
|
|
s.filter( g => g < d3a.quantileSorted(s, 0.05) || g > d3a.quantileSorted(s, 0.95))
|
2021-09-11 17:26:50 +02:00
|
|
|
|
).flat(),
|
|
|
|
|
|
...aes.gunArrays[src_number || 1].out
|
2021-09-04 19:13:57 +02:00
|
|
|
|
};
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const data = [ traceManifold, ...tracesGunPressures, tracesGunsPressuresIndividual ]
|
|
|
|
|
|
return data;
|
|
|
|
|
|
}
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
if (!this.data) {
|
|
|
|
|
|
console.log("missing data");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const sources = [ ...new Set(unpack(this.data.items, "meta").map( s => s.src_number ))];
|
|
|
|
|
|
const data = sources.map( src_number => transformSeries(this.data.items, src_number) ).flat();
|
|
|
|
|
|
console.log("Sources", sources);
|
|
|
|
|
|
console.log(data);
|
|
|
|
|
|
this.busy = false;
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const layout = {
|
|
|
|
|
|
//autosize: true,
|
|
|
|
|
|
title: {text: "Gun pressures – sequence %{meta.sequence}"},
|
|
|
|
|
|
autocolorscale: true,
|
|
|
|
|
|
// colorscale: "sequential",
|
|
|
|
|
|
hovermode: "x",
|
|
|
|
|
|
yaxis: {
|
|
|
|
|
|
title: "Pressure (psi)",
|
|
|
|
|
|
//zeroline: false
|
|
|
|
|
|
},
|
|
|
|
|
|
xaxis: {
|
|
|
|
|
|
title: "Shotpoint",
|
|
|
|
|
|
showspikes: true
|
|
|
|
|
|
},
|
|
|
|
|
|
meta: this.data.meta
|
|
|
|
|
|
};
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const config = {
|
2021-09-28 18:30:26 +02:00
|
|
|
|
editable: false,
|
2021-09-04 19:13:57 +02:00
|
|
|
|
displaylogo: false
|
|
|
|
|
|
};
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
this.graph = Plotly.newPlot(this.$refs.graphSeries, data, layout, config);
|
|
|
|
|
|
this.$refs.graphSeries.on('plotly_hover', (d) => {
|
|
|
|
|
|
const point = d.points[0].x;
|
|
|
|
|
|
const item = this.data.items.find(s => s.point == point);
|
|
|
|
|
|
const guns = item.meta.guns.filter( g => g[2] == item.meta.src_number );
|
|
|
|
|
|
const gunIds = guns.map( g => "G"+g[1] );
|
|
|
|
|
|
const pressures = unpack(guns, 11);
|
|
|
|
|
|
const volumes = unpack(guns, 12);
|
|
|
|
|
|
const maxVolume = d3a.max(volumes);
|
|
|
|
|
|
const data = [{
|
|
|
|
|
|
type: "bar",
|
|
|
|
|
|
x: gunIds,
|
|
|
|
|
|
y: pressures,
|
|
|
|
|
|
width: volumes.map( v => v/maxVolume ),
|
|
|
|
|
|
transforms: [{
|
|
|
|
|
|
type: "groupby",
|
|
|
|
|
|
groups: unpack(guns, 0)
|
|
|
|
|
|
}],
|
|
|
|
|
|
}];
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const layout = {
|
|
|
|
|
|
title: {text: "Gun pressures – shot %{meta.point}"},
|
|
|
|
|
|
height: 300,
|
|
|
|
|
|
yaxis: {
|
|
|
|
|
|
title: "Pressure (psi)",
|
|
|
|
|
|
range: [ Math.min(d3a.min(pressures), 1950), Math.max(d3a.max(pressures), 2050) ]
|
|
|
|
|
|
},
|
|
|
|
|
|
xaxis: {
|
|
|
|
|
|
title: "Gun number",
|
|
|
|
|
|
type: 'category'
|
|
|
|
|
|
},
|
|
|
|
|
|
meta: {
|
|
|
|
|
|
point
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const config = { displaylogo: false };
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
Plotly.react(this.$refs.graphBar, data, layout, config);
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
async plotViolin () {
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
function transformViolin (d, opts = {}) {
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const styles = [];
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
unpack(unpack(d, "meta"), "guns").flat().forEach(i => {
|
|
|
|
|
|
const gunId = i[1];
|
|
|
|
|
|
const arrayId = i[2];
|
|
|
|
|
|
if (!styles[gunId]) {
|
|
|
|
|
|
styles[gunId] = Object.assign({target: gunId}, aes.gunArrayViolins[arrayId]);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const data = {
|
|
|
|
|
|
type: 'violin',
|
|
|
|
|
|
x: unpack(unpack(unpack(d, "meta"), "guns").flat(), 1), // Gun number
|
|
|
|
|
|
y: unpack(unpack(unpack(d, "meta"), "guns").flat(), 11), // Gun pressure
|
|
|
|
|
|
points: 'none',
|
|
|
|
|
|
box: {
|
|
|
|
|
|
visible: true
|
|
|
|
|
|
},
|
|
|
|
|
|
line: {
|
|
|
|
|
|
color: 'green',
|
|
|
|
|
|
},
|
|
|
|
|
|
meanline: {
|
|
|
|
|
|
visible: true
|
|
|
|
|
|
},
|
|
|
|
|
|
transforms: [{
|
|
|
|
|
|
type: 'groupby',
|
|
|
|
|
|
groups: unpack(unpack(unpack(d, "meta"), "guns").flat(), 1),
|
|
|
|
|
|
styles: styles.filter(i => !!i)
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
return data;
|
|
|
|
|
|
}
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
console.log("plot violin");
|
|
|
|
|
|
if (!this.data) {
|
|
|
|
|
|
console.log("missing data");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
console.log("Will plot sequence", this.data.meta.project, this.data.meta.sequence);
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const data = [ transformViolin(this.data.items) ];
|
|
|
|
|
|
this.busy = false;
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const layout = {
|
|
|
|
|
|
//autosize: true,
|
|
|
|
|
|
showlegend: false,
|
|
|
|
|
|
title: {text: "Individual gun pressures – sequence %{meta.sequence}"},
|
|
|
|
|
|
autocolorscale: true,
|
|
|
|
|
|
// colorscale: "sequential",
|
|
|
|
|
|
yaxis: {
|
|
|
|
|
|
title: "Pressure (psi)",
|
|
|
|
|
|
zeroline: false
|
|
|
|
|
|
},
|
|
|
|
|
|
xaxis: {
|
|
|
|
|
|
title: "Gun number"
|
|
|
|
|
|
},
|
|
|
|
|
|
meta: this.data.meta
|
|
|
|
|
|
};
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
const config = {
|
2021-09-28 18:30:26 +02:00
|
|
|
|
editable: false,
|
2021-09-04 19:13:57 +02:00
|
|
|
|
displaylogo: false
|
|
|
|
|
|
};
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
this.graph = Plotly.newPlot(this.$refs.graphViolin, data, layout, config);
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
replot () {
|
|
|
|
|
|
if (!this.graph) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
console.log("Replotting");
|
|
|
|
|
|
Object.values(this.$refs).forEach( ref => {
|
|
|
|
|
|
if (ref.data) {
|
|
|
|
|
|
console.log("Replotting", ref, ref.clientWidth, ref.clientHeight);
|
|
|
|
|
|
Plotly.relayout(ref, {
|
|
|
|
|
|
width: ref.clientWidth,
|
|
|
|
|
|
height: ref.clientHeight
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
...mapActions(["api"])
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
mounted () {
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
if (this.data) {
|
|
|
|
|
|
this.plot();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.busy = true;
|
|
|
|
|
|
}
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
this.resizeObserver = new ResizeObserver(this.replot)
|
|
|
|
|
|
this.resizeObserver.observe(this.$refs.graphSeries);
|
|
|
|
|
|
this.resizeObserver.observe(this.$refs.graphViolin);
|
2021-09-28 18:15:19 +02:00
|
|
|
|
this.resizeObserver.observe(this.$refs.graphBar);
|
2021-09-04 19:13:57 +02:00
|
|
|
|
},
|
2022-04-29 14:48:21 +02:00
|
|
|
|
|
2021-09-04 19:13:57 +02:00
|
|
|
|
beforeDestroy () {
|
|
|
|
|
|
if (this.resizeObserver) {
|
2021-09-28 18:15:19 +02:00
|
|
|
|
this.resizeObserver.unobserve(this.$refs.graphBar);
|
2021-09-28 18:14:39 +02:00
|
|
|
|
this.resizeObserver.unobserve(this.$refs.graphViolin);
|
2021-09-04 19:13:57 +02:00
|
|
|
|
this.resizeObserver.unobserve(this.$refs.graphSeries);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|