Repository: projectmesa/mesa
Pull request #1342 (2022-05-25 07:05:07)

feat: Implement StaticText UserParam

codecov[bot]: # [Codecov](https://codecov.io/gh/projectmesa/mesa/pull/1342?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa) Report
> Merging [#1342](https://codecov.io/gh/projectmesa/mesa/pull/1342?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa) (7133bae) into [main](https://codecov.io/gh/projectmesa/mesa/commit/182553490a8967801caff18bd17938d975129c2e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa) (1825534) will **increase** coverage by `0.17%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main    #1342      +/-   ##
==========================================
+ Coverage   90.77%   90.95%   +0.17%     
==========================================
  Files          19       19              
  Lines        1323     1327       +4     
  Branches      255      252       -3     
==========================================
+ Hits         1201     1207       +6     
+ Misses         86       85       -1     
+ Partials       36       35       -1     
```


| [Impacted Files](https://codecov.io/gh/projectmesa/mesa/pull/1342?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa) | Coverage Δ | |
|---|---|---|
| [mesa/visualization/UserParam.py](https://codecov.io/gh/projectmesa/mesa/pull/1342/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa#diff-bWVzYS92aXN1YWxpemF0aW9uL1VzZXJQYXJhbS5weQ==) | `94.61% <100.00%> (+0.26%)` | :arrow_up: |
| [mesa/space.py](https://codecov.io/gh/projectmesa/mesa/pull/1342/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa#diff-bWVzYS9zcGFjZS5weQ==) | `94.41% <0.00%> (-0.04%)` | :arrow_down: |
| [mesa/visualization/ModularVisualization.py](https://codecov.io/gh/projectmesa/mesa/pull/1342/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa#diff-bWVzYS92aXN1YWxpemF0aW9uL01vZHVsYXJWaXN1YWxpemF0aW9uLnB5) | `76.81% <0.00%> (+1.44%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/projectmesa/mesa/pull/1342?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/projectmesa/mesa/pull/1342?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa). Last update [1825534...7133bae](https://codecov.io/gh/projectmesa/mesa/pull/1342?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=projectmesa).


Patch:
diff --git a/examples/bank_reserves/Readme.md b/examples/bank_reserves/Readme.md
index 07210604..27570d20 100644
--- a/examples/bank_reserves/Readme.md
+++ b/examples/bank_reserves/Readme.md
@@ -7,7 +7,7 @@ A highly abstracted, simplified model of an economy, with only one type of agent
 The model demonstrates the following Mesa features:
  - MultiGrid for creating shareable space for agents
  - DataCollector for collecting data on individual model runs
- - UserSettableParameters for adjusting initial model parameters
+ - Slider for adjusting initial model parameters
  - ModularServer for visualization of agent interaction
  - Agent object inheritance
  - Using a BatchRunner to collect data on multiple combinations of model parameters
diff --git a/examples/bank_reserves/bank_reserves/agents.py b/examples/bank_reserves/bank_reserves/agents.py
index b8b22b72..d59390df 100644
--- a/examples/bank_reserves/bank_reserves/agents.py
+++ b/examples/bank_reserves/bank_reserves/agents.py
@@ -20,8 +20,8 @@ class Bank(mesa.Agent):
         super().__init__(unique_id, model)
         # for tracking total value of loans outstanding
         self.bank_loans = 0
-        """percent of deposits the bank must keep in reserves - this is a
-           UserSettableParameter in server.py"""
+        """percent of deposits the bank must keep in reserves - this is set via
+           Slider in server.py"""
         self.reserve_percent = reserve_percent
         # for tracking total value of deposits
         self.deposits = 0
diff --git a/examples/bank_reserves/bank_reserves/model.py b/examples/bank_reserves/bank_reserves/model.py
index 2696f0cd..a27b1bda 100644
--- a/examples/bank_reserves/bank_reserves/model.py
+++ b/examples/bank_reserves/bank_reserves/model.py
@@ -103,7 +103,7 @@ class BankReserves(mesa.Model):
     grid_w = 20
 
     """init parameters "init_people", "rich_threshold", and "reserve_percent"
-       are all UserSettableParameters"""
+       are all set via Slider"""
 
     def __init__(
         self,
diff --git a/examples/bank_reserves/bank_reserves/server.py b/examples/bank_reserves/bank_reserves/server.py
index 927d0808..c66cd920 100644
--- a/examples/bank_reserves/bank_reserves/server.py
+++ b/examples/bank_reserves/bank_reserves/server.py
@@ -50,19 +50,17 @@ def person_portrayal(agent):
 
 # dictionary of user settable parameters - these map to the model __init__ parameters
 model_params = {
-    "init_people": mesa.visualization.UserSettableParameter(
-        "slider", "People", 25, 1, 200, description="Initial Number of People"
+    "init_people": mesa.visualization.Slider(
+        "People", 25, 1, 200, description="Initial Number of People"
     ),
-    "rich_threshold": mesa.visualization.UserSettableParameter(
-        "slider",
+    "rich_threshold": mesa.visualization.Slider(
         "Rich Threshold",
         10,
         1,
         20,
         description="Upper End of Random Initial Wallet Amount",
     ),
-    "reserve_percent": mesa.visualization.UserSettableParameter(
-        "slider",
+    "reserve_percent": mesa.visualization.Slider(
         "Reserves",
         50,
         1,
diff --git a/examples/bank_reserves/batch_run.py b/examples/bank_reserves/batch_run.py
index 9f5de64e..768fe187 100644
--- a/examples/bank_reserves/batch_run.py
+++ b/examples/bank_reserves/batch_run.py
@@ -114,7 +114,7 @@ class BankReservesModel(mesa.Model):
     grid_w = 20
 
     """init parameters "init_people", "rich_threshold", and "reserve_percent"
-       are all UserSettableParameters"""
+       are all set via Slider"""
 
     def __init__(
         self,
diff --git a/examples/boltzmann_wealth_model/boltzmann_wealth_model/server.py b/examples/boltzmann_wealth_model/boltzmann_wealth_model/server.py
index b3a1e22b..a49546ce 100644
--- a/examples/boltzmann_wealth_model/boltzmann_wealth_model/server.py
+++ b/examples/boltzmann_wealth_model/boltzmann_wealth_model/server.py
@@ -22,8 +22,7 @@ chart = mesa.visualization.ChartModule(
 )
 
 model_params = {
-    "N": mesa.visualization.UserSettableParameter(
-        "slider",
+    "N": mesa.visualization.Slider(
         "Number of agents",
         100,
         2,
diff --git a/examples/boltzmann_wealth_model_network/boltzmann_wealth_model_network/server.py b/examples/boltzmann_wealth_model_network/boltzmann_wealth_model_network/server.py
index a8e48cce..abc493a3 100644
--- a/examples/boltzmann_wealth_model_network/boltzmann_wealth_model_network/server.py
+++ b/examples/boltzmann_wealth_model_network/boltzmann_wealth_model_network/server.py
@@ -33,8 +33,7 @@ chart = mesa.visualization.ChartModule(
 )
 
 model_params = {
-    "num_agents": mesa.visualization.UserSettableParameter(
-        "slider",
+    "num_agents": mesa.visualization.Slider(
         "Number of agents",
         7,
         2,
@@ -42,8 +41,7 @@ model_params = {
         1,
         description="Choose how many agents to include in the model",
     ),
-    "num_nodes": mesa.visualization.UserSettableParameter(
-        "slider",
+    "num_nodes": mesa.visualization.Slider(
         "Number of nodes",
         10,
         3,
diff --git a/examples/charts/charts/agents.py b/examples/charts/charts/agents.py
index 67a0956b..0d18c453 100644
--- a/examples/charts/charts/agents.py
+++ b/examples/charts/charts/agents.py
@@ -20,8 +20,8 @@ class Bank(mesa.Agent):
         super().__init__(unique_id, model)
         # for tracking total value of loans outstanding
         self.bank_loans = 0
-        """percent of deposits the bank must keep in reserves - this is a
-           UserSettableParameter in server.py"""
+        """percent of deposits the bank must keep in reserves - this is set via
+           Slider in server.py"""
         self.reserve_percent = reserve_percent
         # for tracking total value of deposits
         self.deposits = 0
diff --git a/examples/charts/charts/model.py b/examples/charts/charts/model.py
index 0f26e9b5..295dfc27 100644
--- a/examples/charts/charts/model.py
+++ b/examples/charts/charts/model.py
@@ -87,7 +87,7 @@ class Charts(mesa.Model):
     grid_w = 20
 
     """init parameters "init_people", "rich_threshold", and "reserve_percent"
-       are all UserSettableParameters"""
+       are all set via Slider"""
 
     def __init__(
         self,
diff --git a/examples/charts/charts/server.py b/examples/charts/charts/server.py
index 195a3b5a..ba7bfbdf 100644
--- a/examples/charts/charts/server.py
+++ b/examples/charts/charts/server.py
@@ -50,19 +50,17 @@ def person_portrayal(agent):
 
 # dictionary of user settable parameters - these map to the model __init__ parameters
 model_params = {
-    "init_people": mesa.visualization.UserSettableParameter(
-        "slider", "People", 25, 1, 200, description="Initial Number of People"
+    "init_people": mesa.visualization.Slider(
+        "People", 25, 1, 200, description="Initial Number of People"
     ),
-    "rich_threshold": mesa.visualization.UserSettableParameter(
-        "slider",
+    "rich_threshold": mesa.visualization.Slider(
         "Rich Threshold",
         10,
         1,
         20,
         description="Upper End of Random Initial Wallet Amount",
     ),
-    "reserve_percent": mesa.visualization.UserSettableParameter(
-        "slider",
+    "reserve_percent": mesa.visualization.Slider(
         "Reserves",
         50,
         1,
diff --git a/examples/forest_fire/forest_fire/server.py b/examples/forest_fire/forest_fire/server.py
index 253aea0a..6d8f9fd3 100644
--- a/examples/forest_fire/forest_fire/server.py
+++ b/examples/forest_fire/forest_fire/server.py
@@ -29,9 +29,7 @@ pie_chart = mesa.visualization.PieChartModule(
 model_params = {
     "height": 100,
     "width": 100,
-    "density": mesa.visualization.UserSettableParameter(
-        "slider", "Tree density", 0.65, 0.01, 1.0, 0.01
-    ),
+    "density": mesa.visualization.Slider("Tree density", 0.65, 0.01, 1.0, 0.01),
 }
 server = mesa.visualization.ModularServer(
     ForestFire, [canvas_element, tree_chart, pie_chart], "Forest Fire", model_params
diff --git a/examples/schelling/server.py b/examples/schelling/server.py
index 3f4d09db..12377491 100644
--- a/examples/schelling/server.py
+++ b/examples/schelling/server.py
@@ -39,15 +39,9 @@ happy_chart = mesa.visualization.ChartModule([{"Label": "happy", "Color": "Black
 model_params = {
     "height": 20,
     "width": 20,
-    "density": mesa.visualization.UserSettableParameter(
-        "slider", "Agent density", 0.8, 0.1, 1.0, 0.1
-    ),
-    "minority_pc": mesa.visualization.UserSettableParameter(
-        "slider", "Fraction minority", 0.2, 0.00, 1.0, 0.05
-    ),
-    "homophily": mesa.visualization.UserSettableParameter(
-        "slider", "Homophily", 3, 0, 8, 1
-    ),
+    "density": mesa.visualization.Slider("Agent density", 0.8, 0.1, 1.0, 0.1),
+    "minority_pc": mesa.visualization.Slider("Fraction minority", 0.2, 0.00, 1.0, 0.05),
+    "homophily": mesa.visualization.Slider("Homophily", 3, 0, 8, 1),
 }
 
 server = mesa.visualization.ModularServer(
diff --git a/examples/virus_on_network/virus_on_network/server.py b/examples/virus_on_network/virus_on_network/server.py
index fe7f6028..3aa6e4f9 100644
--- a/examples/virus_on_network/virus_on_network/server.py
+++ b/examples/virus_on_network/virus_on_network/server.py
@@ -71,8 +71,7 @@ class MyTextElement(mesa.visualization.TextElement):
 
 
 model_params = {
-    "num_nodes": mesa.visualization.UserSettableParameter(
-        "slider",
+    "num_nodes": mesa.visualization.Slider(
         "Number of agents",
         10,
         10,
@@ -80,11 +79,10 @@ model_params = {
         1,
         description="Choose how many agents to include in the model",
     ),
-    "avg_node_degree": mesa.visualization.UserSettableParameter(
-        "slider", "Avg Node Degree", 3, 3, 8, 1, description="Avg Node Degree"
+    "avg_node_degree": mesa.visualization.Slider(
+        "Avg Node Degree", 3, 3, 8, 1, description="Avg Node Degree"
     ),
-    "initial_outbreak_size": mesa.visualization.UserSettableParameter(
-        "slider",
+    "initial_outbreak_size": mesa.visualization.Slider(
         "Initial Outbreak Size",
         1,
         1,
@@ -92,8 +90,7 @@ model_params = {
         1,
         description="Initial Outbreak Size",
     ),
-    "virus_spread_chance": mesa.visualization.UserSettableParameter(
-        "slider",
+    "virus_spread_chance": mesa.visualization.Slider(
         "Virus Spread Chance",
         0.4,
         0.0,
@@ -101,8 +98,7 @@ model_params = {
         0.1,
         description="Probability that susceptible neighbor will be infected",
     ),
-    "virus_check_frequency": mesa.visualization.UserSettableParameter(
-        "slider",
+    "virus_check_frequency": mesa.visualization.Slider(
         "Virus Check Frequency",
         0.4,
         0.0,
@@ -110,8 +106,7 @@ model_params = {
         0.1,
         description="Frequency the nodes check whether they are infected by " "a virus",
     ),
-    "recovery_chance": mesa.visualization.UserSettableParameter(
-        "slider",
+    "recovery_chance": mesa.visualization.Slider(
         "Recovery Chance",
         0.3,
         0.0,
@@ -119,8 +114,7 @@ model_params = {
         0.1,
         description="Probability that the virus will be removed",
     ),
-    "gain_resistance_chance": mesa.visualization.UserSettableParameter(
-        "slider",
+    "gain_resistance_chance": mesa.visualization.Slider(
         "Gain Resistance Chance",
         0.5,
         0.0,
diff --git a/examples/wolf_sheep/wolf_sheep/server.py b/examples/wolf_sheep/wolf_sheep/server.py
index fcdda90a..bccf4ec8 100644
--- a/examples/wolf_sheep/wolf_sheep/server.py
+++ b/examples/wolf_sheep/wolf_sheep/server.py
@@ -48,6 +48,8 @@ chart_element = mesa.visualization.ChartModule(
 )
 
 model_params = {
+    # The following line is an example to showcase StaticText.
+    "title": mesa.visualization.StaticText("Parameters:"),
     "grass": mesa.visualization.Checkbox("Grass Enabled", True),
     "grass_regrowth_time": mesa.visualization.Slider("Grass Regrowth Time", 20, 1, 50),
     "initial_sheep": mesa.visualization.Slider(
diff --git a/mesa/visualization/UserParam.py b/mesa/visualization/UserParam.py
index b7d53e13..62b187e8 100644
--- a/mesa/visualization/UserParam.py
+++ b/mesa/visualization/UserParam.py
@@ -253,3 +253,18 @@ class Choice(UserParam):
                 "Selected choice value not in available choices, selected first choice from 'choices' list"
             )
             self._value = self.choices[0]
+
+
+class StaticText(UserParam):
+    """
+    A non-input textbox for displaying model info.
+
+    Example:
+    static_text = StaticText("This is a descriptive textbox")
+    """
+
+    def __init__(self, value=None):
+        self.param_type = STATIC_TEXT
+        self._value = value
+        valid = isinstance(self.value, str)
+        self.maybe_raise_error(valid)


Test patch:
diff --git a/tests/test_usersettableparam.py b/tests/test_usersettableparam.py
index 50aca435..deb4da42 100644
--- a/tests/test_usersettableparam.py
+++ b/tests/test_usersettableparam.py
@@ -1,5 +1,11 @@
 from unittest import TestCase
-from mesa.visualization.UserParam import UserSettableParameter, Slider, Checkbox, Choice
+from mesa.visualization.UserParam import (
+    UserSettableParameter,
+    Slider,
+    Checkbox,
+    Choice,
+    StaticText,
+)
 
 
 class TestOption(TestCase):
@@ -20,6 +26,7 @@ class TestOption(TestCase):
             "slider", value=123, min_value=100, max_value=200
         )
         self.slider_option_standalone = Slider(value=123, min_value=100, max_value=200)
+        self.static_text_option = StaticText("Hurr, Durr Im'a Sheep")
 
     def test_number(self):
         assert self.number_option.value == 123
@@ -52,3 +59,6 @@ class TestOption(TestCase):
             assert option.json["value"] == 200
         with self.assertRaises(ValueError):
             Slider()
+
+    def test_static_text(self):
+        assert self.static_text_option.value == "Hurr, Durr Im'a Sheep"