Source code for pm4py.visualization.process_tree.variants.frequency_annotation

'''
    PM4Py – A Process Mining Library for Python
Copyright (C) 2024 Process Intelligence Solutions UG (haftungsbeschränkt)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see this software project's root or
visit <https://www.gnu.org/licenses/>.

Website: https://processintelligence.solutions
Contact: info@processintelligence.solutions
'''
import tempfile
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, constants


[docs] class Parameters(Enum): FORMAT = "format" ENABLE_DEEPCOPY = "enable_deepcopy" FONT_SIZE = "font_size" BGCOLOR = "bgcolor" RANKDIR = "rankdir" NUM_EVENTS_PROPERTY = "num_events_property" NUM_CASES_PROPERTY = "num_cases_property" ENABLE_GRAPH_TITLE = "enable_graph_title" GRAPH_TITLE = "graph_title"
# maps the operators to the ProM strings operators_mapping = { "->": "seq", "X": "xor", "+": "and", "*": "xor loop", "O": "or", "<>": "interleaving", } # root node parameter ROOT_NODE_PARAMETER = "@@root_node"
[docs] 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")
[docs] 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") filename.close() bgcolor = exec_utils.get_param_value( Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR ) rankdir = exec_utils.get_param_value( Parameters.RANKDIR, parameters, constants.DEFAULT_RANKDIR_GVIZ ) enable_graph_title = exec_utils.get_param_value( Parameters.ENABLE_GRAPH_TITLE, parameters, constants.DEFAULT_ENABLE_GRAPH_TITLES, ) graph_title = exec_utils.get_param_value( Parameters.GRAPH_TITLE, parameters, "Process Tree" ) font_size = exec_utils.get_param_value( Parameters.FONT_SIZE, parameters, 15 ) font_size = str(font_size) viz = Graph( "pt", filename=filename.name, engine="dot", graph_attr={"bgcolor": bgcolor, "rankdir": rankdir}, ) viz.attr("node", shape="ellipse", fixedsize="false") if enable_graph_title: viz.attr( label='<<FONT POINT-SIZE="' + str(2 * int(font_size)) + '">' + graph_title + "</FONT>>", labelloc="top", ) 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.replace("html", "plain-ext") return viz