Skip to content

Resource

Resource

Bases: BaseModel, ABC

Abstract base class for resources.

Attributes:

Name Type Description
label str | None

Optional human-readable label for this resource class.

description str | None

Optional human-readable description for this resource class.

Source code in src/ocelescope/src/ocelescope/resource/resource.py
class Resource(BaseModel, ABC):
    """Abstract base class for resources.

    Attributes:
        label: Optional human-readable label for this resource class.
        description: Optional human-readable description for this resource class.
    """

    label: ClassVar[str | None] = None
    description: ClassVar[str | None] = None

    @classmethod
    def get_type(cls):
        """Return the simple type name of this resource.

        Returns:
            str: The class name (e.g., ``"PetriNet"``).
        """
        return cls.__name__

    @computed_field
    @property
    def _ocelescope_resource_type(self) -> str:
        return self.get_type()

    def visualize(self) -> Visualization | None:
        """Produce a visualization for this resource.

        Implementations should return a concrete :class:`Visualization`
        or ``None`` if no visualization exists.

        Returns:
            Optional[Visualization]: A visualization object or ``None``.
        """

        return

get_type classmethod

get_type()

Return the simple type name of this resource.

Returns:

Name Type Description
str

The class name (e.g., "PetriNet").

Source code in src/ocelescope/src/ocelescope/resource/resource.py
@classmethod
def get_type(cls):
    """Return the simple type name of this resource.

    Returns:
        str: The class name (e.g., ``"PetriNet"``).
    """
    return cls.__name__

visualize

visualize()

Produce a visualization for this resource.

Implementations should return a concrete :class:Visualization or None if no visualization exists.

Returns:

Type Description
Visualization | None

Optional[Visualization]: A visualization object or None.

Source code in src/ocelescope/src/ocelescope/resource/resource.py
def visualize(self) -> Visualization | None:
    """Produce a visualization for this resource.

    Implementations should return a concrete :class:`Visualization`
    or ``None`` if no visualization exists.

    Returns:
        Optional[Visualization]: A visualization object or ``None``.
    """

    return

PetriNet

Bases: Resource

An object-centric Petri net representation.

Attributes:

Name Type Description
places list[Place]

List of places in the Petri net.

transitions list[Transition]

List of transitions in the Petri net.

arcs list[Arc]

List of arcs connecting places and transitions.

Source code in src/ocelescope/src/ocelescope/resource/default/petri_net.py
class PetriNet(Resource):
    """An object-centric Petri net representation.

    Attributes:
        places: List of places in the Petri net.
        transitions: List of transitions in the Petri net.
        arcs: List of arcs connecting places and transitions.
    """

    label = "Petri Net"
    description = "An object-centric petri net"

    places: list[Place] = []
    transitions: list[Transition] = []
    arcs: list[Arc] = []

    def visualize(self):
        # Use your color generator function
        object_types = list({p.object_type for p in self.places})
        color_map = generate_color_map(object_types)

        # Build nodes
        nodes: list[GraphNode] = []

        for place in self.places:
            nodes.append(
                GraphNode(
                    id=place.id,
                    label=place.object_type if place.place_type else None,
                    shape="circle",
                    color=color_map.get(place.object_type, "#cccccc"),
                    width=30,
                    label_pos="bottom",
                    height=30,
                    annotation=place.annotation.visualize()
                    if place.annotation is not None
                    else None,
                )
            )

        for transition in self.transitions:
            label = transition.label or None
            nodes.append(
                GraphNode(
                    id=transition.id,
                    label=label,
                    width=None if label else 10,
                    height=None if label else 40,
                    shape="rectangle",
                    color="#ffffff" if label else "#000000",
                    border_color="#000000" if label else None,
                    annotation=transition.annotation.visualize()
                    if transition.annotation is not None
                    else None,
                )
            )

        # Build edges
        edges: list[GraphEdge] = []

        for arc in self.arcs:
            object_type = next(
                (p.object_type for p in self.places if p.id in {arc.source, arc.target}),
                "default",
            )
            edges.append(
                GraphEdge(
                    source=arc.source,
                    target=arc.target,
                    end_arrow="triangle",
                    color=color_map.get(object_type, "#cccccc"),
                    annotation=arc.annotation.visualize() if arc.annotation is not None else None,
                )
            )

        return Graph(
            type="graph",
            nodes=nodes,
            edges=edges,
            layout_config=GraphvizLayoutConfig(
                engine="dot",
                graphAttrs={
                    "rankdir": "LR",
                    "ranksep": "0.7",
                    "nodesep": "0.7",
                },
            ),
        )