mesa - Visualisierung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
hcshm
User
Beiträge: 48
Registriert: Dienstag 11. Februar 2020, 08:23

Ich möchte ein mesa-Agentenmodell animiert visualisieren. Das Modell selbst läuft einwandfrei, die Visualisierung indes funktioniert nicht. Kann mir bitte jemand helfen?

Code: Alles auswählen

#!/usr/bin/env python3
"""Agenten suchen in einem Grid nach einem Schatz. Sobald ein Agent den
Schatz gefunden hat, wird er entfernt. Sobald alle Agenten den Schatz
entdeckt haben, stoppt der Durchlauf des Modells"""

import mesa
from mesa.visualization.modules import CanvasGrid
from mesa.visualization.ModularVisualization import ModularServer


class Treasure(mesa.Agent):
    def __init__(self, unique_id, model, name):
        super().__init__(unique_id, model)
        self.name = name


class Actor(mesa.Agent):
    def __init__(self, unique_id, model, name, treasure):
        super().__init__(unique_id, model)
        self.name = name
        self._state = self.move
        self.treasure = treasure

    def move(self):
        if self.pos != self.treasure.pos:
            possible_steps = self.model.grid.get_neighborhood(
                self.pos,
                moore=True,
                include_center=False)
            new_position = self.random.choice(possible_steps)
            print(f"{self.name} position: {self.pos}")
            self.model.grid.move_agent(self, new_position)
        else:
            self.model.schedule.remove(self)
           
    def step(self):
        self._state()


class MyModel(mesa.Model):
    def __init__(self, width, height):
        super().__init__(width, height)
        self.grid = mesa.space.MultiGrid(width, height, True)
        self.schedule = mesa.time.BaseScheduler(self)
        self.agent_population = []
        for name in ["gelb", "blau", "rot", "schwarz"]:
            agent = Actor(self.next_id(), self, name, None)
            self.schedule.add(agent)
            coord = (
                self.random.randrange(self.grid.width),
                self.random.randrange(self.grid.height))
            print(f"Anfangsposition von {agent.name}: {coord}")
            self.grid.place_agent(agent, coord)
            self.agent_population.append(agent)

        for name in ["gold"]:
            treasure = Treasure(self.next_id(), self, name)
            coord = (
                self.random.randrange(self.grid.width),
                self.random.randrange(self.grid.height))
            print(f"Position von {treasure.name}: {coord}")
            self.grid.place_agent(treasure, coord)
            for agent in self.agent_population:
                agent.treasure = treasure

    def step(self):
        if self.schedule.get_agent_count():
            self.schedule.step()
        else:
            self.running = False


def object_portrayal(agent):
    portrayal = {}

    if type(agent) is Actor:
        portrayal["Shape"] = "circle"
        portrayal["Filled"] = "true"
        portrayal["Layer"] = 0
        portrayal["r"] = 0.5

        if agent.name == "gelb":
            portrayal["Color"] = "yellow"
        elif agent.name == "blau":
            portrayal["Color"] = "blue"
        elif agent.name == "rot":
            portrayal["Color"] = "red"
        elif agent.name == "schwarz":
            portrayal["Color"] = "black"

    elif type(agent) is Treasure:
        portrayal["Shape"] = "rect"
        portrayal["Color"] = "orange"
        portrayal["Filled"] = "true"
        portrayal["Layer"] = 0
        portrayal["r"] = 0.8

    return portrayal


def main():
    mymodel = MyModel(5, 5)
    mymodel.run_model()
    for agent in mymodel.agent_population:
        print(f"Endposition von {agent.name}: {agent.pos}")


if __name__ == "__main__":
    grid = CanvasGrid(object_portrayal, 5, 5, 500, 500)
    server = ModularServer(MyModel, [grid], "MyModel", {"width": 5, "height": 5})
    server.portrayal = object_portrayal
    server.launch()

Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@hcshm: Das Rahmenwerk reagiert doof auf Fehler in den Daten, also wenn `object_portrayal()` einen falschen Wert liefert. "rect" hat kein "r" sondern "w" und "h" für die Grösse. Wenn man da "r" liefert, gibt es keine Fehlermeldung, die Darstellung für den Schritt wird einfach nur bis dort hin ausgeführt, weshalb das immer unnvollständig aussieht.

Die zweite ``for``-Schleife in `MyModel.__init__()` macht keinen Sinn. Die geht nur über ein einziges Element und über mehr geht auch gar nicht, weil dann das `treasure`-Attribut der Agenten immer wieder überschrieben wird.

Ich würde den Agenten das auch gar nicht als Attribut mitgeben. Das gehört ja nicht zum Zustand des einzelnen Agenten, sondern der ”Welt”, und auf die haben die Agenten ja bereits Zugriff.

Typprüfungen macht man wenn überhaupt mit `isinstance()` statt mit `type()` und ``is``. Wenn man anhand des Typs ”dispatchen” will, würde ich auch nicht selbst auf Typen testen sondern eher so etwas wie `functools.singledispatch()` verwenden.

Code: Alles auswählen

#!/usr/bin/env python3
"""
Agenten suchen in einem Grid nach einem Schatz. Sobald ein Agent den Schatz
gefunden hat, wird er entfernt. Sobald alle Agenten den Schatz entdeckt haben,
stoppt der Durchlauf des Modells.
"""
from functools import singledispatch

import mesa
from mesa.visualization.ModularVisualization import ModularServer
from mesa.visualization.modules import CanvasGrid

NAME_TO_COLOR = {
    "gelb": "yellow",
    "blau": "blue",
    "rot": "red",
    "schwarz": "black",
}


class Treasure(mesa.Agent):
    def __init__(self, unique_id, model, name):
        super().__init__(unique_id, model)
        self.name = name


class Actor(mesa.Agent):
    def __init__(self, unique_id, model, name):
        super().__init__(unique_id, model)
        self.name = name

    def step(self):
        if self.pos != self.model.treasure.pos:
            possible_steps = self.model.grid.get_neighborhood(
                self.pos, moore=True, include_center=False
            )
            new_position = self.random.choice(possible_steps)
            print(f"{self.name} position: {self.pos}")
            self.model.grid.move_agent(self, new_position)
        else:
            self.model.schedule.remove(self)


class Model(mesa.Model):
    def __init__(self, width, height):
        super().__init__(width, height)
        self.grid = mesa.space.MultiGrid(width, height, True)
        self.schedule = mesa.time.BaseScheduler(self)
        for name in ["gelb", "blau", "rot", "schwarz"]:
            agent = Actor(self.next_id(), self, name)
            self.schedule.add(agent)
            coord = (
                self.random.randrange(self.grid.width),
                self.random.randrange(self.grid.height),
            )
            print(f"Anfangsposition von {agent.name}: {coord}")
            self.grid.place_agent(agent, coord)

        self.treasure = Treasure(self.next_id(), self, "gold")
        coord = (
            self.random.randrange(self.grid.width),
            self.random.randrange(self.grid.height),
        )
        print(f"Position von {self.treasure.name}: {coord}")
        self.grid.place_agent(self.treasure, coord)

    def step(self):
        if self.schedule.get_agent_count():
            self.schedule.step()
        else:
            self.running = False


@singledispatch
def object_portrayal(agent):
    raise ValueError(f"don't know what to do with {agent!r}")


@object_portrayal.register(Actor)
def portray_actor(agent):
    return {
        "Shape": "circle",
        "Color": NAME_TO_COLOR[agent.name],
        "Filled": "true",
        "Layer": 0,
        "r": 0.5,
    }


@object_portrayal.register(Treasure)
def portray_treasure(agent):
    size = 0.8
    return {
        "Shape": "rect",
        "Color": "orange",
        "Filled": "true",
        "Layer": 0,
        "w": size,
        "h": size,
    }


def main():
    grid_size = 5
    server = ModularServer(
        Model,
        [CanvasGrid(object_portrayal, grid_size, grid_size, 500, 500)],
        "Model",
        {"width": grid_size, "height": grid_size},
    )
    server.launch()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
hcshm
User
Beiträge: 48
Registriert: Dienstag 11. Februar 2020, 08:23

Grandios, blackjack! Besonders freue ich mich über den Hinweis auf functools.singledispatch(), um Funktionen je nach Argumenttyp unterschiedlich laufen zu lassen (diese Möglichkeit kannte ich nicht, was bei meinem Kenntnisstand aber auch kein Wunder ist).
Auch Deine weiteren Erläuterungen sind mal wieder enorm wertvoll und lehrreich.
Kurzum: Ich drucke mir Deine Antwort mal wieder aus und hefte sie in meinen goldgeränderten Ordner "blackjack-Lehrstücke". Vielen Dank!!!
Antworten