Visdcc
Dash Core Components for Visualization.
- Installing
- Basic Usage
- Advanced Usage
- Learning more about dash ...
Installing :
pip install visdcc
pip install dash==2.3.0
Basic Usage :
from dash import Dash, html, dcc
from dash.dependencies import Input, Output, State
import visdcc
app = Dash(__name__)
app.layout = html.Div(...)
@app.callback(...)
def myfun(...):
...
return ...
if __name__ == '__main__':
app.run_server()
See detail example code
1. visdcc.Network :
See documents of vis.js : https://visjs.github.io/vis-network/docs/network/
CSS : https://cdnjs.cloudflare.com/ajax/libs/vis/4.20.1/vis.min.css
Plot basic network :
app.layout = html.Div([
visdcc.Network(id = 'net',
options = dict(height= '600px', width= '100%')),
dcc.Input(id = 'label',
placeholder = 'Enter a label ...',
type = 'text',
value = '' ),
html.Br(),html.Br(),
dcc.RadioItems(id = 'color',
options=[{'label': 'Red' , 'value': '#ff0000'},
{'label': 'Green', 'value': '#00ff00'},
{'label': 'Blue' , 'value': '#0000ff'} ],
value='Red' )
])
@app.callback(
Output('net', 'data'),
[Input('label', 'value')])
def myfun(x):
data ={'nodes':[{'id': 1, 'label': x , 'color':'#00ffff'},
{'id': 2, 'label': 'Node 2'},
{'id': 4, 'label': 'Node 4'},
{'id': 5, 'label': 'Node 5'},
{'id': 6, 'label': 'Node 6'} ],
'edges':[{'id':'1-3', 'from': 1, 'to': 3},
{'id':'1-2', 'from': 1, 'to': 2} ]
}
return data
@app.callback(
Output('net', 'options'),
[Input('color', 'value')])
def myfun(x):
return {'nodes':{'color': x}}
Get selected nodes and edges :
app.layout = html.Div([
visdcc.Network(id = 'net',
selection = {'nodes':[], 'edges':[]},
options = dict(height= '600px', width= '100%')),
html.Div(id = 'nodes'),
html.Div(id = 'edges')
])
@app.callback(
Output('nodes', 'children'),
[Input('net', 'selection')])
def myfun(x):
s = 'Selected nodes : '
if len(x['nodes']) > 0 : s += str(x['nodes'][0])
return s
@app.callback(
Output('edges', 'children'),
[Input('net', 'selection')])
def myfun(x):
s = 'Selected edges : '
if len(x['edges']) > 0 : s = [s] + [html.Div(i) for i in x['edges']]
return s
Animate or move the camera :
app.layout = html.Div([
visdcc.Network(id = 'net',
options = dict(height= '600px', width= '100%')),
dcc.Input(id = 'label',
placeholder = 'Enter a scale ...',
type = 'text',
value = '' ),
dcc.Input(id = 'labelx',
placeholder = 'Enter x position ...',
type = 'text',
value = '' ),
dcc.Input(id = 'labely',
placeholder = 'Enter y position ...',
type = 'text',
value = '' ),
dcc.Input(id = 'node',
placeholder = 'Enter node id ...',
type = 'text',
value = '' )
])
@app.callback(
Output('net', 'moveTo'),
[Input('label', 'value'),
Input('labelx', 'value'),
Input('labely', 'value')])
def myfun(z, x, y):
if z == '': z = 1
if x == '': x = 1
if y == '': y = 1
return {'position': {'x': int(x), 'y': int(y)}, 'scale': int(z)}
@app.callback(
Output('net', 'fit'),
[Input('node', 'value')])
def myfun(x):
if x == '': return {'Is_used': False}
else: return {'nodes': [x], 'animation': True}
Animate or move the camera by javascript :
from dash import html, dcc, callback_context as ctx
from dash_extensions.enrich import DashProxy as Dash, MultiplexerTransform, Input, Output, State
from flask import Flask, request, send_file
import visdcc
server = Flask(__name__)
app = Dash(server=server, prevent_initial_callbacks=True, transforms=[MultiplexerTransform()])
app.layout = html.Div([
visdcc.Network(id = 'net',
options = dict(height= '600px', width= '100%')),
dcc.Input(id = 'label',
placeholder = 'Enter a scale ...',
type = 'text',
value = '' ),
dcc.Input(id = 'labelx',
placeholder = 'Enter x position ...',
type = 'text',
value = '' ),
dcc.Input(id = 'labely',
placeholder = 'Enter y position ...',
type = 'text',
value = '' ),
dcc.Input(id = 'node',
placeholder = 'Enter node id ...',
type = 'text',
value = '' )
])
@app.callback(
Output('net', 'run'),
[Input('label', 'value'),
Input('labelx', 'value'),
Input('labely', 'value')])
def myfun(z, x, y):
if z == '': z = '1'
if x == '': x = '1'
if y == '': y = '1'
javascript = "this.net.moveTo({{'position': {{'x': {}, 'y': {}}}, 'scale': {}}})".format(x,y,z)
print(javascript)
return javascript
@app.callback(
Output('net', 'run'),
[Input('node', 'value')])
def myfun(x):
if x == '': return ""
else:
javascript = "this.net.fit({{'nodes':[{}], 'animation': true}})".format(x)
print(javascript)
return javascript
2. visdcc.DataTable :
See documents of antd.js : https://ant.design/components/table/
- Using regular expression to filter the string.
- Using boolean expression like
x > 20 & x < 70
to filter the number.
CSS :
- https://unpkg.com/[email protected]/dist/antd.css
- https://rawgit.com/jimmybow/CSS/master/visdcc/DataTable/Filter.css
Plot basic table and get selected cell :
external_stylesheets = ['https://unpkg.com/[email protected]/dist/antd.css',
'https://rawgit.com/jimmybow/CSS/master/visdcc/DataTable/Filter.css']
Data_Sample = {
'dataSource':[ {'key': 1, 'name': 'Jacky', 'age': 20},
{'key': 2, 'name': 'Mei' , 'age': 18},
{'key': 3, 'name': 'Jay', 'age': 72},
{'key': 4, 'name': 'Sandy' , 'age': 14},
{'key': 5, 'name': 'Jerry', 'age': 56},
{'key': 6, 'name': 'May' , 'age': 22},
{'key': 7, 'name': 'Jimmy', 'age': 34},
{'key': 8, 'name': 'Jeff' , 'age': 28},
{'key': 9, 'name': 'Bob', 'age': 15} ],
'columns':[{'title': 'Names',
'dataIndex': 'name',
'key': 'name',
'Is_sort': True,
'Is_click': True,
'width': 120,
'fixed': True },
{'title': 'Ages',
'dataIndex': 'age',
'key': 'age',
'Is_sort': True,
'Is_click': True } ]
}
app = Dash(__name__, external_stylesheets = external_stylesheets)
app.layout = html.Div([
visdcc.DataTable(id = 'table' ,
box_type = 'radio',
data = Data_Sample,
scroll = {'x':600,'y':400},
pagination = {'pageSize': 5},
style = {'width':'25%'}
),
html.Div(id = 'text1'),
html.Div(id = 'text2'),
html.Div(id = 'text3'),
html.Div(id = 'text4'),
html.Div(id = 'text5')
])
@app.callback(
Output('text1', 'children'),
[Input('table', 'box_selected_keys')])
def myfun(x):
if x == None : return('')
else : return("Selected row key is " + ', '.join([str(i) for i in x]) )
@app.callback(
Output('text2', 'children'),
[Input('table', 'selectedcell')])
def myfun(x):
if x == None : return('')
else : return('Clicked cell is on row : {} col : {}'.format(x['row'], x['col']) )
@app.callback(
Output('text3', 'children'),
[Input('table', 'row_filtered')])
def myfun(x):
if x == None : return('')
else : return("row_filtered are " + str(x) )
@app.callback(
Output('text4', 'children'),
[Input('table', 'col_filtered')])
def myfun(x):
if x == None : return('')
else : return("col_filtered are " + str(x) )
@app.callback(
Output('text5', 'children'),
[Input('table', 'searchText')])
def myfun(x):
if x == None : return('')
else : return("searchText are " + str(x) )
3. visdcc.Run_js :
Run your javascript !
Open url on new window :
app.layout = html.Div([
html.Button('open url', id = 'button'),
visdcc.Run_js(id = 'javascript')
])
@app.callback(
Output('javascript', 'run'),
[Input('button', 'n_clicks')])
def myfun(x):
if x:
return "window.open('https://yahoo.com/')"
return ""
Apply jQuery Datatables :
def generate_html_table_from_df(df, id):
Thead = html.Thead(
[html.Tr([html.Th(col) for col in df.columns])]
)
Tbody = html.Tbody(
[html.Tr(
[html.Td( df.iloc[i, j], id = '{}_{}_{}'.format(id, i, j) ) for j in range(len(df.columns))]
) for i in range(len(df))]
)
return html.Table([Thead, Tbody], id = id, className = "display")
df = pd.DataFrame({'name': ['Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff',
'Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff',
'Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff'],
'age': [18, 71, 14, 56, 22, 28, 15,
18, 71, 14, 56, 22, 28, 15,
18, 71, 14, 56, 22, 28, 15]}, columns = ['name', 'age'])
external_scripts = ['https://code.jquery.com/jquery-3.3.1.min.js',
'https://cdn.datatables.net/v/dt/dt-1.10.18/datatables.min.js']
external_stylesheets = ['https://cdn.datatables.net/v/dt/dt-1.10.18/datatables.min.css']
app = Dash(__name__,
external_scripts = external_scripts,
external_stylesheets = external_stylesheets
)
app.layout = html.Div([
html.Button('apply datatable', id = 'button'),
visdcc.Run_js(id = 'javascript'),
html.Br(),
html.Div(
generate_html_table_from_df(df, id = 'datatable'),
style = {'width': '40%'}
),
html.H1(id = 'output_div')
])
@app.callback(
Output('javascript', 'run'),
[Input('button', 'n_clicks')])
def myfun(x):
if x:
return "$('#datatable').DataTable()"
return ""
@app.callback(
Output('output_div', 'children'),
[Input('datatable_{}_{}'.format(i, j), 'n_clicks') for i in range(len(df)) for j in range(len(df.columns))])
def myfun(*args):
ctx = dash.callback_context
if not ctx.triggered or ctx.triggered[0]['value'] is None: return ""
input_id = ctx.triggered[0]['prop_id'].split('.')[0]
row = input_id.split('_')[1]
col = input_id.split('_')[2]
return "you click on row {} col {}".format(row, col)
Add event and callback :
def generate_html_table_from_df(df, id):
Thead = html.Thead(
[html.Tr([html.Th(col) for col in df.columns])]
)
Tbody = html.Tbody(
[html.Tr(
[html.Td( df.iloc[i, j], id = '{}_{}_{}'.format(id, i, j) ) for j in range(len(df.columns))]
) for i in range(len(df))]
)
return html.Table([Thead, Tbody], id = id, className = "display")
df = pd.DataFrame({'name': ['Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff',
'Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff',
'Jacky', 'Mei', 'Jay', 'Sandy', 'Jerry', 'Jimmy', 'Jeff'],
'age': [18, 71, 14, 56, 22, 28, 15,
18, 71, 14, 56, 22, 28, 15,
18, 71, 14, 56, 22, 28, 15]}, columns = ['name', 'age'])
external_scripts = ['https://code.jquery.com/jquery-3.3.1.min.js',
'https://cdn.datatables.net/v/dt/dt-1.10.18/datatables.min.js']
external_stylesheets = ['https://cdn.datatables.net/v/dt/dt-1.10.18/datatables.min.css']
app = Dash(__name__,
external_scripts = external_scripts,
external_stylesheets = external_stylesheets
)
app.layout = html.Div([
html.Button('Add mousemove event', id = 'button'),
visdcc.Run_js(id = 'javascript', run = "$('#datatable').DataTable()", event = 'null'),
html.Br(),
html.Div(
generate_html_table_from_df(df, id = 'datatable'),
style = {'width': '40%'}
),
html.Div(id = 'output_div')
])
@app.callback(
Output('javascript', 'run'),
[Input('button', 'n_clicks')])
def myfun(x):
if x is None: return ""
return '''
var target = $('#datatable')[0]
target.addEventListener('mousemove', function(evt) {
setProps({
'event': {'x':evt.x, 'y':evt.y }
})
console.log(evt)
})
console.log(this)
'''
@app.callback(
Output('output_div', 'children'),
[Input('javascript', 'event')])
def myfun(x):
return str(x)