Commit 636ad586 authored by Jim Hoekstra's avatar Jim Hoekstra 👋🏻
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request !21
parents 1336f30f 8015d9b2
......@@ -8,4 +8,4 @@ if os.getenv('MSX_URL_PREFIX', False):
URL_PREFIX = os.environ['MSX_URL_PREFIX']
app = dash.Dash(name=__name__, external_stylesheets=external_stylesheets, url_base_pathname=URL_PREFIX,
suppress_callback_exceptions=True)
suppress_callback_exceptions=True, title='TALK Tool')
body {
background-color: whitesmoke;
}
.header {
height: 7vh;
margin-top: 3vh;
}
.graph {
height: 80vh;
}
.footer {
height: 7vh;
margin-bottom: 3vh;
}
.content {
width: 90%;
margin: auto;
}
......@@ -11,13 +11,33 @@ from dash_app.words import AssociatedWords
word2vec_model = AssociatedWords()
@app.callback(
Output(component_id='msx-graph', component_property='autoRefreshLayout'),
Input(component_id='submit-word-button', component_property='n_clicks'),
Input(component_id='add-word-button', component_property='n_clicks'),
Input(component_id='extend-graph-button', component_property='n_clicks'),
Input(component_id='remove-word-button', component_property='n_clicks'),
State(component_id='msx-graph-div', component_property='children'),
)
def set_auto_refresh_layout(submit_word_button, add_word_button, extend_graph_button, remove_word_button, msx_graph):
callback_context = dash.callback_context
button_id = callback_context.triggered[0]['prop_id'].split('.')[0]
if button_id == 'submit-word-button':
return True
else:
return False
@app.callback(
Output(component_id='msx-graph-div', component_property='children'),
Input(component_id='submit-word-button', component_property='n_clicks'),
State(component_id='base-word-input', component_property='value'),
)
def update_graph_div(submit_word_button):
def update_graph_div(submit_word_button, base_word_input):
graph = Graph()
graph.set_nodes_and_edges({'nodes': [], 'edges': []})
base_word_lower = base_word_input.lower()
graph.add_node(base_word_lower, is_base_node=1)
# graph.set_nodes_and_edges({'nodes': [], 'edges': []})
return graph.get_cytoscape_graph('msx-graph')
......@@ -27,42 +47,57 @@ def update_graph_div(submit_word_button):
State(component_id='base-word-input', component_property='value'),
)
def update_base_word(submit_word_button, base_word_input):
return base_word_input
if base_word_input is not None:
base_word_input_lowercase = base_word_input.lower()
if base_word_input_lowercase != '':
return base_word_input_lowercase
else:
raise PreventUpdate
else:
raise PreventUpdate
@app.callback(
Output(component_id='graph-elements-div', component_property='children'),
Input(component_id='submit-word-button', component_property='n_clicks'),
Input(component_id='base-word-div', component_property='children'),
Input(component_id='add-word-button', component_property='n_clicks'),
Input(component_id='extend-graph-button', component_property='n_clicks'),
Input(component_id='remove-word-button', component_property='n_clicks'),
State(component_id='base-word-input', component_property='value'),
State(component_id='add-word-input', component_property='value'),
State(component_id='graph-elements-div', component_property='children'),
State(component_id='msx-graph-div', component_property='children'),
State(component_id='msx-graph', component_property='selectedNodeData'),
State(component_id='base-word-div', component_property='children'),
prevent_initial_call=True
)
def update_graph_elements(submit_word_button, add_word_button, extend_graph_button, remove_word_button, base_word_input,
add_word_input, nodes_and_edges, selected_nodes, base_word_state):
def update_graph_elements(base_word_state, add_word_button, extend_graph_button, remove_word_button, base_word_input,
add_word_input, nodes_and_edges, msx_graph, selected_nodes):
callback_context = dash.callback_context
button_id = callback_context.triggered[0]['prop_id'].split('.')[0]
graph = Graph()
if button_id == 'submit-word-button':
graph.fill_with_associations(word2vec_model, base_word_input)
new_nodes_and_edges = graph.get_nodes_and_edges()
return json.dumps(new_nodes_and_edges)
if button_id == 'base-word-div':
if base_word_input is not None:
if base_word_input != '':
graph.fill_with_associations(word2vec_model, base_word_input)
new_nodes_and_edges = graph.get_nodes_and_edges()
return json.dumps(new_nodes_and_edges)
else:
raise PreventUpdate
raise PreventUpdate
if button_id == 'add-word-button':
graph.set_nodes_and_edges(json.loads(nodes_and_edges))
if add_word_input is not None and add_word_input != '' and add_word_input not in graph.get_all_words():
graph.add_node(add_word_input)
graph.add_edge(base_word_state, add_word_input)
new_nodes_and_edges = json.dumps(graph.get_nodes_and_edges())
return new_nodes_and_edges
if add_word_input is not None:
add_word_input_lowercase = add_word_input.lower()
if add_word_input_lowercase != '' and add_word_input_lowercase not in graph.get_all_words():
graph.add_node(add_word_input_lowercase)
graph.add_edge(base_word_state, add_word_input_lowercase)
new_nodes_and_edges = json.dumps(graph.get_nodes_and_edges())
return new_nodes_and_edges
else:
raise PreventUpdate
else:
raise PreventUpdate
......@@ -91,25 +126,8 @@ def update_graph_elements(submit_word_button, add_word_button, extend_graph_butt
@app.callback(
Output(component_id='msx-graph', component_property='elements'),
Input(component_id='graph-elements-div', component_property='children'),
prevent_initial_call=True
)
def update_graph(nodes_and_edges):
graph = Graph()
graph.set_nodes_and_edges(json.loads(nodes_and_edges))
return graph.get_elements()
@app.callback(
Output(component_id='msx-graph', component_property='autoRefreshLayout'),
Input(component_id='add-word-button', component_property='n_clicks'),
Input(component_id='extend-graph-button', component_property='n_clicks'),
Input(component_id='remove-word-button', component_property='n_clicks'),
prevent_initial_call=True
)
def set_auto_refresh_layout(add_word_button, extend_graph_button, remove_word_button):
callback_context = dash.callback_context
button_id = callback_context.triggered[0]['prop_id'].split('.')[0]
if button_id == 'add-word-button' or button_id == 'remove-word-button':
return False
if button_id == 'extend-graph-button':
return True
import dash_cytoscape as cyto
import pandas as pd
import numpy as np
from math import factorial
......@@ -8,6 +9,7 @@ class Graph:
def __init__(self):
self.nodes = []
self.edges = []
self.positions = {}
self.COUNT_THRESHOLD = 2
self.MAX_NUM_WORDS = 10
......@@ -22,24 +24,44 @@ class Graph:
self.edges = []
def fill_with_associations(self, word2vec_model, base_word):
associated_words = word2vec_model.get_associated_words(base_word)
base_word_lower = base_word.lower()
associated_words = word2vec_model.get_associated_words(base_word_lower)
self.clear_graph_elements()
self.add_node(base_word, is_base_node=1)
self.add_node(base_word_lower, is_base_node=1)
self.add_nodes(associated_words)
self.add_edges(base_word, associated_words)
self.add_edges(base_word_lower, associated_words)
def add_nodes(self, nodes):
for node in nodes:
self.add_node(node)
def add_node(self, node, is_base_node=0):
node_dict = {'data': {'id': node, 'label': node, 'is_base_node': is_base_node}}
node_dict = {'data': {'id': node, 'label': node, 'is_base_node': is_base_node}, 'position': self.get_node_position(node, is_base_node)}
if is_base_node:
node_dict['selectable'] = False
node_dict['grabbable'] = False
if node_dict not in self.nodes:
self.nodes.append(node_dict)
def get_node_position(self, node_id, is_base_node):
if is_base_node:
return {'x': 0, 'y': 0}
else:
position_id = 0
while str(position_id) in self.positions:
position_id += 1
length = position_id * 4 + 80
angle = ((90.0 - 37.5 * position_id) / 180.0) * np.pi
if angle < -np.pi:
angle += (2 * np.pi)
x = length * np.cos(angle)
y = length * np.sin(angle)
position = {'x': x, 'y': -y}
self.positions[str(position_id)] = node_id
return position
def add_edges(self, source, targets):
for target in targets:
self.add_edge(source, target)
......@@ -56,6 +78,7 @@ class Graph:
if node_idx_to_remove >= 0:
self.nodes.pop(node_idx_to_remove)
self.positions = {position_id: node_id for position_id, node_id in self.positions.items() if node_id != node}
self.remove_edges(node)
def remove_edges(self, node):
......@@ -68,11 +91,12 @@ class Graph:
self.edges.pop(edge_idx_to_remove)
def get_nodes_and_edges(self):
return {'nodes': self.nodes, 'edges': self.edges}
return {'nodes': self.nodes, 'edges': self.edges, 'positions': self.positions}
def set_nodes_and_edges(self, nodes_and_edges):
self.nodes = nodes_and_edges['nodes']
self.edges = nodes_and_edges['edges']
self.positions = nodes_and_edges['positions']
def get_elements(self):
elements = []
......@@ -83,9 +107,9 @@ class Graph:
def get_cytoscape_graph(self, component_id):
elements = self.get_elements()
return cyto.Cytoscape(id=component_id,
autoRefreshLayout=True,
layout={'name': 'cose', 'animate': True},
style={'width': '100%', 'height': '550px'},
autoRefreshLayout=False,
layout={'name': 'preset'},
style={'width': '100%', 'height': '100%'},
elements=elements,
userZoomingEnabled=False,
userPanningEnabled=False,
......
......@@ -13,11 +13,9 @@ external_stylesheets = [
layout = html.Div(children=[
html.Div(className='container', children=[
html.Br(),
html.Br(),
html.Div(className='content', children=[
html.Div(children=[
html.Div(className='row', children=[
html.Div(className='row header', children=[
html.Div(className='col-1', children=[
html.H2(children='Term:'),
]),
......@@ -28,30 +26,27 @@ layout = html.Div(children=[
html.Button(id='submit-word-button', n_clicks_timestamp=0, children='Submit Term', className='btn btn-success btn-lg')]),
])
]),
html.Br(),
html.Div(id='base-word-div',
style={'display': 'none'},
),
html.Div(id='graph-elements-div',
style={'display': 'none'},
),
html.Div(id='msx-graph-div', children=[]),
html.Div(children=[
html.Div(className='row', children=[
html.Div(className='col-3', children=[
dcc.Input(id='add-word-input', value='', type='text', className='form-control form-control-lg'),
]),
html.Div(className='col-2', children=[
html.Button(id='add-word-button', n_clicks_timestamp=0, children='Add Association', className='btn btn-success btn-lg'),
]),
html.Div(className='col-2', children=[
html.Button(id='extend-graph-button', n_clicks_timestamp=0, children='Extend Graph', className='btn btn-success btn-lg'),
]),
html.Div(className='col-2', children=[
]),
html.Div(className='col-3', children=[
html.Button(id='remove-word-button', n_clicks_timestamp=0, children='Remove Selected Association', className='btn btn-danger btn-lg')]),
]),
html.Div(className='graph', id='msx-graph-div', children=[]),
html.Div(className='row footer', children=[
html.Div(className='col-3', children=[
dcc.Input(id='add-word-input', value='', type='text', className='form-control form-control-lg'),
]),
html.Div(className='col-2', children=[
html.Button(id='add-word-button', n_clicks_timestamp=0, children='Add Association', className='btn btn-success btn-lg'),
]),
html.Div(className='col-2', children=[
html.Button(id='extend-graph-button', n_clicks_timestamp=0, children='Extend Graph', className='btn btn-success btn-lg'),
]),
html.Div(className='col-2', children=[
]),
html.Div(className='col-3', children=[
html.Button(id='remove-word-button', n_clicks_timestamp=0, children='Remove Selected Association', className='btn btn-danger btn-lg')]),
]),
]),
])
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment