Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion hatchet/external/roundtrip/roundtrip/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,8 @@ def pass_to_js(
pass

# Patch: Ensure all ' and " are escaped
data = data.replace('"', '\\"').replace("'", "\\'")
if data is not None:
data = data.replace('"', '\\"').replace("'", "\\'")

conv_spec = None

Expand Down
69 changes: 65 additions & 4 deletions hatchet/vis/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,28 @@ def serialize(obj):
except ValueError:
raise "Input data is not of type graphframe or json serializable."

def _pass_through(json_query):
return json_query

def _query_to_dict(json_query):
import json
return json.loads(json_query)

return json_query
def _to_js(data):
if data is None:
return "{}"
return data.to_json()

return json.loads(json_query)
def _selection_to_js(data):
if data is None:
return "{}"
return data['selection']

def _from_js(data):
import json
import pandas as pd
data = json.loads(data)
return pd.DataFrame(data)


@magics_class
Expand All @@ -53,7 +68,53 @@ def cct(self, line):

RT.load_webpack(path.join(self.vis_dist, "cct_bundle.html"), cache=False)
RT.var_to_js(
args[0], "hatchet_tree_def", watch=False, to_js_converter=_gf_to_json
args[0], "hatchet_tree_def", watch=True, to_js_converter=_gf_to_json
)

if(len(args) > 1):
RT.var_to_js(
args[1], "node_query", watch=True, from_js_converter=_query_to_dict
)

#secret configuration var
RT.var_to_js(
"?vis_state", "visualization_state", watch=True, from_js_converter=_query_to_dict
)

RT.initialize()

@line_magic
def table(self, line):
args = line.split(" ")

RT.load_webpack(path.join(self.vis_dist, "table_bundle.html"), cache=False)

self.shell.user_ns[args[0][1:]].drop_index_levels()
if(len(args) > 1 and self.shell.user_ns[args[1][1:]]):
self.shell.user_ns['df'] = self.shell.user_ns[args[0][1:]].filter(self.shell.user_ns[args[1][1:]]['selection']).dataframe
elif(len(args) == 1):
self.shell.user_ns['df'] = self.shell.user_ns[args[0][1:]].dataframe


RT.var_to_js(
'df',
"table_src",
watch=True,
to_js_converter=_to_js
)

RT.var_to_js(
args[0],
"reload_watcher",
watch=True,
to_js_converter=_gf_to_json
)

RT.var_to_js(
args[1],
"query_watcher",
watch=True,
to_js_converter=_selection_to_js
)

RT.initialize()
Expand All @@ -62,7 +123,7 @@ def cct(self, line):
def cct_fetch_query(self, line):
args = line.split(" ")

RT.fetch_data("jsNodeSelected", args[0], converter=_query_to_dict)
RT.fetch_data("jsNodeSelected", args[0], converter=_pass_through)


def load_ipython_extension(ipython):
Expand Down
5 changes: 5 additions & 0 deletions hatchet/vis/scripts/cct/cct_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ class Controller{
break;
case (globals.signals.COLLAPSESUBTREE):
this.model.handleDoubleClick(evt.node);
this.model.storeSnapshotQuery();
break;
case(globals.signals.COMPOSEINTERNAL):
this.model.handleNodeComposition(evt.node);
this.model.storeSnapshotQuery();
break;
case(globals.signals.DECOMPOSENODE):
// this.model.handleNodeDecomposition(evt.node);
Expand Down Expand Up @@ -54,12 +56,15 @@ class Controller{
break;
case(globals.signals.REQUESTMASSPRUNE):
this.model.pruneTree(evt.threshold);
this.model.storeSnapshotQuery();
break;
case(globals.signals.RESETVIEW):
this.model.resetView();
break;
case(globals.signals.PRUNERANGEUPDATE):
this.model.updatePruneRange(evt.low, evt.high);
this.model.storeSnapshotQuery();

break;
case(globals.signals.SNAPSHOT):
this.model.storeSnapshotQuery();
Expand Down
74 changes: 61 additions & 13 deletions hatchet/vis/scripts/cct/cct_model.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,16 @@ class Model{
};

//setup model
//secret vis state loading >:D


RT['jsNodeSelected'] = 'MATCH (\\"*\\")->(a) WHERE a.\\"name\\" IS NOT NONE';
if('node_query' in RT){
RT['node_query'] = JSON.stringify({'tree_state':'MATCH (\\"*\\")->(a) WHERE a.\\"name\\" IS NOT NONE', 'selection':''});
}
if("json_def" in RT){
let jsonTree = RT["json_def"]
}
let cleanTree = RT["hatchet_tree_def"];
let _forestData = JSON.parse(cleanTree);
this.forest = new Forest(_forestData);
Expand All @@ -53,6 +62,23 @@ class Model{
this.state.prune_range = {"low": Number.MAX_SAFE_INTEGER, "high": Number.MIN_SAFE_INTEGER};
//prunes away non-internal zero nodes
this.forest.initializePrunedTrees(this.state.primaryMetric);

console.log(RT['visualization_state'])
if(RT['visualization_state'] == '{}'){
RT['visualization_state'] = JSON.stringify({"primaryMetric": this.state.primaryMetric, "secondaryMetric": this.state.secondaryMetric});
} else {
let cached_state = JSON.parse(RT['visualization_state']);

console.log(cached_state.primaryMetric, this.forest.metricColumns);
//got to make sure the cached metric is present, otherwise default
if(this.forest.metricColumns.includes(cached_state.primaryMetric)){
this.state.primaryMetric = cached_state.primaryMetric;
}
if( this.forest.metricColumns.includes(cached_state.primaryMetric)){
this.state.secondaryMetric = cached_state.secondaryMetric;
}
}

}

// --------------------------------------------
Expand Down Expand Up @@ -144,8 +170,6 @@ class Model{


// let conditions = ''


// let queryStr = `MATCH (n)
// WHERE ${conditions}`;

Expand Down Expand Up @@ -352,12 +376,7 @@ class Model{
*/
this.state['selectedNodes'] = nodes;
this.updateTooltip(nodes);

// if(nodes.length > 0 && nodes[0]){
// RT['jsNodeSelected'] = JSON.stringify(this._printQuery(nodes));
// } else {
// RT['jsNodeSelected'] = JSON.stringify(["*"]);
// }
this.storeSelectionQuery(nodes);

this._observers.notify();
}
Expand Down Expand Up @@ -557,7 +576,9 @@ class Model{
else if(source.includes("secondary")){
this.state.secondaryMetric = newMetric;
}


RT['visualization_state'] = JSON.stringify({"primaryMetric": this.state.primaryMetric, "secondaryMetric": this.state.secondaryMetric});

if(source.includes("primary")){
if(this.state.pruneEnabled){
this.forest.resetMutable();
Expand All @@ -571,6 +592,8 @@ class Model{

}



this._observers.notify();
}

Expand Down Expand Up @@ -668,8 +691,6 @@ class Model{

norms = norms.concat(aggs);

console.log(norms);

let full_query = '';

//inclusive query
Expand All @@ -690,10 +711,8 @@ class Model{
}
}


full_query=`${path_query}`


if(this.data.removedNodes.length > 0){
//exclusive query
initial_flag = true;
Expand All @@ -712,9 +731,38 @@ class Model{
}

RT['jsNodeSelected'] = full_query;
if('node_query' in RT){
let existing = JSON.parse(RT['node_query']);
RT['node_query'] = JSON.stringify({'tree_state':full_query, 'selection':existing['selection']});
}

}

storeSelectionQuery(selectedNodes){
//query all nodes matching this nid
let path_query = `MATCH (n)`;
let initial_flag = true;
for(const node of selectedNodes){
if(initial_flag){
if(node.data.aggregate){
path_query += `WHERE n.\\"node_id\\" = ${node.data.prototype.data.metrics._hatchet_nid}`;
}
else{
path_query += `WHERE n.\\"node_id\\" = ${node.data.metrics._hatchet_nid}`;
}
initial_flag = false;
}
else{
path_query += ` OR n.\\"node_id\\" = ${node.data.metrics._hatchet_nid}`;
}
}

if('node_query' in RT){
let existing = JSON.parse(RT['node_query']);
RT['node_query'] = JSON.stringify({'tree_state':existing['tree_state'], 'selection':path_query});
}
}

}


Expand Down
15 changes: 10 additions & 5 deletions hatchet/vis/scripts/cct/cct_scented_slider_popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ class ScentedSliderPopup extends View{

this._svg.style('visibility', ()=>{
if(this.model.state.pruneEnabled) return 'visible';
self.options_dropdown.style('visibility', 'hidden');
return 'hidden';
});

Expand Down Expand Up @@ -522,6 +523,10 @@ class ScentedSliderPopup extends View{
*
*/


this.current_selection_text.text(this.model.state.primaryMetric);


this._svg.select('.selection-button')
.select('rect')
.attr('fill', ()=>{
Expand All @@ -531,7 +536,10 @@ class ScentedSliderPopup extends View{
else{
return 'rgba(100,100,200,1)';
}
});
})
.attr('height', ()=>{return this.current_selection_text.node().getBBox().height+4})
.attr('width', ()=>{return this.current_selection_text.node().getBBox().width+10});


this._svg.select('.selection-button')
.select('text')
Expand All @@ -546,10 +554,7 @@ class ScentedSliderPopup extends View{

option_rects
.attr('width', max_option_width + 10);


this.current_selection_text.text(this.model.state.primaryMetric);


this.hist_grp.select('.left-axis')
.transition()
.duration(globals.duration)
Expand Down
58 changes: 58 additions & 0 deletions hatchet/vis/scripts/table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as d3 from 'd3';
import '../styles/table.css';

let json = window.Roundtrip['table_src']
let data = JSON.parse(json)

console.log(data);

var pivot = []
for(let i of Object.keys(data[Object.keys(data)[0]])){
let row = {}
for(let key of Object.keys(data)){
row[key] = data[key][i];
}

pivot.push(row);
}


console.log(pivot);

let table = d3.select(element)
.select('#table-area')
.append('table')
.attr('border', '1');


table.append('tr')
.selectAll('.header')
.data(Object.keys(data))
.enter()
.append('th')
.attr('class', 'header')
.html(d=>d);


let newrows = table.selectAll('.tbrow')
.data(pivot)
.enter()
.append('tr')
.attr('class', (d, i) => {
if(i % 2 == 0){
return 'tbrow';
}
else{
return 'tbrow alt';
}
});

newrows.selectAll('.tbcells')
.data(d=>{return Object.values(d);})
.enter()
.append('td')
.attr('class', 'tbcells')
.html(d=>{return d;});



2 changes: 1 addition & 1 deletion hatchet/vis/static/cct_bundle.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html><head><meta charset="utf-8"><title>Webpack App</title><meta name="viewport" content="width=device-width,initial-scale=1"><script defer="defer" src="/home/cscully-allison/Programming/Projects/hatchet/hatchet/vis/static/cct_bundle.js"></script></head><body></body></html>
<!doctype html><html><head><meta charset="utf-8"><title>Webpack App</title><meta name="viewport" content="width=device-width,initial-scale=1"><script defer="defer" src="/home/cscully-allison/Programming/Projects/hatchet-llnl/hatchet/vis/static/cct_bundle.js"></script></head><body></body></html>
Loading