-
Notifications
You must be signed in to change notification settings - Fork 300
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'ft-1516-frequency-annotation-trees-tree-alignments' int…
…o 'integration' PM4PY-1516 Frequency annotation of process tree using process tree alignments See merge request process-mining/pm4py/pm4py-core!572
- Loading branch information
Showing
7 changed files
with
199 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import pm4py | ||
import os | ||
from pm4py.algo.conformance.alignments.process_tree.util import search_graph_pt_frequency_annotation | ||
from pm4py.visualization.process_tree import visualizer as pt_visualizer | ||
|
||
|
||
def execute_script(): | ||
log = pm4py.read_xes(os.path.join("..", "tests", "input_data", "receipt.xes")) | ||
tree = pm4py.discover_process_tree_inductive(log) | ||
aligned_traces = pm4py.conformance_diagnostics_alignments(log, tree) | ||
tree = search_graph_pt_frequency_annotation.apply(tree, aligned_traces) | ||
gviz = pt_visualizer.apply(tree, parameters={"format": "svg"}, variant=pt_visualizer.Variants.FREQUENCY_ANNOTATION) | ||
pt_visualizer.view(gviz) | ||
|
||
|
||
if __name__ == "__main__": | ||
execute_script() |
2 changes: 1 addition & 1 deletion
2
pm4py/algo/conformance/alignments/process_tree/util/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
from pm4py.algo.conformance.alignments.process_tree.util import search_graph_pt_replay_semantics | ||
from pm4py.algo.conformance.alignments.process_tree.util import search_graph_pt_replay_semantics, search_graph_pt_frequency_annotation |
63 changes: 63 additions & 0 deletions
63
pm4py/algo/conformance/alignments/process_tree/util/search_graph_pt_frequency_annotation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
from pm4py.objects.process_tree.obj import ProcessTree | ||
from typing import Optional, Dict, Any, Union | ||
from pm4py.util import typing, exec_utils | ||
from enum import Enum | ||
from collections import Counter | ||
from pm4py.objects.process_tree.utils import bottomup | ||
|
||
|
||
class Parameters(Enum): | ||
NUM_EVENTS_PROPERTY = "num_events_property" | ||
NUM_CASES_PROPERTY = "num_cases_property" | ||
|
||
|
||
def apply(pt: ProcessTree, align_result: Union[typing.AlignmentResult, typing.ListAlignments], | ||
parameters: Optional[Dict[Any, Any]] = None) -> ProcessTree: | ||
""" | ||
Annotate a process tree with frequency information (number of events / number of cases), | ||
given the results of an alignment performed on the process tree. | ||
Parameters | ||
---------------- | ||
pt | ||
Process tree | ||
parameters | ||
Parameters of the algorithm, including: | ||
- Parameters.NUM_EVENTS_PROPERTY => number of events | ||
- Parameters.NUM_CASES_PROPERTY => number of cases | ||
Returns | ||
---------------- | ||
pt | ||
Annotated process tree | ||
""" | ||
if parameters is None: | ||
parameters = {} | ||
|
||
num_events_property = exec_utils.get_param_value(Parameters.NUM_EVENTS_PROPERTY, parameters, "num_events") | ||
num_cases_property = exec_utils.get_param_value(Parameters.NUM_CASES_PROPERTY, parameters, "num_cases") | ||
bottomup_nodes = bottomup.get_bottomup_nodes(pt, parameters=parameters) | ||
|
||
all_paths_open_enabled_events = [] | ||
all_paths_open_enabled_cases = [] | ||
for trace in align_result: | ||
state = trace["state"] | ||
paths = [] | ||
while state.parent is not None: | ||
if state.path: | ||
paths.append(state.path) | ||
state = state.parent | ||
paths.reverse() | ||
paths_enabled = [y[0] for x in paths for y in x if y[1] is ProcessTree.OperatorState.ENABLED] | ||
paths_open = [y[0] for x in paths for y in x if y[1] is ProcessTree.OperatorState.OPEN if | ||
y[0] not in paths_enabled] | ||
all_paths_open_enabled_events = all_paths_open_enabled_events + paths_enabled + paths_open | ||
all_paths_open_enabled_cases = all_paths_open_enabled_cases + list(set(paths_enabled + paths_open)) | ||
all_paths_open_enabled_events_counter = Counter(all_paths_open_enabled_events) | ||
all_paths_open_enabled_cases_counter = Counter(all_paths_open_enabled_cases) | ||
|
||
for node in bottomup_nodes: | ||
node._properties[num_events_property] = all_paths_open_enabled_events_counter[node] | ||
node._properties[num_cases_property] = all_paths_open_enabled_cases_counter[node] | ||
|
||
return pt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
pm4py/visualization/process_tree/variants/frequency_annotation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import tempfile | ||
import uuid | ||
from copy import deepcopy, copy | ||
from enum import Enum | ||
|
||
from graphviz import Graph | ||
|
||
from pm4py.objects.process_tree.utils import generic | ||
from pm4py.util import exec_utils | ||
from typing import Optional, Dict, Any, Union | ||
from pm4py.objects.process_tree.obj import ProcessTree | ||
import graphviz | ||
from pm4py.util import vis_utils | ||
|
||
|
||
class Parameters(Enum): | ||
FORMAT = "format" | ||
ENABLE_DEEPCOPY = "enable_deepcopy" | ||
FONT_SIZE = "font_size" | ||
BGCOLOR = "bgcolor" | ||
NUM_EVENTS_PROPERTY = "num_events_property" | ||
NUM_CASES_PROPERTY = "num_cases_property" | ||
|
||
|
||
# maps the operators to the ProM strings | ||
operators_mapping = {"->": "seq", "X": "xor", "+": "and", "*": "xor loop", "O": "or"} | ||
|
||
# root node parameter | ||
ROOT_NODE_PARAMETER = "@@root_node" | ||
|
||
|
||
def repr_tree_2(tree, viz, parameters): | ||
num_events_property = exec_utils.get_param_value(Parameters.NUM_EVENTS_PROPERTY, parameters, "num_events") | ||
num_cases_property = exec_utils.get_param_value(Parameters.NUM_CASES_PROPERTY, parameters, "num_cases") | ||
root_node = parameters[ROOT_NODE_PARAMETER] | ||
|
||
root_node_num_cases = root_node._properties[num_cases_property] | ||
this_node_num_cases = tree._properties[num_cases_property] if num_cases_property in tree._properties else 0 | ||
this_node_num_events = tree._properties[num_events_property] if num_events_property in tree._properties else 0 | ||
|
||
font_size = exec_utils.get_param_value(Parameters.FONT_SIZE, parameters, 15) | ||
font_size = str(font_size) | ||
|
||
this_node_id = str(id(tree)) | ||
|
||
if tree.operator is None: | ||
if tree.label is None: | ||
viz.node(this_node_id, "tau", style='filled', fillcolor='black', shape='point', width="0.075", fontsize=font_size) | ||
else: | ||
node_color = vis_utils.get_trans_freq_color(this_node_num_cases, 0, root_node_num_cases) | ||
node_label = str(tree) + "\nC=%d E=%d" % (this_node_num_cases, this_node_num_events) | ||
viz.node(this_node_id, node_label, fontsize=font_size, style="filled", fillcolor=node_color) | ||
else: | ||
node_color = vis_utils.get_trans_freq_color(this_node_num_cases, 0, root_node_num_cases) | ||
viz.node(this_node_id, operators_mapping[str(tree.operator)], fontsize=font_size, style="filled", fillcolor=node_color) | ||
|
||
for child in tree.children: | ||
repr_tree_2(child, viz, parameters) | ||
|
||
if tree.parent is not None: | ||
viz.edge(str(id(tree.parent)), this_node_id, dirType='none') | ||
|
||
|
||
def apply(tree: ProcessTree, parameters: Optional[Dict[Union[str, Parameters], Any]] = None) -> graphviz.Graph: | ||
""" | ||
Obtain a Process Tree representation through GraphViz | ||
Parameters | ||
----------- | ||
tree | ||
Process tree | ||
parameters | ||
Possible parameters of the algorithm | ||
Returns | ||
----------- | ||
gviz | ||
GraphViz object | ||
""" | ||
if parameters is None: | ||
parameters = {} | ||
|
||
parameters = copy(parameters) | ||
parameters[ROOT_NODE_PARAMETER] = tree | ||
|
||
filename = tempfile.NamedTemporaryFile(suffix='.gv') | ||
|
||
bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, "transparent") | ||
|
||
viz = Graph("pt", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) | ||
viz.attr('node', shape='ellipse', fixedsize='false') | ||
|
||
image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") | ||
|
||
enable_deepcopy = exec_utils.get_param_value(Parameters.ENABLE_DEEPCOPY, parameters, False) | ||
|
||
if enable_deepcopy: | ||
# since the process tree object needs to be sorted in the visualization, make a deepcopy of it before | ||
# proceeding | ||
tree = deepcopy(tree) | ||
generic.tree_sort(tree) | ||
|
||
repr_tree_2(tree, viz, parameters) | ||
|
||
viz.attr(overlap='false') | ||
viz.attr(splines='false') | ||
viz.format = image_format | ||
|
||
return viz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters