diff --git a/gis/geo_pathogen/README.md b/gis/geo_pathogen/README.md
new file mode 100644
index 000000000..d7d9d4c9a
--- /dev/null
+++ b/gis/geo_pathogen/README.md
@@ -0,0 +1,74 @@
+# Geographic Disease Spread Model
+
+A fast-spreading pathogen outbreak geo-model with no exposed/latency period.
+The model simulates how quarantine compliance rates at the population level affect outbreak dynamics in a real geo mapped environment,
+analyzing changes in infection, death and immunity rates here the the dots represent not population directly but sets of highly populated areas.
+
+**It showcases:**
+- **Disease spread on a real geographic map**Disease spread using real geographic proximity(not grid cells) and agent movement is bounded within the Eurasian continent.
+- **Two-threshold quarantine system** - quarantine triggers when infected
+ count exceeds an upper threshold and lifts only when it drops below a
+ lower one, preventing quarantine from lifting the moment a single agent
+ recovers
+- **Compliance rate** - a configurable fraction of citizens actually follow
+ quarantine orders, attempting to simulate real-world partial adherence. The rest
+ keep moving freely by not following quarantine instructions.
+- **Geographic flee behavior** — compliant healthy agents moves away from quarantined zones during lockdown.
+- **Infected agents freeze** — simulating a government isolating/quarantining an infected
+ zone. Non-compliant agents ignore this entirely.
+- **Emergence of different outcomes** — combination of different configurations produce dramatically different outbreak curves.
+
+## How It Works
+
+1. **Initialization** — citizens are placed randomly(more or less realistically) on a geographic map using mesa-geo. A configurable number are set initially as infected.
+2. **Disease Spread** — each step, healthy agents check their neighbours within a certain proximity for infected if its within the set infection radius, if there's an infection there is a configurable chance of transmission.
+ No latency period — infection is immediate on contact,chance of getting an infection is 60%.
+3. **Quarantine System** — the model monitors total infected count each step.
+ When it exceeds the upper threshold, quarantine activates. It only lifts
+ when infected drops below the lower threshold.
+4. **Agent Behaviour during Quarantine:**
+ - Compliant agents - flee away from all infected agents.
+ - Non-compliant agents - move randomly, ignoring quarantine
+ - Infected agents - compliant ones, freeze in place, simulating isolation or a lockdowned zone
+5. **Recovery** — after 10 steps of infection, agents recover to full
+ immunity or die with the probability of 10%. Dead agents remain
+ on the grid as red circles(this is an intentional mechanic) as a visual indicator to assess how compliance affects the model.
+
+## Interesting Cases to Observe
+
+| Scenario | Parameters | What to observe |
+|----------|-----------|-----------------|
+| No compliance | `compliance=0.0` | Unconstrained outbreak, maximum spread |
+| Full compliance | `compliance=1.0` | Quarantine collapses the outbreak |
+| Partial compliance | `compliance=0.5` | Realistic middle ground |
+| Late quarantine | `quarantine_threshold_strt=60` | Triggers too late to matter |
+| Dense population | `n=240` | Flee behaviour is constrained by crowding and even quarantine doesn't help |
+| Sparse population| `n=70` | May stop the outbreak almost immediately or sometimes quarantine doesn't trigger this causes slow wide spread infection|
+
+The model proposed here is simple and often can provide some quite unexpected outcomes in certain configurations. It is recommended to play around with the model parameters as outcomes can be dramatic even with small changes.
+
+| Compliance = 0.0 | Compliance = 1.0 |
+|-----------------|-----------------|
+|  |  |
+
+| Dense Population (n=240) | Sparse Population (n=80) |
+|-----------------------------------|-----------------------------------|
+|  |  |
+
+## Usage
+```
+pip install -r requirements.txt
+solara run app.py
+```
+
+## Default Parameters
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `n` | Number of citizens | 100 |
+| `infn` | Initially infected | 5 |
+| `spread_chance` | Transmission probability on contact | 0.6 |
+| `death_chance` | probability of death after infection(only once) | 0.1 |
+| `compliance` | Fraction of citizens who follow quarantine | 0.25 |
+| `quarantine_threshold_strt` | Infected count that triggers quarantine | 25 |
+| `quarantine_threshold_stp` | Infected count that lifts quarantine | 5 |
\ No newline at end of file
diff --git a/gis/geo_pathogen/agents.py b/gis/geo_pathogen/agents.py
new file mode 100644
index 000000000..06b11ee2d
--- /dev/null
+++ b/gis/geo_pathogen/agents.py
@@ -0,0 +1,84 @@
+import random
+
+import mesa_geo as mg
+from shapely.geometry import Point
+
+
+class Citizen(mg.GeoAgent):
+ def __init__(self, model, geometry, crs):
+ super().__init__(model, geometry, crs)
+
+ self.state = "healthy"
+ self.stage = 0
+ self.compliant = random.random() < self.model.compliance_rate
+
+ def step(self):
+ if self.model.quarantine_status and self.compliant:
+ self.quarantine()
+ else:
+ self.move()
+
+ if self.state == "infected":
+ self.stage += 1
+ if self.stage > 9:
+ chance_of_death = random.random()
+
+ if chance_of_death < 0.1:
+ self.state = "dead"
+ # self.remove()
+
+ else:
+ self.state = "immune"
+
+ cell_state = "healthy"
+
+ cell_neigh = self.model.space.get_neighbors_within_distance(
+ self, self.model.exposure
+ )
+
+ for i in cell_neigh:
+ if isinstance(i, Citizen) and i.state == "infected":
+ cell_state = "infected"
+
+ if self.state == "healthy" and cell_state == "infected":
+ chances = random.random()
+ if chances > 0.40:
+ self.state = "infected"
+
+ def quarantine(self):
+ if self.state == "dead" or self.state == "infected":
+ return
+ infected = [
+ a
+ for a in self.model.agents
+ if isinstance(a, Citizen) and a.state == "infected"
+ ]
+ if not infected:
+ self.move()
+ return
+ nearest = min(infected, key=lambda a: self.geometry.distance(a.geometry))
+ dx = self.geometry.x - nearest.geometry.x
+ dy = self.geometry.y - nearest.geometry.y
+ dist = max((dx**2 + dy**2) ** 0.5, 1)
+ scale = self.model.mobility_range / dist
+ np = Point(self.geometry.x + dx * scale, self.geometry.y + dy * scale)
+ if self.model.asia_boundary.contains(np):
+ self.geometry = np
+
+ def move(self):
+ if self.state != "dead":
+ change_x = self.random.randint(
+ -self.model.mobility_range, self.model.mobility_range
+ )
+ change_y = self.random.randint(
+ -self.model.mobility_range, self.model.mobility_range
+ )
+ np = Point(self.geometry.x + change_x, self.geometry.y + change_y)
+ if self.model.asia_boundary.contains(np):
+ self.geometry = np
+
+
+class CountryAgent(mg.GeoAgent):
+ def __init__(self, model, geometry, crs):
+ super().__init__(model, geometry, crs)
+ self.atype = "safe"
diff --git a/gis/geo_pathogen/app.py b/gis/geo_pathogen/app.py
new file mode 100644
index 000000000..7df26eb9c
--- /dev/null
+++ b/gis/geo_pathogen/app.py
@@ -0,0 +1,59 @@
+from agents import Citizen
+from mesa.visualization import SolaraViz, make_plot_component
+from mesa_geo.visualization import make_geospace_component
+from model import GeoModel
+
+
+def citizen_draw(agent):
+ if not isinstance(agent, Citizen):
+ return {"color": "Gray", "fillOpacity": 0.1, "weight": 1}
+
+ if agent.state == "healthy":
+ return {"color": "Green", "radius": 3}
+ elif agent.state == "infected":
+ return {"color": "Red", "radius": 3}
+ elif agent.state == "immune":
+ return {"color": "Blue", "radius": 3}
+ elif agent.state == "dead":
+ return {"color": "Black", "radius": 3}
+
+
+model_params = {
+ "compliance": {
+ "type": "SliderFloat",
+ "value": 0.7,
+ "label": "Quarantine Compliance Rate",
+ "min": 0.0,
+ "max": 1.0,
+ "step": 0.1,
+ },
+ "n": {
+ "type": "SliderInt",
+ "value": 100,
+ "label": "Citizens",
+ "min": 10,
+ "max": 300,
+ "step": 10,
+ },
+ "infn": {
+ "type": "SliderInt",
+ "value": 5,
+ "label": "Infected",
+ "min": 1,
+ "max": 20,
+ "step": 1,
+ },
+}
+
+model = GeoModel(n=100, infn=5)
+
+renderer = make_geospace_component(citizen_draw)
+
+graph_ot = make_plot_component(["healthy", "infected", "immune", "dead", "quarantine"])
+
+page = SolaraViz(
+ model,
+ components=[renderer, graph_ot],
+ model_params=model_params,
+ name="Compliance/Quarantine during Outbreak Model",
+)
diff --git a/gis/geo_pathogen/country_data/ne_110m_admin_0_countries.README.html b/gis/geo_pathogen/country_data/ne_110m_admin_0_countries.README.html
new file mode 100644
index 000000000..d29bbe88c
--- /dev/null
+++ b/gis/geo_pathogen/country_data/ne_110m_admin_0_countries.README.html
@@ -0,0 +1,547 @@
+
+
+
+
There are 258 countries in the world. Greenland as separate from Denmark. Most users will want this file instead of sovereign states, though some users will want map units instead when needing to distinguish overseas regions of France.
+
+
Natural Earth shows de facto boundaries by default according to who controls the territory, versus de jure.
Countries distinguish between metropolitan (homeland) and independent and semi-independent portions of sovereign states. If you want to see the dependent overseas regions broken out (like in ISO codes, see France for example), use map units instead.
+
Each country is coded with a world region that roughly follows the United Nations setup.
+
Includes some thematic data from the United Nations, U.S. Central Intelligence Agency, and elsewhere.
+
Disclaimer
+
Natural Earth Vector draws boundaries of countries according to defacto status. We show who actually controls the situation on the ground. Please feel free to mashup our disputed areas (link) theme to match your particular political outlook.
+
+ This entry was posted
+ on Monday, September 21st, 2009 at 10:21 am and is filed under 110m-cultural-vectors.
+ You can follow any responses to this entry through the RSS 2.0 feed.
+
+ Both comments and pings are currently closed.
+
+
+
+
[…] earlier. It’s the result of a conversion of a polygon shapefile of country boundaries (from Natural Earth, a fantastic, public domain, physical/cultural spatial data source) to a raster data […]
[…] earlier. It’s the result of a conversion of a polygon shapefile of country boundaries (from Natural Earth, a fantastic, public domain, physical/cultural spatial data source) to a raster data […]
+ + +[…] Le mappe sono scaricate da https://www.naturalearthdata.com […]
+ + +[…] Le mappe sono scaricate da https://www.naturalearthdata.com […]
+ + +