Mesa 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Mesa might be problematic. Click here for more details.

Files changed (41) hide show
  1. {Mesa-1.1.0.dist-info → Mesa-1.2.0.dist-info}/LICENSE +1 -1
  2. {Mesa-1.1.0.dist-info → Mesa-1.2.0.dist-info}/METADATA +15 -14
  3. {Mesa-1.1.0.dist-info → Mesa-1.2.0.dist-info}/RECORD +41 -41
  4. {Mesa-1.1.0.dist-info → Mesa-1.2.0.dist-info}/WHEEL +1 -1
  5. mesa/__init__.py +8 -9
  6. mesa/agent.py +2 -3
  7. mesa/batchrunner.py +19 -28
  8. mesa/datacollection.py +15 -28
  9. mesa/main.py +4 -4
  10. mesa/model.py +2 -6
  11. mesa/space.py +379 -286
  12. mesa/time.py +21 -22
  13. mesa/visualization/ModularVisualization.py +11 -9
  14. mesa/visualization/TextVisualization.py +0 -3
  15. mesa/visualization/UserParam.py +8 -11
  16. mesa/visualization/__init__.py +0 -1
  17. mesa/visualization/modules/BarChartVisualization.py +7 -8
  18. mesa/visualization/modules/CanvasGridVisualization.py +1 -3
  19. mesa/visualization/modules/ChartVisualization.py +2 -3
  20. mesa/visualization/modules/HexGridVisualization.py +1 -3
  21. mesa/visualization/modules/NetworkVisualization.py +1 -2
  22. mesa/visualization/modules/PieChartVisualization.py +2 -6
  23. mesa/visualization/templates/js/GridDraw.js +6 -10
  24. mesa/visualization/templates/js/HexDraw.js +5 -9
  25. mesa/visualization/templates/js/InteractionHandler.js +0 -2
  26. tests/test_batchrunner.py +3 -4
  27. tests/test_batchrunnerMP.py +4 -4
  28. tests/test_datacollector.py +2 -2
  29. tests/test_examples.py +8 -5
  30. tests/test_grid.py +104 -37
  31. tests/test_import_namespace.py +0 -1
  32. tests/test_lifespan.py +4 -3
  33. tests/test_main.py +5 -1
  34. tests/test_scaffold.py +2 -1
  35. tests/test_space.py +13 -20
  36. tests/test_time.py +44 -14
  37. tests/test_tornado.py +4 -2
  38. tests/test_usersettableparam.py +4 -3
  39. tests/test_visualization.py +4 -8
  40. {Mesa-1.1.0.dist-info → Mesa-1.2.0.dist-info}/entry_points.txt +0 -0
  41. {Mesa-1.1.0.dist-info → Mesa-1.2.0.dist-info}/top_level.txt +0 -0
mesa/time.py CHANGED
@@ -25,14 +25,14 @@ Key concepts:
25
25
  # Remove this __future__ import once the oldest supported Python is 3.10
26
26
  from __future__ import annotations
27
27
 
28
- from collections import OrderedDict, defaultdict
28
+ from collections import defaultdict
29
29
 
30
30
  # mypy
31
31
  from typing import Iterator, Union
32
+
32
33
  from mesa.agent import Agent
33
34
  from mesa.model import Model
34
35
 
35
-
36
36
  # BaseScheduler has a self.time of int, while
37
37
  # StagedActivation has a self.time of float
38
38
  TimeT = Union[float, int]
@@ -45,7 +45,6 @@ class BaseScheduler:
45
45
  Assumes that each agent added has a *step* method which takes no arguments.
46
46
 
47
47
  (This is explicitly meant to replicate the scheduler in MASON).
48
-
49
48
  """
50
49
 
51
50
  def __init__(self, model: Model) -> None:
@@ -53,7 +52,7 @@ class BaseScheduler:
53
52
  self.model = model
54
53
  self.steps = 0
55
54
  self.time: TimeT = 0
56
- self._agents: dict[int, Agent] = OrderedDict()
55
+ self._agents: dict[int, Agent] = {}
57
56
 
58
57
  def add(self, agent: Agent) -> None:
59
58
  """Add an Agent object to the schedule.
@@ -61,9 +60,7 @@ class BaseScheduler:
61
60
  Args:
62
61
  agent: An Agent to be added to the schedule. NOTE: The agent must
63
62
  have a step() method.
64
-
65
63
  """
66
-
67
64
  if agent.unique_id in self._agents:
68
65
  raise Exception(
69
66
  f"Agent with unique id {repr(agent.unique_id)} already added to scheduler"
@@ -76,7 +73,6 @@ class BaseScheduler:
76
73
 
77
74
  Args:
78
75
  agent: An agent object.
79
-
80
76
  """
81
77
  del self._agents[agent.unique_id]
82
78
 
@@ -89,7 +85,7 @@ class BaseScheduler:
89
85
 
90
86
  def get_agent_count(self) -> int:
91
87
  """Returns the current number of agents in the queue."""
92
- return len(self._agents.keys())
88
+ return len(self._agents)
93
89
 
94
90
  @property
95
91
  def agents(self) -> list[Agent]:
@@ -98,15 +94,16 @@ class BaseScheduler:
98
94
  def agent_buffer(self, shuffled: bool = False) -> Iterator[Agent]:
99
95
  """Simple generator that yields the agents while letting the user
100
96
  remove and/or add agents during stepping.
101
-
102
97
  """
98
+ # To be able to remove and/or add agents during stepping
99
+ # it's necessary to cast the keys view to a list.
103
100
  agent_keys = list(self._agents.keys())
104
101
  if shuffled:
105
102
  self.model.random.shuffle(agent_keys)
106
103
 
107
- for key in agent_keys:
108
- if key in self._agents:
109
- yield self._agents[key]
104
+ for agent_key in agent_keys:
105
+ if agent_key in self._agents:
106
+ yield self._agents[agent_key]
110
107
 
111
108
 
112
109
  class RandomActivation(BaseScheduler):
@@ -117,7 +114,6 @@ class RandomActivation(BaseScheduler):
117
114
  default behavior for an ABM.
118
115
 
119
116
  Assumes that all agents have a step(model) method.
120
-
121
117
  """
122
118
 
123
119
  def step(self) -> None:
@@ -137,11 +133,12 @@ class SimultaneousActivation(BaseScheduler):
137
133
  This scheduler requires that each agent have two methods: step and advance.
138
134
  step() activates the agent and stages any necessary changes, but does not
139
135
  apply them yet. advance() then applies the changes.
140
-
141
136
  """
142
137
 
143
138
  def step(self) -> None:
144
139
  """Step all agents, then advance them."""
140
+ # To be able to remove and/or add agents during stepping
141
+ # it's necessary to cast the keys view to a list.
145
142
  agent_keys = list(self._agents.keys())
146
143
  for agent_key in agent_keys:
147
144
  self._agents[agent_key].step()
@@ -164,7 +161,6 @@ class StagedActivation(BaseScheduler):
164
161
 
165
162
  This schedule tracks steps and time separately. Time advances in fractional
166
163
  increments of 1 / (# of stages), meaning that 1 step = 1 unit of time.
167
-
168
164
  """
169
165
 
170
166
  def __init__(
@@ -184,22 +180,24 @@ class StagedActivation(BaseScheduler):
184
180
  shuffle_between_stages: If True, shuffle the agents after each
185
181
  stage; otherwise, only shuffle at the start
186
182
  of each step.
187
-
188
183
  """
189
184
  super().__init__(model)
190
- self.stage_list = ["step"] if not stage_list else stage_list
185
+ self.stage_list = stage_list if stage_list else ["step"]
191
186
  self.shuffle = shuffle
192
187
  self.shuffle_between_stages = shuffle_between_stages
193
188
  self.stage_time = 1 / len(self.stage_list)
194
189
 
195
190
  def step(self) -> None:
196
191
  """Executes all the stages for all agents."""
192
+ # To be able to remove and/or add agents during stepping
193
+ # it's necessary to cast the keys view to a list.
197
194
  agent_keys = list(self._agents.keys())
198
195
  if self.shuffle:
199
196
  self.model.random.shuffle(agent_keys)
200
197
  for stage in self.stage_list:
201
198
  for agent_key in agent_keys:
202
- getattr(self._agents[agent_key], stage)() # Run stage
199
+ if agent_key in self._agents:
200
+ getattr(self._agents[agent_key], stage)() # Run stage
203
201
  # We recompute the keys because some agents might have been removed
204
202
  # in the previous loop.
205
203
  agent_keys = list(self._agents.keys())
@@ -241,7 +239,6 @@ class RandomActivationByType(BaseScheduler):
241
239
  Args:
242
240
  agent: An Agent to be added to the schedule.
243
241
  """
244
-
245
242
  super().add(agent)
246
243
  agent_class: type[Agent] = type(agent)
247
244
  self.agents_by_type[agent_class][agent.unique_id] = agent
@@ -250,7 +247,6 @@ class RandomActivationByType(BaseScheduler):
250
247
  """
251
248
  Remove all instances of a given agent from the schedule.
252
249
  """
253
-
254
250
  del self._agents[agent.unique_id]
255
251
 
256
252
  agent_class: type[Agent] = type(agent)
@@ -266,6 +262,8 @@ class RandomActivationByType(BaseScheduler):
266
262
  shuffle_agents: If True, the order of execution of each agents in a
267
263
  type group is shuffled.
268
264
  """
265
+ # To be able to remove and/or add agents during stepping
266
+ # it's necessary to cast the keys view to a list.
269
267
  type_keys: list[type[Agent]] = list(self.agents_by_type.keys())
270
268
  if shuffle_types:
271
269
  self.model.random.shuffle(type_keys)
@@ -286,10 +284,11 @@ class RandomActivationByType(BaseScheduler):
286
284
  if shuffle_agents:
287
285
  self.model.random.shuffle(agent_keys)
288
286
  for agent_key in agent_keys:
289
- self.agents_by_type[type_class][agent_key].step()
287
+ if agent_key in self.agents_by_type[type_class]:
288
+ self.agents_by_type[type_class][agent_key].step()
290
289
 
291
290
  def get_type_count(self, type_class: type[Agent]) -> int:
292
291
  """
293
292
  Returns the current number of agents of certain type in the queue.
294
293
  """
295
- return len(self.agents_by_type[type_class].values())
294
+ return len(self.agents_by_type[type_class])
@@ -93,20 +93,20 @@ Client -> Server:
93
93
  {
94
94
  "type": "get_params"
95
95
  }
96
-
97
96
  """
98
97
  import asyncio
99
98
  import os
100
99
  import platform
100
+ import webbrowser
101
+
101
102
  import tornado.autoreload
103
+ import tornado.escape
104
+ import tornado.gen
102
105
  import tornado.ioloop
103
106
  import tornado.web
104
107
  import tornado.websocket
105
- import tornado.escape
106
- import tornado.gen
107
- import webbrowser
108
108
 
109
- from mesa.visualization.UserParam import UserSettableParameter, UserParam
109
+ from mesa.visualization.UserParam import UserParam, UserSettableParameter
110
110
 
111
111
  # Suppress several pylint warnings for this file.
112
112
  # Attributes being defined outside of init is a Tornado feature.
@@ -145,7 +145,6 @@ class VisualizationElement:
145
145
  Methods:
146
146
  render: Takes a model object, and produces JSON data which can be sent
147
147
  to the client.
148
-
149
148
  """
150
149
 
151
150
  package_includes = []
@@ -165,7 +164,6 @@ class VisualizationElement:
165
164
 
166
165
  Returns:
167
166
  A JSON-ready object.
168
-
169
167
  """
170
168
  return "<b>VisualizationElement goes here</b>."
171
169
 
@@ -297,7 +295,12 @@ class ModularServer(tornado.web.Application):
297
295
  tornado.web.StaticFileHandler,
298
296
  {"path": os.path.dirname(__file__) + "/templates"},
299
297
  )
300
- self.handlers = [page_handler, socket_handler, static_handler]
298
+ custom_handler = (
299
+ r"/local/custom/(.*)",
300
+ tornado.web.StaticFileHandler,
301
+ {"path": ""},
302
+ )
303
+ self.handlers = [page_handler, socket_handler, static_handler, custom_handler]
301
304
 
302
305
  self.settings = {
303
306
  "debug": True,
@@ -384,7 +387,6 @@ class ModularServer(tornado.web.Application):
384
387
  def render_model(self):
385
388
  """Turn the current state of the model into a dictionary of
386
389
  visualizations
387
-
388
390
  """
389
391
  visualization_state = []
390
392
  for element in self.visualization_elements:
@@ -24,7 +24,6 @@ one ASCII character via a converter method. This (as opposed to a dictionary)
24
24
  is used so as to allow the method to access Agent internals, as well as to
25
25
  potentially render a cell based on several values (e.g. an Agent grid and a
26
26
  Patch value grid).
27
-
28
27
  """
29
28
  # Pylint instructions: allow single-character variable names.
30
29
  # pylint: disable=invalid-name
@@ -38,7 +37,6 @@ class TextVisualization:
38
37
  model: The underlying model object to be visualized.
39
38
  elements: List of visualization elements, which will be rendered
40
39
  in the order they are added.
41
-
42
40
  """
43
41
 
44
42
  def __init__(self, model):
@@ -97,7 +95,6 @@ class TextGrid(ASCIIElement):
97
95
 
98
96
  Properties:
99
97
  grid: The underlying grid object.
100
-
101
98
  """
102
99
 
103
100
  grid = None
@@ -1,6 +1,5 @@
1
- from warnings import warn
2
1
  import numbers
3
-
2
+ from warnings import warn
4
3
 
5
4
  NUMBER = "number"
6
5
  CHECKBOX = "checkbox"
@@ -67,7 +66,6 @@ class UserSettableParameter:
67
66
  choices=None,
68
67
  description=None,
69
68
  ):
70
-
71
69
  warn(
72
70
  "UserSettableParameter is deprecated in favor of UserParam objects "
73
71
  "such as Slider, Checkbox, Choice, StaticText, NumberInput. "
@@ -75,7 +73,7 @@ class UserSettableParameter:
75
73
  "UserSettableParameter will be removed in the next major release."
76
74
  )
77
75
  if choices is None:
78
- choices = list()
76
+ choices = []
79
77
  if param_type not in self.TYPES:
80
78
  raise ValueError(f"{param_type} is not a valid Option type")
81
79
  self.param_type = param_type
@@ -92,7 +90,7 @@ class UserSettableParameter:
92
90
  valid = True
93
91
 
94
92
  if self.param_type == self.NUMBER:
95
- valid = not (self.value is None)
93
+ valid = self.value is not None
96
94
 
97
95
  elif self.param_type == self.SLIDER:
98
96
  valid = not (
@@ -123,12 +121,11 @@ class UserSettableParameter:
123
121
  self._value = self.min_value
124
122
  elif self._value > self.max_value:
125
123
  self._value = self.max_value
126
- elif self.param_type == self.CHOICE:
127
- if self._value not in self.choices:
128
- print(
129
- "Selected choice value not in available choices, selected first choice from 'choices' list"
130
- )
131
- self._value = self.choices[0]
124
+ elif (self.param_type == self.CHOICE) and self._value not in self.choices:
125
+ print(
126
+ "Selected choice value not in available choices, selected first choice from 'choices' list"
127
+ )
128
+ self._value = self.choices[0]
132
129
 
133
130
  @property
134
131
  def json(self):
@@ -6,5 +6,4 @@ TextVisualization: Base class for writing ASCII visualizations of model state.
6
6
 
7
7
  TextServer: Class which takes a TextVisualization child class as an input, and
8
8
  renders it in-browser, along with an interface.
9
-
10
9
  """
@@ -3,10 +3,10 @@ Pie Chart Module
3
3
  ============
4
4
 
5
5
  Module for drawing live-updating bar charts using d3.js
6
-
7
6
  """
8
7
  import json
9
- from mesa.visualization.ModularVisualization import VisualizationElement, D3_JS_FILE
8
+
9
+ from mesa.visualization.ModularVisualization import D3_JS_FILE, VisualizationElement
10
10
 
11
11
 
12
12
  class BarChartModule(VisualizationElement):
@@ -24,7 +24,6 @@ class BarChartModule(VisualizationElement):
24
24
  canvas_height, canvas_width: The width and height to draw the chart on the page, in pixels.
25
25
  Default to 800 x 400
26
26
  data_collector_name: Name of the DataCollector object in the model to retrieve data from.
27
-
28
27
  """
29
28
 
30
29
  package_includes = [D3_JS_FILE, "BarChartModule.js"]
@@ -76,20 +75,20 @@ class BarChartModule(VisualizationElement):
76
75
  if self.scope == "agent":
77
76
  df = data_collector.get_agent_vars_dataframe().astype("float")
78
77
  latest_step = df.index.levels[0][-1]
79
- labelStrings = [f["Label"] for f in self.fields]
80
- dict = df.loc[latest_step].T.loc[labelStrings].to_dict()
78
+ label_strings = [f["Label"] for f in self.fields]
79
+ dict = df.loc[latest_step].T.loc[label_strings].to_dict()
81
80
  current_values = list(dict.values())
82
81
 
83
82
  elif self.scope == "model":
84
- outDict = {}
83
+ out_dict = {}
85
84
  for s in self.fields:
86
85
  name = s["Label"]
87
86
  try:
88
87
  val = data_collector.model_vars[name][-1]
89
88
  except (IndexError, KeyError):
90
89
  val = 0
91
- outDict[name] = val
92
- current_values.append(outDict)
90
+ out_dict[name] = val
91
+ current_values.append(out_dict)
93
92
  else:
94
93
  raise ValueError("scope must be 'agent' or 'model'")
95
94
  return current_values
@@ -3,9 +3,9 @@ Modular Canvas Rendering
3
3
  ========================
4
4
 
5
5
  Module for visualizing model objects in grid cells.
6
-
7
6
  """
8
7
  from collections import defaultdict
8
+
9
9
  from mesa.visualization.ModularVisualization import VisualizationElement
10
10
 
11
11
 
@@ -59,7 +59,6 @@ class CanvasGrid(VisualizationElement):
59
59
  canvas_height, canvas_width: Size, in pixels, of the grid visualization
60
60
  to draw on the client.
61
61
  template: "canvas_module.html" stores the module's HTML template.
62
-
63
62
  """
64
63
 
65
64
  package_includes = ["GridDraw.js", "CanvasModule.js", "InteractionHandler.js"]
@@ -80,7 +79,6 @@ class CanvasGrid(VisualizationElement):
80
79
  grid_width, grid_height: Size of the grid, in cells.
81
80
  canvas_height, canvas_width: Size of the canvas to draw in the
82
81
  client, in pixels. (default: 500x500)
83
-
84
82
  """
85
83
  self.portrayal_method = portrayal_method
86
84
  self.grid_width = grid_width
@@ -3,10 +3,10 @@ Chart Module
3
3
  ============
4
4
 
5
5
  Module for drawing live-updating line charts using Charts.js
6
-
7
6
  """
8
7
  import json
9
- from mesa.visualization.ModularVisualization import VisualizationElement, CHART_JS_FILE
8
+
9
+ from mesa.visualization.ModularVisualization import CHART_JS_FILE, VisualizationElement
10
10
 
11
11
 
12
12
  class ChartModule(VisualizationElement):
@@ -39,7 +39,6 @@ class ChartModule(VisualizationElement):
39
39
  More Pythonic customization; in particular, have both series-level and
40
40
  chart-level options settable in Python, and passed to the front-end
41
41
  the same way that "Color" is currently.
42
-
43
42
  """
44
43
 
45
44
  package_includes = [CHART_JS_FILE, "ChartModule.js"]
@@ -3,9 +3,9 @@ Modular Canvas Rendering
3
3
  ========================
4
4
 
5
5
  Module for visualizing model objects in hexagonal grid cells.
6
-
7
6
  """
8
7
  from collections import defaultdict
8
+
9
9
  from mesa.visualization.ModularVisualization import VisualizationElement
10
10
 
11
11
 
@@ -36,7 +36,6 @@ class CanvasHexGrid(VisualizationElement):
36
36
  canvas_height, canvas_width: Size, in pixels, of the grid visualization
37
37
  to draw on the client.
38
38
  template: "canvas_module.html" stores the module's HTML template.
39
-
40
39
  """
41
40
 
42
41
  package_includes = ["HexDraw.js", "CanvasHexModule.js", "InteractionHandler.js"]
@@ -60,7 +59,6 @@ class CanvasHexGrid(VisualizationElement):
60
59
  grid_width, grid_height: Size of the grid, in cells.
61
60
  canvas_height, canvas_width: Size of the canvas to draw in the
62
61
  client, in pixels. (default: 500x500)
63
-
64
62
  """
65
63
  self.portrayal_method = portrayal_method
66
64
  self.grid_width = grid_width
@@ -3,9 +3,8 @@ Network Visualization Module
3
3
  ============
4
4
 
5
5
  Module for rendering the network, using [d3.js](https://d3js.org/) framework.
6
-
7
6
  """
8
- from mesa.visualization.ModularVisualization import VisualizationElement, D3_JS_FILE
7
+ from mesa.visualization.ModularVisualization import D3_JS_FILE, VisualizationElement
9
8
 
10
9
 
11
10
  class NetworkModule(VisualizationElement):
@@ -3,17 +3,16 @@ Pie Chart Module
3
3
  ============
4
4
 
5
5
  Module for drawing live-updating pie charts using d3.js
6
-
7
6
  """
8
7
  import json
9
- from mesa.visualization.ModularVisualization import VisualizationElement, D3_JS_FILE
8
+
9
+ from mesa.visualization.ModularVisualization import D3_JS_FILE, VisualizationElement
10
10
 
11
11
 
12
12
  class PieChartModule(VisualizationElement):
13
13
  """Each chart can visualize one set of fields from a datacollector as a
14
14
  pie chart.
15
15
 
16
-
17
16
  Attributes:
18
17
  fields: A list of dictionaries containing information on fields to
19
18
  plot. Each dictionary must contain (at least) the "Label" and
@@ -24,9 +23,6 @@ class PieChartModule(VisualizationElement):
24
23
  the page, in pixels. Default to 500 x 500
25
24
  data_collector_name: Name of the DataCollector object in the model to
26
25
  retrieve data from.
27
-
28
-
29
-
30
26
  """
31
27
 
32
28
  package_includes = [D3_JS_FILE, "PieChartModule.js"]
@@ -57,7 +57,7 @@ const GridVisualization = function (
57
57
  // Calls the appropriate shape(agent)
58
58
  this.drawLayer = function (portrayalLayer) {
59
59
  // Re-initialize the lookup table
60
- interactionHandler ? interactionHandler.mouseoverLookupTable.init() : null;
60
+ if (interactionHandler) interactionHandler.mouseoverLookupTable.init();
61
61
 
62
62
  for (const i in portrayalLayer) {
63
63
  const p = portrayalLayer[i];
@@ -72,9 +72,7 @@ const GridVisualization = function (
72
72
  p.y = gridHeight - p.y - 1;
73
73
 
74
74
  // if a handler exists, add coordinates for the portrayalLayer index
75
- interactionHandler
76
- ? interactionHandler.mouseoverLookupTable.set(p.x, p.y, i)
77
- : null;
75
+ if (interactionHandler) interactionHandler.mouseoverLookupTable.set(p.x, p.y, i);
78
76
 
79
77
  // If the stroke color is not defined, then the first color in the colors array is the stroke color.
80
78
  if (!p.stroke_color) p.stroke_color = p.Color[0];
@@ -127,9 +125,7 @@ const GridVisualization = function (
127
125
  this.drawCustomImage(p.Shape, p.x, p.y, p.scale, p.text, p.text_color);
128
126
  }
129
127
  // if a handler exists, update its mouse listeners with the new data
130
- interactionHandler
131
- ? interactionHandler.updateMouseListeners(portrayalLayer)
132
- : null;
128
+ if (interactionHandler) interactionHandler.updateMouseListeners(portrayalLayer);
133
129
  };
134
130
 
135
131
  // DRAWING METHODS
@@ -359,7 +355,7 @@ const GridVisualization = function (
359
355
 
360
356
  this.drawCustomImage = function (shape, x, y, scale, text, text_color_) {
361
357
  const img = new Image();
362
- img.src = "local/".concat(shape);
358
+ img.src = "local/custom/".concat(shape);
363
359
  if (scale === undefined) {
364
360
  scale = 1;
365
361
  }
@@ -393,8 +389,8 @@ const GridVisualization = function (
393
389
  this.drawGridLines = function () {
394
390
  context.beginPath();
395
391
  context.strokeStyle = "#eee";
396
- maxX = cellWidth * gridWidth;
397
- maxY = cellHeight * gridHeight;
392
+ const maxX = cellWidth * gridWidth;
393
+ const maxY = cellHeight * gridHeight;
398
394
 
399
395
  // Draw horizontal grid lines:
400
396
  for (let y = 0; y <= maxY; y += cellHeight) {
@@ -55,12 +55,12 @@ const HexVisualization = function (
55
55
  const maxR = Math.min(cellHeight, cellWidth) / 2 - 1;
56
56
 
57
57
  // Configure the interaction handler to use a hex coordinate mapper
58
- interactionHandler ? interactionHandler.setCoordinateMapper("hex") : null;
58
+ if (interactionHandler) interactionHandler.setCoordinateMapper("hex");
59
59
 
60
60
  // Calls the appropriate shape(agent)
61
61
  this.drawLayer = function (portrayalLayer) {
62
62
  // Re-initialize the lookup table
63
- interactionHandler ? interactionHandler.mouseoverLookupTable.init() : null;
63
+ if (interactionHandler) interactionHandler.mouseoverLookupTable.init();
64
64
  for (const i in portrayalLayer) {
65
65
  const p = portrayalLayer[i];
66
66
  // Does the inversion of y positioning because of html5
@@ -69,9 +69,7 @@ const HexVisualization = function (
69
69
  p.y = gridHeight - p.y - 1;
70
70
 
71
71
  // if a handler exists, add coordinates for the portrayalLayer index
72
- interactionHandler
73
- ? interactionHandler.mouseoverLookupTable.set(p.x, p.y, i)
74
- : null;
72
+ if (interactionHandler) interactionHandler.mouseoverLookupTable.set(p.x, p.y, i);
75
73
 
76
74
  if (p.Shape == "hex")
77
75
  this.drawHex(p.x, p.y, p.r, p.Color, p.Filled, p.text, p.text_color);
@@ -93,9 +91,7 @@ const HexVisualization = function (
93
91
  this.drawCustomImage(p.Shape, p.x, p.y, p.scale, p.text, p.text_color);
94
92
  }
95
93
  // if a handler exists, update its mouse listeners with the new data
96
- interactionHandler
97
- ? interactionHandler.updateMouseListeners(portrayalLayer)
98
- : null;
94
+ if (interactionHandler) interactionHandler.updateMouseListeners(portrayalLayer);
99
95
  };
100
96
 
101
97
  // DRAWING METHODS
@@ -158,7 +154,7 @@ const HexVisualization = function (
158
154
  } else {
159
155
  cy = (y + 0.5) * cellHeight + cellHeight / 2;
160
156
  }
161
- maxHexRadius = cellHeight / Math.sqrt(3);
157
+ const maxHexRadius = cellHeight / Math.sqrt(3);
162
158
  const r = radius * maxHexRadius;
163
159
 
164
160
  function hex_corner(x, y, size, i) {
@@ -125,8 +125,6 @@ const InteractionHandler = function (width, height, gridWidth, gridHeight, ctx)
125
125
 
126
126
  // map the event to x,y coordinates
127
127
  const position = coordinateMapper(event);
128
- const yPosition = Math.floor(event.offsetY / cellHeight);
129
- const xPosition = Math.floor(event.offsetX / cellWidth);
130
128
 
131
129
  // look up the portrayal items the coordinates refer to and draw a tooltip
132
130
  mouseoverLookupTable
tests/test_batchrunner.py CHANGED
@@ -1,20 +1,19 @@
1
1
  """
2
2
  Test the BatchRunner
3
3
  """
4
+ import unittest
4
5
  from functools import reduce
5
6
  from operator import mul
6
- import unittest
7
7
 
8
8
  from mesa import Agent, Model
9
- from mesa.time import BaseScheduler
10
- from mesa.datacollection import DataCollector
11
9
  from mesa.batchrunner import (
12
10
  BatchRunner,
13
11
  FixedBatchRunner,
14
12
  ParameterProduct,
15
13
  ParameterSampler,
16
14
  )
17
-
15
+ from mesa.datacollection import DataCollector
16
+ from mesa.time import BaseScheduler
18
17
 
19
18
  NUM_AGENTS = 7
20
19
 
@@ -1,15 +1,15 @@
1
1
  """
2
2
  Test the BatchRunner
3
3
  """
4
+ import unittest
4
5
  from functools import reduce
6
+ from multiprocessing import cpu_count, freeze_support
5
7
  from operator import mul
6
- import unittest
7
8
 
8
9
  from mesa import Agent, Model
9
- from mesa.time import BaseScheduler
10
- from mesa.datacollection import DataCollector
11
10
  from mesa.batchrunner import BatchRunnerMP, ParameterProduct, ParameterSampler
12
- from multiprocessing import freeze_support, cpu_count
11
+ from mesa.datacollection import DataCollector
12
+ from mesa.time import BaseScheduler
13
13
 
14
14
  NUM_AGENTS = 7
15
15
 
@@ -3,7 +3,7 @@ Test the DataCollector
3
3
  """
4
4
  import unittest
5
5
 
6
- from mesa import Model, Agent
6
+ from mesa import Agent, Model
7
7
  from mesa.time import BaseScheduler
8
8
 
9
9
 
@@ -148,7 +148,7 @@ class TestDataCollector(unittest.TestCase):
148
148
  assert len(data_collector.tables["Final_Values"]) == 2
149
149
  assert "agent_id" in data_collector.tables["Final_Values"]
150
150
  assert "final_value" in data_collector.tables["Final_Values"]
151
- for key, data in data_collector.tables["Final_Values"].items():
151
+ for _key, data in data_collector.tables["Final_Values"].items():
152
152
  assert len(data) == 9
153
153
 
154
154
  with self.assertRaises(Exception):