Skip to content

Instantly share code, notes, and snippets.

@asher-pembroke
Created April 11, 2021 02:01
Show Gist options
  • Select an option

  • Save asher-pembroke/8a6a488ca44a78beecb379b4ed88f1b0 to your computer and use it in GitHub Desktop.

Select an option

Save asher-pembroke/8a6a488ca44a78beecb379b4ed88f1b0 to your computer and use it in GitHub Desktop.
pixel puzzler/conway game of life/plotly dash demo
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import dash_daq as daq
# from plotly.offline import iplot
import dash_extendable_graph as deg
import plotly.graph_objs as go
import numpy as np
N_default = 4
z_default = np.zeros((N_default, N_default))
colorscale= [
[0, 'rgb(250, 250, 250)'], #0
[1., 'rgb(0, 0, 0)'], #1
]
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
theme = {
'dark': False,
'detail': '#007439',
'primary': '#00EA64',
'secondary': '#6E6E6E'
}
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
trace = go.Heatmap(z=z_default, text = [], showscale=False, hoverinfo='text', colorscale=colorscale, xgap=1, ygap=1, zmin=0, zmax=1)
layout = go.Layout({'xaxis': {
# 'range': [0.2, 1],
'showgrid': False, # thin lines in the background
'zeroline': False, # thick line at x=0
'visible': False, # numbers below
'fixedrange' : True,
},
'yaxis': {
# 'range': [0.2, 1],
'showgrid': False, # thin lines in the background
'zeroline': False, # thick line at x=0
'visible': False, # numbers below
'fixedrange' : True,
'scaleanchor' : 'x',
'scaleratio' : 1,
},
# (yaxis=dict(scaleanchor="x", scaleratio=1)
})
fig = go.Figure([trace], layout=layout)
app.layout = html.Div([
html.Div([
html.Div(html.Button('Randomize', id='randomize', n_clicks=0), className='three columns'),
daq.BooleanSwitch(id='edit-play', on=True, className='three columns'),
dcc.Slider(
id='N',
min=1,
max=100,
step=1,
value=4,
className='three columns',
updatemode='drag',
),
html.Div(html.Button('Conway', id='conway', n_clicks=0), className='three columns'),
], className = 'row'),
deg.ExtendableGraph(id='game-board',
# dcc.Graph(id='game-board',
# animate=True,
className='row',
figure=fig,
style={'width': '90vh', 'height': '90vh', 'maxWidth': '650px', 'margin':'0 auto'},
config={'displayModeBar': False}),
html.Div(id='debug-click'),
html.Div(id='debug-fig'),
dcc.Interval(
id='interval_extendablegraph_update',
interval=1000,
n_intervals=0,
max_intervals=-1),
])
@app.callback(
Output('game-board', 'figure'),
Input('game-board', 'clickData'),
Input('N', 'value'),
Input('conway', 'n_clicks'),
Input('randomize', 'n_clicks'),
State('edit-play', 'on'),
State('game-board', 'figure'))
def update_figure(click_data, n, conway_button, randomize_button, edit_mode, game_board):
ctx = dash.callback_context
z = np.array(game_board['data'][0]['z'])
if not ctx.triggered:
button_id = 'No clicks yet'
else:
button_id = ctx.triggered[0]['prop_id'].split('.')[0]
if button_id == 'conway':
game_board['data'][0]['z'] = conway(z)
return game_board
elif button_id == 'randomize':
game_board['data'][0]['z'] = 1*(np.random.random((n,n))>.75)
return game_board
if n != len(z):
if n > len(z):
z = np.pad(z, ((0,n-len(z)),(0,n-len(z))), mode='constant', constant_values=0)
elif n < len(z):
z = z[:n, :n]
game_board['data'][0]['z'] = z
return game_board
if click_data is None:
raise PreventUpdate
else:
click = click_data['points'][0]
j = min(click['x'], n-1)
i = min(click['y'], n-1)
z[i,j] = 1-z[i,j]
if edit_mode:
pass
else:
for row in [i-1, i+1]:
if (row >= 0) & (row < n):
z[row, j] = 1-z[row, j]
for col in [j-1, j+1]:
if (col >= 0) & (col < n):
z[i, col] = 1-z[i, col]
game_board['data'][0]['z'] = z
return game_board
def conway(X):
"""borows heavily from
# http://jakevdp.github.io/blog/2013/08/07/conways-game-of-life/
"""
"""Game of life step using generator expressions"""
nbrs_count = sum(np.roll(np.roll(X, i, 0), j, 1)
for i in (-1, 0, 1) for j in (-1, 0, 1)
if (i != 0 or j != 0))
return 1*((nbrs_count == 3) | (X & (nbrs_count == 2)))
# @app.callback(
# Output('debug-click', 'children'),
# Input('game-board', 'clickData'),)
# def update_debug(click_data):
# return ''
@app.callback(
Output('debug-fig', 'children'),
Input('game-board', 'figure'),)
def update_debug(fig):
z_data = np.array(fig['data'][0]['z'])
if (z_data.max() == 0) | (z_data.min() == 1):
return html.Div('Success!', style=dict(color='green', textAlign='center'))
return html.Div(html.Br())
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment