Source code for pm4py.util.vis_utils

'''
    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 base64
import os
import subprocess
import sys
from typing import Optional, Dict


MAX_EDGE_PENWIDTH_GRAPHVIZ = 2.6
MIN_EDGE_PENWIDTH_GRAPHVIZ = 1.0


[docs] def human_readable_stat( timedelta, stat_locale: Optional[Dict[str, str]] = None ) -> str: """ Transform a timedelta into a human readable string Parameters ---------- timedelta Timedelta Returns ---------- string Human readable string """ if stat_locale is None: stat_locale = {} c = int(float(timedelta)) years = c // 31104000 months = c // 2592000 days = c // 86400 hours = c // 3600 % 24 minutes = c // 60 % 60 seconds = c % 60 if years > 0: return str(years) + stat_locale.get("year", "Y") elif months > 0: return str(months) + stat_locale.get("month", "MO") elif days > 0: return str(days) + stat_locale.get("day", "D") elif hours > 0: return str(hours) + stat_locale.get("hour", "h") elif minutes > 0: return str(minutes) + stat_locale.get("minute", "m") elif seconds > 0: return str(seconds) + stat_locale.get("second", "s") else: c = int(float(timedelta) * 1000) if c > 0: return str(c) + stat_locale.get("millisecond", "ms") else: return str(int(float(timedelta) * 10**9)) + stat_locale.get( "nanosecond", "ns" )
[docs] def get_arc_penwidth(arc_measure, min_arc_measure, max_arc_measure): """ Calculate arc width given the current arc measure value, the minimum arc measure value and the maximum arc measure value Parameters ----------- arc_measure Current arc measure value min_arc_measure Minimum measure value among all arcs max_arc_measure Maximum measure value among all arcs Returns ----------- penwidth Current arc width in the graph """ return MIN_EDGE_PENWIDTH_GRAPHVIZ + ( MAX_EDGE_PENWIDTH_GRAPHVIZ - MIN_EDGE_PENWIDTH_GRAPHVIZ ) * (arc_measure - min_arc_measure) / ( max_arc_measure - min_arc_measure + 0.00001 )
[docs] def get_trans_freq_color(trans_count, min_trans_count, max_trans_count): """ Gets transition frequency color Parameters ---------- trans_count Current transition count min_trans_count Minimum transition count max_trans_count Maximum transition count Returns ---------- color Frequency color for visible transition """ trans_base_color = int( 255 - 100 * (trans_count - min_trans_count) / (max_trans_count - min_trans_count + 0.00001) ) trans_base_color_hex = str(hex(trans_base_color))[2:].upper() return "#" + trans_base_color_hex + trans_base_color_hex + "FF"
[docs] def get_base64_from_gviz(gviz): """ Get base 64 from string content of the file Parameters ----------- gviz Graphviz diagram Returns ----------- base64 Base64 string """ render = gviz.render(view=False) with open(render, "rb") as f: return base64.b64encode(f.read())
[docs] def get_base64_from_file(temp_file): """ Get base 64 from string content of the file Parameters ----------- temp_file Temporary file path Returns ----------- base64 Base64 string """ with open(temp_file, "rb") as f: return base64.b64encode(f.read())
[docs] def check_visualization_inside_jupyter(): """ Checks if the visualization of the model is performed inside a Jupyter notebook """ try: shell = get_ipython().__class__.__name__ if shell == "ZMQInteractiveShell" or shell == "Shell": return True else: return False except NameError: return False
[docs] def view_image_in_jupyter(file_name): """ Visualizes a picture inside the Jupyter notebooks Parameters ------------- file_name Name of the file """ from IPython.display import Image image = Image(file_name) from IPython.display import display return display(image)
[docs] def open_opsystem_image_viewer(file_name): """ Visualizes a picture using the image viewer of the operating system Parameters ------------- file_name Name of the file """ if sys.platform.startswith("darwin"): subprocess.call(("open", file_name)) elif os.name == "nt": # For Windows os.startfile(file_name) elif os.name == "posix": # For Linux, Mac, etc. subprocess.call(("xdg-open", file_name))
[docs] def get_corr_hex(num): """ Gets correspondence between a number and an hexadecimal string Parameters ------------- num Number Returns ------------- hex_string Hexadecimal string """ if num < 10: return str(int(num)) elif num < 11: return "A" elif num < 12: return "B" elif num < 13: return "C" elif num < 14: return "D" elif num < 15: return "E" elif num < 16: return "F"
[docs] def value_to_color(val, min_value, max_value): # Normalize values to the range [0, 1] val = (val - min_value) / (max_value - min_value + 0.000001) # Function to interpolate between two colors def interpolate_color(val, color1, color2): return tuple( int(color1[i] + (color2[i] - color1[i]) * val) for i in range(3) ) # Blue to red color gradient blue = (0, 0, 255) # RGB for blue red = (255, 0, 0) # RGB for red # Map normalized values to colors color = interpolate_color(val, blue, red) # Convert RGB colors to hexadecimal format def rgb_to_hex(rgb): return "#{:02x}{:02x}{:02x}".format(rgb[0], rgb[1], rgb[2]) hex_color = rgb_to_hex(color) return hex_color