From 95adc421cd05d5dd4a98880f04e5f1979775e54c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 21 Mar 2024 07:51:50 +0000 Subject: [PATCH 01/52] chore(deps): update dependency graphviz to v0.20.3 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index aebb537a3..5bece6068 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -3,7 +3,7 @@ contourpy==1.2.0 cycler==0.12.1 deprecation==2.1.0 fonttools==4.49.0 -graphviz==0.20.2 +graphviz==0.20.3 intervaltree==3.1.0 kiwisolver==1.4.5 lxml==5.1.0 From 2f1c5a9efa971f3c6eaf536028774beeed1a9ef3 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Fri, 22 Mar 2024 07:24:47 +0100 Subject: [PATCH 02/52] docs(pm4py): updated changelog --- CHANGELOG.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74a19c33a..c15c56877 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ # Changelog of pm4py +## pm4py 2.7.12.1 (2024.XX.YY) + +### Added + +### Changed + +### Deprecated + +### Fixed +* 1c6887fda74d2b0a36f483351a6978738517e61e + * bug fix inductive miner infreuent +* e7e8ebf6894d9bc85febc43c82613d185e16ee3b + * solving performance bottleneck in IM + +### Removed + +### Other + + +--- + + ## pm4py 2.7.12 (2024.03.21) ### Added @@ -34,8 +56,10 @@ ### Other + --- + ## pm4py 2.7.11 (2024.03.01) ### Added From cdcf0d21455a98c678b74f52ab73057586872c5e Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Fri, 22 Mar 2024 07:25:44 +0100 Subject: [PATCH 03/52] bumped version number --- pm4py/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pm4py/meta.py b/pm4py/meta.py index 6eed73219..0e4f76bf6 100644 --- a/pm4py/meta.py +++ b/pm4py/meta.py @@ -1,5 +1,5 @@ __name__ = 'pm4py' -VERSION = '2.7.12' +VERSION = '2.7.12.1' __version__ = VERSION __doc__ = 'Process mining for Python' __author__ = 'Fraunhofer Institute for Applied Information Technology FIT' From 7b4787b93b32a682f080b563b1c9c8902ee9754f Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Fri, 22 Mar 2024 07:26:08 +0100 Subject: [PATCH 04/52] performed safety check --- safety_checks/20240322 | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 safety_checks/20240322 diff --git a/safety_checks/20240322 b/safety_checks/20240322 new file mode 100644 index 000000000..e4dd557af --- /dev/null +++ b/safety_checks/20240322 @@ -0,0 +1,47 @@ ++==============================================================================+ + + /$$$$$$ /$$ + /$$__ $$ | $$ + /$$$$$$$ /$$$$$$ | $$ \__//$$$$$$ /$$$$$$ /$$ /$$ + /$$_____/ |____ $$| $$$$ /$$__ $$|_ $$_/ | $$ | $$ + | $$$$$$ /$$$$$$$| $$_/ | $$$$$$$$ | $$ | $$ | $$ + \____ $$ /$$__ $$| $$ | $$_____/ | $$ /$$| $$ | $$ + /$$$$$$$/| $$$$$$$| $$ | $$$$$$$ | $$$$/| $$$$$$$ + |_______/ \_______/|__/ \_______/ \___/ \____ $$ + /$$ | $$ + | $$$$$$/ + by safetycli.com \______/ + ++==============================================================================+ + + REPORT + + Safety is using PyUp's free open-source vulnerability database. This +data is 30 days old and limited. + For real-time enhanced vulnerability data, fix recommendations, severity +reporting, cybersecurity support, team and project policy management and more +sign up at https://pyup.io or email sales@pyup.io + + Safety v3.0.1 is scanning for Vulnerabilities... + Scanning dependencies in your files: + + -> requirements_stable.txt + + Using open-source vulnerability database + Found and scanned 24 packages + Timestamp 2024-03-22 07:25:58 + 0 vulnerabilities reported + 0 vulnerabilities ignored ++==============================================================================+ + + No known security vulnerabilities reported. + ++==============================================================================+ + + Safety is using PyUp's free open-source vulnerability database. This +data is 30 days old and limited. + For real-time enhanced vulnerability data, fix recommendations, severity +reporting, cybersecurity support, team and project policy management and more +sign up at https://pyup.io or email sales@pyup.io + ++==============================================================================+ From 67b7e3412811d2dbd97e53936984ffcbbd251354 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Fri, 22 Mar 2024 07:27:15 +0100 Subject: [PATCH 05/52] updated dependencies sheet --- third_party/LICENSES_TRANSITIVE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/LICENSES_TRANSITIVE.md b/third_party/LICENSES_TRANSITIVE.md index fe92dea2d..ee6fd2eeb 100644 --- a/third_party/LICENSES_TRANSITIVE.md +++ b/third_party/LICENSES_TRANSITIVE.md @@ -11,7 +11,7 @@ libraries are added/removed. | cycler | https://pypi.org/project/cycler | BSD License | 0.12.1 | | deprecation | https://pypi.org/project/deprecation | Apache Software License (Apache 2) | 2.1.0 | | fonttools | https://pypi.org/project/fonttools | MIT License (MIT) | 4.49.0 | -| graphviz | https://pypi.org/project/graphviz | MIT License (MIT) | 0.20.2 | +| graphviz | https://pypi.org/project/graphviz | MIT License (MIT) | 0.20.3 | | intervaltree | https://pypi.org/project/intervaltree | Apache Software License (Apache License, Version 2.0) | 3.1.0 | | kiwisolver | https://pypi.org/project/kiwisolver | BSD License | 1.4.5 | | lxml | https://pypi.org/project/lxml | BSD License (BSD-3-Clause) | 5.1.0 | From 3b1d9c8ceb6e220342af4d064f1338798a7ffa2e Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Wed, 27 Mar 2024 11:56:25 +0100 Subject: [PATCH 06/52] docs(pm4py): updated changelog --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c15c56877..244ff2124 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,20 @@ * bug fix inductive miner infreuent * e7e8ebf6894d9bc85febc43c82613d185e16ee3b * solving performance bottleneck in IM +* 4811bbde07f6639deb7c87bdda61504de0889873 + * resolved indeterminism in IM fallthroughs +* df1db968adf8bb5f483410be0ceef2928c2b3e6c + * missing tree sort in IM +* 4958e2b8407c01923e5b65c7e46a5f89d8f927dc + * missing fold of PT objects in IM +* 8e404c6c2b53cf14687d1f82d53a4a0fc4ac99d6 + * fixed folding of PTs +* a871cbc4bdeaa81013fbfa7a6ec5054d494cb329 + * fixed parsing of PTs +* a72cd92410653bf2f0b2ff35ab5d06bf73a95305 + eddae51259114caf4e1447beee4981f2e00bcb9c + 69dcf7a836a5af3ab5da64701f43e3d8cf6b07aa + * fixed WF-net-to-PT conversion ### Removed From 5d83531f5cbd71176f8dc6954558d94f51eb7e1d Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Wed, 27 Mar 2024 11:57:00 +0100 Subject: [PATCH 07/52] docs(pm4py): performed safety check --- safety_checks/20240327 | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 safety_checks/20240327 diff --git a/safety_checks/20240327 b/safety_checks/20240327 new file mode 100644 index 000000000..183420d01 --- /dev/null +++ b/safety_checks/20240327 @@ -0,0 +1,47 @@ ++==============================================================================+ + + /$$$$$$ /$$ + /$$__ $$ | $$ + /$$$$$$$ /$$$$$$ | $$ \__//$$$$$$ /$$$$$$ /$$ /$$ + /$$_____/ |____ $$| $$$$ /$$__ $$|_ $$_/ | $$ | $$ + | $$$$$$ /$$$$$$$| $$_/ | $$$$$$$$ | $$ | $$ | $$ + \____ $$ /$$__ $$| $$ | $$_____/ | $$ /$$| $$ | $$ + /$$$$$$$/| $$$$$$$| $$ | $$$$$$$ | $$$$/| $$$$$$$ + |_______/ \_______/|__/ \_______/ \___/ \____ $$ + /$$ | $$ + | $$$$$$/ + by safetycli.com \______/ + ++==============================================================================+ + + REPORT + + Safety is using PyUp's free open-source vulnerability database. This +data is 30 days old and limited. + For real-time enhanced vulnerability data, fix recommendations, severity +reporting, cybersecurity support, team and project policy management and more +sign up at https://pyup.io or email sales@pyup.io + + Safety v3.0.1 is scanning for Vulnerabilities... + Scanning dependencies in your files: + + -> requirements_stable.txt + + Using open-source vulnerability database + Found and scanned 24 packages + Timestamp 2024-03-27 11:56:49 + 0 vulnerabilities reported + 0 vulnerabilities ignored ++==============================================================================+ + + No known security vulnerabilities reported. + ++==============================================================================+ + + Safety is using PyUp's free open-source vulnerability database. This +data is 30 days old and limited. + For real-time enhanced vulnerability data, fix recommendations, severity +reporting, cybersecurity support, team and project policy management and more +sign up at https://pyup.io or email sales@pyup.io + ++==============================================================================+ From c74d7478c76de299954c7b07426bbbf2b3740930 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Thu, 28 Mar 2024 07:47:17 +0100 Subject: [PATCH 08/52] docs(pm4py): updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 244ff2124..a959ae3d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ### Added ### Changed +* 5641f9f2c830b567c138524a0b5e705a3836102a + * minor change OCEL names_stripping ### Deprecated @@ -28,6 +30,10 @@ eddae51259114caf4e1447beee4981f2e00bcb9c 69dcf7a836a5af3ab5da64701f43e3d8cf6b07aa * fixed WF-net-to-PT conversion +* 0980ac460d69beb9ede4403a3ed002c1cd30536e + * fixed docstring OCEL flattening +* 6f9c67f48ad89e88d58c2481e85c6f3de9e6e1a5 + * fix small issues with stochastic Petri net ### Removed From f69beb0752ec65d00e228831dd8081acfca1abc8 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 31 Mar 2024 07:28:22 +0000 Subject: [PATCH 09/52] chore(deps): update dependency lxml to v5.2.0 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index 5bece6068..092c9d172 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -6,7 +6,7 @@ fonttools==4.49.0 graphviz==0.20.3 intervaltree==3.1.0 kiwisolver==1.4.5 -lxml==5.1.0 +lxml==5.2.0 matplotlib==3.8.3 networkx==3.2.1 numpy==1.26.4 From 6277fb5b7299e2eb9dfea5ec5c2bb3cf82ab8fb1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 1 Apr 2024 12:28:26 +0000 Subject: [PATCH 10/52] chore(deps): update dependency pillow to v10.3.0 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index 092c9d172..a24b7b5e3 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -12,7 +12,7 @@ networkx==3.2.1 numpy==1.26.4 packaging==24.0 pandas==2.2.1 -pillow==10.2.0 +pillow==10.3.0 pydotplus==2.0.2 pyparsing==3.1.2 python-dateutil==2.9.0.post0 From f3e50508947a09d79e8d162f23edca2fe4bf9035 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 2 Apr 2024 21:31:13 +0000 Subject: [PATCH 11/52] chore(deps): update dependency contourpy to v1.2.1 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index a24b7b5e3..daf5e0b70 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -1,5 +1,5 @@ colorama==0.4.6 -contourpy==1.2.0 +contourpy==1.2.1 cycler==0.12.1 deprecation==2.1.0 fonttools==4.49.0 From a8174ee3319151e212637131bc13eef54b68f129 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 2 Apr 2024 22:31:38 +0000 Subject: [PATCH 12/52] chore(deps): update dependency scipy to v1.13.0 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index a24b7b5e3..2d22e8527 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -17,7 +17,7 @@ pydotplus==2.0.2 pyparsing==3.1.2 python-dateutil==2.9.0.post0 pytz==2024.1 -scipy==1.12.0 +scipy==1.13.0 six==1.16.0 sortedcontainers==2.4.0 tqdm==4.66.2 From 1e29ec8256f040163fda630b47e6a930ec797440 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 4 Apr 2024 02:28:08 +0000 Subject: [PATCH 13/52] chore(deps): update dependency matplotlib to v3.8.4 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index a24b7b5e3..77d9fa8bb 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -7,7 +7,7 @@ graphviz==0.20.3 intervaltree==3.1.0 kiwisolver==1.4.5 lxml==5.2.0 -matplotlib==3.8.3 +matplotlib==3.8.4 networkx==3.2.1 numpy==1.26.4 packaging==24.0 From ecffd366a3a6cb2bd8bc6ea85cb38be0e0035655 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Thu, 4 Apr 2024 09:12:40 +0200 Subject: [PATCH 14/52] updating dependencies --- Dockerfile | 2 +- requirements_stable.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index b8ea7cf88..cba479ab6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ RUN apt-get -y install libtool flex bison pkg-config g++ libssl-dev automake RUN apt-get -y install libjemalloc-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-regex-dev python3-dev autoconf flex bison cmake RUN apt-get -y install libxml2-dev libxslt-dev libfreetype6-dev libsuitesparse-dev RUN pip install -U wheel six pytest -RUN pip install colorama==0.4.6 contourpy==1.2.0 cycler==0.12.1 deprecation==2.1.0 fonttools==4.49.0 graphviz==0.20.1 intervaltree==3.1.0 kiwisolver==1.4.5 lxml==5.1.0 matplotlib==3.8.3 networkx==3.2.1 numpy==1.26.4 packaging==23.2 pandas==2.2.1 pillow==10.2.0 pydotplus==2.0.2 pyparsing==3.1.1 python-dateutil==2.9.0.post0 pytz==2024.1 scipy==1.12.0 six==1.16.0 sortedcontainers==2.4.0 tqdm==4.66.2 tzdata==2024.1 +RUN pip install colorama==0.4.6 contourpy==1.2.1 cycler==0.12.1 deprecation==2.1.0 fonttools==4.50.0 graphviz==0.20.3 intervaltree==3.1.0 kiwisolver==1.4.5 lxml==5.2.1 matplotlib==3.8.4 networkx==3.2.1 numpy==1.26.4 packaging==24.0 pandas==2.2.1 pillow==10.3.0 pydotplus==2.0.2 pyparsing==3.1.2 python-dateutil==2.9.0.post0 pytz==2024.1 scipy==1.13.0 six==1.16.0 sortedcontainers==2.4.0 tqdm==4.66.2 tzdata==2024.1 COPY . /app RUN cd /app && python setup.py install diff --git a/requirements_stable.txt b/requirements_stable.txt index 30f8915ad..d137d42e6 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -2,11 +2,11 @@ colorama==0.4.6 contourpy==1.2.1 cycler==0.12.1 deprecation==2.1.0 -fonttools==4.49.0 +fonttools==4.50.0 graphviz==0.20.3 intervaltree==3.1.0 kiwisolver==1.4.5 -lxml==5.2.0 +lxml==5.2.1 matplotlib==3.8.4 networkx==3.2.1 numpy==1.26.4 From 53cd107636fb196084453d97d65375a4d797fe21 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Thu, 4 Apr 2024 09:14:36 +0200 Subject: [PATCH 15/52] updating dependencies sheet --- third_party/LICENSES_TRANSITIVE.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/third_party/LICENSES_TRANSITIVE.md b/third_party/LICENSES_TRANSITIVE.md index ee6fd2eeb..98b8ad802 100644 --- a/third_party/LICENSES_TRANSITIVE.md +++ b/third_party/LICENSES_TRANSITIVE.md @@ -7,25 +7,25 @@ libraries are added/removed. | Name | URL | License | Version | | --------------------------- | ------------------------------------------------------------ | --------------------- |-------------| | colorama | https://pypi.org/project/colorama | BSD License | 0.4.6 | -| contourpy | https://pypi.org/project/contourpy | BSD License | 1.2.0 | +| contourpy | https://pypi.org/project/contourpy | BSD License | 1.2.1 | | cycler | https://pypi.org/project/cycler | BSD License | 0.12.1 | | deprecation | https://pypi.org/project/deprecation | Apache Software License (Apache 2) | 2.1.0 | -| fonttools | https://pypi.org/project/fonttools | MIT License (MIT) | 4.49.0 | +| fonttools | https://pypi.org/project/fonttools | MIT License (MIT) | 4.50.0 | | graphviz | https://pypi.org/project/graphviz | MIT License (MIT) | 0.20.3 | | intervaltree | https://pypi.org/project/intervaltree | Apache Software License (Apache License, Version 2.0) | 3.1.0 | | kiwisolver | https://pypi.org/project/kiwisolver | BSD License | 1.4.5 | -| lxml | https://pypi.org/project/lxml | BSD License (BSD-3-Clause) | 5.1.0 | -| matplotlib | https://pypi.org/project/matplotlib | Python Software Foundation License (PSF) | 3.8.3 | +| lxml | https://pypi.org/project/lxml | BSD License (BSD-3-Clause) | 5.2.1 | +| matplotlib | https://pypi.org/project/matplotlib | Python Software Foundation License (PSF) | 3.8.4 | | networkx | https://pypi.org/project/networkx | BSD License | 3.2.1 | | numpy | https://pypi.org/project/numpy | BSD License | 1.26.4 | | packaging | https://pypi.org/project/packaging | Apache Software License, BSD License | 24.0 | | pandas | https://pypi.org/project/pandas | BSD License | 2.2.1 | -| pillow | https://pypi.org/project/pillow | Historical Permission Notice and Disclaimer (HPND) (HPND) | 10.2.0 | +| pillow | https://pypi.org/project/pillow | Historical Permission Notice and Disclaimer (HPND) (HPND) | 10.3.0 | | pydotplus | https://pypi.org/project/pydotplus | MIT License (UNKNOWN) | 2.0.2 | | pyparsing | https://pypi.org/project/pyparsing | MIT License | 3.1.2 | | python-dateutil | https://pypi.org/project/python-dateutil | Apache Software License, BSD License (Dual License) | 2.9.0.post0 | | pytz | https://pypi.org/project/pytz | MIT License (MIT) | 2024.1 | -| scipy | https://pypi.org/project/scipy | BSD License | 1.12.0 | +| scipy | https://pypi.org/project/scipy | BSD License | 1.13.0 | | six | https://pypi.org/project/six | MIT License (MIT) | 1.16.0 | | sortedcontainers | https://pypi.org/project/sortedcontainers | Apache Software License (Apache 2.0) | 2.4.0 | | tqdm | https://pypi.org/project/tqdm | MIT License, Mozilla Public License 2.0 (MPL 2.0) (MPL-2.0 AND MIT) | 4.66.2 | From 23e2ed2bf21982a7b5ea369e930ee4be312e521d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 5 Apr 2024 15:29:48 +0000 Subject: [PATCH 16/52] chore(deps): update dependency fonttools to v4.51.0 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index d137d42e6..8844957c1 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -2,7 +2,7 @@ colorama==0.4.6 contourpy==1.2.1 cycler==0.12.1 deprecation==2.1.0 -fonttools==4.50.0 +fonttools==4.51.0 graphviz==0.20.3 intervaltree==3.1.0 kiwisolver==1.4.5 From b3cf675ddb5fd0bd09d9c7244d7e437300505108 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 6 Apr 2024 13:28:38 +0000 Subject: [PATCH 17/52] chore(deps): update dependency networkx to v3.3 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index 8844957c1..871519792 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -8,7 +8,7 @@ intervaltree==3.1.0 kiwisolver==1.4.5 lxml==5.2.1 matplotlib==3.8.4 -networkx==3.2.1 +networkx==3.3 numpy==1.26.4 packaging==24.0 pandas==2.2.1 From 19db6f2d9ac65058d7d5b25cdd126f0eb27223f4 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 8 Apr 2024 07:52:37 +0200 Subject: [PATCH 18/52] docs(pm4py): updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a959ae3d1..51e89cafd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,12 @@ * fixed docstring OCEL flattening * 6f9c67f48ad89e88d58c2481e85c6f3de9e6e1a5 * fix small issues with stochastic Petri net +* 6781a90df2ba8d90155e7b5135520076843cac33 + * bug fix DECLARE discovery and conformance checking +* 7330d5100c8b8916eba9e4b0f31e8fa1f9157c98 + * bug fix log skeleton discovery (always after, always before) +* ec2f0b5b43d83a7b9fa154456241e3c685fcb721 + * bug fix log-to-prefix-tree discovery (final nodes) ### Removed From ea0c081370bf7b51226446055a8a3c0ddb733018 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 8 Apr 2024 08:08:42 +0200 Subject: [PATCH 19/52] feat(pm4py): prefix tree __repr__ --- pm4py/objects/trie/obj.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pm4py/objects/trie/obj.py b/pm4py/objects/trie/obj.py index f49f2e25a..b02daf290 100644 --- a/pm4py/objects/trie/obj.py +++ b/pm4py/objects/trie/obj.py @@ -42,3 +42,22 @@ def _get_depth(self): label = property(_get_label, _set_label) final = property(_get_final, _set_final) depth = property(_get_depth, _set_depth) + + def repr_trie(self, indent_level=0): + stri = [] + + if self.label: + stri.append("\t"*indent_level + self.label) + indent_level += 1 + for child in self.children: + stri.append(child.repr_trie(indent_level=indent_level)) + if self.final: + stri.append("\t"*indent_level + "-- END --") + + return "\n".join(stri) + + def __repr__(self): + return self.repr_trie() + + def __str__(self): + return self.repr_trie() From 0198eeba77249ace222e8035f93c8486ca1b7b73 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 10 Apr 2024 00:30:31 +0000 Subject: [PATCH 20/52] chore(deps): update python docker tag to v3.12.3 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index cba479ab6..74c321342 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.2 +FROM python:3.12.3 RUN apt-get update RUN apt-get -y upgrade From 0ead2ab6b86e14b169584e5ce7ca9dc32a535186 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 10 Apr 2024 20:31:01 +0000 Subject: [PATCH 21/52] chore(deps): update dependency pandas to v2.2.2 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index 871519792..e825e10d7 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -11,7 +11,7 @@ matplotlib==3.8.4 networkx==3.3 numpy==1.26.4 packaging==24.0 -pandas==2.2.1 +pandas==2.2.2 pillow==10.3.0 pydotplus==2.0.2 pyparsing==3.1.2 From 50317815ccacfe30d7d5d3eab2986fbc3ba1c00e Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Thu, 11 Apr 2024 06:09:49 +0200 Subject: [PATCH 22/52] docs(pm4py): updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51e89cafd..e72676eaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ### Changed * 5641f9f2c830b567c138524a0b5e705a3836102a * minor change OCEL names_stripping +* c48882b88326608dc5c6a4101b8123c71a852e18 + * parameter to enable/disable visualizations' view ### Deprecated @@ -40,6 +42,10 @@ * bug fix log skeleton discovery (always after, always before) * ec2f0b5b43d83a7b9fa154456241e3c685fcb721 * bug fix log-to-prefix-tree discovery (final nodes) +* d580fedd4b770ed85f6864cd6d435db2477684f2 + * bumping release number. forcing numpy<2 and pandas<3 +* 4f8bbf6d884e25c5474479fd86fe7331076ac2fe + * bug fixes for Pandas >= 3.0 future support ### Removed From 7ab01621e53e570ef53edb9ecfb8d611b7c13564 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Tue, 16 Apr 2024 15:14:51 +0200 Subject: [PATCH 23/52] feat(pm4py): updated LTL filters documentation in simplified interface --- pm4py/filtering.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pm4py/filtering.py b/pm4py/filtering.py index 1177e37bd..a32dc4cfa 100644 --- a/pm4py/filtering.py +++ b/pm4py/filtering.py @@ -858,9 +858,9 @@ def filter_ocel_events_timestamp(ocel: OCEL, min_timest: Union[datetime.datetime return event_attributes.apply_timestamp(ocel, min_timest, max_timest, parameters={"pm4py:param:timestamp_key": timestamp_key}) -def filter_four_eyes_principle(log: Union[EventLog, pd.DataFrame], activity1: str, activity2: str, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", resource_key: str = "org:resource") -> Union[EventLog, pd.DataFrame]: +def filter_four_eyes_principle(log: Union[EventLog, pd.DataFrame], activity1: str, activity2: str, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", resource_key: str = "org:resource", keep_violations: bool = False) -> Union[EventLog, pd.DataFrame]: """ - Filter the cases of the log which violates the four eyes principle on the provided activities. + Filter out the cases of the log violating the four eyes principle on the provided activities. :param log: event log :param activity1: first activity @@ -869,6 +869,7 @@ def filter_four_eyes_principle(log: Union[EventLog, pd.DataFrame], activity1: st :param timestamp_key: attribute to be used for the timestamp :param case_id_key: attribute to be used as case identifier :param resource_key: attribute to be used as resource + :param keep_violations: boolean to discard (if False) or retain (if True) the violations :rtype: ``Union[EventLog, pd.DataFrame]`` .. code-block:: python3 @@ -880,7 +881,7 @@ def filter_four_eyes_principle(log: Union[EventLog, pd.DataFrame], activity1: st __event_log_deprecation_warning(log) properties = get_properties(log, activity_key=activity_key, timestamp_key=timestamp_key, case_id_key=case_id_key, resource_key=resource_key) - properties["positive"] = True + properties["positive"] = not keep_violations if check_is_pandas_dataframe(log): check_pandas_dataframe_columns(log, activity_key=activity_key, timestamp_key=timestamp_key, case_id_key=case_id_key) @@ -892,7 +893,7 @@ def filter_four_eyes_principle(log: Union[EventLog, pd.DataFrame], activity1: st return ltl_checker.four_eyes_principle(log, activity1, activity2, parameters=properties) -def filter_activity_done_different_resources(log: Union[EventLog, pd.DataFrame], activity: str, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", resource_key: str = "org:resource") -> Union[EventLog, pd.DataFrame]: +def filter_activity_done_different_resources(log: Union[EventLog, pd.DataFrame], activity: str, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", resource_key: str = "org:resource", keep_violations: bool = True) -> Union[EventLog, pd.DataFrame]: """ Filters the cases where an activity is repeated by different resources. @@ -902,6 +903,7 @@ def filter_activity_done_different_resources(log: Union[EventLog, pd.DataFrame], :param timestamp_key: attribute to be used for the timestamp :param case_id_key: attribute to be used as case identifier :param resource_key: attribute to be used as resource + :param keep_violations: boolean to discard (if False) or retain (if True) the violations :rtype: ``Union[EventLog, pd.DataFrame]`` .. code-block:: python3 @@ -913,6 +915,7 @@ def filter_activity_done_different_resources(log: Union[EventLog, pd.DataFrame], __event_log_deprecation_warning(log) properties = get_properties(log, activity_key=activity_key, timestamp_key=timestamp_key, case_id_key=case_id_key, resource_key=resource_key) + properties["positive"] = keep_violations if check_is_pandas_dataframe(log): check_pandas_dataframe_columns(log, activity_key=activity_key, timestamp_key=timestamp_key, case_id_key=case_id_key) From 9c4dde0d52793d5b30c4220fa3c085eb86e45165 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Wed, 17 Apr 2024 08:07:31 +0200 Subject: [PATCH 24/52] docs(pm4py): updated changelog --- CHANGELOG.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e72676eaf..d6d34008d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,35 @@ # Changelog of pm4py -## pm4py 2.7.12.1 (2024.XX.YY) +## pm4py 2.7.13 (2024.04.19) + +### Added + +### Changed +* 75c893999e32b3a1a6081db854b9a3cd10eaaa44 + * Dockerfile refactoring +* 7b80dad1fcc6955730357f46754c4a511b83ee58 + * updating requirements list +* 52459f95d42e2fc39568b0d685bd794c319f205a + * refactoring dependencies generation script + +### Deprecated + +### Fixed + +### Removed + +### Other +* ed708047252f96f3bf103ba81d6139b433c39b85 + * printing Python versions in tests and examples +* c48882b88326608dc5c6a4101b8123c71a852e18 + * parameter to enable/disable visualizations + + +--- + + +## pm4py 2.7.12.1 (2024.04.17) ### Added From 3d3f187e0e78b239f98136adfa7eaf3aef4ee39d Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Wed, 17 Apr 2024 08:07:51 +0200 Subject: [PATCH 25/52] bumped release number --- pm4py/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pm4py/meta.py b/pm4py/meta.py index 0e4f76bf6..607ebd82c 100644 --- a/pm4py/meta.py +++ b/pm4py/meta.py @@ -1,5 +1,5 @@ __name__ = 'pm4py' -VERSION = '2.7.12.1' +VERSION = '2.7.13' __version__ = VERSION __doc__ = 'Process mining for Python' __author__ = 'Fraunhofer Institute for Applied Information Technology FIT' From 3cf4e76454ddb410367caed951ca8b63dfbb8347 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Wed, 17 Apr 2024 08:08:42 +0200 Subject: [PATCH 26/52] performed safety check --- safety_checks/20240417 | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 safety_checks/20240417 diff --git a/safety_checks/20240417 b/safety_checks/20240417 new file mode 100644 index 000000000..5ebd008ad --- /dev/null +++ b/safety_checks/20240417 @@ -0,0 +1,47 @@ ++==============================================================================+ + + /$$$$$$ /$$ + /$$__ $$ | $$ + /$$$$$$$ /$$$$$$ | $$ \__//$$$$$$ /$$$$$$ /$$ /$$ + /$$_____/ |____ $$| $$$$ /$$__ $$|_ $$_/ | $$ | $$ + | $$$$$$ /$$$$$$$| $$_/ | $$$$$$$$ | $$ | $$ | $$ + \____ $$ /$$__ $$| $$ | $$_____/ | $$ /$$| $$ | $$ + /$$$$$$$/| $$$$$$$| $$ | $$$$$$$ | $$$$/| $$$$$$$ + |_______/ \_______/|__/ \_______/ \___/ \____ $$ + /$$ | $$ + | $$$$$$/ + by safetycli.com \______/ + ++==============================================================================+ + + REPORT + + Safety is using PyUp's free open-source vulnerability database. This +data is 30 days old and limited. + For real-time enhanced vulnerability data, fix recommendations, severity +reporting, cybersecurity support, team and project policy management and more +sign up at https://pyup.io or email sales@pyup.io + + Safety v3.0.1 is scanning for Vulnerabilities... + Scanning dependencies in your files: + + -> requirements_stable.txt + + Using open-source vulnerability database + Found and scanned 26 packages + Timestamp 2024-04-17 08:08:26 + 0 vulnerabilities reported + 0 vulnerabilities ignored ++==============================================================================+ + + No known security vulnerabilities reported. + ++==============================================================================+ + + Safety is using PyUp's free open-source vulnerability database. This +data is 30 days old and limited. + For real-time enhanced vulnerability data, fix recommendations, severity +reporting, cybersecurity support, team and project policy management and more +sign up at https://pyup.io or email sales@pyup.io + ++==============================================================================+ From 397d7d5b011ea16c9a78be2e9382dff689632475 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 29 Apr 2024 06:52:33 +0200 Subject: [PATCH 27/52] docs(pm4py): updated changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d34008d..395236b38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Changelog of pm4py -## pm4py 2.7.13 (2024.04.19) +## pm4py 2.7.13 (2024.05.03) ### Added @@ -12,10 +12,14 @@ * updating requirements list * 52459f95d42e2fc39568b0d685bd794c319f205a * refactoring dependencies generation script +* 928ecf5f8192ff1ef7944c5b0a7be7c530814ad9 + * refactoring OpenAI query interface ### Deprecated ### Fixed +* 954c2fbdc258b90bcba85001592a5d2950a79724 + * bug fix temporal profile conformance checking ### Removed From 01e4545608029712a242bd3c149786d183db5aa7 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 13 May 2024 12:38:15 +0200 Subject: [PATCH 28/52] refactor(pm4py): refactoring OCEL object representation (added unique activities per object type) --- pm4py/objects/ocel/obj.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/pm4py/objects/ocel/obj.py b/pm4py/objects/ocel/obj.py index 9e1a82bb3..7d6fd7642 100644 --- a/pm4py/objects/ocel/obj.py +++ b/pm4py/objects/ocel/obj.py @@ -4,6 +4,7 @@ from pm4py.util import exec_utils, pandas_utils import pandas as pd import numpy as np +from collections import Counter from copy import copy, deepcopy @@ -18,7 +19,8 @@ class Parameters(Enum): class OCEL(object): - def __init__(self, events=None, objects=None, relations=None, globals=None, parameters=None, o2o=None, e2e=None, object_changes=None): + def __init__(self, events=None, objects=None, relations=None, globals=None, parameters=None, o2o=None, e2e=None, + object_changes=None): if parameters is None: parameters = {} @@ -33,10 +35,12 @@ def __init__(self, events=None, objects=None, relations=None, globals=None, para self.event_timestamp = exec_utils.get_param_value(Parameters.EVENT_TIMESTAMP, parameters, constants.DEFAULT_EVENT_TIMESTAMP) self.qualifier = exec_utils.get_param_value(Parameters.QUALIFIER, parameters, constants.DEFAULT_QUALIFIER) - self.changed_field = exec_utils.get_param_value(Parameters.CHANGED_FIELD, parameters, constants.DEFAULT_CHNGD_FIELD) + self.changed_field = exec_utils.get_param_value(Parameters.CHANGED_FIELD, parameters, + constants.DEFAULT_CHNGD_FIELD) if events is None: - events = pandas_utils.instantiate_dataframe({self.event_id_column: [], self.event_activity: [], self.event_timestamp: []}) + events = pandas_utils.instantiate_dataframe( + {self.event_id_column: [], self.event_activity: [], self.event_timestamp: []}) if objects is None: objects = pandas_utils.instantiate_dataframe({self.object_id_column: [], self.object_type_column: []}) if relations is None: @@ -46,11 +50,15 @@ def __init__(self, events=None, objects=None, relations=None, globals=None, para if globals is None: globals = {} if o2o is None: - o2o = pandas_utils.instantiate_dataframe({self.object_id_column: [], self.object_id_column+"_2": [], self.qualifier: []}) + o2o = pandas_utils.instantiate_dataframe( + {self.object_id_column: [], self.object_id_column + "_2": [], self.qualifier: []}) if e2e is None: - e2e = pandas_utils.instantiate_dataframe({self.event_id_column: [], self.event_id_column+"_2": [], self.qualifier: []}) + e2e = pandas_utils.instantiate_dataframe( + {self.event_id_column: [], self.event_id_column + "_2": [], self.qualifier: []}) if object_changes is None: - object_changes = pandas_utils.instantiate_dataframe({self.object_id_column: [], self.object_type_column: [], self.event_timestamp: [], self.changed_field: []}) + object_changes = pandas_utils.instantiate_dataframe( + {self.object_id_column: [], self.object_type_column: [], self.event_timestamp: [], + self.changed_field: []}) if self.qualifier not in relations: relations[self.qualifier] = [None] * len(relations) @@ -90,10 +98,13 @@ def get_summary(self) -> str: ret.append(", number of object types: %d" % (self.objects[self.object_type_column].nunique())) ret.append(", events-objects relationships: %d)" % (len(self.relations))) ret.append("\n") - ret.append("Activities occurrences: " + str(self.events[self.event_activity].value_counts().to_dict())) + ret.append("Activities occurrences: " + str(Counter(self.events[self.event_activity].value_counts().to_dict()))) ret.append("\n") ret.append("Object types occurrences (number of objects): " + str( - self.objects[self.object_type_column].value_counts().to_dict())) + Counter(self.objects[self.object_type_column].value_counts().to_dict()))) + ret.append("\n") + ret.append("Unique activities per object type: " + str( + Counter(self.relations.groupby(self.object_type_column)[self.event_activity].nunique().to_dict()))) ret.append("\n") ret.append( "Please use .get_extended_table() to get a dataframe representation of the events related to the objects.") @@ -102,7 +113,8 @@ def get_summary(self) -> str: def is_ocel20(self): unique_qualifiers = [] if self.qualifier in self.relations.columns: - unique_qualifiers = [x for x in pandas_utils.format_unique(self.relations[self.qualifier].unique()) if not self.__check_is_nan(x)] + unique_qualifiers = [x for x in pandas_utils.format_unique(self.relations[self.qualifier].unique()) if + not self.__check_is_nan(x)] return len(self.o2o) > 0 or len(self.object_changes) > 0 or len(unique_qualifiers) > 0 @@ -122,7 +134,8 @@ def __repr__(self): return str(self.get_summary()) def __copy__(self): - return OCEL(self.events, self.objects, self.relations, copy(self.globals), copy(self.parameters), copy(self.o2o), copy(self.e2e), copy(self.object_changes)) + return OCEL(self.events, self.objects, self.relations, copy(self.globals), copy(self.parameters), + copy(self.o2o), copy(self.e2e), copy(self.object_changes)) def __deepcopy__(self, memo): return OCEL(self.events.copy(), self.objects.copy(), self.relations.copy(), deepcopy(self.globals), From c7500a422ccc935d63301380f87d5f02c5e48c31 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 13 May 2024 12:47:13 +0200 Subject: [PATCH 29/52] fix(pm4py): trigger warnings in OCEL importing when event/object identifiers are not unique in the event log --- pm4py/objects/ocel/util/ocel_consistency.py | 23 +++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/pm4py/objects/ocel/util/ocel_consistency.py b/pm4py/objects/ocel/util/ocel_consistency.py index 6cb001c2e..ff2490b33 100644 --- a/pm4py/objects/ocel/util/ocel_consistency.py +++ b/pm4py/objects/ocel/util/ocel_consistency.py @@ -1,5 +1,6 @@ from pm4py.objects.ocel.obj import OCEL from typing import Optional, Dict, Any +import warnings def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None) -> OCEL: @@ -23,12 +24,12 @@ def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None) -> OCEL: parameters = {} fields = { - "events": ["ocel:eid", "ocel:activity"], - "objects": ["ocel:oid", "ocel:type"], - "relations": ["ocel:eid", "ocel:oid", "ocel:activity", "ocel:type"], - "o2o": ["ocel:oid", "ocel:oid_2"], - "e2e": ["ocel:eid", "ocel:eid_2"], - "object_changes": ["ocel:oid"] + "events": [ocel.event_id_column, ocel.event_activity], + "objects": [ocel.object_id_column, ocel.object_type_column], + "relations": [ocel.event_id_column, ocel.object_id_column, ocel.event_activity, ocel.object_type_column], + "o2o": [ocel.object_id_column, ocel.object_id_column+"_2"], + "e2e": [ocel.event_id_column, ocel.event_id_column+"_2"], + "object_changes": [ocel.object_id_column] } for tab in fields: @@ -40,4 +41,14 @@ def apply(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None) -> OCEL: df = df[df[fie].str.len() > 0] setattr(ocel, tab, df) + # check if the event IDs or object IDs are unique + num_ev_ids = ocel.events[ocel.event_id_column].nunique() + num_obj_ids = ocel.objects[ocel.object_id_column].nunique() + + if num_ev_ids < len(ocel.events): + warnings.warn("The event identifiers in the OCEL are not unique!") + + if num_obj_ids < len(ocel.objects): + warnings.warn("The object identifiers in the OCEL are not unique!") + return ocel From 140b9e52a44155caf37b847bc793020a2fd02532 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 13 May 2024 12:57:45 +0200 Subject: [PATCH 30/52] fix(pm4py): hotfixing BPMN import when no waypoints per flow are provided --- pm4py/objects/bpmn/importer/variants/lxml.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pm4py/objects/bpmn/importer/variants/lxml.py b/pm4py/objects/bpmn/importer/variants/lxml.py index 906a21643..4349540b2 100644 --- a/pm4py/objects/bpmn/importer/variants/lxml.py +++ b/pm4py/objects/bpmn/importer/variants/lxml.py @@ -255,7 +255,11 @@ def parse_element(bpmn_graph, counts, curr_el, parents, incoming_dict, outgoing_ if outgoing_dict[seq_flow_id][0] in nodes_dict: outgoing_dict[seq_flow_id] = (nodes_dict[outgoing_dict[seq_flow_id][0]], outgoing_dict[seq_flow_id][1], outgoing_dict[seq_flow_id][2], outgoing_dict[seq_flow_id][3], outgoing_dict[seq_flow_id][4]) - + # also supports flows without waypoints + flows_without_waypoints = set(flow_info).union(set(outgoing_dict).intersection(set(incoming_dict))) + for flow_id in flows_without_waypoints: + flow_info[flow_id] = [] + for flow_id in flow_info: if flow_id in outgoing_dict and flow_id in incoming_dict: flow = None From 709936a70fab98ae80e3bb44673605d48a62569b Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 27 May 2024 07:59:04 +0200 Subject: [PATCH 31/52] docs(pm4py): updated changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 395236b38..8bc72936e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ ### Fixed * 954c2fbdc258b90bcba85001592a5d2950a79724 * bug fix temporal profile conformance checking +* cd8f9fb9f49a5955f0a26f547770aefa8ff222b8 + * issue with closing in-memory files when parsing a XES from string +* d51bd9e24aed442f011917d6b77793b118bbf89f + * minor fix OCEL interleavings computation ### Removed @@ -28,7 +32,8 @@ * printing Python versions in tests and examples * c48882b88326608dc5c6a4101b8123c71a852e18 * parameter to enable/disable visualizations - +* 607d2eb601299a23335f8c1976cc59f63bcae5f2 + * added example for Inductive Miner LC --- From 013d6f5ce02189402298adb26a68208870ea6c07 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 27 May 2024 07:59:47 +0200 Subject: [PATCH 32/52] performed safety check --- safety_checks/20270524 | Bin 0 -> 4278 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 safety_checks/20270524 diff --git a/safety_checks/20270524 b/safety_checks/20270524 new file mode 100644 index 0000000000000000000000000000000000000000..7d0483a704db6e1dd8e88d11d0a592b34b55ed2b GIT binary patch literal 4278 zcmeHJU60aG5S?ce|3e>4d|08#`VmPqzUZTF_QNL=QlKm-P^2s_$^LfroEe5&ppCnc zO(fYgZSS3X?#!7pb1A=n9m(7O_&Sou@<{JU{^g40N#UyUWGF_gLfpn~UfR-DFN|BZ z>jqY?RY%+8Y+g2Pk+>H|_=<>aiE(Y`x@(D6C}U>pRZMJ^zU_(;>t;Qp2gY+IA>Xhs zV1g!OO1tkXj?0-4X|X&%&OH;i1t!}O0>ZQ`MlMD#j?0<2*3^S&%egFHUn45y>Pl`i z^jwO}d|buEqK4dJRdiFQpo#G?CfgWi80_V~%9(_Y2whUt$*qR7+8Z0|+igw4UdIL; z_c7ygCZ6N{y-joa|66tLkAp`K)uJNtT9b|}!7rCY`jW~Vv#yL}D0RFu8Dnj~SEvpv zX*^h;!}-3P$_F`-&vGi~(1zT-zs?FOM$jNu&cmtPE=uNe`B}S`+L_QLhMm1{#%oeBF5*OJlWbsnIj| z>cNu0Ki~8`R_`h1^yXQ81g9D1WSan2LtJ9XkgNylgN*6tHk_XU*N2bml~?ODdL$R- zHAKt_coNC%7Px21ZmGP;WvaZ0rMg6Rp-e}S+|yMhU9TLo>3R>*b6^tfaMxgp7@2(2 zy>lQKfx6Id1SD|@Vx^k>1RjEZV`Y;nJ68M>SXO_k7$OJ2&oR%Xg}#q5TIzZo=nU(o zGJPkoj9}rZ93fgR@3+v^UAK^9RPQ-%*4uh8M+W3R!Q48rzl!z+49Yres8Q?iQeXGM z*^ZYUP}aE|O|WkJ7?;^E5ry4s)wWDp>d$+tChxFX$A1!5^as#G9a%5Tk$D@p^*Q&~ zF}}uK%>M!i&ubqi$+@xbuaHOalmsQM+ne$V{HIX2E8p>CZ{%ym&cTbBSO#O@B59&7 zO?iP+)R32WHsv*}4Ln)hBrW o)PCDN^>@|IfA^^2;V2Qw! Date: Mon, 1 Jul 2024 06:42:58 +0200 Subject: [PATCH 33/52] updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bc72936e..c887cbe5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ * issue with closing in-memory files when parsing a XES from string * d51bd9e24aed442f011917d6b77793b118bbf89f * minor fix OCEL interleavings computation +* 39d769cad1327c47d5948b0c40be4a90e41fcce7 + * removed indeterminism in TBR with duplicate transitions ### Removed From 82286504adac8ff3cf3bafecd4f9e8e3da508a1b Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 07:51:30 +0200 Subject: [PATCH 34/52] feat(pm4py): improved DFG sorting for visualization based on reachability from start/end activities --- pm4py/visualization/dfg/util/dfg_gviz.py | 88 ++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 6 deletions(-) diff --git a/pm4py/visualization/dfg/util/dfg_gviz.py b/pm4py/visualization/dfg/util/dfg_gviz.py index f16f46608..af729abba 100644 --- a/pm4py/visualization/dfg/util/dfg_gviz.py +++ b/pm4py/visualization/dfg/util/dfg_gviz.py @@ -1,8 +1,11 @@ import tempfile from copy import copy +import sys from graphviz import Digraph from pm4py.util import constants +from typing import Dict, List, Tuple +from collections import defaultdict, deque from pm4py.visualization.common.utils import * @@ -116,6 +119,78 @@ def assign_penwidth_edges(dfg): return penwidth +def sort_dfg_reachability(dfg: List[Tuple[str, str]], + start_activities_to_include: List[str], + end_activities_to_include: List[str]) -> Tuple[List[str], List[Tuple[str, str]]]: + """ + Sort the edges of the directly-follows graph based on reachability principles + (start activities are putting at the beginning, end activities at the end) + + Parameters + ---------------- + dfg + List of edges of the directly-follows graph (without frequency/performance annotation) + start_activities_to_include + Start activities + end_activities + End activities + + Returns + ---------------- + sorted_activities + Activities sorted by reachability + sorted_edges + Edges sorted by reachability + """ + # identify all unique activities + activities_dfg = set(x[0] for x in dfg).union(set(x[1] for x in dfg)) + + # create adjacency lists and in-degree count + adjacency_list = defaultdict(list) + in_degree = defaultdict(int) + + for u, v in dfg: + adjacency_list[u].append(v) + in_degree[v] += 1 + if u not in in_degree: + in_degree[u] = 0 + + # initialize the queue with start activities + queue = deque(start_activities_to_include) + distance = {activity: 0 for activity in start_activities_to_include} + + # ensure all activities are present in the distance dictionary + for activity in activities_dfg: + if activity not in distance: + distance[activity] = float('inf') + + # perform BFS to calculate the distance of each activity from the start activities + while queue: + current = queue.popleft() + current_distance = distance[current] + + for neighbor in adjacency_list[current]: + if distance[neighbor] > current_distance + 1: + distance[neighbor] = current_distance + 1 + queue.append(neighbor) + + # sort edges based on the distance of their source activities + def edge_priority(edge): + u, v = edge + if u in start_activities_to_include: + return (0, distance[u], distance[v], u, v) + if v in end_activities_to_include: + return (2, distance[u], distance[v], u, v) + return (1, distance[u], distance[v], u, v) + + sorted_edges = sorted(dfg, key=edge_priority) + + # Step 6: Sort activities based on their distance + sorted_activities = sorted(activities_dfg, key=lambda x: (distance[x], x)) + + return sorted_activities, sorted_edges + + def graphviz_visualization(activities_count, dfg, image_format="png", measure="frequency", max_no_of_edges_in_diagram=100000, start_activities=None, end_activities=None, serv_time=None, font_size="12", bgcolor=constants.DEFAULT_BGCOLOR, rankdir=constants.DEFAULT_RANKDIR_GVIZ): @@ -198,6 +273,13 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f # take unique elements as a list not as a set (in this way, nodes are added in the same order to the graph) activities_to_include = sorted(list(set(activities_in_dfg))) + start_activities_to_include = [act for act in start_activities if act in activities_to_include] + end_activities_to_include = [act for act in end_activities if act in activities_to_include] + + dfg_edges = sorted(list(dfg.keys())) + if start_activities_to_include and end_activities_to_include: + activities_to_include, dfg_edges = sort_dfg_reachability(dfg_edges, start_activities_to_include, end_activities_to_include) + activities_map = {} for act in activities_to_include: @@ -213,9 +295,6 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f viz.node(str(hash(act)), act, fontsize=font_size) activities_map[act] = str(hash(act)) - # make edges addition always in the same order - dfg_edges = sorted(list(dfg.keys())) - # represent edges for edge in dfg_edges: if "frequency" in measure or "cost" in measure: @@ -224,9 +303,6 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f label = human_readable_stat(dfg[edge]) viz.edge(str(hash(edge[0])), str(hash(edge[1])), label=label, penwidth=str(penwidth[edge]), fontsize=font_size) - start_activities_to_include = [act for act in start_activities if act in activities_map] - end_activities_to_include = [act for act in end_activities if act in activities_map] - if start_activities_to_include: viz.node("@@startnode", "<●>", shape='circle', fontsize="34") for act in start_activities_to_include: From 236acbe936c0a38d2ace5c2e99218a342db9e781 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 07:52:17 +0200 Subject: [PATCH 35/52] Revert "feat(pm4py): improved DFG sorting for visualization based on reachability from start/end activities" This reverts commit 82286504adac8ff3cf3bafecd4f9e8e3da508a1b. --- pm4py/visualization/dfg/util/dfg_gviz.py | 88 ++---------------------- 1 file changed, 6 insertions(+), 82 deletions(-) diff --git a/pm4py/visualization/dfg/util/dfg_gviz.py b/pm4py/visualization/dfg/util/dfg_gviz.py index af729abba..f16f46608 100644 --- a/pm4py/visualization/dfg/util/dfg_gviz.py +++ b/pm4py/visualization/dfg/util/dfg_gviz.py @@ -1,11 +1,8 @@ import tempfile from copy import copy -import sys from graphviz import Digraph from pm4py.util import constants -from typing import Dict, List, Tuple -from collections import defaultdict, deque from pm4py.visualization.common.utils import * @@ -119,78 +116,6 @@ def assign_penwidth_edges(dfg): return penwidth -def sort_dfg_reachability(dfg: List[Tuple[str, str]], - start_activities_to_include: List[str], - end_activities_to_include: List[str]) -> Tuple[List[str], List[Tuple[str, str]]]: - """ - Sort the edges of the directly-follows graph based on reachability principles - (start activities are putting at the beginning, end activities at the end) - - Parameters - ---------------- - dfg - List of edges of the directly-follows graph (without frequency/performance annotation) - start_activities_to_include - Start activities - end_activities - End activities - - Returns - ---------------- - sorted_activities - Activities sorted by reachability - sorted_edges - Edges sorted by reachability - """ - # identify all unique activities - activities_dfg = set(x[0] for x in dfg).union(set(x[1] for x in dfg)) - - # create adjacency lists and in-degree count - adjacency_list = defaultdict(list) - in_degree = defaultdict(int) - - for u, v in dfg: - adjacency_list[u].append(v) - in_degree[v] += 1 - if u not in in_degree: - in_degree[u] = 0 - - # initialize the queue with start activities - queue = deque(start_activities_to_include) - distance = {activity: 0 for activity in start_activities_to_include} - - # ensure all activities are present in the distance dictionary - for activity in activities_dfg: - if activity not in distance: - distance[activity] = float('inf') - - # perform BFS to calculate the distance of each activity from the start activities - while queue: - current = queue.popleft() - current_distance = distance[current] - - for neighbor in adjacency_list[current]: - if distance[neighbor] > current_distance + 1: - distance[neighbor] = current_distance + 1 - queue.append(neighbor) - - # sort edges based on the distance of their source activities - def edge_priority(edge): - u, v = edge - if u in start_activities_to_include: - return (0, distance[u], distance[v], u, v) - if v in end_activities_to_include: - return (2, distance[u], distance[v], u, v) - return (1, distance[u], distance[v], u, v) - - sorted_edges = sorted(dfg, key=edge_priority) - - # Step 6: Sort activities based on their distance - sorted_activities = sorted(activities_dfg, key=lambda x: (distance[x], x)) - - return sorted_activities, sorted_edges - - def graphviz_visualization(activities_count, dfg, image_format="png", measure="frequency", max_no_of_edges_in_diagram=100000, start_activities=None, end_activities=None, serv_time=None, font_size="12", bgcolor=constants.DEFAULT_BGCOLOR, rankdir=constants.DEFAULT_RANKDIR_GVIZ): @@ -273,13 +198,6 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f # take unique elements as a list not as a set (in this way, nodes are added in the same order to the graph) activities_to_include = sorted(list(set(activities_in_dfg))) - start_activities_to_include = [act for act in start_activities if act in activities_to_include] - end_activities_to_include = [act for act in end_activities if act in activities_to_include] - - dfg_edges = sorted(list(dfg.keys())) - if start_activities_to_include and end_activities_to_include: - activities_to_include, dfg_edges = sort_dfg_reachability(dfg_edges, start_activities_to_include, end_activities_to_include) - activities_map = {} for act in activities_to_include: @@ -295,6 +213,9 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f viz.node(str(hash(act)), act, fontsize=font_size) activities_map[act] = str(hash(act)) + # make edges addition always in the same order + dfg_edges = sorted(list(dfg.keys())) + # represent edges for edge in dfg_edges: if "frequency" in measure or "cost" in measure: @@ -303,6 +224,9 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f label = human_readable_stat(dfg[edge]) viz.edge(str(hash(edge[0])), str(hash(edge[1])), label=label, penwidth=str(penwidth[edge]), fontsize=font_size) + start_activities_to_include = [act for act in start_activities if act in activities_map] + end_activities_to_include = [act for act in end_activities if act in activities_map] + if start_activities_to_include: viz.node("@@startnode", "<●>", shape='circle', fontsize="34") for act in start_activities_to_include: From c5338435127d9019e885747f067e6b04e498bdaa Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 09:25:06 +0200 Subject: [PATCH 36/52] feat(pm4py): changes to the header in the dfg vis --- pm4py/visualization/dfg/util/dfg_gviz.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pm4py/visualization/dfg/util/dfg_gviz.py b/pm4py/visualization/dfg/util/dfg_gviz.py index f16f46608..0f38d0c34 100644 --- a/pm4py/visualization/dfg/util/dfg_gviz.py +++ b/pm4py/visualization/dfg/util/dfg_gviz.py @@ -1,8 +1,11 @@ import tempfile from copy import copy +import sys from graphviz import Digraph from pm4py.util import constants +from typing import Dict, List, Tuple +from collections import defaultdict, deque from pm4py.visualization.common.utils import * @@ -198,6 +201,11 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f # take unique elements as a list not as a set (in this way, nodes are added in the same order to the graph) activities_to_include = sorted(list(set(activities_in_dfg))) + start_activities_to_include = [act for act in start_activities if act in activities_to_include] + end_activities_to_include = [act for act in end_activities if act in activities_to_include] + + dfg_edges = sorted(list(dfg.keys())) + activities_map = {} for act in activities_to_include: @@ -213,9 +221,6 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f viz.node(str(hash(act)), act, fontsize=font_size) activities_map[act] = str(hash(act)) - # make edges addition always in the same order - dfg_edges = sorted(list(dfg.keys())) - # represent edges for edge in dfg_edges: if "frequency" in measure or "cost" in measure: @@ -224,9 +229,6 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f label = human_readable_stat(dfg[edge]) viz.edge(str(hash(edge[0])), str(hash(edge[1])), label=label, penwidth=str(penwidth[edge]), fontsize=font_size) - start_activities_to_include = [act for act in start_activities if act in activities_map] - end_activities_to_include = [act for act in end_activities if act in activities_map] - if start_activities_to_include: viz.node("@@startnode", "<●>", shape='circle', fontsize="34") for act in start_activities_to_include: From 261c33050d9a6a317492ad1aa7144b3b6a41bfd8 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 09:26:37 +0200 Subject: [PATCH 37/52] feat(pm4py): changes to the header in the dfg vis --- pm4py/visualization/dfg/util/dfg_gviz.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pm4py/visualization/dfg/util/dfg_gviz.py b/pm4py/visualization/dfg/util/dfg_gviz.py index 0f38d0c34..366b51d56 100644 --- a/pm4py/visualization/dfg/util/dfg_gviz.py +++ b/pm4py/visualization/dfg/util/dfg_gviz.py @@ -179,9 +179,6 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f if edge not in dfg_allowed_keys: del dfg[edge] - # calculate edges penwidth - penwidth = assign_penwidth_edges(dfg) - activities_count_int = copy(activities_count) activities_in_dfg = set(activities_count) @@ -204,6 +201,9 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f start_activities_to_include = [act for act in start_activities if act in activities_to_include] end_activities_to_include = [act for act in end_activities if act in activities_to_include] + # calculate edges penwidth + penwidth = assign_penwidth_edges(dfg) + dfg_edges = sorted(list(dfg.keys())) activities_map = {} From ac9674c547129f76fa7ab7edce167d42236e4bae Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 09:36:30 +0200 Subject: [PATCH 38/52] feat(pm4py): fixing penwidth assignation in start/end edges of DFG visualization --- pm4py/visualization/dfg/util/dfg_gviz.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pm4py/visualization/dfg/util/dfg_gviz.py b/pm4py/visualization/dfg/util/dfg_gviz.py index 366b51d56..4faca4d8b 100644 --- a/pm4py/visualization/dfg/util/dfg_gviz.py +++ b/pm4py/visualization/dfg/util/dfg_gviz.py @@ -202,7 +202,15 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f end_activities_to_include = [act for act in end_activities if act in activities_to_include] # calculate edges penwidth - penwidth = assign_penwidth_edges(dfg) + ext_dfg = copy(dfg) + if start_activities_to_include is not None and start_activities_to_include: + for sact in start_activities_to_include: + ext_dfg[(constants.DEFAULT_ARTIFICIAL_START_ACTIVITY, sact)] = start_activities[sact] + if end_activities_to_include is not None and end_activities_to_include: + for eact in end_activities_to_include: + ext_dfg[(eact, constants.DEFAULT_ARTIFICIAL_END_ACTIVITY)] = end_activities[eact] + + penwidth = assign_penwidth_edges(ext_dfg) dfg_edges = sorted(list(dfg.keys())) @@ -233,14 +241,14 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f viz.node("@@startnode", "<●>", shape='circle', fontsize="34") for act in start_activities_to_include: label = str(start_activities[act]) if isinstance(start_activities, dict) and measure == "frequency" else "" - viz.edge("@@startnode", activities_map[act], label=label, fontsize=font_size) + viz.edge("@@startnode", activities_map[act], label=label, fontsize=font_size, penwidth=str(penwidth[(constants.DEFAULT_ARTIFICIAL_START_ACTIVITY, act)])) if end_activities_to_include: # <■> viz.node("@@endnode", "<■>", shape='doublecircle', fontsize="32") for act in end_activities_to_include: label = str(end_activities[act]) if isinstance(end_activities, dict) and measure == "frequency" else "" - viz.edge(activities_map[act], "@@endnode", label=label, fontsize=font_size) + viz.edge(activities_map[act], "@@endnode", label=label, fontsize=font_size, penwidth=str(penwidth[(act, constants.DEFAULT_ARTIFICIAL_END_ACTIVITY)])) viz.attr(overlap='false') viz.attr(fontsize='11') From ae743493114bbd3b0b9794c4f92e7166f1964311 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 11:21:53 +0200 Subject: [PATCH 39/52] feat(pm4py): changing petri net visualize imports --- pm4py/visualization/petri_net/common/visualize.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pm4py/visualization/petri_net/common/visualize.py b/pm4py/visualization/petri_net/common/visualize.py index d2227de44..82964508f 100644 --- a/pm4py/visualization/petri_net/common/visualize.py +++ b/pm4py/visualization/petri_net/common/visualize.py @@ -3,9 +3,12 @@ from graphviz import Digraph from pm4py.objects.petri_net.obj import Marking +from pm4py.objects.petri_net.obj import Marking, PetriNet from pm4py.objects.petri_net import properties as petri_properties from pm4py.util import exec_utils, constants from enum import Enum +from typing import List, Tuple, Dict +from collections import defaultdict, deque from pm4py.util.constants import PARAMETER_CONSTANT_ACTIVITY_KEY, PARAMETER_CONSTANT_TIMESTAMP_KEY From da9c33b59af62199ab0952f8839ed1e2f7e7783f Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 11:22:58 +0200 Subject: [PATCH 40/52] fix --- pm4py/visualization/petri_net/common/visualize.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pm4py/visualization/petri_net/common/visualize.py b/pm4py/visualization/petri_net/common/visualize.py index 82964508f..27d6ca682 100644 --- a/pm4py/visualization/petri_net/common/visualize.py +++ b/pm4py/visualization/petri_net/common/visualize.py @@ -2,7 +2,6 @@ from graphviz import Digraph -from pm4py.objects.petri_net.obj import Marking from pm4py.objects.petri_net.obj import Marking, PetriNet from pm4py.objects.petri_net import properties as petri_properties from pm4py.util import exec_utils, constants From 226911eaab6cad11b9411cbf0758ac76db15b573 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 11:42:10 +0200 Subject: [PATCH 41/52] feat(pm4py): preliminary visualization commit shared by several MRs --- pm4py/util/constants.py | 1 + pm4py/visualization/dfg/util/dfg_gviz.py | 10 +++++++++- .../visualization/petri_net/common/visualize.py | 17 +++++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/pm4py/util/constants.py b/pm4py/util/constants.py index 4a8d84c5c..5625e9e78 100644 --- a/pm4py/util/constants.py +++ b/pm4py/util/constants.py @@ -121,6 +121,7 @@ def get_default_is_aware_enabled(): OPENAI_EXEC_RESULT = True if get_param_from_env("PM4PY_OPENAI_EXEC_RESULT", "False").lower() == "true" else False DEFAULT_GVIZ_VIEW = get_param_from_env("PM4PY_DEFAULT_GVIZ_VIEW", None) DEFAULT_ENABLE_VISUALIZATIONS_VIEW = get_param_from_env("PM4PY_DEFAULT_ENABLE_VISUALIZATIONS_VIEW", True) +DEFAULT_ENABLE_GRAPH_TITLES = get_param_from_env("PM4PY_DEFAULT_ENABLE_GRAPH_TITLES", False) JQUERY_LINK = "https://code.jquery.com/jquery-3.6.3.min.js" GRAPHVIZJS_LINK = "https://github.com/mdaines/viz-js/releases/download/v1.8.2/viz.js" diff --git a/pm4py/visualization/dfg/util/dfg_gviz.py b/pm4py/visualization/dfg/util/dfg_gviz.py index 366b51d56..6f1d1dbe2 100644 --- a/pm4py/visualization/dfg/util/dfg_gviz.py +++ b/pm4py/visualization/dfg/util/dfg_gviz.py @@ -121,7 +121,8 @@ def assign_penwidth_edges(dfg): def graphviz_visualization(activities_count, dfg, image_format="png", measure="frequency", max_no_of_edges_in_diagram=100000, start_activities=None, end_activities=None, serv_time=None, - font_size="12", bgcolor=constants.DEFAULT_BGCOLOR, rankdir=constants.DEFAULT_RANKDIR_GVIZ): + font_size="12", bgcolor=constants.DEFAULT_BGCOLOR, rankdir=constants.DEFAULT_RANKDIR_GVIZ, + enable_graph_title: bool = constants.DEFAULT_ENABLE_GRAPH_TITLES, graph_title: str = "Directly-Follows Graph"): """ Do GraphViz visualization of a DFG graph @@ -149,6 +150,10 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f Background color of the visualization (i.e., 'transparent', 'white', ...) rankdir Direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + enable_graph_title + Enables the visualization of a graph's title + graph_title + Graph title to display (if enable_graph_title) Returns ----------- @@ -165,6 +170,9 @@ def graphviz_visualization(activities_count, dfg, image_format="png", measure="f viz = Digraph("", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor, 'rankdir': rankdir}) + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + # first, remove edges in diagram that exceeds the maximum number of edges in the diagram dfg_key_value_list = [] for edge in dfg: diff --git a/pm4py/visualization/petri_net/common/visualize.py b/pm4py/visualization/petri_net/common/visualize.py index 27d6ca682..ffec643b0 100644 --- a/pm4py/visualization/petri_net/common/visualize.py +++ b/pm4py/visualization/petri_net/common/visualize.py @@ -21,6 +21,8 @@ class Parameters(Enum): FONT_SIZE = "font_size" BGCOLOR = "bgcolor" DECORATIONS = "decorations" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def apply(net, initial_marking, final_marking, decorations=None, parameters=None): @@ -54,17 +56,21 @@ def apply(net, initial_marking, final_marking, decorations=None, parameters=None set_rankdir = exec_utils.get_param_value(Parameters.RANKDIR, parameters, None) font_size = exec_utils.get_param_value(Parameters.FONT_SIZE, parameters, "12") bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR) + 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, "Petri Net") if decorations is None: decorations = exec_utils.get_param_value(Parameters.DECORATIONS, parameters, None) return graphviz_visualization(net, image_format=image_format, initial_marking=initial_marking, final_marking=final_marking, decorations=decorations, debug=debug, - set_rankdir=set_rankdir, font_size=font_size, bgcolor=bgcolor) + set_rankdir=set_rankdir, font_size=font_size, bgcolor=bgcolor, + enable_graph_title=enable_graph_title, graph_title=graph_title) def graphviz_visualization(net, image_format="png", initial_marking=None, final_marking=None, decorations=None, - debug=False, set_rankdir=None, font_size="12", bgcolor=constants.DEFAULT_BGCOLOR): + debug=False, set_rankdir=None, font_size="12", bgcolor=constants.DEFAULT_BGCOLOR, + enable_graph_title: bool = constants.DEFAULT_ENABLE_GRAPH_TITLES, graph_title: str = "Petri Net"): """ Provides visualization for the petrinet @@ -84,6 +90,10 @@ def graphviz_visualization(net, image_format="png", initial_marking=None, final_ Enables debug mode set_rankdir Sets the rankdir to LR (horizontal layout) + enable_graph_title + Enables the visualization of a graph's title + graph_title + Graph title to display (if enable_graph_title) Returns ------- @@ -108,6 +118,9 @@ def graphviz_visualization(net, image_format="png", initial_marking=None, final_ else: viz.graph_attr['rankdir'] = 'LR' + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + # transitions viz.attr('node', shape='box') for t in net.transitions: From b13800b89e90b06a74310bd2674e08b2d590a159 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 11:56:36 +0200 Subject: [PATCH 42/52] feat(pm4py): intermediate commit shared by some MRs --- .../align_table/variants/classic.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/pm4py/visualization/align_table/variants/classic.py b/pm4py/visualization/align_table/variants/classic.py index 24dcf1303..d0a49c02d 100644 --- a/pm4py/visualization/align_table/variants/classic.py +++ b/pm4py/visualization/align_table/variants/classic.py @@ -2,7 +2,7 @@ import tempfile from pm4py.statistics.variants.log import get as variants_get -from pm4py.util import exec_utils +from pm4py.util import exec_utils, constants from enum import Enum from typing import Optional, Dict, Any from pm4py.objects.log.obj import EventLog @@ -12,6 +12,8 @@ class Parameters(Enum): FORMAT = "format" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def apply(log: EventLog, aligned_traces: typing.ListAlignments, parameters: Optional[Dict[Any, Any]] = None) -> graphviz.Source: @@ -43,8 +45,18 @@ def apply(log: EventLog, aligned_traces: typing.ListAlignments, parameters: Opti variants_idx_list = sorted(variants_idx_list, key=lambda x: len(x[1]), reverse=True) image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") + 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, "Alignments") + + table_alignments_list = ["digraph {\n"] + + if enable_graph_title: + table_alignments_list.append('label=<'+graph_title+'>;\nlabelloc="top";\n') + + table_alignments_list.append("tbl [\n") + table_alignments_list.append("shape=plaintext\n") + table_alignments_list.append("label=<\n") - table_alignments_list = ["digraph {\n", "tbl [\n", "shape=plaintext\n", "label=<\n"] table_alignments_list.append("\n") table_alignments_list.append("\n") @@ -79,6 +91,7 @@ def apply(log: EventLog, aligned_traces: typing.ListAlignments, parameters: Opti filename.close() gviz = Source(table_alignments, filename=filename.name) + gviz.format = image_format return gviz From 96c54b0389bfef719727005b585219f893394d38 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 13:59:26 +0200 Subject: [PATCH 43/52] feat(pm4py): possibility to set the visualization's title in pm4py visualizations --- pm4py/vis.py | 402 ++++++++++++++---- pm4py/visualization/bpmn/variants/classic.py | 7 + pm4py/visualization/dfg/variants/cost.py | 7 +- pm4py/visualization/dfg/variants/frequency.py | 7 +- .../visualization/dfg/variants/performance.py | 7 +- .../dotted_chart/variants/classic.py | 11 +- .../footprints/variants/comparison.py | 16 +- .../variants/comparison_symmetric.py | 16 +- .../footprints/variants/single.py | 16 +- .../heuristics_net/variants/pydotplus_vis.py | 11 + .../network_analysis/variants/frequency.py | 8 + .../network_analysis/variants/performance.py | 8 + .../ocel/object_graph/variants/graphviz.py | 8 + .../ocel/ocdfg/variants/classic.py | 7 + .../ocel/ocpn/variants/wo_decoration.py | 10 +- .../performance_spectrum/variants/neato.py | 10 +- pm4py/visualization/powl/variants/basic.py | 12 +- pm4py/visualization/powl/variants/net.py | 16 +- pm4py/visualization/powl/visualizer.py | 2 +- .../variants/frequency_annotation.py | 9 + .../process_tree/variants/symbolic.py | 9 + .../process_tree/variants/wo_decoration.py | 9 + .../util/visualize_graphviz.py | 7 + .../variants/trans_frequency.py | 8 + .../transition_system/variants/view_based.py | 2 + pm4py/visualization/trie/variants/classic.py | 8 + 26 files changed, 539 insertions(+), 94 deletions(-) diff --git a/pm4py/vis.py b/pm4py/vis.py index aad3f27ed..baf77572f 100644 --- a/pm4py/vis.py +++ b/pm4py/vis.py @@ -26,7 +26,8 @@ def view_petri_net(petri_net: PetriNet, initial_marking: Optional[Marking] = None, final_marking: Optional[Marking] = None, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", - decorations: Dict[Any, Any] = None, debug: bool = False, rankdir: str = constants.DEFAULT_RANKDIR_GVIZ): + decorations: Dict[Any, Any] = None, debug: bool = False, rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, + graph_title: Optional[str] = None): """ Views a (composite) Petri net @@ -38,6 +39,7 @@ def view_petri_net(petri_net: PetriNet, initial_marking: Optional[Marking] = Non :param decorations: Decorations (color, label) associated to the elements of the Petri net :param debug: Boolean enabling/disabling the debug mode (show place and transition's names) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -48,13 +50,19 @@ def view_petri_net(petri_net: PetriNet, initial_marking: Optional[Marking] = Non """ format = str(format).lower() from pm4py.visualization.petri_net import visualizer as pn_visualizer + parameters = {pn_visualizer.Variants.WO_DECORATION.value.Parameters.FORMAT: format, "bgcolor": bgcolor, "decorations": decorations, "debug": debug, "set_rankdir": rankdir} + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title gviz = pn_visualizer.apply(petri_net, initial_marking, final_marking, - parameters={pn_visualizer.Variants.WO_DECORATION.value.Parameters.FORMAT: format, "bgcolor": bgcolor, "decorations": decorations, "debug": debug, "set_rankdir": rankdir}) + parameters=parameters) pn_visualizer.view(gviz) def save_vis_petri_net(petri_net: PetriNet, initial_marking: Marking, final_marking: Marking, file_path: str, bgcolor: str = "white", - decorations: Dict[Any, Any] = None, debug: bool = False, rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, **kwargs): + decorations: Dict[Any, Any] = None, debug: bool = False, rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, + graph_title: Optional[str] = None, **kwargs): """ Saves a Petri net visualization to a file @@ -66,6 +74,7 @@ def save_vis_petri_net(petri_net: PetriNet, initial_marking: Marking, final_mark :param decorations: Decorations (color, label) associated to the elements of the Petri net :param debug: Boolean enabling/disabling the debug mode (show place and transition's names) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -77,13 +86,19 @@ def save_vis_petri_net(petri_net: PetriNet, initial_marking: Marking, final_mark file_path = str(file_path) format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.petri_net import visualizer as pn_visualizer + parameters = {pn_visualizer.Variants.WO_DECORATION.value.Parameters.FORMAT: format, "bgcolor": bgcolor, "decorations": decorations, "debug": debug, "set_rankdir": rankdir} + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title gviz = pn_visualizer.apply(petri_net, initial_marking, final_marking, - parameters={pn_visualizer.Variants.WO_DECORATION.value.Parameters.FORMAT: format, "bgcolor": bgcolor, "decorations": decorations, "debug": debug, "set_rankdir": rankdir}) + parameters=parameters) return pn_visualizer.save(gviz, file_path) def view_performance_dfg(dfg: dict, start_activities: dict, end_activities: dict, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, - aggregation_measure="mean", bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, serv_time: Optional[Dict[str, float]] = None): + aggregation_measure="mean", bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, serv_time: Optional[Dict[str, float]] = None, + graph_title: Optional[str] = None): """ Views a performance DFG @@ -95,6 +110,7 @@ def view_performance_dfg(dfg: dict, start_activities: dict, end_activities: dict :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) :param serv_time: (optional) provides the activities' service times, used to decorate the graph + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -114,12 +130,17 @@ def view_performance_dfg(dfg: dict, start_activities: dict, end_activities: dict parameters[dfg_parameters.AGGREGATION_MEASURE] = aggregation_measure parameters["bgcolor"] = bgcolor parameters["rankdir"] = rankdir + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title gviz = dfg_perf_visualizer.apply(dfg, serv_time=serv_time, parameters=parameters) dfg_visualizer.view(gviz) def save_vis_performance_dfg(dfg: dict, start_activities: dict, end_activities: dict, file_path: str, - aggregation_measure="mean", bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, serv_time: Optional[Dict[str, float]] = None, **kwargs): + aggregation_measure="mean", bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, serv_time: Optional[Dict[str, float]] = None, + graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of a performance DFG @@ -131,6 +152,7 @@ def save_vis_performance_dfg(dfg: dict, start_activities: dict, end_activities: :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) :param serv_time: (optional) provides the activities' service times, used to decorate the graph + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -151,11 +173,15 @@ def save_vis_performance_dfg(dfg: dict, start_activities: dict, end_activities: parameters[dfg_parameters.AGGREGATION_MEASURE] = aggregation_measure parameters["bgcolor"] = bgcolor parameters["rankdir"] = rankdir + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title gviz = dfg_perf_visualizer.apply(dfg, serv_time=serv_time, parameters=parameters) return dfg_visualizer.save(gviz, file_path) -def view_dfg(dfg: dict, start_activities: dict, end_activities: dict, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", max_num_edges: int = sys.maxsize, rankdir: str = constants.DEFAULT_RANKDIR_GVIZ): +def view_dfg(dfg: dict, start_activities: dict, end_activities: dict, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", max_num_edges: int = sys.maxsize, rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None): """ Views a (composite) DFG @@ -166,6 +192,7 @@ def view_dfg(dfg: dict, start_activities: dict, end_activities: dict, format: st :param bgcolor: Background color of the visualization (default: white) :param max_num_edges: maximum number of edges to represent in the graph :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -184,12 +211,16 @@ def view_dfg(dfg: dict, start_activities: dict, end_activities: dict, format: st parameters["bgcolor"] = bgcolor parameters["rankdir"] = rankdir parameters["maxNoOfEdgesInDiagram"] = max_num_edges + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title gviz = dfg_visualizer.apply(dfg, variant=dfg_visualizer.Variants.FREQUENCY, parameters=parameters) dfg_visualizer.view(gviz) -def save_vis_dfg(dfg: dict, start_activities: dict, end_activities: dict, file_path: str, bgcolor: str = "white", max_num_edges: int = sys.maxsize, rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, **kwargs): +def save_vis_dfg(dfg: dict, start_activities: dict, end_activities: dict, file_path: str, bgcolor: str = "white", max_num_edges: int = sys.maxsize, rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None, **kwargs): """ Saves a DFG visualization to a file @@ -200,6 +231,7 @@ def save_vis_dfg(dfg: dict, start_activities: dict, end_activities: dict, file_p :param bgcolor: Background color of the visualization (default: white) :param max_num_edges: maximum number of edges to represent in the graph :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -219,12 +251,16 @@ def save_vis_dfg(dfg: dict, start_activities: dict, end_activities: dict, file_p parameters["bgcolor"] = bgcolor parameters["rankdir"] = rankdir parameters["maxNoOfEdgesInDiagram"] = max_num_edges + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title gviz = dfg_visualizer.apply(dfg, variant=dfg_visualizer.Variants.FREQUENCY, parameters=parameters) return dfg_visualizer.save(gviz, file_path) -def view_process_tree(tree: ProcessTree, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ): +def view_process_tree(tree: ProcessTree, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None): """ Views a process tree @@ -232,6 +268,7 @@ def view_process_tree(tree: ProcessTree, format: str = constants.DEFAULT_FORMAT_ :param format: Format of the visualization (if html is provided, GraphvizJS is used to render the visualization in an HTML page) :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -243,11 +280,16 @@ def view_process_tree(tree: ProcessTree, format: str = constants.DEFAULT_FORMAT_ format = str(format).lower() from pm4py.visualization.process_tree import visualizer as pt_visualizer parameters = pt_visualizer.Variants.WO_DECORATION.value.Parameters - gviz = pt_visualizer.apply(tree, parameters={parameters.FORMAT: format, "bgcolor": bgcolor, "rankdir": rankdir}) + properties = {parameters.FORMAT: format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + gviz = pt_visualizer.apply(tree, parameters=properties) pt_visualizer.view(gviz) -def save_vis_process_tree(tree: ProcessTree, file_path: str, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, **kwargs): +def save_vis_process_tree(tree: ProcessTree, file_path: str, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of a process tree @@ -255,6 +297,7 @@ def save_vis_process_tree(tree: ProcessTree, file_path: str, bgcolor: str = "whi :param file_path: Destination path :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -267,11 +310,16 @@ def save_vis_process_tree(tree: ProcessTree, file_path: str, bgcolor: str = "whi format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.process_tree import visualizer as pt_visualizer parameters = pt_visualizer.Variants.WO_DECORATION.value.Parameters - gviz = pt_visualizer.apply(tree, parameters={parameters.FORMAT: format, "bgcolor": bgcolor, "rankdir": rankdir}) + properties = {parameters.FORMAT: format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + gviz = pt_visualizer.apply(tree, parameters=properties) return pt_visualizer.save(gviz, file_path) -def save_vis_bpmn(bpmn_graph: BPMN, file_path: str, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, variant_str: str = "classic", **kwargs): +def save_vis_bpmn(bpmn_graph: BPMN, file_path: str, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, variant_str: str = "classic", graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of a BPMN graph @@ -280,6 +328,7 @@ def save_vis_bpmn(bpmn_graph: BPMN, file_path: str, bgcolor: str = "white", rank :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) :param variant_str: variant of the visualization to be used ("classic" or "dagrejs") + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -298,11 +347,17 @@ def save_vis_bpmn(bpmn_graph: BPMN, file_path: str, bgcolor: str = "white", rank elif variant_str == "dagrejs": variant = bpmn_visualizer.Variants.DAGREJS - gviz = bpmn_visualizer.apply(bpmn_graph, variant=variant, parameters={"format": format, "bgcolor": bgcolor, "rankdir": rankdir}) + properties = {"format": format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = bpmn_visualizer.apply(bpmn_graph, variant=variant, parameters=properties) return bpmn_visualizer.save(gviz, file_path, variant=variant) -def view_bpmn(bpmn_graph: BPMN, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, variant_str: str = "classic"): +def view_bpmn(bpmn_graph: BPMN, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, variant_str: str = "classic", graph_title: Optional[str] = None): """ Views a BPMN graph @@ -311,6 +366,7 @@ def view_bpmn(bpmn_graph: BPMN, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) :param variant_str: variant of the visualization to be used ("classic" or "dagrejs") + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -328,17 +384,24 @@ def view_bpmn(bpmn_graph: BPMN, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW elif variant_str == "dagrejs": variant = bpmn_visualizer.Variants.DAGREJS - gviz = bpmn_visualizer.apply(bpmn_graph, variant=variant, parameters={"format": format, "bgcolor": bgcolor, "rankdir": rankdir}) + properties = {"format": format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = bpmn_visualizer.apply(bpmn_graph, variant=variant, parameters=properties) bpmn_visualizer.view(gviz, variant=variant) -def view_heuristics_net(heu_net: HeuristicsNet, format: str = "png", bgcolor: str = "white"): +def view_heuristics_net(heu_net: HeuristicsNet, format: str = "png", bgcolor: str = "white", graph_title: Optional[str] = None): """ Views an heuristics net :param heu_net: Heuristics net :param format: Format of the visualization :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -350,17 +413,24 @@ def view_heuristics_net(heu_net: HeuristicsNet, format: str = "png", bgcolor: st format = str(format).lower() from pm4py.visualization.heuristics_net import visualizer as hn_visualizer parameters = hn_visualizer.Variants.PYDOTPLUS.value.Parameters - gviz = hn_visualizer.apply(heu_net, parameters={parameters.FORMAT: format, "bgcolor": bgcolor}) + properties = {parameters.FORMAT: format, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = hn_visualizer.apply(heu_net, parameters=properties) hn_visualizer.view(gviz) -def save_vis_heuristics_net(heu_net: HeuristicsNet, file_path: str, bgcolor: str = "white", **kwargs): +def save_vis_heuristics_net(heu_net: HeuristicsNet, file_path: str, bgcolor: str = "white", graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of an heuristics net :param heu_net: Heuristics net :param file_path: Destination path :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -373,7 +443,13 @@ def save_vis_heuristics_net(heu_net: HeuristicsNet, file_path: str, bgcolor: str format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.heuristics_net import visualizer as hn_visualizer parameters = hn_visualizer.Variants.PYDOTPLUS.value.Parameters - gviz = hn_visualizer.apply(heu_net, parameters={parameters.FORMAT: format, "bgcolor": bgcolor}) + properties = {parameters.FORMAT: format, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = hn_visualizer.apply(heu_net, parameters=properties) return hn_visualizer.save(gviz, file_path) @@ -396,7 +472,7 @@ def __dotted_attribute_selection(log: Union[EventLog, pd.DataFrame], attributes) return log, attributes -def view_dotted_chart(log: Union[EventLog, pd.DataFrame], format: str = "png", attributes=None, bgcolor: str = "white", show_legend: bool = True): +def view_dotted_chart(log: Union[EventLog, pd.DataFrame], format: str = "png", attributes=None, bgcolor: str = "white", show_legend: bool = True, graph_title: Optional[str] = None): """ Displays the dotted chart @@ -421,6 +497,7 @@ def view_dotted_chart(log: Union[EventLog, pd.DataFrame], format: str = "png", a :param attributes: Attributes that should be used to construct the dotted chart. If None, the default dotted chart will be shown: x-axis: time y-axis: cases (in order of occurrence in the event log) color: activity. For custom attributes, use a list of attributes of the form [x-axis attribute, y-axis attribute, color attribute], e.g., ["concept:name", "org:resource", "concept:name"]) :param bgcolor: background color to be used in the dotted chart :param show_legend: boolean (enables/disables showing the legend) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -440,13 +517,17 @@ def view_dotted_chart(log: Union[EventLog, pd.DataFrame], format: str = "png", a parameters["format"] = format parameters["bgcolor"] = bgcolor parameters["show_legend"] = show_legend + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title from pm4py.visualization.dotted_chart import visualizer as dotted_chart_visualizer gviz = dotted_chart_visualizer.apply(log, attributes, parameters=parameters) dotted_chart_visualizer.view(gviz) -def save_vis_dotted_chart(log: Union[EventLog, pd.DataFrame], file_path: str, attributes=None, bgcolor: str = "white", show_legend: bool = True, **kwargs): +def save_vis_dotted_chart(log: Union[EventLog, pd.DataFrame], file_path: str, attributes=None, bgcolor: str = "white", show_legend: bool = True, graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of the dotted chart @@ -471,6 +552,7 @@ def save_vis_dotted_chart(log: Union[EventLog, pd.DataFrame], file_path: str, at :param attributes: Attributes that should be used to construct the dotted chart (for example, ["concept:name", "org:resource"]) :param bgcolor: background color to be used in the dotted chart :param show_legend: boolean (enables/disables showing the legend) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -490,6 +572,10 @@ def save_vis_dotted_chart(log: Union[EventLog, pd.DataFrame], file_path: str, at parameters["format"] = format parameters["bgcolor"] = bgcolor parameters["show_legend"] = show_legend + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title from pm4py.visualization.dotted_chart import visualizer as dotted_chart_visualizer gviz = dotted_chart_visualizer.apply(log, attributes, parameters=parameters) @@ -556,7 +642,7 @@ def save_vis_sna(sna_metric: SNA, file_path: str, variant_str: Optional[str] = N return sna_visualizer.save(gviz, file_path, variant=variant) -def view_case_duration_graph(log: Union[EventLog, pd.DataFrame], format: str = "png", activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name"): +def view_case_duration_graph(log: Union[EventLog, pd.DataFrame], format: str = "png", activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", graph_title: Optional[str] = None): """ Visualizes the case duration graph @@ -565,6 +651,7 @@ def view_case_duration_graph(log: Union[EventLog, pd.DataFrame], format: str = " :param activity_key: attribute to be used as activity :param case_id_key: attribute to be used as case identifier :param timestamp_key: attribute to be used as timestamp + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -582,12 +669,16 @@ def view_case_duration_graph(log: Union[EventLog, pd.DataFrame], format: str = " from pm4py.statistics.traces.generic.log import case_statistics graph = case_statistics.get_kde_caseduration(log, parameters=get_properties(log, activity_key=activity_key, case_id_key=case_id_key, timestamp_key=timestamp_key)) from pm4py.visualization.graphs import visualizer as graphs_visualizer + properties = {"format": format} + if graph_title is not None: + properties["title"] = graph_title + graph_vis = graphs_visualizer.apply(graph[0], graph[1], variant=graphs_visualizer.Variants.CASES, - parameters={"format": format}) + parameters=properties) graphs_visualizer.view(graph_vis) -def save_vis_case_duration_graph(log: Union[EventLog, pd.DataFrame], file_path: str, activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", **kwargs): +def save_vis_case_duration_graph(log: Union[EventLog, pd.DataFrame], file_path: str, activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", graph_title: Optional[str] = None, **kwargs): """ Saves the case duration graph in the specified path @@ -596,6 +687,7 @@ def save_vis_case_duration_graph(log: Union[EventLog, pd.DataFrame], file_path: :param activity_key: attribute to be used as activity :param case_id_key: attribute to be used as case identifier :param timestamp_key: attribute to be used as timestamp + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -614,12 +706,16 @@ def save_vis_case_duration_graph(log: Union[EventLog, pd.DataFrame], file_path: graph = case_statistics.get_kde_caseduration(log, parameters=get_properties(log, activity_key=activity_key, case_id_key=case_id_key, timestamp_key=timestamp_key)) format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.graphs import visualizer as graphs_visualizer + properties = {"format": format} + if graph_title is not None: + properties["title"] = graph_title + graph_vis = graphs_visualizer.apply(graph[0], graph[1], variant=graphs_visualizer.Variants.CASES, - parameters={"format": format}) + parameters=properties) return graphs_visualizer.save(graph_vis, file_path) -def view_events_per_time_graph(log: Union[EventLog, pd.DataFrame], format: str = "png", activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name"): +def view_events_per_time_graph(log: Union[EventLog, pd.DataFrame], format: str = "png", activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", graph_title: Optional[str] = None): """ Visualizes the events per time graph @@ -628,6 +724,7 @@ def view_events_per_time_graph(log: Union[EventLog, pd.DataFrame], format: str = :param activity_key: attribute to be used as activity :param case_id_key: attribute to be used as case identifier :param timestamp_key: attribute to be used as timestamp + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -645,12 +742,16 @@ def view_events_per_time_graph(log: Union[EventLog, pd.DataFrame], format: str = from pm4py.statistics.attributes.log import get as attributes_get graph = attributes_get.get_kde_date_attribute(log, parameters=get_properties(log, activity_key=activity_key, case_id_key=case_id_key, timestamp_key=timestamp_key)) from pm4py.visualization.graphs import visualizer as graphs_visualizer + properties = {"format": format} + if graph_title is not None: + properties["title"] = graph_title + graph_vis = graphs_visualizer.apply(graph[0], graph[1], variant=graphs_visualizer.Variants.DATES, - parameters={"format": format}) + parameters=properties) graphs_visualizer.view(graph_vis) -def save_vis_events_per_time_graph(log: Union[EventLog, pd.DataFrame], file_path: str, activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", **kwargs): +def save_vis_events_per_time_graph(log: Union[EventLog, pd.DataFrame], file_path: str, activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", graph_title: Optional[str] = None, **kwargs): """ Saves the events per time graph in the specified path @@ -659,6 +760,7 @@ def save_vis_events_per_time_graph(log: Union[EventLog, pd.DataFrame], file_path :param activity_key: attribute to be used as activity :param case_id_key: attribute to be used as case identifier :param timestamp_key: attribute to be used as timestamp + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -677,12 +779,17 @@ def save_vis_events_per_time_graph(log: Union[EventLog, pd.DataFrame], file_path graph = attributes_get.get_kde_date_attribute(log, attribute=timestamp_key, parameters=get_properties(log, activity_key=activity_key, case_id_key=case_id_key, timestamp_key=timestamp_key)) format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.graphs import visualizer as graphs_visualizer + properties = {"format": format} + if graph_title is not None: + properties["title"] = graph_title + graph_vis = graphs_visualizer.apply(graph[0], graph[1], variant=graphs_visualizer.Variants.DATES, - parameters={"format": format}) + parameters=properties) + return graphs_visualizer.save(graph_vis, file_path) -def view_performance_spectrum(log: Union[EventLog, pd.DataFrame], activities: List[str], format: str = "png", activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", bgcolor: str = "white"): +def view_performance_spectrum(log: Union[EventLog, pd.DataFrame], activities: List[str], format: str = "png", activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", bgcolor: str = "white", graph_title: Optional[str] = None): """ Displays the performance spectrum @@ -699,6 +806,7 @@ def view_performance_spectrum(log: Union[EventLog, pd.DataFrame], activities: Li :param case_id_key: attribute to be used as case identifier :param timestamp_key: attribute to be used as timestamp :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -717,11 +825,18 @@ def view_performance_spectrum(log: Union[EventLog, pd.DataFrame], activities: Li perf_spectrum = performance_spectrum.apply(log, activities, parameters=properties) from pm4py.visualization.performance_spectrum import visualizer as perf_spectrum_visualizer from pm4py.visualization.performance_spectrum.variants import neato - gviz = perf_spectrum_visualizer.apply(perf_spectrum, parameters={neato.Parameters.FORMAT.value: format, "bgcolor": bgcolor}) + + parameters = {neato.Parameters.FORMAT.value: format, "bgcolor": bgcolor} + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title + + gviz = perf_spectrum_visualizer.apply(perf_spectrum, parameters=parameters) perf_spectrum_visualizer.view(gviz) -def save_vis_performance_spectrum(log: Union[EventLog, pd.DataFrame], activities: List[str], file_path: str, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", bgcolor: str = "white", **kwargs): +def save_vis_performance_spectrum(log: Union[EventLog, pd.DataFrame], activities: List[str], file_path: str, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", bgcolor: str = "white", graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of the performance spectrum to a file @@ -736,6 +851,7 @@ def save_vis_performance_spectrum(log: Union[EventLog, pd.DataFrame], activities :param timestamp_key: attribute to be used for the timestamp :param case_id_key: attribute to be used as case identifier :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -755,7 +871,14 @@ def save_vis_performance_spectrum(log: Union[EventLog, pd.DataFrame], activities from pm4py.visualization.performance_spectrum import visualizer as perf_spectrum_visualizer from pm4py.visualization.performance_spectrum.variants import neato format = os.path.splitext(file_path)[1][1:].lower() - gviz = perf_spectrum_visualizer.apply(perf_spectrum, parameters={neato.Parameters.FORMAT.value: format, "bgcolor": bgcolor}) + + parameters = {neato.Parameters.FORMAT.value: format, "bgcolor": bgcolor} + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title + + gviz = perf_spectrum_visualizer.apply(perf_spectrum, parameters=parameters) return perf_spectrum_visualizer.save(gviz, file_path) @@ -801,7 +924,7 @@ def __builds_events_distribution_graph(log: Union[EventLog, pd.DataFrame], param return title, x_axis, y_axis, x, y -def view_events_distribution_graph(log: Union[EventLog, pd.DataFrame], distr_type: str = "days_week", format="png", activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name"): +def view_events_distribution_graph(log: Union[EventLog, pd.DataFrame], distr_type: str = "days_week", format="png", activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", graph_title: Optional[str] = None): """ Shows the distribution of the events in the specified dimension @@ -813,6 +936,7 @@ def view_events_distribution_graph(log: Union[EventLog, pd.DataFrame], distr_typ :param activity_key: attribute to be used as activity :param case_id_key: attribute to be used as case identifier :param timestamp_key: attribute to be used as timestamp + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -831,13 +955,16 @@ def view_events_distribution_graph(log: Union[EventLog, pd.DataFrame], distr_typ parameters["x_axis"] = x_axis; parameters["y_axis"] = y_axis; parameters["format"] = format + if graph_title is not None: + parameters["title"] = graph_title + from pm4py.visualization.graphs import visualizer as graphs_visualizer gviz = graphs_visualizer.apply(x, y, variant=graphs_visualizer.Variants.BARPLOT, parameters=parameters) graphs_visualizer.view(gviz) def save_vis_events_distribution_graph(log: Union[EventLog, pd.DataFrame], file_path: str, - distr_type: str = "days_week", activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", **kwargs): + distr_type: str = "days_week", activity_key="concept:name", timestamp_key="time:timestamp", case_id_key="case:concept:name", graph_title: Optional[str] = None, **kwargs): """ Saves the distribution of the events in a picture file @@ -849,6 +976,7 @@ def save_vis_events_distribution_graph(log: Union[EventLog, pd.DataFrame], file_ :param activity_key: attribute to be used as activity :param case_id_key: attribute to be used as case identifier :param timestamp_key: attribute to be used as timestamp + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -868,12 +996,15 @@ def save_vis_events_distribution_graph(log: Union[EventLog, pd.DataFrame], file_ parameters["x_axis"] = x_axis; parameters["y_axis"] = y_axis; parameters["format"] = format + if graph_title is not None: + parameters["title"] = graph_title + from pm4py.visualization.graphs import visualizer as graphs_visualizer gviz = graphs_visualizer.apply(x, y, variant=graphs_visualizer.Variants.BARPLOT, parameters=parameters) return graphs_visualizer.save(gviz, file_path) -def view_ocdfg(ocdfg: Dict[str, Any], annotation: str = "frequency", act_metric: str = "events", edge_metric="event_couples", act_threshold: int = 0, edge_threshold: int = 0, performance_aggregation: str = "mean", format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ): +def view_ocdfg(ocdfg: Dict[str, Any], annotation: str = "frequency", act_metric: str = "events", edge_metric="event_couples", act_threshold: int = 0, edge_threshold: int = 0, performance_aggregation: str = "mean", format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None): """ Views an OC-DFG (object-centric directly-follows graph) with the provided configuration. @@ -889,6 +1020,7 @@ def view_ocdfg(ocdfg: Dict[str, Any], annotation: str = "frequency", act_metric: :param format: The format of the output visualization (if html is provided, GraphvizJS is used to render the visualization in an HTML page) :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -911,11 +1043,16 @@ def view_ocdfg(ocdfg: Dict[str, Any], annotation: str = "frequency", act_metric: parameters[classic.Parameters.PERFORMANCE_AGGREGATION_MEASURE] = performance_aggregation parameters["bgcolor"] = bgcolor parameters["rankdir"] = rankdir + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title + gviz = classic.apply(ocdfg, parameters=parameters) visualizer.view(gviz) -def save_vis_ocdfg(ocdfg: Dict[str, Any], file_path: str, annotation: str = "frequency", act_metric: str = "events", edge_metric="event_couples", act_threshold: int = 0, edge_threshold: int = 0, performance_aggregation: str = "mean", bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, **kwargs): +def save_vis_ocdfg(ocdfg: Dict[str, Any], file_path: str, annotation: str = "frequency", act_metric: str = "events", edge_metric="event_couples", act_threshold: int = 0, edge_threshold: int = 0, performance_aggregation: str = "mean", bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of an OC-DFG (object-centric directly-follows graph) with the provided configuration. @@ -931,6 +1068,7 @@ def save_vis_ocdfg(ocdfg: Dict[str, Any], file_path: str, annotation: str = "fre :param performance_aggregation: The aggregation measure to use for the performance: mean, median, min, max, sum :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -953,11 +1091,16 @@ def save_vis_ocdfg(ocdfg: Dict[str, Any], file_path: str, annotation: str = "fre parameters[classic.Parameters.PERFORMANCE_AGGREGATION_MEASURE] = performance_aggregation parameters["bgcolor"] = bgcolor parameters["rankdir"] = rankdir + parameters["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + parameters["enable_graph_title"] = True + parameters["graph_title"] = graph_title + gviz = classic.apply(ocdfg, parameters=parameters) return visualizer.save(gviz, file_path) -def view_ocpn(ocpn: Dict[str, Any], format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ): +def view_ocpn(ocpn: Dict[str, Any], format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None): """ Visualizes on the screen the object-centric Petri net @@ -965,6 +1108,7 @@ def view_ocpn(ocpn: Dict[str, Any], format: str = constants.DEFAULT_FORMAT_GVIZ_ :param format: Format of the visualization (if html is provided, GraphvizJS is used to render the visualization in an HTML page) :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -976,11 +1120,17 @@ def view_ocpn(ocpn: Dict[str, Any], format: str = constants.DEFAULT_FORMAT_GVIZ_ format = str(format).lower() from pm4py.visualization.ocel.ocpn import visualizer as ocpn_visualizer - gviz = ocpn_visualizer.apply(ocpn, parameters={"format": format, "bgcolor": bgcolor, "rankdir": rankdir}) + properties = {"format": format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = ocpn_visualizer.apply(ocpn, parameters=properties) ocpn_visualizer.view(gviz) -def save_vis_ocpn(ocpn: Dict[str, Any], file_path: str, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, **kwargs): +def save_vis_ocpn(ocpn: Dict[str, Any], file_path: str, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of the object-centric Petri net into a file @@ -988,6 +1138,7 @@ def save_vis_ocpn(ocpn: Dict[str, Any], file_path: str, bgcolor: str = "white", :param file_path: Target path of the visualization :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -999,11 +1150,17 @@ def save_vis_ocpn(ocpn: Dict[str, Any], file_path: str, bgcolor: str = "white", file_path = str(file_path) format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.ocel.ocpn import visualizer as ocpn_visualizer - gviz = ocpn_visualizer.apply(ocpn, parameters={"format": format, "bgcolor": bgcolor, "rankdir": rankdir}) + properties = {"format": format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = ocpn_visualizer.apply(ocpn, parameters=properties) return ocpn_visualizer.save(gviz, file_path) -def view_network_analysis(network_analysis: Dict[Tuple[str, str], Dict[str, Any]], variant: str = "frequency", format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, activity_threshold: int = 1, edge_threshold: int = 1, bgcolor: str = "white"): +def view_network_analysis(network_analysis: Dict[Tuple[str, str], Dict[str, Any]], variant: str = "frequency", format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, activity_threshold: int = 1, edge_threshold: int = 1, bgcolor: str = "white", graph_title: Optional[str] = None): """ Visualizes the network analysis @@ -1013,6 +1170,7 @@ def view_network_analysis(network_analysis: Dict[Tuple[str, str], Dict[str, Any] :param activity_threshold: The minimum number of occurrences for an activity to be included (default: 1) :param edge_threshold: The minimum number of occurrences for an edge to be included (default: 1) :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1025,11 +1183,17 @@ def view_network_analysis(network_analysis: Dict[Tuple[str, str], Dict[str, Any] from pm4py.visualization.network_analysis import visualizer as network_analysis_visualizer variant = network_analysis_visualizer.Variants.PERFORMANCE if variant == "performance" else network_analysis_visualizer.Variants.FREQUENCY - gviz = network_analysis_visualizer.apply(network_analysis, variant=variant, parameters={"format": format, "activity_threshold": activity_threshold, "edge_threshold": edge_threshold, "bgcolor": bgcolor}) + properties = {"format": format, "activity_threshold": activity_threshold, "edge_threshold": edge_threshold, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = network_analysis_visualizer.apply(network_analysis, variant=variant, parameters=properties) network_analysis_visualizer.view(gviz) -def save_vis_network_analysis(network_analysis: Dict[Tuple[str, str], Dict[str, Any]], file_path: str, variant: str = "frequency", activity_threshold: int = 1, edge_threshold: int = 1, bgcolor: str = "white", **kwargs): +def save_vis_network_analysis(network_analysis: Dict[Tuple[str, str], Dict[str, Any]], file_path: str, variant: str = "frequency", activity_threshold: int = 1, edge_threshold: int = 1, bgcolor: str = "white", graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of the network analysis @@ -1039,6 +1203,7 @@ def save_vis_network_analysis(network_analysis: Dict[Tuple[str, str], Dict[str, :param activity_threshold: The minimum number of occurrences for an activity to be included (default: 1) :param edge_threshold: The minimum number of occurrences for an edge to be included (default: 1) :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1051,17 +1216,24 @@ def save_vis_network_analysis(network_analysis: Dict[Tuple[str, str], Dict[str, format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.network_analysis import visualizer as network_analysis_visualizer variant = network_analysis_visualizer.Variants.PERFORMANCE if variant == "performance" else network_analysis_visualizer.Variants.FREQUENCY - gviz = network_analysis_visualizer.apply(network_analysis, variant=variant, parameters={"format": format, "activity_threshold": activity_threshold, "edge_threshold": edge_threshold, "bgcolor": bgcolor}) + properties = {"format": format, "activity_threshold": activity_threshold, "edge_threshold": edge_threshold, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = network_analysis_visualizer.apply(network_analysis, variant=variant, parameters=properties) return network_analysis_visualizer.save(gviz, file_path) -def view_transition_system(transition_system: TransitionSystem, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white"): +def view_transition_system(transition_system: TransitionSystem, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", graph_title: Optional[str] = None): """ Views a transition system :param transition_system: Transition system :param format: Format of the visualization (if html is provided, GraphvizJS is used to render the visualization in an HTML page) :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1073,17 +1245,24 @@ def view_transition_system(transition_system: TransitionSystem, format: str = co format = str(format).lower() from pm4py.visualization.transition_system import visualizer as ts_visualizer - gviz = ts_visualizer.apply(transition_system, parameters={"format": format, "bgcolor": bgcolor}) + properties = {"format": format, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = ts_visualizer.apply(transition_system, parameters=properties) ts_visualizer.view(gviz) -def save_vis_transition_system(transition_system: TransitionSystem, file_path: str, bgcolor: str = "white", **kwargs): +def save_vis_transition_system(transition_system: TransitionSystem, file_path: str, bgcolor: str = "white", graph_title: Optional[str] = None, **kwargs): """ Persists the visualization of a transition system :param transition_system: Transition system :param file_path: Destination path :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1095,17 +1274,24 @@ def save_vis_transition_system(transition_system: TransitionSystem, file_path: s file_path = str(file_path) format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.transition_system import visualizer as ts_visualizer - gviz = ts_visualizer.apply(transition_system, parameters={"format": format, "bgcolor": bgcolor}) + properties = {"format": format, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = ts_visualizer.apply(transition_system, parameters=properties) return ts_visualizer.save(gviz, file_path) -def view_prefix_tree(trie: Trie, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white"): +def view_prefix_tree(trie: Trie, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", graph_title: Optional[str] = None): """ Views a prefix tree :param prefix_tree: Prefix tree :param format: Format of the visualization (if html is provided, GraphvizJS is used to render the visualization in an HTML page) :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1117,17 +1303,24 @@ def view_prefix_tree(trie: Trie, format: str = constants.DEFAULT_FORMAT_GVIZ_VIE format = str(format).lower() from pm4py.visualization.trie import visualizer as trie_visualizer - gviz = trie_visualizer.apply(trie, parameters={"format": format, "bgcolor": bgcolor}) + properties = {"format": format, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = trie_visualizer.apply(trie, parameters=properties) trie_visualizer.view(gviz) -def save_vis_prefix_tree(trie: Trie, file_path: str, bgcolor: str = "white", **kwargs): +def save_vis_prefix_tree(trie: Trie, file_path: str, bgcolor: str = "white", graph_title: Optional[str] = None, **kwargs): """ Persists the visualization of a prefix tree :param prefix_tree: Prefix tree :param file_path: Destination path :param bgcolor: Background color of the visualization (default: white) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1139,18 +1332,24 @@ def save_vis_prefix_tree(trie: Trie, file_path: str, bgcolor: str = "white", **k file_path = str(file_path) format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.trie import visualizer as trie_visualizer - gviz = trie_visualizer.apply(trie, parameters={"format": format, "bgcolor": bgcolor}) + properties = {"format": format, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = trie_visualizer.apply(trie, parameters=properties) return trie_visualizer.save(gviz, file_path) -def view_alignments(log: Union[EventLog, pd.DataFrame], aligned_traces: List[Dict[str, Any]], format: str = "png"): +def view_alignments(log: Union[EventLog, pd.DataFrame], aligned_traces: List[Dict[str, Any]], format: str = "png", graph_title: Optional[str] = None): """ Views the alignment table as a figure :param log: event log :param aligned_traces: results of an alignment :param format: format of the visualization (default: png) - + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1164,17 +1363,24 @@ def view_alignments(log: Union[EventLog, pd.DataFrame], aligned_traces: List[Dic format = str(format).lower() from pm4py.visualization.align_table import visualizer - gviz = visualizer.apply(log, aligned_traces, parameters={"format": format}) + properties = {"format": format} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = visualizer.apply(log, aligned_traces, parameters=properties) visualizer.view(gviz) -def save_vis_alignments(log: Union[EventLog, pd.DataFrame], aligned_traces: List[Dict[str, Any]], file_path: str, **kwargs): +def save_vis_alignments(log: Union[EventLog, pd.DataFrame], aligned_traces: List[Dict[str, Any]], file_path: str, graph_title: Optional[str] = None, **kwargs): """ Saves an alignment table's figure in the disk :param log: event log :param aligned_traces: results of an alignment :param file_path: target path in the disk + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1188,16 +1394,23 @@ def save_vis_alignments(log: Union[EventLog, pd.DataFrame], aligned_traces: List file_path = str(file_path) format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.align_table import visualizer - gviz = visualizer.apply(log, aligned_traces, parameters={"format": format}) + properties = {"format": format} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = visualizer.apply(log, aligned_traces, parameters=properties) return visualizer.save(gviz, file_path) -def view_footprints(footprints: Union[Tuple[Dict[str, Any], Dict[str, Any]], Dict[str, Any]], format: str = "png"): +def view_footprints(footprints: Union[Tuple[Dict[str, Any], Dict[str, Any]], Dict[str, Any]], format: str = "png", graph_title: Optional[str] = None): """ Views the footprints as a figure :param footprints: footprints :param format: format of the visualization (default: png) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1210,21 +1423,27 @@ def view_footprints(footprints: Union[Tuple[Dict[str, Any], Dict[str, Any]], Dic format = str(format).lower() from pm4py.visualization.footprints import visualizer as fps_visualizer + properties = {"format": format} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title if isinstance(footprints, dict): - gviz = fps_visualizer.apply(footprints, parameters={"format": format}) + gviz = fps_visualizer.apply(footprints, parameters=properties) else: - gviz = fps_visualizer.apply(footprints[0], footprints[1], variant=fps_visualizer.Variants.COMPARISON_SYMMETRIC, parameters={"format": format}) + gviz = fps_visualizer.apply(footprints[0], footprints[1], variant=fps_visualizer.Variants.COMPARISON_SYMMETRIC, parameters=properties) fps_visualizer.view(gviz) -def save_vis_footprints(footprints: Union[Tuple[Dict[str, Any], Dict[str, Any]], Dict[str, Any]], file_path: str, **kwargs): +def save_vis_footprints(footprints: Union[Tuple[Dict[str, Any], Dict[str, Any]], Dict[str, Any]], file_path: str, graph_title: Optional[str] = None, **kwargs): """ Saves the footprints' visualization on disk :param footprints: footprints :param file_path: target path of the visualization + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1238,16 +1457,21 @@ def save_vis_footprints(footprints: Union[Tuple[Dict[str, Any], Dict[str, Any]], format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.footprints import visualizer as fps_visualizer + properties = {"format": format} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title if isinstance(footprints, dict): - gviz = fps_visualizer.apply(footprints, parameters={"format": format}) + gviz = fps_visualizer.apply(footprints, parameters=properties) else: - gviz = fps_visualizer.apply(footprints[0], footprints[1], variant=fps_visualizer.Variants.COMPARISON_SYMMETRIC, parameters={"format": format}) + gviz = fps_visualizer.apply(footprints[0], footprints[1], variant=fps_visualizer.Variants.COMPARISON_SYMMETRIC, parameters=properties) return fps_visualizer.save(gviz, file_path) -def view_powl(powl: POWL, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", variant_str: str = "basic"): +def view_powl(powl: POWL, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", variant_str: str = "basic", graph_title: Optional[str] = None): """ Perform a visualization of a POWL model. @@ -1259,6 +1483,7 @@ def view_powl(powl: POWL, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgco :param bgcolor: background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) :param variant_str: variant of the visualization to be used (values: "basic", "net") + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1278,15 +1503,19 @@ def view_powl(powl: POWL, format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgco variant = POWLVisualizationVariants.NET format = str(format).lower() - parameters = parameters={"format": format, "bgcolor": bgcolor} + properties = {"format": format, "bgcolor": bgcolor} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title from pm4py.visualization.powl import visualizer as powl_visualizer - gviz = powl_visualizer.apply(powl, variant=variant, parameters=parameters) + gviz = powl_visualizer.apply(powl, variant=variant, parameters=properties) - powl_visualizer.view(gviz, parameters=parameters) + powl_visualizer.view(gviz, parameters=properties) -def save_vis_powl(powl: POWL, file_path: str, bgcolor: str = "white", rankdir: str = "TB", **kwargs): +def save_vis_powl(powl: POWL, file_path: str, bgcolor: str = "white", rankdir: str = "TB", graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of a POWL model. @@ -1297,6 +1526,7 @@ def save_vis_powl(powl: POWL, file_path: str, bgcolor: str = "white", rankdir: s :param file_path: target path of the visualization :param bgcolor: background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1308,15 +1538,19 @@ def save_vis_powl(powl: POWL, file_path: str, bgcolor: str = "white", rankdir: s """ file_path = str(file_path) format = os.path.splitext(file_path)[1][1:].lower() - parameters = {"format": format, "bgcolor": bgcolor, "rankdir": rankdir} + properties = {"format": format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title from pm4py.visualization.powl import visualizer as powl_visualizer - gviz = powl_visualizer.apply(powl, parameters=parameters) + gviz = powl_visualizer.apply(powl, parameters=properties) - return powl_visualizer.save(gviz, file_path, parameters=parameters) + return powl_visualizer.save(gviz, file_path, parameters=properties) -def view_object_graph(ocel: OCEL, graph: Set[Tuple[str, str]], format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ): +def view_object_graph(ocel: OCEL, graph: Set[Tuple[str, str]], format: str = constants.DEFAULT_FORMAT_GVIZ_VIEW, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None): """ Visualizes an object graph on the screen @@ -1325,6 +1559,7 @@ def view_object_graph(ocel: OCEL, graph: Set[Tuple[str, str]], format: str = con :param format: format of the visualization (if html is provided, GraphvizJS is used to render the visualization in an HTML page) :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1337,11 +1572,17 @@ def view_object_graph(ocel: OCEL, graph: Set[Tuple[str, str]], format: str = con format = str(format).lower() from pm4py.visualization.ocel.object_graph import visualizer as obj_graph_vis - gviz = obj_graph_vis.apply(ocel, graph, parameters={"format": format, "bgcolor": bgcolor, "rankdir": rankdir}) + properties = {"format": format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = obj_graph_vis.apply(ocel, graph, parameters=properties) obj_graph_vis.view(gviz) -def save_vis_object_graph(ocel: OCEL, graph: Set[Tuple[str, str]], file_path: str, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, **kwargs): +def save_vis_object_graph(ocel: OCEL, graph: Set[Tuple[str, str]], file_path: str, bgcolor: str = "white", rankdir: str = constants.DEFAULT_RANKDIR_GVIZ, graph_title: Optional[str] = None, **kwargs): """ Saves the visualization of an object graph @@ -1350,6 +1591,7 @@ def save_vis_object_graph(ocel: OCEL, graph: Set[Tuple[str, str]], file_path: st :param file_path: Destination path :param bgcolor: Background color of the visualization (default: white) :param rankdir: sets the direction of the graph ("LR" for left-to-right; "TB" for top-to-bottom) + :param graph_title: Sets the title of the visualization (if provided) .. code-block:: python3 @@ -1362,5 +1604,11 @@ def save_vis_object_graph(ocel: OCEL, graph: Set[Tuple[str, str]], file_path: st file_path = str(file_path) format = os.path.splitext(file_path)[1][1:].lower() from pm4py.visualization.ocel.object_graph import visualizer as obj_graph_vis - gviz = obj_graph_vis.apply(ocel, graph, parameters={"format": format, "bgcolor": bgcolor, "rankdir": rankdir}) + properties = {"format": format, "bgcolor": bgcolor, "rankdir": rankdir} + properties["enable_graph_title"] = constants.DEFAULT_ENABLE_GRAPH_TITLES + if graph_title: + properties["enable_graph_title"] = True + properties["graph_title"] = graph_title + + gviz = obj_graph_vis.apply(ocel, graph, parameters=properties) return obj_graph_vis.save(gviz, file_path) diff --git a/pm4py/visualization/bpmn/variants/classic.py b/pm4py/visualization/bpmn/variants/classic.py index 8b125b0fe..dade0d1a1 100644 --- a/pm4py/visualization/bpmn/variants/classic.py +++ b/pm4py/visualization/bpmn/variants/classic.py @@ -18,6 +18,8 @@ class Parameters(Enum): ENABLE_SWIMLANES = "enable_swimlanes" INCLUDE_NAME_IN_EVENTS = "include_name_in_events" SWIMLANES_MARGIN = "swimlanes_margin" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def add_bpmn_node(graph, n, font_size, include_name_in_events): @@ -82,6 +84,8 @@ def apply(bpmn_graph: BPMN, parameters: Optional[Dict[Any, Any]] = None) -> grap include_name_in_events = exec_utils.get_param_value(Parameters.INCLUDE_NAME_IN_EVENTS, parameters, True) swimlanes_margin = exec_utils.get_param_value(Parameters.SWIMLANES_MARGIN, parameters, 35) swimlanes_margin = str(swimlanes_margin) + 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, "BPMN Diagram") filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() @@ -89,6 +93,9 @@ def apply(bpmn_graph: BPMN, parameters: Optional[Dict[Any, Any]] = None) -> grap viz = Digraph("", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.graph_attr['rankdir'] = rankdir + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + nodes, edges = get_sorted_nodes_edges(bpmn_graph) process_ids = [] for n in nodes: diff --git a/pm4py/visualization/dfg/variants/cost.py b/pm4py/visualization/dfg/variants/cost.py index 4fe41828d..5df240738 100644 --- a/pm4py/visualization/dfg/variants/cost.py +++ b/pm4py/visualization/dfg/variants/cost.py @@ -27,6 +27,8 @@ class Parameters(Enum): AGGREGATION_MEASURE = "aggregation_measure" RANKDIR = "rankdir" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Optional[Dict[Any, Any]] = None, @@ -67,6 +69,8 @@ def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Opt rankdir = exec_utils.get_param_value(Parameters.RANKDIR, parameters, constants.DEFAULT_RANKDIR_GVIZ) bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR) + 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, "Cost-Based Directly-Follows Graph") # if all the aggregation measures are provided for a given key, # then pick one of the values for the representation @@ -104,4 +108,5 @@ def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Opt return dfg_gviz.graphviz_visualization(activities_count, dfg, image_format=image_format, measure="cost", max_no_of_edges_in_diagram=max_no_of_edges_in_diagram, start_activities=start_activities, end_activities=end_activities, serv_time=serv_time, - font_size=font_size, bgcolor=bgcolor, rankdir=rankdir) + font_size=font_size, bgcolor=bgcolor, rankdir=rankdir, + enable_graph_title=enable_graph_title, graph_title=graph_title) diff --git a/pm4py/visualization/dfg/variants/frequency.py b/pm4py/visualization/dfg/variants/frequency.py index 4edecfee2..d42c1c41e 100644 --- a/pm4py/visualization/dfg/variants/frequency.py +++ b/pm4py/visualization/dfg/variants/frequency.py @@ -23,6 +23,8 @@ class Parameters(Enum): FONT_SIZE = "font_size" RANKDIR = "rankdir" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Optional[Dict[Any, Any]] = None, activities_count : Dict[str, int] = None, serv_time: Dict[str, float] = None) -> graphviz.Digraph: @@ -66,6 +68,8 @@ def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Opt rankdir = exec_utils.get_param_value(Parameters.RANKDIR, parameters, constants.DEFAULT_RANKDIR_GVIZ) bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR) + 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, "Frequency Directly-Follows Graph") if activities_count is None: if log is not None: @@ -90,4 +94,5 @@ def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Opt return dfg_gviz.graphviz_visualization(activities_count, dfg, image_format=image_format, measure="frequency", max_no_of_edges_in_diagram=max_no_of_edges_in_diagram, start_activities=start_activities, end_activities=end_activities, serv_time=serv_time, - font_size=font_size, bgcolor=bgcolor, rankdir=rankdir) + font_size=font_size, bgcolor=bgcolor, rankdir=rankdir, + enable_graph_title=enable_graph_title, graph_title=graph_title) diff --git a/pm4py/visualization/dfg/variants/performance.py b/pm4py/visualization/dfg/variants/performance.py index c9fa57625..3acd02528 100644 --- a/pm4py/visualization/dfg/variants/performance.py +++ b/pm4py/visualization/dfg/variants/performance.py @@ -25,6 +25,8 @@ class Parameters(Enum): AGGREGATION_MEASURE = "aggregation_measure" RANKDIR = "rankdir" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Optional[Dict[Any, Any]] = None, activities_count : Dict[str, int] = None, serv_time: Dict[str, float] = None) -> graphviz.Digraph: @@ -64,6 +66,8 @@ def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Opt rankdir = exec_utils.get_param_value(Parameters.RANKDIR, parameters, constants.DEFAULT_RANKDIR_GVIZ) bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR) + 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, "Performance Directly-Follows Graph") # if all the aggregation measures are provided for a given key, # then pick one of the values for the representation @@ -101,4 +105,5 @@ def apply(dfg: Dict[Tuple[str, str], int], log: EventLog = None, parameters: Opt return dfg_gviz.graphviz_visualization(activities_count, dfg, image_format=image_format, measure="performance", max_no_of_edges_in_diagram=max_no_of_edges_in_diagram, start_activities=start_activities, end_activities=end_activities, serv_time=serv_time, - font_size=font_size, bgcolor=bgcolor, rankdir=rankdir) + font_size=font_size, bgcolor=bgcolor, rankdir=rankdir, + enable_graph_title=enable_graph_title, graph_title=graph_title) diff --git a/pm4py/visualization/dotted_chart/variants/classic.py b/pm4py/visualization/dotted_chart/variants/classic.py index 6fc30aef7..49019972a 100644 --- a/pm4py/visualization/dotted_chart/variants/classic.py +++ b/pm4py/visualization/dotted_chart/variants/classic.py @@ -6,7 +6,7 @@ from random import randint from typing import List, Any, Tuple, Dict, Optional, Union -from pm4py.util import exec_utils +from pm4py.util import exec_utils, constants class Parameters(Enum): @@ -14,6 +14,8 @@ class Parameters(Enum): DOT_SIZE = "dot_size" LAYOUT_EXT_MULTIPLIER = "layout_ext_multiplier" SHOW_LEGEND = "show_legend" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def __build_unique_values(points_list: List[Any]) -> List[Any]: @@ -133,6 +135,9 @@ def apply(points_list: List[Any], attributes: List[str], parameters: Optional[Di layout_ext_multiplier = exec_utils.get_param_value(Parameters.LAYOUT_EXT_MULTIPLIER, parameters, 50) show_legend = exec_utils.get_param_value(Parameters.SHOW_LEGEND, parameters, True) + 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, "Dotted Chart") + unique_values = __build_unique_values(points_list) corr_dict, attr_type = __build_corr_dict(unique_values) color_dict = __build_color_dict(unique_values[2]) if len(attributes) == 3 else None @@ -153,6 +158,10 @@ def apply(points_list: List[Any], attributes: List[str], parameters: Optional[Di output_file_img.close() lines = ["graph G {"] + + if enable_graph_title: + lines.append('label=<'+graph_title+'>;\nlabelloc="top";\n') + lines.append("origin [label=\"\", shape=none, width=\"0px\", height=\"0px\", pos=\"0,0!\"];") lines.append("rightX [label=\"\", shape=none, width=\"0px\", height=\"0px\", pos=\"%d,0!\"];" % (x_length)) lines.append("topY [label=\"\", shape=none, width=\"0px\", height=\"0px\", pos=\"0,%d!\"];" % (y_length)) diff --git a/pm4py/visualization/footprints/variants/comparison.py b/pm4py/visualization/footprints/variants/comparison.py index c93807693..ac8897dc9 100644 --- a/pm4py/visualization/footprints/variants/comparison.py +++ b/pm4py/visualization/footprints/variants/comparison.py @@ -1,12 +1,14 @@ from graphviz import Source import tempfile -from pm4py.util import exec_utils +from pm4py.util import exec_utils, constants from enum import Enum from typing import Optional, Dict, Any, Union class Parameters(Enum): FORMAT = "format" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" XOR_SYMBOL = "#" @@ -64,11 +66,21 @@ def apply(fp1: Dict[str, Any], fp2: Dict[str, Any], parameters: Optional[Dict[Un fp_table[x[0]][x[1]] = ("red", PARALLEL_SYMBOL) image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") + 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, "Footprints") filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() - footprints_table = ["digraph {\n", "tbl [\n", "shape=plaintext\n", "label=<\n"] + footprints_table = ["digraph {\n"] + + if enable_graph_title: + footprints_table.append('label=<'+graph_title+'>;\nlabelloc="top";\n') + + footprints_table.append("tbl [\n") + footprints_table.append("shape=plaintext\n") + footprints_table.append("label=<\n") + footprints_table.append("
VariantAlignment
\n") footprints_table.append("") diff --git a/pm4py/visualization/footprints/variants/comparison_symmetric.py b/pm4py/visualization/footprints/variants/comparison_symmetric.py index 70ec7c11a..e750bc16d 100644 --- a/pm4py/visualization/footprints/variants/comparison_symmetric.py +++ b/pm4py/visualization/footprints/variants/comparison_symmetric.py @@ -1,12 +1,14 @@ from graphviz import Source import tempfile -from pm4py.util import exec_utils +from pm4py.util import exec_utils, constants from enum import Enum from typing import Optional, Dict, Any, Union class Parameters(Enum): FORMAT = "format" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" UNKNOWN_SYMBOL = "?" @@ -49,11 +51,21 @@ def apply(fp1: Dict[str, Any], fp2: Dict[str, Any], parameters: Optional[Dict[Un fp_table = {} image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") + 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, "Footprints") filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() - footprints_table = ["digraph {\n", "tbl [\n", "shape=plaintext\n", "label=<\n"] + footprints_table = ["digraph {\n"] + + if enable_graph_title: + footprints_table.append('label=<'+graph_title+'>;\nlabelloc="top";\n') + + footprints_table.append("tbl [\n") + footprints_table.append("shape=plaintext\n") + footprints_table.append("label=<\n") + footprints_table.append("
\n") footprints_table.append("") diff --git a/pm4py/visualization/footprints/variants/single.py b/pm4py/visualization/footprints/variants/single.py index 865ff409c..47a876b76 100644 --- a/pm4py/visualization/footprints/variants/single.py +++ b/pm4py/visualization/footprints/variants/single.py @@ -1,12 +1,14 @@ from graphviz import Source import tempfile -from pm4py.util import exec_utils +from pm4py.util import exec_utils, constants from enum import Enum from typing import Optional, Dict, Any, Union class Parameters(Enum): FORMAT = "format" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" XOR_SYMBOL = "#" @@ -56,11 +58,21 @@ def apply(fp: Dict[str, Any], parameters: Optional[Dict[Union[str, Parameters], fp_table[x[0]][x[1]] = PARALLEL_SYMBOL image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") + 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, "Footprints") filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() - footprints_table = ["digraph {\n", "tbl [\n", "shape=plaintext\n", "label=<\n"] + footprints_table = ["digraph {\n"] + + if enable_graph_title: + footprints_table.append('label=<'+graph_title+'>;\nlabelloc="top";\n') + + footprints_table.append("tbl [\n") + footprints_table.append("shape=plaintext\n") + footprints_table.append("label=<\n") + footprints_table.append("
\n") footprints_table.append("") for act in activities: diff --git a/pm4py/visualization/heuristics_net/variants/pydotplus_vis.py b/pm4py/visualization/heuristics_net/variants/pydotplus_vis.py index ba7968eaa..5cf7998fb 100644 --- a/pm4py/visualization/heuristics_net/variants/pydotplus_vis.py +++ b/pm4py/visualization/heuristics_net/variants/pydotplus_vis.py @@ -14,6 +14,8 @@ class Parameters(Enum): FORMAT = "format" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def get_corr_hex(num): @@ -121,11 +123,20 @@ def get_graph(heu_net: HeuristicsNet, parameters: Optional[Dict[Union[str, Param if parameters is None: parameters = {} + 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, "Heuristics Net") + bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR) graph = pydotplus.Dot(strict=True) graph.obj_dict['attributes']['bgcolor'] = bgcolor graph.set_bgcolor(bgcolor) + if enable_graph_title: + graph.set_label(graph_title) + graph.set_labelloc("top") + graph.set_labeljust("center") + graph.set_fontsize(20) + corr_nodes = {} corr_nodes_names = {} is_frequency = False diff --git a/pm4py/visualization/network_analysis/variants/frequency.py b/pm4py/visualization/network_analysis/variants/frequency.py index 49645fbe8..c0dd9606e 100644 --- a/pm4py/visualization/network_analysis/variants/frequency.py +++ b/pm4py/visualization/network_analysis/variants/frequency.py @@ -13,6 +13,8 @@ class Parameters(Enum): BGCOLOR = "bgcolor" ACTIVITY_THRESHOLD = "activity_threshold" EDGE_THRESHOLD = "edge_threshold" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def apply(network_analysis_edges: Dict[Tuple[str, str], Dict[str, int]], parameters: Optional[Dict[Any, Any]] = None) -> Digraph: @@ -43,12 +45,18 @@ def apply(network_analysis_edges: Dict[Tuple[str, str], Dict[str, int]], paramet activity_threshold = exec_utils.get_param_value(Parameters.ACTIVITY_THRESHOLD, parameters, 1) edge_threshold = exec_utils.get_param_value(Parameters.EDGE_THRESHOLD, parameters, 1) + 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, "Network Analysis") + filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() viz = Digraph("pt", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.attr('node', shape='ellipse', fixedsize='false') + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + nodes = set(x[0] for x in network_analysis_edges).union(set(x[1] for x in network_analysis_edges)) nodes_in_degree = {x: 0 for x in nodes} nodes_out_degree = {x: 0 for x in nodes} diff --git a/pm4py/visualization/network_analysis/variants/performance.py b/pm4py/visualization/network_analysis/variants/performance.py index b0d7a7761..9d5f1eb8c 100644 --- a/pm4py/visualization/network_analysis/variants/performance.py +++ b/pm4py/visualization/network_analysis/variants/performance.py @@ -15,6 +15,8 @@ class Parameters(Enum): ACTIVITY_THRESHOLD = "activity_threshold" EDGE_THRESHOLD = "edge_threshold" AGGREGATION_MEASURE = "aggregation_measure" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def apply(network_analysis_edges0: Dict[Tuple[str, str], Dict[str, Any]], parameters: Optional[Dict[Any, Any]] = None) -> Digraph: @@ -60,12 +62,18 @@ def apply(network_analysis_edges0: Dict[Tuple[str, str], Dict[str, Any]], parame elif aggregation_measure == "sum": aggregation_f = sum + 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, "Network Analysis") + filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() viz = Digraph("pt", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.attr('node', shape='ellipse', fixedsize='false') + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + network_analysis_edges = {} network_analysis_edges_agg_performance = {} for x in network_analysis_edges0: diff --git a/pm4py/visualization/ocel/object_graph/variants/graphviz.py b/pm4py/visualization/ocel/object_graph/variants/graphviz.py index b26e78344..66be7fb2b 100644 --- a/pm4py/visualization/ocel/object_graph/variants/graphviz.py +++ b/pm4py/visualization/ocel/object_graph/variants/graphviz.py @@ -13,6 +13,8 @@ class Parameters(Enum): BGCOLOR = "bgcolor" RANKDIR = "rankdir" DIRECTED = "directed" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def ot_to_color(ot: str) -> str: @@ -55,6 +57,9 @@ def apply(ocel: OCEL, graph: Set[Tuple[str, str]], parameters: Optional[Dict[Any rankdir = exec_utils.get_param_value(Parameters.RANKDIR, parameters, constants.DEFAULT_RANKDIR_GVIZ) directed = exec_utils.get_param_value(Parameters.DIRECTED, parameters, True) + 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, "Object-Centric Graph") + filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() @@ -64,6 +69,9 @@ def apply(ocel: OCEL, graph: Set[Tuple[str, str]], parameters: Optional[Dict[Any viz = Graph("ograph", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.attr('node', shape='ellipse', fixedsize='false') + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + ob_type = ocel.objects.groupby(ocel.object_id_column).first()[ocel.object_type_column].to_dict() nodes = set(x[0] for x in graph).union(set(x[1] for x in graph)) diff --git a/pm4py/visualization/ocel/ocdfg/variants/classic.py b/pm4py/visualization/ocel/ocdfg/variants/classic.py index 8dd04684b..cb1c8b3cb 100644 --- a/pm4py/visualization/ocel/ocdfg/variants/classic.py +++ b/pm4py/visualization/ocel/ocdfg/variants/classic.py @@ -18,6 +18,8 @@ class Parameters(Enum): EDGE_THRESHOLD = "edge_threshold" ANNOTATION = "annotation" PERFORMANCE_AGGREGATION_MEASURE = "aggregationMeasure" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def ot_to_color(ot: str) -> str: @@ -167,6 +169,8 @@ def apply(ocdfg: Dict[str, Any], parameters: Optional[Dict[Any, Any]] = None) -> annotation = exec_utils.get_param_value(Parameters.ANNOTATION, parameters, "frequency") performance_aggregation_measure = exec_utils.get_param_value(Parameters.PERFORMANCE_AGGREGATION_MEASURE, parameters, "mean") + 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, "Object-Centric DFG") act_count = {} act_ot_count = {} @@ -217,6 +221,9 @@ def apply(ocdfg: Dict[str, Any], parameters: Optional[Dict[Any, Any]] = None) -> viz = Digraph("ocdfg", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.attr('node', shape='ellipse', fixedsize='false') + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + min_edges_count = {} max_edges_count = {} diff --git a/pm4py/visualization/ocel/ocpn/variants/wo_decoration.py b/pm4py/visualization/ocel/ocpn/variants/wo_decoration.py index 42425f3d9..ecbb642d6 100644 --- a/pm4py/visualization/ocel/ocpn/variants/wo_decoration.py +++ b/pm4py/visualization/ocel/ocpn/variants/wo_decoration.py @@ -12,6 +12,8 @@ class Parameters(Enum): FORMAT = "format" BGCOLOR = "bgcolor" RANKDIR = "rankdir" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def ot_to_color(ot: str) -> str: @@ -54,12 +56,18 @@ def apply(ocpn: Dict[str, Any], parameters: Optional[Dict[Any, Any]] = None) -> 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, "Object-Centric Petri net") + filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() - viz = Digraph("ocdfg", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) + viz = Digraph("ocpn", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.attr('node', shape='ellipse', fixedsize='false') + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + activities_map = {} transition_map = {} places = {} diff --git a/pm4py/visualization/performance_spectrum/variants/neato.py b/pm4py/visualization/performance_spectrum/variants/neato.py index 7b70f50e3..75f3b824f 100644 --- a/pm4py/visualization/performance_spectrum/variants/neato.py +++ b/pm4py/visualization/performance_spectrum/variants/neato.py @@ -9,7 +9,7 @@ import matplotlib as mpl import matplotlib.cm as cm -from pm4py.util import exec_utils +from pm4py.util import exec_utils, constants from pm4py.util.dt_parsing.variants import strpfromiso from pm4py.util.colors import get_string_from_int_below_255 @@ -22,6 +22,8 @@ class Parameters(Enum): N_DIV_DATES = "n_div_dates" PERC_PATHS = "perc_paths" LAYOUT_EXT_MULTIPLIER = "layout_ext_multiplier" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def give_color_to_line(dir: float) -> str: @@ -85,6 +87,9 @@ def apply(perf_spectrum: Dict[str, Any], parameters: Optional[Dict[Union[str, Pa perc_paths = exec_utils.get_param_value(Parameters.PERC_PATHS, parameters, 1.0) layout_ext_multiplier = exec_utils.get_param_value(Parameters.LAYOUT_EXT_MULTIPLIER, parameters, 100) + 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, "Performance Spectrum") + output_file_gv = tempfile.NamedTemporaryFile(suffix=".gv") output_file_gv.close() @@ -94,6 +99,9 @@ def apply(perf_spectrum: Dict[str, Any], parameters: Optional[Dict[Union[str, Pa lines = [] lines.append("graph G {") + if enable_graph_title: + lines.append('label=<'+graph_title+'>;\nlabelloc="top";\n') + min_x = min(x[0] for x in perf_spectrum["points"]) max_x = max(x[-1] for x in perf_spectrum["points"]) all_diffs = [x[i + 1] - x[i] for x in perf_spectrum["points"] for i in range(len(x) - 1)] diff --git a/pm4py/visualization/powl/variants/basic.py b/pm4py/visualization/powl/variants/basic.py index 112d3a5ea..8e848f1eb 100644 --- a/pm4py/visualization/powl/variants/basic.py +++ b/pm4py/visualization/powl/variants/basic.py @@ -3,7 +3,8 @@ from enum import Enum from graphviz import Digraph from pm4py.objects.process_tree.obj import Operator -from pm4py.util import exec_utils +from pm4py.util import exec_utils, constants +from typing import Optional, Dict, Any from pm4py.objects.powl.obj import POWL, Transition, SilentTransition, StrictPartialOrder, OperatorPOWL, \ FrequentTransition @@ -22,9 +23,11 @@ class Parameters(Enum): ENABLE_DEEPCOPY = "enable_deepcopy" FONT_SIZE = "font_size" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" -def apply(powl: POWL) -> Digraph: +def apply(powl: POWL, parameters: Optional[Dict[Any, Any]] = None) -> Digraph: """ Obtain a POWL model representation through GraphViz @@ -38,6 +41,11 @@ def apply(powl: POWL) -> Digraph: gviz GraphViz Digraph """ + if parameters is None: + parameters = {} + + 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, "POWL model") filename = tempfile.NamedTemporaryFile(suffix='.gv') diff --git a/pm4py/visualization/powl/variants/net.py b/pm4py/visualization/powl/variants/net.py index 5a963eb49..355bfa89f 100644 --- a/pm4py/visualization/powl/variants/net.py +++ b/pm4py/visualization/powl/variants/net.py @@ -5,8 +5,9 @@ from enum import Enum import tempfile import graphviz +from typing import Optional, Dict, Any from graphviz import Digraph -from pm4py.util import constants +from pm4py.util import constants, exec_utils from pm4py.objects.bpmn.obj import BPMN from pm4py.objects.bpmn.util.sorting import get_sorted_nodes_edges from pm4py.objects.conversion.powl.converter import apply as powl_to_pn @@ -17,6 +18,8 @@ class Parameters(Enum): FORMAT = "format" RANKDIR = "rankdir" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" FREQUENCY_TAG_IMAGES = True @@ -135,7 +138,13 @@ def add_node(n, viz): raise Exception("Unexpected instance of class " + str(type(n)) + "!") -def apply(powl: POWL) -> graphviz.Digraph: +def apply(powl: POWL, parameters: Optional[Dict[Any, Any]] = None) -> graphviz.Digraph: + if parameters is None: + parameters = {} + + 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, "POWL Model") + pn_2, init_2, final_2 = powl_to_pn(powl) bpmn_graph = to_bpmn(pn_2, init_2, final_2) @@ -165,6 +174,9 @@ def apply(powl: POWL) -> graphviz.Digraph: viz = Digraph("", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.graph_attr['rankdir'] = rankdir + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + gateway_edges = {} for e in edges: diff --git a/pm4py/visualization/powl/visualizer.py b/pm4py/visualization/powl/visualizer.py index ab41cff2d..3cc6cd525 100644 --- a/pm4py/visualization/powl/visualizer.py +++ b/pm4py/visualization/powl/visualizer.py @@ -56,7 +56,7 @@ def apply(powl: POWL, variant=DEFAULT_VARIANT, frequency_tags=True, parameters: if frequency_tags: powl = powl.simplify_using_frequent_transitions() - viz = exec_utils.get_variant(variant).apply(powl) + viz = exec_utils.get_variant(variant).apply(powl, parameters=parameters) svg_content = viz.pipe().decode('utf-8') def inline_images_and_svgs(svg_content): diff --git a/pm4py/visualization/process_tree/variants/frequency_annotation.py b/pm4py/visualization/process_tree/variants/frequency_annotation.py index 7741b29df..4039edddd 100644 --- a/pm4py/visualization/process_tree/variants/frequency_annotation.py +++ b/pm4py/visualization/process_tree/variants/frequency_annotation.py @@ -20,6 +20,8 @@ class Parameters(Enum): 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 @@ -88,10 +90,17 @@ def apply(tree: ProcessTree, parameters: Optional[Dict[Union[str, Parameters], A 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='<'+graph_title+'>', 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) diff --git a/pm4py/visualization/process_tree/variants/symbolic.py b/pm4py/visualization/process_tree/variants/symbolic.py index 2a8c39aa2..734c7c4e9 100644 --- a/pm4py/visualization/process_tree/variants/symbolic.py +++ b/pm4py/visualization/process_tree/variants/symbolic.py @@ -18,6 +18,8 @@ class Parameters(Enum): FONT_SIZE = "font_size" BGCOLOR = "bgcolor" RANKDIR = "rankdir" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def get_color(node, color_map): @@ -84,10 +86,17 @@ def apply(tree: ProcessTree, parameters: Optional[Dict[Union[str, Parameters], A 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='<'+graph_title+'>', labelloc="top") + image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") color_map = exec_utils.get_param_value(Parameters.COLOR_MAP, parameters, {}) diff --git a/pm4py/visualization/process_tree/variants/wo_decoration.py b/pm4py/visualization/process_tree/variants/wo_decoration.py index 7c64528cd..44ce82ec6 100644 --- a/pm4py/visualization/process_tree/variants/wo_decoration.py +++ b/pm4py/visualization/process_tree/variants/wo_decoration.py @@ -18,6 +18,8 @@ class Parameters(Enum): FONT_SIZE = "font_size" BGCOLOR = "bgcolor" RANKDIR = "rankdir" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" # maps the operators to the ProM strings @@ -87,10 +89,17 @@ def apply(tree: ProcessTree, parameters: Optional[Dict[Union[str, Parameters], A 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) + font_size = exec_utils.get_param_value(Parameters.FONT_SIZE, parameters, 15) + font_size = str(font_size) + 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") 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='<'+graph_title+'>', labelloc="top") + image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") color_map = exec_utils.get_param_value(Parameters.COLOR_MAP, parameters, {}) diff --git a/pm4py/visualization/transition_system/util/visualize_graphviz.py b/pm4py/visualization/transition_system/util/visualize_graphviz.py index a4d7d02b3..89a1d4a9c 100644 --- a/pm4py/visualization/transition_system/util/visualize_graphviz.py +++ b/pm4py/visualization/transition_system/util/visualize_graphviz.py @@ -14,6 +14,8 @@ class Parameters(Enum): FILLCOLORS = "fillcolors" FONT_SIZE = "font_size" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def visualize(ts, parameters=None): @@ -28,6 +30,8 @@ def visualize(ts, parameters=None): font_size = exec_utils.get_param_value(Parameters.FONT_SIZE, parameters, 11) font_size = str(font_size) bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR) + 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, "Transition System") for state in ts.states: state.label = state.name @@ -47,6 +51,9 @@ def visualize(ts, parameters=None): viz = Digraph(ts.name, filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + # states viz.attr('node') for s in ts.states: diff --git a/pm4py/visualization/transition_system/variants/trans_frequency.py b/pm4py/visualization/transition_system/variants/trans_frequency.py index 14ed37035..0dce43fe3 100644 --- a/pm4py/visualization/transition_system/variants/trans_frequency.py +++ b/pm4py/visualization/transition_system/variants/trans_frequency.py @@ -14,6 +14,8 @@ class Parameters(Enum): FORMAT = "format" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def get_perc(total_events, arc_events): @@ -29,11 +31,17 @@ def apply(tsys: TransitionSystem, parameters: Optional[Dict[Union[str, Parameter image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR) + 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, "Transition System") + filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() viz = Digraph(tsys.name, filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + states_dictio = {} for s in tsys.states: diff --git a/pm4py/visualization/transition_system/variants/view_based.py b/pm4py/visualization/transition_system/variants/view_based.py index 3cacba457..67a47e488 100644 --- a/pm4py/visualization/transition_system/variants/view_based.py +++ b/pm4py/visualization/transition_system/variants/view_based.py @@ -12,6 +12,8 @@ class Parameters(Enum): FORCE_NAMES = "force_names" FILLCOLORS = "fillcolors" FONT_SIZE = "font_size" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def apply(tsys: TransitionSystem, parameters: Optional[Dict[Union[str, Parameters], Any]] = None) -> graphviz.Digraph: diff --git a/pm4py/visualization/trie/variants/classic.py b/pm4py/visualization/trie/variants/classic.py index 33c418d17..4be586ebc 100644 --- a/pm4py/visualization/trie/variants/classic.py +++ b/pm4py/visualization/trie/variants/classic.py @@ -11,6 +11,8 @@ class Parameters(Enum): FORMAT = "format" BGCOLOR = "bgcolor" + ENABLE_GRAPH_TITLE = "enable_graph_title" + GRAPH_TITLE = "graph_title" def draw_recursive(trie_node: Trie, parent: Union[str, None], gviz: Graph): @@ -58,12 +60,18 @@ def apply(trie: Trie, parameters: Optional[Dict[Union[str, Parameters], Any]] = image_format = exec_utils.get_param_value(Parameters.FORMAT, parameters, "png") bgcolor = exec_utils.get_param_value(Parameters.BGCOLOR, parameters, constants.DEFAULT_BGCOLOR) + 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, "Prefix Tree") + filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() viz = Graph("pt", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.attr('node', shape='ellipse', fixedsize='false') + if enable_graph_title: + viz.attr(label='<'+graph_title+'>', labelloc="top") + draw_recursive(trie, None, viz) viz.attr(overlap='false') From b34996b3b4a5cd74c1b6ebe2f531c9af0338c82c Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 1 Jul 2024 14:39:20 +0200 Subject: [PATCH 44/52] fix(pm4py): consistency check in OCEL 1.0/2.0 exporting --- pm4py/objects/ocel/exporter/csv/variants/pandas.py | 2 ++ pm4py/objects/ocel/exporter/jsonocel/variants/classic.py | 2 ++ pm4py/objects/ocel/exporter/jsonocel/variants/ocel20.py | 2 ++ pm4py/objects/ocel/exporter/sqlite/variants/ocel20.py | 2 ++ pm4py/objects/ocel/exporter/sqlite/variants/pandas_exporter.py | 2 ++ pm4py/objects/ocel/exporter/xmlocel/variants/classic.py | 2 ++ pm4py/objects/ocel/exporter/xmlocel/variants/ocel20.py | 2 ++ 7 files changed, 14 insertions(+) diff --git a/pm4py/objects/ocel/exporter/csv/variants/pandas.py b/pm4py/objects/ocel/exporter/csv/variants/pandas.py index 6bea00f44..48859d4ce 100644 --- a/pm4py/objects/ocel/exporter/csv/variants/pandas.py +++ b/pm4py/objects/ocel/exporter/csv/variants/pandas.py @@ -1,6 +1,7 @@ from pm4py.objects.ocel.obj import OCEL from typing import Optional, Dict, Any from pm4py.objects.ocel.util import ocel_consistency +from pm4py.objects.ocel.util import filtering_utils from enum import Enum from pm4py.util import exec_utils, constants as pm4_constants @@ -30,6 +31,7 @@ def apply(ocel: OCEL, output_path: str, objects_path=None, parameters: Optional[ encoding = exec_utils.get_param_value(Parameters.ENCODING, parameters, pm4_constants.DEFAULT_ENCODING) ocel = ocel_consistency.apply(ocel, parameters=parameters) + ocel = filtering_utils.propagate_relations_filtering(ocel, parameters=parameters) ocel.get_extended_table().to_csv(output_path, index=False, na_rep="", encoding=encoding) diff --git a/pm4py/objects/ocel/exporter/jsonocel/variants/classic.py b/pm4py/objects/ocel/exporter/jsonocel/variants/classic.py index bc07f4cb1..de537f136 100644 --- a/pm4py/objects/ocel/exporter/jsonocel/variants/classic.py +++ b/pm4py/objects/ocel/exporter/jsonocel/variants/classic.py @@ -9,6 +9,7 @@ from pm4py.objects.ocel.obj import OCEL from pm4py.objects.ocel.util import attributes_names from pm4py.objects.ocel.util import related_objects +from pm4py.objects.ocel.util import filtering_utils from pm4py.util import exec_utils, constants as pm4_constants, pandas_utils from pm4py.objects.ocel.util import ocel_consistency @@ -101,6 +102,7 @@ def apply(ocel: OCEL, target_path: str, parameters: Optional[Dict[Any, Any]] = N encoding = exec_utils.get_param_value(Parameters.ENCODING, parameters, pm4_constants.DEFAULT_ENCODING) ocel = ocel_consistency.apply(ocel, parameters=parameters) + ocel = filtering_utils.propagate_relations_filtering(ocel, parameters=parameters) base_object = get_base_json_object(ocel, parameters=parameters) diff --git a/pm4py/objects/ocel/exporter/jsonocel/variants/ocel20.py b/pm4py/objects/ocel/exporter/jsonocel/variants/ocel20.py index e5c171561..a5303f93c 100644 --- a/pm4py/objects/ocel/exporter/jsonocel/variants/ocel20.py +++ b/pm4py/objects/ocel/exporter/jsonocel/variants/ocel20.py @@ -6,6 +6,7 @@ from pm4py.objects.ocel.obj import OCEL from pm4py.util import exec_utils, constants as pm4_constants from pm4py.objects.ocel.util import ocel_consistency +from pm4py.objects.ocel.util import filtering_utils from pm4py.objects.ocel.exporter.jsonocel.variants import classic from pm4py.objects.ocel.util import attributes_per_type @@ -27,6 +28,7 @@ def get_enriched_object(ocel: OCEL, parameters: Optional[Dict[Any, Any]] = None) event_timestamp = exec_utils.get_param_value(Parameters.EVENT_TIMESTAMP, parameters, ocel.event_timestamp) ocel = ocel_consistency.apply(ocel, parameters=parameters) + ocel = filtering_utils.propagate_relations_filtering(ocel, parameters=parameters) base_object = classic.get_base_json_object(ocel, parameters=parameters) diff --git a/pm4py/objects/ocel/exporter/sqlite/variants/ocel20.py b/pm4py/objects/ocel/exporter/sqlite/variants/ocel20.py index 26dd766f3..a6fff22d5 100644 --- a/pm4py/objects/ocel/exporter/sqlite/variants/ocel20.py +++ b/pm4py/objects/ocel/exporter/sqlite/variants/ocel20.py @@ -7,6 +7,7 @@ from enum import Enum from pm4py.util import exec_utils, pandas_utils from pm4py.objects.ocel.util import ocel_consistency +from pm4py.objects.ocel.util import filtering_utils class Parameters(Enum): @@ -25,6 +26,7 @@ def apply(ocel: OCEL, file_path: str, parameters: Optional[Dict[Any, Any]] = Non os.remove(file_path) ocel = ocel_consistency.apply(ocel, parameters=parameters) + ocel = filtering_utils.propagate_relations_filtering(ocel, parameters=parameters) event_id = ocel.event_id_column event_activity = ocel.event_activity diff --git a/pm4py/objects/ocel/exporter/sqlite/variants/pandas_exporter.py b/pm4py/objects/ocel/exporter/sqlite/variants/pandas_exporter.py index 8fa0bcbc1..4284b130e 100644 --- a/pm4py/objects/ocel/exporter/sqlite/variants/pandas_exporter.py +++ b/pm4py/objects/ocel/exporter/sqlite/variants/pandas_exporter.py @@ -1,6 +1,7 @@ from pm4py.objects.ocel.obj import OCEL from typing import Dict, Any, Optional from pm4py.objects.ocel.util import ocel_consistency +from pm4py.objects.ocel.util import filtering_utils import os @@ -26,6 +27,7 @@ def apply(ocel: OCEL, target_path: str, parameters: Optional[Dict[Any, Any]] = N os.remove(target_path) ocel = ocel_consistency.apply(ocel, parameters=parameters) + ocel = filtering_utils.propagate_relations_filtering(ocel, parameters=parameters) conn = sqlite3.connect(target_path) diff --git a/pm4py/objects/ocel/exporter/xmlocel/variants/classic.py b/pm4py/objects/ocel/exporter/xmlocel/variants/classic.py index 0f3546750..8a0a4f6d2 100644 --- a/pm4py/objects/ocel/exporter/xmlocel/variants/classic.py +++ b/pm4py/objects/ocel/exporter/xmlocel/variants/classic.py @@ -11,6 +11,7 @@ from pm4py.objects.ocel.util import related_objects from pm4py.util import exec_utils, constants as pm4_constants, pandas_utils from pm4py.objects.ocel.util import ocel_consistency +from pm4py.objects.ocel.util import filtering_utils class Parameters(Enum): @@ -56,6 +57,7 @@ def apply(ocel: OCEL, target_path: str, parameters: Optional[Dict[Any, Any]] = N encoding = exec_utils.get_param_value(Parameters.ENCODING, parameters, pm4_constants.DEFAULT_ENCODING) ocel = ocel_consistency.apply(ocel, parameters=parameters) + ocel = filtering_utils.propagate_relations_filtering(ocel, parameters=parameters) all_object_types = pandas_utils.format_unique(ocel.objects[object_type].unique()) all_attribute_names = attributes_names.get_attribute_names(ocel, parameters=parameters) diff --git a/pm4py/objects/ocel/exporter/xmlocel/variants/ocel20.py b/pm4py/objects/ocel/exporter/xmlocel/variants/ocel20.py index f73a1d5f5..980d09446 100644 --- a/pm4py/objects/ocel/exporter/xmlocel/variants/ocel20.py +++ b/pm4py/objects/ocel/exporter/xmlocel/variants/ocel20.py @@ -9,6 +9,7 @@ from pm4py.util import exec_utils, constants as pm4_constants from pm4py.objects.ocel.util import ocel_consistency from pm4py.objects.ocel.util import attributes_per_type +from pm4py.objects.ocel.util import filtering_utils class Parameters(Enum): @@ -39,6 +40,7 @@ def apply(ocel: OCEL, target_path: str, parameters: Optional[Dict[Any, Any]] = N changed_field_column = exec_utils.get_param_value(Parameters.CHANGED_FIELD, parameters, ocel.changed_field) ocel = ocel_consistency.apply(ocel, parameters=parameters) + ocel = filtering_utils.propagate_relations_filtering(ocel, parameters=parameters) objects0 = ocel.objects.to_dict("records") events0 = ocel.events.to_dict("records") From 07b169bde4c17d1b316018b92a6e82b3602f6a3e Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Wed, 3 Jul 2024 11:23:29 +0200 Subject: [PATCH 45/52] updating third party dependencies --- Dockerfile | 6 +++--- requirements_stable.txt | 2 +- third_party/LICENSES_TRANSITIVE.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index f1a9b6fea..1b25c98b2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,12 +7,12 @@ RUN apt-get -y install gcc g++ flex bison pkg-config automake autoconf cmake RUN apt-get -y install python3-dev python3-pydot python3-tk RUN apt-get -y install libopenblas-dev liblapack-dev libboost-all-dev libncurses5-dev libtool libssl-dev libjemalloc-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-regex-dev libxml2-dev libxslt-dev libfreetype6-dev libsuitesparse-dev libclang-16-dev llvm-16-dev libthrift-dev libfftw3-dev RUN python3 -m pip install --upgrade pip -RUN pip3 install deprecation==2.1.0 graphviz==0.20.3 intervaltree==3.1.0 networkx==3.3 packaging==24.1 python-dateutil==2.9.0.post0 pytz==2024.1 setuptools==70.1.1 six==1.16.0 sortedcontainers==2.4.0 tzdata==2024.1 wheel==0.43.0 +RUN pip3 install deprecation==2.1.0 graphviz==0.20.3 intervaltree==3.1.0 networkx==3.3 packaging==24.1 python-dateutil==2.9.0.post0 pytz==2024.1 setuptools==70.2.0 six==1.16.0 sortedcontainers==2.4.0 tzdata==2024.1 wheel==0.43.0 RUN pip3 install colorama==0.4.6 cycler==0.12.1 pydotplus==2.0.2 pyparsing==3.1.2 tqdm==4.66.4 RUN pip3 install lxml==5.2.2 numpy==2.0.0 pandas==2.2.2 scipy==1.14.0 RUN pip3 install contourpy==1.2.1 fonttools==4.53.0 kiwisolver==1.4.5 matplotlib==3.9.0 pillow==10.4.0 -RUN pip3 install anyio==4.4.0 asttokens==2.4.1 attrs==23.2.0 certifi==2024.6.2 charset-normalizer==3.3.2 convertdate==2.4.0 decorator==5.1.1 distro==1.9.0 executing==2.0.1 h11==0.14.0 httpcore==1.0.5 httpx==0.27.0 idna==3.7 ipython==8.26.0 jedi==0.19.1 Jinja2==3.1.4 jsonpickle==3.2.2 jsonschema-specifications==2023.12.1 lunardate==0.2.2 MarkupSafe==2.1.5 matplotlib-inline==0.1.7 parso==0.8.4 prompt-toolkit==3.0.47 pure-eval==0.2.2 pydantic==2.7.4 Pygments==2.18.0 pyluach==2.2.0 PyMeeus==0.5.12 referencing==0.35.1 rpds-py==0.18.1 sniffio==1.3.1 stack-data==0.6.3 traitlets==5.14.3 typing_extensions==4.12.2 urllib3==2.2.2 wcwidth==0.2.13 -RUN pip3 install jsonschema==4.22.0 openai==1.35.7 pyvis==0.3.2 requests==2.32.3 workalendar==17.0.0 +RUN pip3 install anyio==4.4.0 asttokens==2.4.1 attrs==23.2.0 certifi==2024.6.2 charset-normalizer==3.3.2 convertdate==2.4.0 decorator==5.1.1 distro==1.9.0 executing==2.0.1 h11==0.14.0 httpcore==1.0.5 httpx==0.27.0 idna==3.7 ipython==8.26.0 jedi==0.19.1 Jinja2==3.1.4 jsonpickle==3.2.2 jsonschema-specifications==2023.12.1 lunardate==0.2.2 MarkupSafe==2.1.5 matplotlib-inline==0.1.7 parso==0.8.4 prompt-toolkit==3.0.47 pure-eval==0.2.2 pydantic==2.8.0 Pygments==2.18.0 pyluach==2.2.0 PyMeeus==0.5.12 referencing==0.35.1 rpds-py==0.18.1 sniffio==1.3.1 stack-data==0.6.3 traitlets==5.14.3 typing_extensions==4.12.2 urllib3==2.2.2 wcwidth==0.2.13 +RUN pip3 install jsonschema==4.22.0 openai==1.35.9 pyvis==0.3.2 requests==2.32.3 workalendar==17.0.0 RUN pip3 install -U meson-python==0.15.0 Cython==3.0.10 ninja==1.11.1.1 spin==0.8 build==1.2.1 setuptools_scm==8.0.4 #RUN cd / && git clone https://github.com/numpy/numpy.git && cd /numpy && git submodule update --init && pip3 install . diff --git a/requirements_stable.txt b/requirements_stable.txt index 89893ae19..1284a586d 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -18,7 +18,7 @@ pyparsing==3.1.2 python-dateutil==2.9.0.post0 pytz==2024.1 scipy==1.14.0 -setuptools==70.1.1 +setuptools==70.2.0 six==1.16.0 sortedcontainers==2.4.0 tqdm==4.66.4 diff --git a/third_party/LICENSES_TRANSITIVE.md b/third_party/LICENSES_TRANSITIVE.md index a962869cf..ef1e266b0 100644 --- a/third_party/LICENSES_TRANSITIVE.md +++ b/third_party/LICENSES_TRANSITIVE.md @@ -26,7 +26,7 @@ | python-dateutil | https://pypi.org/project/python-dateutil | Apache Software License, BSD License (Dual License) | 2.9.0.post0 | | pytz | https://pypi.org/project/pytz | MIT License (MIT) | 2024.1 | | scipy | https://pypi.org/project/scipy | BSD License | 1.14.0 | -| setuptools | https://pypi.org/project/setuptools | MIT License | 70.1.1 | +| setuptools | https://pypi.org/project/setuptools | MIT License | 70.2.0 | | six | https://pypi.org/project/six | MIT License (MIT) | 1.16.0 | | sortedcontainers | https://pypi.org/project/sortedcontainers | Apache Software License (Apache 2.0) | 2.4.0 | | tqdm | https://pypi.org/project/tqdm | MIT License, Mozilla Public License 2.0 (MPL 2.0) (MPL-2.0 AND MIT) | 4.66.4 | From 3c649d2223ff1317ab72cb284520ed9ef86a2e8f Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Thu, 4 Jul 2024 15:24:09 +0200 Subject: [PATCH 46/52] updated third party dependencies --- Dockerfile | 6 +++--- requirements_stable.txt | 2 +- third_party/LICENSES_TRANSITIVE.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1b25c98b2..71162a102 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,9 +10,9 @@ RUN python3 -m pip install --upgrade pip RUN pip3 install deprecation==2.1.0 graphviz==0.20.3 intervaltree==3.1.0 networkx==3.3 packaging==24.1 python-dateutil==2.9.0.post0 pytz==2024.1 setuptools==70.2.0 six==1.16.0 sortedcontainers==2.4.0 tzdata==2024.1 wheel==0.43.0 RUN pip3 install colorama==0.4.6 cycler==0.12.1 pydotplus==2.0.2 pyparsing==3.1.2 tqdm==4.66.4 RUN pip3 install lxml==5.2.2 numpy==2.0.0 pandas==2.2.2 scipy==1.14.0 -RUN pip3 install contourpy==1.2.1 fonttools==4.53.0 kiwisolver==1.4.5 matplotlib==3.9.0 pillow==10.4.0 -RUN pip3 install anyio==4.4.0 asttokens==2.4.1 attrs==23.2.0 certifi==2024.6.2 charset-normalizer==3.3.2 convertdate==2.4.0 decorator==5.1.1 distro==1.9.0 executing==2.0.1 h11==0.14.0 httpcore==1.0.5 httpx==0.27.0 idna==3.7 ipython==8.26.0 jedi==0.19.1 Jinja2==3.1.4 jsonpickle==3.2.2 jsonschema-specifications==2023.12.1 lunardate==0.2.2 MarkupSafe==2.1.5 matplotlib-inline==0.1.7 parso==0.8.4 prompt-toolkit==3.0.47 pure-eval==0.2.2 pydantic==2.8.0 Pygments==2.18.0 pyluach==2.2.0 PyMeeus==0.5.12 referencing==0.35.1 rpds-py==0.18.1 sniffio==1.3.1 stack-data==0.6.3 traitlets==5.14.3 typing_extensions==4.12.2 urllib3==2.2.2 wcwidth==0.2.13 -RUN pip3 install jsonschema==4.22.0 openai==1.35.9 pyvis==0.3.2 requests==2.32.3 workalendar==17.0.0 +RUN pip3 install contourpy==1.2.1 fonttools==4.53.0 kiwisolver==1.4.5 matplotlib==3.9.1 pillow==10.4.0 +RUN pip3 install anyio==4.4.0 asttokens==2.4.1 attrs==23.2.0 certifi==2024.7.4 charset-normalizer==3.3.2 convertdate==2.4.0 decorator==5.1.1 distro==1.9.0 executing==2.0.1 h11==0.14.0 httpcore==1.0.5 httpx==0.27.0 idna==3.7 ipython==8.26.0 jedi==0.19.1 Jinja2==3.1.4 jsonpickle==3.2.2 jsonschema-specifications==2023.12.1 lunardate==0.2.2 MarkupSafe==2.1.5 matplotlib-inline==0.1.7 parso==0.8.4 prompt-toolkit==3.0.47 pure-eval==0.2.2 pydantic==2.8.2 Pygments==2.18.0 pyluach==2.2.0 PyMeeus==0.5.12 referencing==0.35.1 rpds-py==0.18.1 sniffio==1.3.1 stack-data==0.6.3 traitlets==5.14.3 typing_extensions==4.12.2 urllib3==2.2.2 wcwidth==0.2.13 +RUN pip3 install jsonschema==4.22.0 openai==1.35.10 pyvis==0.3.2 requests==2.32.3 workalendar==17.0.0 RUN pip3 install -U meson-python==0.15.0 Cython==3.0.10 ninja==1.11.1.1 spin==0.8 build==1.2.1 setuptools_scm==8.0.4 #RUN cd / && git clone https://github.com/numpy/numpy.git && cd /numpy && git submodule update --init && pip3 install . diff --git a/requirements_stable.txt b/requirements_stable.txt index 1284a586d..dccacecda 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -7,7 +7,7 @@ graphviz==0.20.3 intervaltree==3.1.0 kiwisolver==1.4.5 lxml==5.2.2 -matplotlib==3.9.0 +matplotlib==3.9.1 networkx==3.3 numpy==2.0.0 packaging==24.1 diff --git a/third_party/LICENSES_TRANSITIVE.md b/third_party/LICENSES_TRANSITIVE.md index ef1e266b0..15f22e56a 100644 --- a/third_party/LICENSES_TRANSITIVE.md +++ b/third_party/LICENSES_TRANSITIVE.md @@ -15,7 +15,7 @@ | intervaltree | https://pypi.org/project/intervaltree | Apache Software License (Apache License, Version 2.0) | 3.1.0 | | kiwisolver | https://pypi.org/project/kiwisolver | BSD License | 1.4.5 | | lxml | https://pypi.org/project/lxml | BSD License (BSD-3-Clause) | 5.2.2 | -| matplotlib | https://pypi.org/project/matplotlib | Python Software Foundation License | 3.9.0 | +| matplotlib | https://pypi.org/project/matplotlib | Python Software Foundation License | 3.9.1 | | networkx | https://pypi.org/project/networkx | BSD License | 3.3 | | numpy | https://pypi.org/project/numpy | BSD License | 2.0.0 | | packaging | https://pypi.org/project/packaging | Apache Software License, BSD License | 24.1 | From 44bccfa72581a8e4d8c54a9a8f510c0d1401a017 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Mon, 8 Jul 2024 09:16:28 +0200 Subject: [PATCH 47/52] added third party dependencies --- Dockerfile | 2 +- requirements_stable.txt | 2 +- third_party/LICENSES_TRANSITIVE.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 71162a102..546f0d866 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN python3 -m pip install --upgrade pip RUN pip3 install deprecation==2.1.0 graphviz==0.20.3 intervaltree==3.1.0 networkx==3.3 packaging==24.1 python-dateutil==2.9.0.post0 pytz==2024.1 setuptools==70.2.0 six==1.16.0 sortedcontainers==2.4.0 tzdata==2024.1 wheel==0.43.0 RUN pip3 install colorama==0.4.6 cycler==0.12.1 pydotplus==2.0.2 pyparsing==3.1.2 tqdm==4.66.4 RUN pip3 install lxml==5.2.2 numpy==2.0.0 pandas==2.2.2 scipy==1.14.0 -RUN pip3 install contourpy==1.2.1 fonttools==4.53.0 kiwisolver==1.4.5 matplotlib==3.9.1 pillow==10.4.0 +RUN pip3 install contourpy==1.2.1 fonttools==4.53.1 kiwisolver==1.4.5 matplotlib==3.9.1 pillow==10.4.0 RUN pip3 install anyio==4.4.0 asttokens==2.4.1 attrs==23.2.0 certifi==2024.7.4 charset-normalizer==3.3.2 convertdate==2.4.0 decorator==5.1.1 distro==1.9.0 executing==2.0.1 h11==0.14.0 httpcore==1.0.5 httpx==0.27.0 idna==3.7 ipython==8.26.0 jedi==0.19.1 Jinja2==3.1.4 jsonpickle==3.2.2 jsonschema-specifications==2023.12.1 lunardate==0.2.2 MarkupSafe==2.1.5 matplotlib-inline==0.1.7 parso==0.8.4 prompt-toolkit==3.0.47 pure-eval==0.2.2 pydantic==2.8.2 Pygments==2.18.0 pyluach==2.2.0 PyMeeus==0.5.12 referencing==0.35.1 rpds-py==0.18.1 sniffio==1.3.1 stack-data==0.6.3 traitlets==5.14.3 typing_extensions==4.12.2 urllib3==2.2.2 wcwidth==0.2.13 RUN pip3 install jsonschema==4.22.0 openai==1.35.10 pyvis==0.3.2 requests==2.32.3 workalendar==17.0.0 RUN pip3 install -U meson-python==0.15.0 Cython==3.0.10 ninja==1.11.1.1 spin==0.8 build==1.2.1 setuptools_scm==8.0.4 diff --git a/requirements_stable.txt b/requirements_stable.txt index dccacecda..3d53e9aa8 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -2,7 +2,7 @@ colorama==0.4.6 contourpy==1.2.1 cycler==0.12.1 deprecation==2.1.0 -fonttools==4.53.0 +fonttools==4.53.1 graphviz==0.20.3 intervaltree==3.1.0 kiwisolver==1.4.5 diff --git a/third_party/LICENSES_TRANSITIVE.md b/third_party/LICENSES_TRANSITIVE.md index 15f22e56a..bee2f8d8b 100644 --- a/third_party/LICENSES_TRANSITIVE.md +++ b/third_party/LICENSES_TRANSITIVE.md @@ -10,7 +10,7 @@ | contourpy | https://pypi.org/project/contourpy | BSD License | 1.2.1 | | cycler | https://pypi.org/project/cycler | BSD License | 0.12.1 | | deprecation | https://pypi.org/project/deprecation | Apache Software License (Apache 2) | 2.1.0 | -| fonttools | https://pypi.org/project/fonttools | MIT License (MIT) | 4.53.0 | +| fonttools | https://pypi.org/project/fonttools | MIT License (MIT) | 4.53.1 | | graphviz | https://pypi.org/project/graphviz | MIT License (MIT) | 0.20.3 | | intervaltree | https://pypi.org/project/intervaltree | Apache Software License (Apache License, Version 2.0) | 3.1.0 | | kiwisolver | https://pypi.org/project/kiwisolver | BSD License | 1.4.5 | From 5e5503c8a2da1af5fee64ede98e11db86cb5c2e3 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 9 Jul 2024 16:37:26 +0000 Subject: [PATCH 48/52] chore(deps): update dependency setuptools to v70.3.0 --- requirements_stable.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_stable.txt b/requirements_stable.txt index 3d53e9aa8..db1c4e9ba 100644 --- a/requirements_stable.txt +++ b/requirements_stable.txt @@ -18,7 +18,7 @@ pyparsing==3.1.2 python-dateutil==2.9.0.post0 pytz==2024.1 scipy==1.14.0 -setuptools==70.2.0 +setuptools==70.3.0 six==1.16.0 sortedcontainers==2.4.0 tqdm==4.66.4 From 9bd7e5e4a02e27a0dc9b1520f97003f8900f45fe Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Thu, 11 Jul 2024 15:10:02 +0200 Subject: [PATCH 49/52] docs(pm4py): updated changelog --- CHANGELOG.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c887cbe5e..54b111b96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,25 @@ # Changelog of pm4py -## pm4py 2.7.13 (2024.05.03) +## pm4py 2.7.14 (2024.XX.YY) + +### Added + +### Changed + +### Deprecated + +### Fixed + +### Removed + +### Other + + +--- + + +## pm4py 2.7.13 (2024.07.11) ### Added @@ -14,6 +32,10 @@ * refactoring dependencies generation script * 928ecf5f8192ff1ef7944c5b0a7be7c530814ad9 * refactoring OpenAI query interface +* 5fee9b4ac61c227ac77cbd28b888a7321ba401bf + * refactor OCEL object repr +* 6c1ea7a38b3ef18fe9d490164ecebd85c432915f + * possibility to set the title in pm4py visualizations ### Deprecated @@ -26,6 +48,12 @@ * minor fix OCEL interleavings computation * 39d769cad1327c47d5948b0c40be4a90e41fcce7 * removed indeterminism in TBR with duplicate transitions +* 2fb8e6bffcac11b14fe13f152ac0b096cdc0d03a + * penwidth assignation in DFG edges +* c753425ffd63da55fc0d3e71ab5b5fb62a2bf359 + * OCEL exporters consistency check +* e98d795c977348dcbe7495d62c8975fae0b9499c + * LTL filters documentation in the simplified interface ### Removed From 38df0f3fd11be77f5b107800e2aa84c6c69ea73b Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Thu, 11 Jul 2024 15:13:42 +0200 Subject: [PATCH 50/52] docs(pm4py): updating third-party dependencies --- Dockerfile | 6 +++--- third_party/LICENSES_TRANSITIVE.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 546f0d866..6f5acbe5c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,12 +7,12 @@ RUN apt-get -y install gcc g++ flex bison pkg-config automake autoconf cmake RUN apt-get -y install python3-dev python3-pydot python3-tk RUN apt-get -y install libopenblas-dev liblapack-dev libboost-all-dev libncurses5-dev libtool libssl-dev libjemalloc-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-regex-dev libxml2-dev libxslt-dev libfreetype6-dev libsuitesparse-dev libclang-16-dev llvm-16-dev libthrift-dev libfftw3-dev RUN python3 -m pip install --upgrade pip -RUN pip3 install deprecation==2.1.0 graphviz==0.20.3 intervaltree==3.1.0 networkx==3.3 packaging==24.1 python-dateutil==2.9.0.post0 pytz==2024.1 setuptools==70.2.0 six==1.16.0 sortedcontainers==2.4.0 tzdata==2024.1 wheel==0.43.0 +RUN pip3 install deprecation==2.1.0 graphviz==0.20.3 intervaltree==3.1.0 networkx==3.3 packaging==24.1 python-dateutil==2.9.0.post0 pytz==2024.1 setuptools==70.3.0 six==1.16.0 sortedcontainers==2.4.0 tzdata==2024.1 wheel==0.43.0 RUN pip3 install colorama==0.4.6 cycler==0.12.1 pydotplus==2.0.2 pyparsing==3.1.2 tqdm==4.66.4 RUN pip3 install lxml==5.2.2 numpy==2.0.0 pandas==2.2.2 scipy==1.14.0 RUN pip3 install contourpy==1.2.1 fonttools==4.53.1 kiwisolver==1.4.5 matplotlib==3.9.1 pillow==10.4.0 -RUN pip3 install anyio==4.4.0 asttokens==2.4.1 attrs==23.2.0 certifi==2024.7.4 charset-normalizer==3.3.2 convertdate==2.4.0 decorator==5.1.1 distro==1.9.0 executing==2.0.1 h11==0.14.0 httpcore==1.0.5 httpx==0.27.0 idna==3.7 ipython==8.26.0 jedi==0.19.1 Jinja2==3.1.4 jsonpickle==3.2.2 jsonschema-specifications==2023.12.1 lunardate==0.2.2 MarkupSafe==2.1.5 matplotlib-inline==0.1.7 parso==0.8.4 prompt-toolkit==3.0.47 pure-eval==0.2.2 pydantic==2.8.2 Pygments==2.18.0 pyluach==2.2.0 PyMeeus==0.5.12 referencing==0.35.1 rpds-py==0.18.1 sniffio==1.3.1 stack-data==0.6.3 traitlets==5.14.3 typing_extensions==4.12.2 urllib3==2.2.2 wcwidth==0.2.13 -RUN pip3 install jsonschema==4.22.0 openai==1.35.10 pyvis==0.3.2 requests==2.32.3 workalendar==17.0.0 +RUN pip3 install anyio==4.4.0 asttokens==2.4.1 attrs==23.2.0 certifi==2024.7.4 charset-normalizer==3.3.2 convertdate==2.4.0 decorator==5.1.1 distro==1.9.0 executing==2.0.1 h11==0.14.0 httpcore==1.0.5 httpx==0.27.0 idna==3.7 ipython==8.26.0 jedi==0.19.1 Jinja2==3.1.4 jsonpickle==3.2.2 jsonschema-specifications==2023.12.1 lunardate==0.2.2 MarkupSafe==2.1.5 matplotlib-inline==0.1.7 parso==0.8.4 prompt-toolkit==3.0.47 pure-eval==0.2.2 pydantic==2.8.2 Pygments==2.18.0 pyluach==2.2.0 PyMeeus==0.5.12 referencing==0.35.1 rpds-py==0.19.0 sniffio==1.3.1 stack-data==0.6.3 traitlets==5.14.3 typing_extensions==4.12.2 urllib3==2.2.2 wcwidth==0.2.13 +RUN pip3 install jsonschema==4.23.0 openai==1.35.13 pyvis==0.3.2 requests==2.32.3 workalendar==17.0.0 RUN pip3 install -U meson-python==0.15.0 Cython==3.0.10 ninja==1.11.1.1 spin==0.8 build==1.2.1 setuptools_scm==8.0.4 #RUN cd / && git clone https://github.com/numpy/numpy.git && cd /numpy && git submodule update --init && pip3 install . diff --git a/third_party/LICENSES_TRANSITIVE.md b/third_party/LICENSES_TRANSITIVE.md index bee2f8d8b..a2c5d19ca 100644 --- a/third_party/LICENSES_TRANSITIVE.md +++ b/third_party/LICENSES_TRANSITIVE.md @@ -26,7 +26,7 @@ | python-dateutil | https://pypi.org/project/python-dateutil | Apache Software License, BSD License (Dual License) | 2.9.0.post0 | | pytz | https://pypi.org/project/pytz | MIT License (MIT) | 2024.1 | | scipy | https://pypi.org/project/scipy | BSD License | 1.14.0 | -| setuptools | https://pypi.org/project/setuptools | MIT License | 70.2.0 | +| setuptools | https://pypi.org/project/setuptools | MIT License | 70.3.0 | | six | https://pypi.org/project/six | MIT License (MIT) | 1.16.0 | | sortedcontainers | https://pypi.org/project/sortedcontainers | Apache Software License (Apache 2.0) | 2.4.0 | | tqdm | https://pypi.org/project/tqdm | MIT License, Mozilla Public License 2.0 (MPL 2.0) (MPL-2.0 AND MIT) | 4.66.4 | From a94a87464799de7cb992b354b083ca64642555bc Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Wed, 18 Dec 2024 13:25:01 +0100 Subject: [PATCH 51/52] revert --- pm4py/visualization/bpmn/variants/classic.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/pm4py/visualization/bpmn/variants/classic.py b/pm4py/visualization/bpmn/variants/classic.py index 1a5672d80..9873f4d38 100644 --- a/pm4py/visualization/bpmn/variants/classic.py +++ b/pm4py/visualization/bpmn/variants/classic.py @@ -39,8 +39,7 @@ class Parameters(Enum): ENABLE_SWIMLANES = "enable_swimlanes" INCLUDE_NAME_IN_EVENTS = "include_name_in_events" SWIMLANES_MARGIN = "swimlanes_margin" - ENABLE_GRAPH_TITLE = "enable_graph_title" - GRAPH_TITLE = "graph_title" + ENDPOINTS_SHAPE = "endpoints_shape" def add_bpmn_node(graph, n, font_size, include_name_in_events, endpoints_shape): @@ -105,8 +104,7 @@ def apply(bpmn_graph: BPMN, parameters: Optional[Dict[Any, Any]] = None) -> grap include_name_in_events = exec_utils.get_param_value(Parameters.INCLUDE_NAME_IN_EVENTS, parameters, True) swimlanes_margin = exec_utils.get_param_value(Parameters.SWIMLANES_MARGIN, parameters, 35) swimlanes_margin = str(swimlanes_margin) - 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, "BPMN Diagram") + endpoints_shape = exec_utils.get_param_value(Parameters.ENDPOINTS_SHAPE, parameters, "circle") filename = tempfile.NamedTemporaryFile(suffix='.gv') filename.close() @@ -114,9 +112,6 @@ def apply(bpmn_graph: BPMN, parameters: Optional[Dict[Any, Any]] = None) -> grap viz = Digraph("", filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) viz.graph_attr['rankdir'] = rankdir - if enable_graph_title: - viz.attr(label='<'+graph_title+'>', labelloc="top") - nodes, edges = get_sorted_nodes_edges(bpmn_graph) process_ids = [] for n in nodes: From 64b07c78a98a04ab14370a9c404d2d0414725c52 Mon Sep 17 00:00:00 2001 From: Alessandro Berti Date: Wed, 18 Dec 2024 16:06:31 +0100 Subject: [PATCH 52/52] revert --- pm4py/filtering.py | 64 +++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/pm4py/filtering.py b/pm4py/filtering.py index d78bcf6a7..3d87c8e62 100644 --- a/pm4py/filtering.py +++ b/pm4py/filtering.py @@ -1177,22 +1177,36 @@ def filter_ocel_events_timestamp( ) """ from pm4py.algo.filtering.ocel import event_attributes - return event_attributes.apply_timestamp(ocel, min_timest, max_timest, parameters={"pm4py:param:timestamp_key": timestamp_key}) + return event_attributes.apply_timestamp( + ocel, + min_timest, + max_timest, + parameters={"pm4py:param:timestamp_key": timestamp_key} + ) -def filter_four_eyes_principle(log: Union[EventLog, pd.DataFrame], activity1: str, activity2: str, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", resource_key: str = "org:resource", keep_violations: bool = False) -> Union[EventLog, pd.DataFrame]: +def filter_four_eyes_principle( + log: Union[EventLog, pd.DataFrame], + activity1: str, + activity2: str, + activity_key: str = "concept:name", + timestamp_key: str = "time:timestamp", + case_id_key: str = "case:concept:name", + resource_key: str = "org:resource", + keep_violations: bool = False +) -> Union[EventLog, pd.DataFrame]: """ - Filter out the cases of the log violating the four eyes principle on the provided activities. + Filters out the cases of the log that violate the four-eyes principle on the provided activities. - :param log: event log - :param activity1: first activity - :param activity2: second activity - :param activity_key: attribute to be used for the activity - :param timestamp_key: attribute to be used for the timestamp - :param case_id_key: attribute to be used as case identifier - :param resource_key: attribute to be used as resource - :param keep_violations: boolean to discard (if False) or retain (if True) the violations - :rtype: ``Union[EventLog, pd.DataFrame]`` + :param log: Event log or Pandas DataFrame. + :param activity1: First activity. + :param activity2: Second activity. + :param activity_key: Attribute to be used for the activity. + :param timestamp_key: Attribute to be used for the timestamp. + :param case_id_key: Attribute to be used as case identifier. + :param resource_key: Attribute to be used as resource. + :param keep_violations: Boolean indicating whether to discard (if False) or retain (if True) the violations. + :return: Filtered event log or Pandas DataFrame. .. code-block:: python3 @@ -1223,18 +1237,26 @@ def filter_four_eyes_principle(log: Union[EventLog, pd.DataFrame], activity1: st return ltl_checker.four_eyes_principle(log, activity1, activity2, parameters=properties) -def filter_activity_done_different_resources(log: Union[EventLog, pd.DataFrame], activity: str, activity_key: str = "concept:name", timestamp_key: str = "time:timestamp", case_id_key: str = "case:concept:name", resource_key: str = "org:resource", keep_violations: bool = True) -> Union[EventLog, pd.DataFrame]: +def filter_activity_done_different_resources( + log: Union[EventLog, pd.DataFrame], + activity: str, + activity_key: str = "concept:name", + timestamp_key: str = "time:timestamp", + case_id_key: str = "case:concept:name", + resource_key: str = "org:resource", + keep_violations: bool = True +) -> Union[EventLog, pd.DataFrame]: """ Filters the cases where an activity is performed by different resources multiple times. - :param log: event log - :param activity: activity to consider - :param activity_key: attribute to be used for the activity - :param timestamp_key: attribute to be used for the timestamp - :param case_id_key: attribute to be used as case identifier - :param resource_key: attribute to be used as resource - :param keep_violations: boolean to discard (if False) or retain (if True) the violations - :rtype: ``Union[EventLog, pd.DataFrame]`` + :param log: Event log or Pandas DataFrame. + :param activity: Activity to consider. + :param activity_key: Attribute to be used for the activity. + :param timestamp_key: Attribute to be used for the timestamp. + :param case_id_key: Attribute to be used as case identifier. + :param resource_key: Attribute to be used as resource. + :param keep_violations: Boolean indicating whether to discard (if False) or retain (if True) the violations. + :return: Filtered event log or Pandas DataFrame. .. code-block:: python3