Skip to content

Commit

Permalink
Move model instantiation to Socket Handler
Browse files Browse the repository at this point in the history
This allows multiple tab to be opened onto the same webserver, with
each tab running their own model.

Fixes projectmesa#856
  • Loading branch information
NeilW committed Jul 4, 2020
1 parent 08513f9 commit 66ae188
Showing 1 changed file with 55 additions and 47 deletions.
102 changes: 55 additions & 47 deletions mesa/visualization/ModularVisualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,21 +179,66 @@ def get(self):


class SocketHandler(tornado.websocket.WebSocketHandler):
""" Handler for websocket. """
"""
Handler for websocket.
Each websocket creates a new instance of the model and renders its
output to the page. This allows you to have multiple tabs open to
the same server, each running its own version of the model.
"""

def open(self):
self.model_kwargs = self.application.model_kwargs.copy()
self.reset_model()
if self.application.verbose:
print("Socket opened!")
print("Model ID:", id(self.model))
self.write_message(
{"type": "model_params", "params": self.application.user_params}
{"type": "model_params", "params": self.user_params}
)

def check_origin(self, origin):
return True

@property
def user_params(self):
result = {}
for param, val in self.model_kwargs.items():
if isinstance(val, UserSettableParameter):
result[param] = val.json

return result

def reset_model(self):
""" Reinstantiate the model object, using the current parameters. """

model_params = {}
for key, val in self.model_kwargs.items():
if isinstance(val, UserSettableParameter):
if (
val.param_type == "static_text"
): # static_text is never used for setting params
continue
model_params[key] = val.value
else:
model_params[key] = val

self.model = self.application.model_cls(**model_params)

def render_model(self):
""" Turn the current state of the model into a dictionary of
visualizations
"""
visualization_state = []
for element in self.application.visualization_elements:
element_state = element.render(self.model)
visualization_state.append(element_state)
return visualization_state

@property
def viz_state_message(self):
return {"type": "viz_state", "data": self.application.render_model()}
return {"type": "viz_state", "data": self.render_model()}

def on_message(self, message):
""" Receiving a message from the websocket, parse, and act accordingly.
Expand All @@ -204,28 +249,28 @@ def on_message(self, message):
msg = tornado.escape.json_decode(message)

if msg["type"] == "get_step":
if not self.application.model.running:
if not self.model.running:
self.write_message({"type": "end"})
else:
self.application.model.step()
self.model.step()
self.write_message(self.viz_state_message)

elif msg["type"] == "reset":
self.application.reset_model()
self.reset_model()
self.write_message(self.viz_state_message)

elif msg["type"] == "submit_params":
param = msg["param"]
value = msg["value"]

# Is the param editable?
if param in self.application.user_params:
if param in self.user_params:
if isinstance(
self.application.model_kwargs[param], UserSettableParameter
self.model_kwargs[param], UserSettableParameter
):
self.application.model_kwargs[param].value = value
self.model_kwargs[param].value = value
else:
self.application.model_kwargs[param] = value
self.model_kwargs[param] = value

else:
if self.application.verbose:
Expand Down Expand Up @@ -299,47 +344,10 @@ def __init__(
self.description = model_cls.__doc__

self.model_kwargs = model_params
self.reset_model()

# Initializing the application itself:
super().__init__(self.handlers, **self.settings)

@property
def user_params(self):
result = {}
for param, val in self.model_kwargs.items():
if isinstance(val, UserSettableParameter):
result[param] = val.json

return result

def reset_model(self):
""" Reinstantiate the model object, using the current parameters. """

model_params = {}
for key, val in self.model_kwargs.items():
if isinstance(val, UserSettableParameter):
if (
val.param_type == "static_text"
): # static_text is never used for setting params
continue
model_params[key] = val.value
else:
model_params[key] = val

self.model = self.model_cls(**model_params)

def render_model(self):
""" Turn the current state of the model into a dictionary of
visualizations
"""
visualization_state = []
for element in self.visualization_elements:
element_state = element.render(self.model)
visualization_state.append(element_state)
return visualization_state

def launch(self, port=None, open_browser=True):
""" Run the app. """
if port is not None:
Expand Down

0 comments on commit 66ae188

Please sign in to comment.