-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* WIP Add initial commit of DatasetExplorer * WIP use artifact name in DataExplorer * WIP Add plot editor to dataset explorer * WIP add PlotEditor and css * Add UI elements for adding/removing data * Fix UI issue with editing plotted data * WIP Add utility for parsing python slices * Add slice string validation * UI support for validating data slice * Update figure updates given the figure data * Add explorer_helpers.py for DatasetExplorer * Add explorer helpers to session for getting metadata * dynamically create variable names for dropdown * Add tests for variable name creation from metadata * Plot actual data selected from "Add Data" button * Fix plot height * Add basic 3D plot support to DataExplorer * Fix async issue with multiple lines * Fix x-axis, y-axis labels * Add validation for plotting data * Remove .only from PythonSlice test suite * Add basic artifact loader to DatasetExplorer * Only show artifacts with data in artifact loader * Update metadata on artifact load into session * Removed hardcoded examples from html * Add some support for colors (uniform only) * Add color support for individual points * Fix selection of keys from artifacts * WIP Use session with queue in dataset explorer * WIP code cleanup dataset explorer * Add compute creation (and shield) for DatasetExplorer * Don't show slice syntax errors until change event * Fix artifacts with extensions. minor code cleanup * Increase territory for access to initialization code (custom serializer support) * Rename DatasetVisualizer -> TensorPlotter * Rename scss,css files * Add "save" action to floating action button * Only load jscolor in the browser * Skip jscolor library when linting * Add InteractiveEditor base class * Update to use InteractiveEditor base classes * Add getSnapshot to tensor plotter * Fix setting the data dialog on open * WIP working on operation code... * Include all artifacts in TensorPlotter * Fixed python slice parsing * Add InteractiveExplorer base class * Use inform dialog w/ auth errors * Update TensorPlotter to inherit from InteractiveExplorer * fix css linting issue * unregister action on destroy * Remove OperationTemplate * Clean up python commands and add dialog on error * Ensure that name,title are set on save * refactor executing python code * Improve error dialog * Misc code cleanup * Skip simple grid lib in linting * Fix quotes in tests
- Loading branch information
Showing
24 changed files
with
3,406 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
src/visualizers/panels/TensorPlotter/TensorPlotterControl.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/*globals define */ | ||
/** | ||
* Generated by VisualizerGenerator 1.7.0 from webgme on Mon May 04 2020 17:09:31 GMT-0500 (Central Daylight Time). | ||
*/ | ||
|
||
define([ | ||
'panels/InteractiveExplorer/InteractiveExplorerControl', | ||
], function ( | ||
InteractiveExplorerControl, | ||
) { | ||
|
||
'use strict'; | ||
|
||
class TensorPlotterControl extends InteractiveExplorerControl { | ||
|
||
getObjectDescriptor(nodeId) { | ||
const desc = super.getObjectDescriptor(nodeId); | ||
|
||
if (desc) { | ||
const node = this.client.getNode(nodeId); | ||
desc.data = node.getAttribute('data'); | ||
desc.type = node.getAttribute('type'); | ||
} | ||
|
||
return desc; | ||
} | ||
|
||
getTerritory(nodeId) { | ||
const territory = {}; | ||
const node = this.client.getNode(nodeId); | ||
const parentId = node.getParentId(); | ||
territory[parentId] = {children: 1}; | ||
|
||
const omitParentNode = event => event.eid !== parentId; | ||
this.territoryEventFilters = [omitParentNode]; | ||
|
||
return territory; | ||
} | ||
} | ||
|
||
return TensorPlotterControl; | ||
}); |
101 changes: 101 additions & 0 deletions
101
src/visualizers/panels/TensorPlotter/TensorPlotterPanel.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/*globals define, _, WebGMEGlobal*/ | ||
/** | ||
* Generated by VisualizerGenerator 1.7.0 from webgme on Mon May 04 2020 17:09:31 GMT-0500 (Central Daylight Time). | ||
*/ | ||
|
||
define([ | ||
'js/PanelBase/PanelBaseWithHeader', | ||
'js/PanelManager/IActivePanel', | ||
'widgets/TensorPlotter/TensorPlotterWidget', | ||
'./TensorPlotterControl' | ||
], function ( | ||
PanelBaseWithHeader, | ||
IActivePanel, | ||
TensorPlotterWidget, | ||
TensorPlotterControl | ||
) { | ||
'use strict'; | ||
|
||
function TensorPlotterPanel(layoutManager, params) { | ||
var options = {}; | ||
//set properties from options | ||
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'TensorPlotterPanel'; | ||
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true; | ||
|
||
//call parent's constructor | ||
PanelBaseWithHeader.apply(this, [options, layoutManager]); | ||
|
||
this._client = params.client; | ||
this._embedded = params.embedded; | ||
|
||
//initialize UI | ||
this._initialize(); | ||
|
||
this.logger.debug('ctor finished'); | ||
} | ||
|
||
//inherit from PanelBaseWithHeader | ||
_.extend(TensorPlotterPanel.prototype, PanelBaseWithHeader.prototype); | ||
_.extend(TensorPlotterPanel.prototype, IActivePanel.prototype); | ||
|
||
TensorPlotterPanel.prototype._initialize = function () { | ||
var self = this; | ||
|
||
//set Widget title | ||
this.setTitle(''); | ||
|
||
this.widget = new TensorPlotterWidget(this.logger, this.$el); | ||
|
||
this.widget.setTitle = function (title) { | ||
self.setTitle(title); | ||
}; | ||
|
||
this.control = new TensorPlotterControl({ | ||
logger: this.logger, | ||
client: this._client, | ||
embedded: this._embedded, | ||
widget: this.widget | ||
}); | ||
|
||
this.onActivate(); | ||
}; | ||
|
||
/* OVERRIDE FROM WIDGET-WITH-HEADER */ | ||
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */ | ||
TensorPlotterPanel.prototype.onReadOnlyChanged = function (isReadOnly) { | ||
//apply parent's onReadOnlyChanged | ||
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly); | ||
|
||
}; | ||
|
||
TensorPlotterPanel.prototype.onResize = function (width, height) { | ||
this.logger.debug('onResize --> width: ' + width + ', height: ' + height); | ||
this.widget.onWidgetContainerResize(width, height); | ||
}; | ||
|
||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */ | ||
TensorPlotterPanel.prototype.destroy = function () { | ||
this.control.destroy(); | ||
this.widget.destroy(); | ||
|
||
PanelBaseWithHeader.prototype.destroy.call(this); | ||
WebGMEGlobal.KeyboardManager.setListener(undefined); | ||
WebGMEGlobal.Toolbar.refresh(); | ||
}; | ||
|
||
TensorPlotterPanel.prototype.onActivate = function () { | ||
this.widget.onActivate(); | ||
this.control.onActivate(); | ||
WebGMEGlobal.KeyboardManager.setListener(this.widget); | ||
WebGMEGlobal.Toolbar.refresh(); | ||
}; | ||
|
||
TensorPlotterPanel.prototype.onDeactivate = function () { | ||
this.widget.onDeactivate(); | ||
this.control.onDeactivate(); | ||
WebGMEGlobal.KeyboardManager.setListener(undefined); | ||
WebGMEGlobal.Toolbar.refresh(); | ||
}; | ||
|
||
return TensorPlotterPanel; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<h4>Available Artifacts</h4> | ||
<ul class="list-group artifacts"> | ||
<li class="list-group-item">Artifact | ||
<span class="glyphicon glyphicon-remove pull-right" aria-hidden="true"></span> | ||
</li> | ||
</ul> |
137 changes: 137 additions & 0 deletions
137
src/visualizers/widgets/TensorPlotter/ArtifactLoader.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/*globals define, $*/ | ||
define([ | ||
'deepforge/EventEmitter', | ||
'deepforge/storage/index', | ||
'underscore', | ||
'text!./ArtifactLoader.html', | ||
'css!./styles/ArtifactLoader.css', | ||
], function( | ||
EventEmitter, | ||
Storage, | ||
_, | ||
Html, | ||
) { | ||
class ArtifactLoader extends EventEmitter { | ||
constructor(container) { | ||
super(); | ||
this.session = null; | ||
this.$el = container; | ||
this.$el.addClass('artifact-loader'); | ||
this.$el.append($(Html)); | ||
this.$artifacts = this.$el.find('.artifacts'); | ||
this.artifacts = []; | ||
this.render = _.debounce(this.render.bind(this), 250); | ||
} | ||
|
||
register(desc) { | ||
this.artifacts.push(new Artifact(desc)); | ||
this.render(); | ||
} | ||
|
||
unregister(artifactId) { | ||
const index = this.artifacts.findIndex(artifact => artifact.id === artifactId); | ||
if (index > -1) { | ||
this.artifacts.splice(index, 1); | ||
this.render(); | ||
} | ||
} | ||
|
||
async load(artifact) { | ||
const desc = artifact.data; | ||
const dataInfo = JSON.parse(desc.data); | ||
const config = await this.getAuthenticationConfig(dataInfo); | ||
|
||
const pyName = desc.name.replace(/\..*$/, ''); | ||
const loading = this.session.addArtifact(pyName, dataInfo, desc.type, config); | ||
artifact.state = ArtifactState.LOADING; | ||
this.render(); | ||
await loading; | ||
artifact.state = ArtifactState.LOADED; | ||
this.render(); | ||
this.emit('load', desc); | ||
} | ||
|
||
async getAuthenticationConfig (dataInfo) { | ||
const {backend} = dataInfo; | ||
const metadata = Storage.getStorageMetadata(backend); | ||
metadata.configStructure = metadata.configStructure | ||
.filter(option => option.isAuth); | ||
|
||
if (metadata.configStructure.length) { | ||
const configDialog = this.getConfigDialog(); | ||
const title = `Authenticate with ${metadata.name}`; | ||
const iconClass = `glyphicon glyphicon-download-alt`; | ||
const config = await configDialog.show(metadata, {title, iconClass}); | ||
|
||
return config[backend]; | ||
} | ||
} | ||
|
||
render() { | ||
this.$artifacts.empty(); | ||
this.artifacts.forEach(artifact => { | ||
const $element = artifact.element(); | ||
if (artifact.state === ArtifactState.NOT_LOADED) { | ||
$element.on('click', event => { | ||
event.stopPropagation(); | ||
event.preventDefault(); | ||
this.load(artifact); | ||
}); | ||
} | ||
this.$artifacts.append($element); | ||
}); | ||
} | ||
} | ||
|
||
class ArtifactState { | ||
constructor(clazz, text, icon) { | ||
this.class = clazz || ''; | ||
this.text = text || ''; | ||
this.icon = icon || ''; | ||
} | ||
|
||
configure($element) { | ||
if (this.text) { | ||
const $state = $('<span>', {class: 'pull-right artifact-state'}); | ||
$state.text(this.text); | ||
$element.append($state); | ||
} | ||
if (this.class) { | ||
$element.addClass(this.class); | ||
} | ||
if (this.icon) { | ||
const $icon = glyph(this.icon); | ||
$element.append($icon); | ||
} | ||
} | ||
} | ||
|
||
ArtifactState.LOADING = new ArtifactState('list-group-item-warning', 'Loading...'); | ||
ArtifactState.NOT_LOADED = new ArtifactState(null, null, 'upload'); | ||
ArtifactState.LOADED = new ArtifactState('list-group-item-success', 'Available'); | ||
|
||
class Artifact { | ||
constructor(data) { | ||
this.id = data.id; | ||
this.data = data; | ||
this.state = ArtifactState.NOT_LOADED; | ||
} | ||
|
||
element() { | ||
const $element = $('<li>', {class: 'list-group-item'}); | ||
$element.text(this.data.name); | ||
|
||
this.state.configure($element); | ||
|
||
return $element; | ||
} | ||
} | ||
|
||
function glyph(name) { | ||
const $el = $('<span>', {class: `glyphicon glyphicon-${name} pull-right`}); | ||
$el.attr('aria-hidden', true); | ||
return $el; | ||
} | ||
|
||
return ArtifactLoader; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* globals define, $ */ | ||
define([ | ||
'underscore', | ||
'deepforge/EventEmitter', | ||
], function( | ||
_, | ||
EventEmitter, | ||
) { | ||
|
||
class DataEditorBase extends EventEmitter { | ||
constructor(html, dataFields, updateOnChange) { | ||
super(); | ||
this.$el = $(html); | ||
|
||
this.$elements = {}; | ||
dataFields.forEach(name => { | ||
this.$elements[name] = this.$el.find(`#${name}`); | ||
if (updateOnChange) { | ||
this.$elements[name].change(() => this.onUpdate()); | ||
} | ||
}); | ||
} | ||
|
||
set(values) { | ||
Object.entries(this.$elements).map(entry => { | ||
const [name, element] = entry; | ||
if (values.hasOwnProperty(name)) { | ||
element.val(values[name]); | ||
} | ||
}); | ||
} | ||
|
||
data() { | ||
const entries = Object.entries(this.$elements) | ||
.map(entry => { | ||
const [name, element] = entry; | ||
const value = element.val(); | ||
return [name, value]; | ||
}) | ||
.filter(entry => !!entry[1]); | ||
return _.object(entries); | ||
} | ||
|
||
onUpdate() { | ||
const values = this.data(); | ||
this.emit('update', values); | ||
} | ||
} | ||
|
||
return DataEditorBase; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<form> | ||
<div class="form-group"> | ||
<label for="title">Title</label> | ||
<input type="text", class="form-control" id="title"/> | ||
</div> | ||
<div class="form-group"> | ||
<label for="xaxis">X Axis Label</label> | ||
<input type="text", class="form-control" id="xaxis"/> | ||
</div> | ||
<div class="form-group"> | ||
<label for="yaxis">Y Axis Label</label> | ||
<input type="text", class="form-control" id="yaxis"/> | ||
</div> | ||
<h4>Plotted Data</h4> | ||
<ul class="list-group plotted-data"> | ||
</ul> | ||
<button class="btn btn-primary">Add Data</button> | ||
</form> |
Oops, something went wrong.