Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plotly Visualizer Widget For DeepForge. Fixes #1308, #1290 #1329

Merged
merged 23 commits into from
Nov 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3c22464
WIP-#1290: Update pipeline.webgmex to incorporate color of line2d(patch)
umesh-timalsina Oct 25, 2019
f6ef511
WIP- #1290: Update the library seed to incorporate subgraphs, add nod…
umesh-timalsina Nov 7, 2019
1fee673
#1290- Modify exisiting widget to support updated metamodel (Should c…
umesh-timalsina Nov 11, 2019
fca7d57
WIP #1308, #1290: Create a new Branch For plotly.js visualizer, plotl…
umesh-timalsina Nov 11, 2019
74c6931
WIP- #1308, #1290: Add single plot support via plotly visualizer(Upda…
umesh-timalsina Nov 11, 2019
21133b7
WIP- #1290, #1308: Add Plotly JSON Helper with changeset to the widget
umesh-timalsina Nov 14, 2019
60c0771
WIP- #1308: Complete ExecutionIndex Graph Creation Logic
umesh-timalsina Nov 16, 2019
edd98cb
WIP- #1308: Add Multiple Execution visualization support to subplots …
umesh-timalsina Nov 20, 2019
f975e4e
WIP: #1308: Remove changeset, matplotlib maps from requirements, chan…
umesh-timalsina Nov 20, 2019
066830e
#1308: Checkout LineGraph visualizer from master
umesh-timalsina Nov 20, 2019
aeac790
#1308:- Refactor ExecutionIndexWidget to consolidate multiple graphs …
umesh-timalsina Nov 21, 2019
50807be
#1308: Fix graph display issue for running executions
umesh-timalsina Nov 22, 2019
9a3705f
Remove invalid codeclimate config
umesh-timalsina Nov 22, 2019
5478bd3
#1308- Codeclimate fix
umesh-timalsina Nov 22, 2019
44f0d98
Merge branch 'master' into 1308-plotly-viz
umesh-timalsina Nov 22, 2019
5fa7cfb
1. Use Map insted of ForEach in PlotlyDescExtractor.js
umesh-timalsina Nov 26, 2019
a654551
Remove unused id from plotlyGraphWidget.removeNode
umesh-timalsina Nov 26, 2019
1ac67e7
Refactor setDisplayedExecutions to take after clicked states only, ch…
umesh-timalsina Nov 26, 2019
3a3aa1a
Modify subgraph title display, refactor ExecuteJob.Metadata.js to rem…
umesh-timalsina Nov 26, 2019
1ae02fc
WIP Fixed indentation issues (eslint)
brollb Nov 27, 2019
b87c04b
WIP Add plotly.min.js to ignore codeclimate files
brollb Nov 27, 2019
106b5c3
Merge branch 'master' into 1308-plotly-viz
brollb Nov 27, 2019
08be7de
WIP minor style fixes
brollb Nov 27, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ exclude_paths:
- src/visualizers/widgets/PipelineIndex/styles/PipelineIndex.css
- src/visualizers/widgets/LineGraph/lib/
- src/visualizers/widgets/PipelineEditor/klay.js
- src/visualizers/widgets/PlotlyGraph/lib/plotly.min.js
- src/plugins/GenerateJob/templates/utils.build.js
246 changes: 246 additions & 0 deletions src/common/viz/PlotlyDescExtractor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
/*globals define*/
define([], function () {
const PlotlyDescExtractor = function (client) {
this._client = client;
};

PlotlyDescExtractor.prototype.constructor = PlotlyDescExtractor;

PlotlyDescExtractor.prototype.getGraphDesc = function (node) {
const id = node.getId(),
jobId = node.getParentId(),
execId = this._client.getNode(jobId).getParentId();
let desc = {
id: id,
execId: execId,
type: 'graph',
name: node.getAttribute('name'),
graphId: node.getAttribute('id'),
title: node.getAttribute('title'),
};
let subGraphNodeIds = node.getChildrenIds();
desc.subGraphs = subGraphNodeIds.map((subGraphNodeId) => {
let subGraphNode = this._client.getNode(subGraphNodeId);
return this.getSubGraphDesc(subGraphNode);
});
brollb marked this conversation as resolved.
Show resolved Hide resolved
desc.subGraphs.sort(this.compareSubgraphIDs);
return desc;
};

PlotlyDescExtractor.prototype.getSubGraphDesc = function (node) {
let id = node.getId(),
graphId = node.getParentId(),
jobId = this._client.getNode(graphId).getParentId(),
execId = this._client.getNode(jobId).getParentId(),
desc;

desc = {
id: id,
execId: execId,
type: 'subgraph',
graphId: this._client.getNode(graphId).getAttribute('id'),
subgraphId: node.getAttribute('id'),
subgraphName: node.getAttribute('name'),
title: node.getAttribute('title'),
xlim: node.getAttribute('xlim'),
ylim: node.getAttribute('ylim'),
xlabel: node.getAttribute('xlabel'),
ylabel: node.getAttribute('ylabel'),
};

const lineIds = node.getChildrenIds();
desc.lines = lineIds.map((lineId) => {
let lineNode = this._client.getNode(lineId);
return this.getLineDesc(lineNode);
});
brollb marked this conversation as resolved.
Show resolved Hide resolved
return desc;
};

PlotlyDescExtractor.prototype.getLineDesc = function (node) {
let id = node.getId(),
subGraphId = node.getParentId(),
graphId = this._client.getNode(subGraphId).getParentId(),
jobId = this._client.getNode(graphId).getParentId(),
execId = this._client.getNode(jobId).getParentId(),
points,
desc;

points = node.getAttribute('points').split(';')
.filter(data => !!data) // remove any ''
.map(pair => {
const [x, y] = pair.split(',').map(num => parseFloat(num));
return {x, y};
});
desc = {
id: id,
execId: execId,
subgraphId: this._client.getNode(node.getParentId()).getAttribute('id'),
lineName: node.getAttribute('name'),
label: node.getAttribute('label'),
name: node.getAttribute('name'),
type: 'line',
points: points,
color: node.getAttribute('color')
};

return desc;
};


PlotlyDescExtractor.prototype.compareSubgraphIDs = function (desc1, desc2) {
if (desc1.subgraphId >= desc2.subgraphId) return 1;
else return -1;
};

PlotlyDescExtractor.prototype.descToPlotlyJSON = function (desc) {
let plotlyJSON = {};
if (desc) {
plotlyJSON.layout = createLayout(desc);
let dataArr = desc.subGraphs.map((subGraph, index) => {
return createScatterTraces(subGraph, index);
});
plotlyJSON.data = flatten(dataArr);
const axesData = addAxesLabels(desc.subGraphs);
Object.keys(axesData).forEach((axis) => {
plotlyJSON.layout[axis] = axesData[axis];
});
plotlyJSON.id = desc.id;
}
return plotlyJSON;
};

/*** Helper Methods For Creating The plotly JSON Reference ***/
const TraceTypes = {
SCATTER: 'scatter',
IMAGE: 'image'
};

const descHasMultipleSubPlots = function (desc) {
return desc.subGraphs.length > 1;
};

const createLayout = function (desc) {
let layout = {
title: desc.title,
height: 500
};
// Every plot should be drawn as n * 2 Grid??
if (descHasMultipleSubPlots(desc)) {
const numRows = Math.ceil(desc.subGraphs.length / 2);
layout.height = 250 * numRows;
let subPlots = [];
let currentSubplotAxes;
for (let i = 0; i < numRows * 2; i += 2) {
if (i === 0)
currentSubplotAxes = ['xy', 'x2y2'];
else
currentSubplotAxes = [`x${i + 1}y${i + 1}`, `x${i + 2}y${i + 2}`];
subPlots.push(currentSubplotAxes);
}
layout.grid = {
subplots: subPlots
};
layout.annotations = addAnnotations(desc.subGraphs);
} else {
if (!layout.title)
layout.title = desc.subGraphs[0].title;
else
layout.title = {
text: `${layout.title}<br>${desc.subGraphs[0].title}`
};
}
return layout;
};

// https://github.com/plotly/plotly.js/issues/2746#issuecomment-528342877
umesh-timalsina marked this conversation as resolved.
Show resolved Hide resolved
// At present the only hacky way to add subplots title
const addAnnotations = function (subGraphs) {
const evenLength = subGraphs.length % 2 === 0 ? subGraphs.length : subGraphs.length + 1;
return subGraphs.map((subGraph, index) => {
const yPosMarker = (index % 2 === 0) ? index : index - 1;
return {
text: `<b>${subGraph.title}</b>`,
font: {
family: 'Arial',
color: 'black',
size: 14
},
showarrow: false,
xref: 'paper',
yref: 'paper',
align: 'center',
x: (index % 2 === 0) ? 0.15 : 0.85,
y: (1 - yPosMarker / evenLength) * 1.1 - 0.06
};
});
};

const createScatterTraces = function (subGraph, index) {
let traceArr = subGraph.lines.map(line => {
let points = pointsToCartesianArray(line.points);
let traceData = {
x: points[0],
y: points[1],
name: line.label,
type: TraceTypes.SCATTER,
mode: line.marker ? 'line+marker' : 'line',
line: {
width: line.lineWidth ? line.lineWidth : 3,
color: line.color
},
};
if (index !== 0) {
traceData.xaxis = `x${index + 1}`;
traceData.yaxis = `y${index + 1}`;
}
return traceData;
});
return traceArr;
};

const addAxesLabels = function (subGraphs) {
let axesData = {};
subGraphs.forEach((subGraph, index) => {
let xAxisName = `xaxis${index + 1}`;
let yAxisName = `yaxis${index + 1}`;
if (index === 0) {
xAxisName = 'xaxis';
yAxisName = 'yaxis';
}
axesData[xAxisName] = {
title: {
text: subGraph.xlabel,
color: '#7f7f7f',
standoff: 0
}
};
axesData[yAxisName] = {
title: {
text: subGraph.ylabel,
color: '#7f7f7f',
standoff: 0
}
};
});
return axesData;
};

const pointsToCartesianArray = function (points) {
let x = [],
y = [];
points.forEach((point) => {
x.push(point.x);
y.push(point.y);
});
return [x, y];
};

const flatten = function (arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
};


return PlotlyDescExtractor;
});
Loading