Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/hotfixes' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
fit-alessandro-berti committed Mar 1, 2024
2 parents 8cf6b17 + bc50822 commit 0d00635
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 28 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
### Added

### Changed
* 56799b618ad1ab727705e24f40aa13a793552326
* refactoring BPMN-GraphViz visualization method
* c56bd55b83133d231f37ac8c89190efb440bb826
* moving hierarchical models indentation to separate class

### Deprecated

Expand All @@ -17,6 +21,14 @@
* fixed typing of get_variants method
* ffd0761e8f5490382b33de4fa8187f1ed80ce802
* fixed stochastic Petri net PNML importing
* c9654d8089c5aa0e930ee932b222cc09be25d8a5
* fixed typing of pm4py.filter-variants
* 8475c194929f74bf4e402b24c637299d8c28042a
* fixed export of multi-swimlanes BPMNs
* d32e236cc99ec1b5de198466fe0966752adeb805
* fixed incongruency in BPMN visualizer
* b40821da2612ae1921aec30da2333dc4e1151f1a
* fixed exception handling in OpenAI requests

### Removed

Expand Down
2 changes: 1 addition & 1 deletion pm4py/filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def filter_trace_attribute_values(log: Union[EventLog, pd.DataFrame], attribute_
return attributes_filter.apply_trace_attribute(log, values, parameters=parameters)


def filter_variants(log: Union[EventLog, pd.DataFrame], variants: Union[Set[str], List[str]], retain: bool = True, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name") -> Union[
def filter_variants(log: Union[EventLog, pd.DataFrame], variants: Union[Set[str], List[str], List[Tuple[str]]], retain: bool = True, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name") -> Union[
EventLog, pd.DataFrame]:
"""
Filter a log on a specified set of variants
Expand Down
19 changes: 17 additions & 2 deletions pm4py/objects/bpmn/exporter/variants/etree.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,23 @@ def get_xml_string(bpmn_graph, parameters=None):
all_processes = set()
process_planes = {}
process_process = {}
process_participants = {}
for node in bpmn_graph.get_nodes():
all_processes.add(node.get_process())
for flow in bpmn_graph.get_flows():
all_processes.add(flow.get_process())

if len(all_processes) > 1:
# when several swimlanes exist, their elements should be annexed to the same BPMN plane
bpmn_plane_id = "id" + str(uuid.uuid4())
process_collaboration = ET.SubElement(definitions, "bpmn:collaboration", {"id": bpmn_plane_id})

for process in all_processes:
part_id = "id" + str(uuid.uuid4())
ET.SubElement(process_collaboration, "bpmn:participant", {"id": part_id, "name": process, "processRef": "id" + process })
process_participants[process] = part_id
else:
bpmn_plane_id = "id" + list(all_processes)[0]

for process in all_processes:
p = ET.SubElement(definitions, "bpmn:process",
Expand All @@ -80,9 +95,9 @@ def get_xml_string(bpmn_graph, parameters=None):

diagram = ET.SubElement(definitions, "bpmndi:BPMNDiagram", {"id": "id" + str(uuid.uuid4()), "name": "diagram"})

plane = ET.SubElement(diagram, "bpmndi:BPMNPlane",
{"bpmnElement": bpmn_plane_id, "id": "id" + str(uuid.uuid4())})
for process in all_processes:
plane = ET.SubElement(diagram, "bpmndi:BPMNPlane",
{"bpmnElement": "id" + process, "id": "id" + str(uuid.uuid4())})
process_planes[process] = plane

for node in bpmn_graph.get_nodes():
Expand Down
96 changes: 81 additions & 15 deletions pm4py/visualization/bpmn/variants/classic.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from graphviz import Digraph
from typing import Optional, Dict, Any
from pm4py.objects.bpmn.obj import BPMN
from pm4py.visualization.common import gview
from pm4py.visualization.common import save as gsave
from pm4py.util import constants
import graphviz

Expand All @@ -31,6 +33,25 @@ class Parameters(Enum):
BGCOLOR = "bgcolor"


def add_bpmn_node(graph, n, font_size):
n_id = str(id(n))

if isinstance(n, BPMN.Task):
graph.node(n_id, shape="box", label=n.get_name(), fontsize=font_size)
elif isinstance(n, BPMN.StartEvent):
graph.node(n_id, label="", shape="circle", style="filled", fillcolor="green", fontsize=font_size)
elif isinstance(n, BPMN.EndEvent):
graph.node(n_id, label="", shape="circle", style="filled", fillcolor="orange", fontsize=font_size)
elif isinstance(n, BPMN.ParallelGateway):
graph.node(n_id, label="+", shape="diamond", fontsize=font_size)
elif isinstance(n, BPMN.ExclusiveGateway):
graph.node(n_id, label="X", shape="diamond", fontsize=font_size)
elif isinstance(n, BPMN.InclusiveGateway):
graph.node(n_id, label="O", shape="diamond", fontsize=font_size)
else:
graph.node(n_id, label="", shape="circle", fontsize=font_size)


def apply(bpmn_graph: BPMN, parameters: Optional[Dict[Any, Any]] = None) -> graphviz.Digraph:
"""
Visualize a BPMN graph
Expand Down Expand Up @@ -68,24 +89,30 @@ def apply(bpmn_graph: BPMN, parameters: Optional[Dict[Any, Any]] = None) -> grap
viz.graph_attr['rankdir'] = rankdir

nodes, edges = get_sorted_nodes_edges(bpmn_graph)
process_ids = []
for n in nodes:
if n.process not in process_ids:
process_ids.append(n.process)
process_ids_members = {n.process: list() for n in nodes}
for n in nodes:
process_ids_members[n.process].append(n)

for n in nodes:
n_id = str(id(n))
if isinstance(n, BPMN.Task):
viz.node(n_id, shape="box", label=n.get_name(), fontsize=font_size)
elif isinstance(n, BPMN.StartEvent):
viz.node(n_id, label="", shape="circle", style="filled", fillcolor="green", fontsize=font_size)
elif isinstance(n, BPMN.EndEvent):
viz.node(n_id, label="", shape="circle", style="filled", fillcolor="orange", fontsize=font_size)
elif isinstance(n, BPMN.ParallelGateway):
viz.node(n_id, label="+", shape="diamond", fontsize=font_size)
elif isinstance(n, BPMN.ExclusiveGateway):
viz.node(n_id, label="X", shape="diamond", fontsize=font_size)
elif isinstance(n, BPMN.InclusiveGateway):
viz.node(n_id, label="O", shape="diamond", fontsize=font_size)
else:
viz.node(n_id, label="", shape="circle", fontsize=font_size)
add_bpmn_node(viz, n, font_size)

"""
viz.node('@@anchor', style='invis')
for subp in process_ids:
with viz.subgraph(name="cluster"+subp) as c:
for n in process_ids_members[subp]:
c.attr(label=subp)
add_bpmn_node(c, n, font_size)
c.attr(rank='same')
viz.edge('@@anchor', str(id(process_ids_members[subp][0])), style='invis')
"""

for e in edges:
n_id_1 = str(id(e[0]))
n_id_2 = str(id(e[1]))
Expand All @@ -98,3 +125,42 @@ def apply(bpmn_graph: BPMN, parameters: Optional[Dict[Any, Any]] = None) -> grap

return viz


def save(gviz: graphviz.Digraph, output_file_path: str, parameters=None):
"""
Save the diagram
Parameters
-----------
gviz
GraphViz diagram
output_file_path
Path where the GraphViz output should be saved
"""
gsave.save(gviz, output_file_path, parameters=parameters)
return ""


def view(gviz: graphviz.Digraph, parameters=None):
"""
View the diagram
Parameters
-----------
gviz
GraphViz diagram
"""
return gview.view(gviz, parameters=parameters)


def matplotlib_view(gviz: graphviz.Digraph, parameters=None):
"""
Views the diagram using Matplotlib
Parameters
---------------
gviz
Graphviz
"""

return gview.matplotlib_view(gviz, parameters=parameters)
16 changes: 6 additions & 10 deletions pm4py/visualization/bpmn/visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
from pm4py.visualization.bpmn.variants import classic
from pm4py.util import exec_utils
from enum import Enum
from pm4py.visualization.common import gview
from pm4py.visualization.common import save as gsave
from pm4py.visualization.common.gview import serialize, serialize_dot
from typing import Optional, Dict, Any
from pm4py.objects.bpmn.obj import BPMN
Expand Down Expand Up @@ -54,7 +52,7 @@ def apply(bpmn_graph: BPMN, variant=DEFAULT_VARIANT, parameters: Optional[Dict[A
return exec_utils.get_variant(variant).apply(bpmn_graph, parameters=parameters)


def save(gviz: graphviz.Digraph, output_file_path: str, parameters=None):
def save(gviz: graphviz.Digraph, output_file_path: str, variant=DEFAULT_VARIANT, parameters=None):
"""
Save the diagram
Expand All @@ -65,11 +63,10 @@ def save(gviz: graphviz.Digraph, output_file_path: str, parameters=None):
output_file_path
Path where the GraphViz output should be saved
"""
gsave.save(gviz, output_file_path, parameters=parameters)
return ""
return exec_utils.get_variant(variant).save(gviz, output_file_path, parameters=parameters)


def view(gviz: graphviz.Digraph, parameters=None):
def view(gviz: graphviz.Digraph, variant=DEFAULT_VARIANT, parameters=None):
"""
View the diagram
Expand All @@ -78,10 +75,10 @@ def view(gviz: graphviz.Digraph, parameters=None):
gviz
GraphViz diagram
"""
return gview.view(gviz, parameters=parameters)
return exec_utils.get_variant(variant).view(gviz, parameters=parameters)


def matplotlib_view(gviz: graphviz.Digraph, parameters=None):
def matplotlib_view(gviz: graphviz.Digraph, variant=DEFAULT_VARIANT, parameters=None):
"""
Views the diagram using Matplotlib
Expand All @@ -90,5 +87,4 @@ def matplotlib_view(gviz: graphviz.Digraph, parameters=None):
gviz
Graphviz
"""

return gview.matplotlib_view(gviz, parameters=parameters)
return exec_utils.get_variant(variant).matplotlib_view(gviz, parameters=parameters)

0 comments on commit 0d00635

Please sign in to comment.