openprocess 0.12.1__tar.gz → 0.12.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openprocess-0.12.1/openprocess.egg-info → openprocess-0.12.2}/PKG-INFO +1 -1
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/__init__.py +1 -1
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/measure.py +2 -3
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/viewers.py +78 -10
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/dotted.py +30 -4
- {openprocess-0.12.1 → openprocess-0.12.2/openprocess.egg-info}/PKG-INFO +1 -1
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_flow_gui.py +9 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_measure.py +2 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/LICENSE +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/README.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/cpnpy/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/analysis/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/analysis/state_space.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/analysis/state_space_process.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/citation.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/cli.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/1 Petri nets/Exercise 1.1 Order handling/answer.pnml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/1 Petri nets/Exercise 1.1 Order handling/question.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/2 Soundness/Exercise 2.1 Spot the flaw/answer.pnml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/2 Soundness/Exercise 2.1 Spot the flaw/net.pnml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/2 Soundness/Exercise 2.1 Spot the flaw/question.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/3 Discovery/Exercise 3.1 The alpha-algorithm/log.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/3 Discovery/Exercise 3.1 The alpha-algorithm/question.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/4 Regions/Exercise 4.1 Regions of a transition system/question.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/4 Regions/Exercise 4.1 Regions of a transition system/ts.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/5 Markings/Exercise 5.1 Markings and matrices/net.pnml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/5 Markings/Exercise 5.1 Markings and matrices/question.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/6 Inductive Miner/Exercise 6.1 Cuts and trees/log.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/6 Inductive Miner/Exercise 6.1 Cuts and trees/question.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/log.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/m1.pnml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/m2.pnml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/m3.pnml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/net.pnml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/7 Conformance/Exercise 7.1 Replay, alignments and workflows/question.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/exercises/pack.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/box.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/check.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/compare.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/cpn.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/discover.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/filter.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/input.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/output.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/predict.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/science.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/boxes/sweeps.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/convert.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/datasets.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/explain.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/figures.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/history.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/library.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/provenance.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/record.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/report.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/reproducibility.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/runner.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/script.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/snapshots.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/sweep.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/types.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/flow/workflow.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/app.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/arc_editing.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/canvas.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/canvas.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/page.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/picker.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/runs.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/stepper.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/summary.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/flow/templates.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/items.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/learn/answer_boxes.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/learn/concealment.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/learn/mode.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/panning.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/resources/openprocess-icon.png +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/__main__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/alignment_view.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/app.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/charts.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/cite.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/command_palette.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/compare_page.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/connections.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/cpn_page.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/definition_view.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/derivation_view.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/documents.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/dotted_chart.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/file_dialogs.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/filter_dialog.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/graph_builders.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/graph_view.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/instances.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/loading.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/log_editor.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/log_page.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/markdown_view.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/mathtext.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/ml_highlighter.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/model_page.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/motion.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/net_comparison.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/notes_overlay.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/petri_page.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/provenance.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/regions_view.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/sidebar.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/spaces.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/style.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/tool_icons.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/updates.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/widgets.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/workers.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/studio/workspace.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/theme.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/gui/tidy.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/io/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/io/cpn_reader.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/io/cpn_writer.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/answers.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/checks.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/computed.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/context.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/exam.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/exercise-packs.md +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/importer.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/notation.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/pack.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/learn/sheet.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/analysis.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/cases.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/columns.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/compare_nets.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/conformance/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/conformance/alignments.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/conformance/quality.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/conformance/token_replay.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/csv_import.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/definitions.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/dfg.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/discovery/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/discovery/alpha.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/discovery/heuristics.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/discovery/inductive.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/discovery/state_regions.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/filtering.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/footprint.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/invariants.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/layout.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/log.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/ocel.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/petrinet.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/playout.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/pm4py_bridge.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/pnml.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/processtree.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/regions.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/stats.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/structure.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/transition_system.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/mining/xes.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/ast_nodes.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/builtins.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/colorsets.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/errors.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/evaluator.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/lexer.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/multiset.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/parser.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/ml/values.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/model/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/model/declarations.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/model/examples.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/model/net.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/model/plain.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/packages.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/palette.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/references.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/sim/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/sim/binding.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/sim/export.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/sim/simulator.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/teaching/__init__.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/teaching/answers.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/teaching/checks.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/teaching/pack.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess/teaching/sheet.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess.egg-info/SOURCES.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess.egg-info/dependency_links.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess.egg-info/entry_points.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess.egg-info/requires.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/openprocess.egg-info/top_level.txt +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/pyproject.toml +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/setup.cfg +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_arc_editing.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_citation.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_colorsets.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_columns.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_cpn_course_model.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_definitions.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_docs.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_exercises_gui.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_flow.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_framework_contract.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_hierarchy.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_history.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_io.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_large_logs.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_learn.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_learn_gui.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_log_editing.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_mining.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_ml.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_multiset.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_ocel.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_packages.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_regions.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_rename.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_report.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_simulation.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_snapshots.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_state_space.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_studio_gui.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_teaching.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_tidy.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_updates.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_wf_structure.py +0 -0
- {openprocess-0.12.1 → openprocess-0.12.2}/tests/test_workspace.py +0 -0
|
@@ -48,7 +48,7 @@ from .sim.simulator import Simulator
|
|
|
48
48
|
#: The one place the version number is written (pyproject.toml, the update
|
|
49
49
|
#: check and packaging/build.py read it from here). A release is tagged
|
|
50
50
|
#: "v" + this, e.g. v0.2.0.
|
|
51
|
-
__version__ = "0.12.
|
|
51
|
+
__version__ = "0.12.2"
|
|
52
52
|
|
|
53
53
|
__all__ = [
|
|
54
54
|
"Arc", "BindingElement", "CPNet", "Marking", "Multiset", "Page", "Place",
|
|
@@ -20,7 +20,7 @@ from typing import Literal
|
|
|
20
20
|
|
|
21
21
|
from ... import flow
|
|
22
22
|
from ...mining.cases import case_value, cases
|
|
23
|
-
from ...mining.dotted import SORT_MODES, X_MODES, DotSettings, Dots, svg
|
|
23
|
+
from ...mining.dotted import SORT_MODES, X_MODES, DotSettings, Dots, how_to_read, svg
|
|
24
24
|
from ...mining.log import EventLog
|
|
25
25
|
from ...mining.petrinet import PetriNet
|
|
26
26
|
from ..box import box
|
|
@@ -229,8 +229,7 @@ def dotted_chart(log: EventLog,
|
|
|
229
229
|
f"{dots.origin + timedelta(seconds=dots.x_max - dots.x_min):%d %b %Y %H:%M}")
|
|
230
230
|
title = f"{log.name}: {rows.lower()} by {X_MODES[dots.mode].lower()}, colour by {colour.lower()}"
|
|
231
231
|
return Figure("Dotted chart", svg=svg(dots, title, unit),
|
|
232
|
-
caption=f"
|
|
233
|
-
f"sorted by {sort.lower()}.")
|
|
232
|
+
caption=f"{how_to_read(settings, dots.mode)} Colour: {colour}.")
|
|
234
233
|
|
|
235
234
|
|
|
236
235
|
@box(name="Who does what", group="Measure")
|
|
@@ -398,17 +398,10 @@ def result_widget(value, page=None, node=None) -> QWidget:
|
|
|
398
398
|
if value.note:
|
|
399
399
|
add(label(value.note, "muted", wrap=True))
|
|
400
400
|
elif isinstance(value, Figure):
|
|
401
|
-
shown = False
|
|
401
|
+
shown, svg = False, None
|
|
402
402
|
if value.svg:
|
|
403
403
|
try:
|
|
404
|
-
|
|
405
|
-
svg = QSvgWidget()
|
|
406
|
-
svg.load(value.svg.encode("utf-8"))
|
|
407
|
-
svg.setMinimumHeight(260)
|
|
408
|
-
svg.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
409
|
-
size = svg.renderer().defaultSize()
|
|
410
|
-
if size.width() > 0:
|
|
411
|
-
svg.setMaximumHeight(int(min(600, max(260, size.height() * 1.4))))
|
|
404
|
+
svg = SvgFigure(value.svg)
|
|
412
405
|
add(svg)
|
|
413
406
|
shown = True
|
|
414
407
|
except ImportError:
|
|
@@ -425,8 +418,11 @@ def result_widget(value, page=None, node=None) -> QWidget:
|
|
|
425
418
|
add(label("The figure has no SVG or PNG form.", "muted"))
|
|
426
419
|
if value.caption:
|
|
427
420
|
add(label(value.caption, "muted", wrap=True))
|
|
421
|
+
buttons = [button("Open larger", lambda: open_figure(value, svg))] if value.svg and shown else []
|
|
428
422
|
if page is not None:
|
|
429
|
-
|
|
423
|
+
buttons.append(button("Save as SVG…", lambda: page.save_figure(value)))
|
|
424
|
+
if buttons:
|
|
425
|
+
add(hbox(*buttons, None))
|
|
430
426
|
elif isinstance(value, Text):
|
|
431
427
|
text = QPlainTextEdit(value.text)
|
|
432
428
|
text.setReadOnly(True)
|
|
@@ -1047,3 +1043,75 @@ def status_text(result: Result | None) -> tuple[str, str]:
|
|
|
1047
1043
|
if result.status == "blocked":
|
|
1048
1044
|
return result.message or "Not allowed to run yet", "warning"
|
|
1049
1045
|
return result.message or "Waiting", "muted"
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
class SvgFigure(QWidget):
|
|
1049
|
+
"""An SVG figure drawn at the width it is given and in its own
|
|
1050
|
+
proportions, never stretched: text stays readable and nothing is cut
|
|
1051
|
+
off. Click it to see it at full size."""
|
|
1052
|
+
|
|
1053
|
+
def __init__(self, svg: str, parent=None) -> None:
|
|
1054
|
+
from PySide6.QtSvg import QSvgRenderer
|
|
1055
|
+
super().__init__(parent)
|
|
1056
|
+
self.renderer = QSvgRenderer(svg.encode("utf-8"), self)
|
|
1057
|
+
size = self.renderer.defaultSize()
|
|
1058
|
+
self.ratio = size.height() / size.width() if size.width() > 0 else 0.6
|
|
1059
|
+
self.svg = svg
|
|
1060
|
+
policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
|
1061
|
+
policy.setHeightForWidth(True)
|
|
1062
|
+
self.setSizePolicy(policy)
|
|
1063
|
+
self.setMinimumWidth(200)
|
|
1064
|
+
self.setCursor(Qt.PointingHandCursor)
|
|
1065
|
+
self.setToolTip("Click to see the figure at full size")
|
|
1066
|
+
|
|
1067
|
+
def hasHeightForWidth(self) -> bool:
|
|
1068
|
+
return True
|
|
1069
|
+
|
|
1070
|
+
def heightForWidth(self, width: int) -> int:
|
|
1071
|
+
return max(1, round(width * self.ratio))
|
|
1072
|
+
|
|
1073
|
+
def sizeHint(self):
|
|
1074
|
+
from PySide6.QtCore import QSize
|
|
1075
|
+
size = self.renderer.defaultSize()
|
|
1076
|
+
return QSize(size.width(), size.height()) if size.width() > 0 else QSize(560, 336)
|
|
1077
|
+
|
|
1078
|
+
def paintEvent(self, event) -> None:
|
|
1079
|
+
from PySide6.QtCore import QRectF
|
|
1080
|
+
from PySide6.QtGui import QPainter
|
|
1081
|
+
painter = QPainter(self)
|
|
1082
|
+
painter.setRenderHint(QPainter.Antialiasing)
|
|
1083
|
+
width = min(self.width(), round(self.height() / self.ratio)) if self.ratio else self.width()
|
|
1084
|
+
height = round(width * self.ratio)
|
|
1085
|
+
self.renderer.render(painter, QRectF((self.width() - width) / 2, 0, width, height))
|
|
1086
|
+
painter.end()
|
|
1087
|
+
|
|
1088
|
+
def mouseReleaseEvent(self, event) -> None:
|
|
1089
|
+
if event.button() == Qt.LeftButton:
|
|
1090
|
+
open_figure(None, self)
|
|
1091
|
+
super().mouseReleaseEvent(event)
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
def open_figure(figure, widget: "SvgFigure | None") -> None:
|
|
1095
|
+
"""The figure in a window of its own, as large as the screen allows;
|
|
1096
|
+
resizing the window resizes the figure, in proportion."""
|
|
1097
|
+
if widget is None:
|
|
1098
|
+
return
|
|
1099
|
+
window = QDialog(widget.window())
|
|
1100
|
+
window.setWindowTitle(getattr(figure, "name", None) or "Figure")
|
|
1101
|
+
full = SvgFigure(widget.svg)
|
|
1102
|
+
full.setCursor(Qt.ArrowCursor)
|
|
1103
|
+
full.setToolTip("")
|
|
1104
|
+
full.mouseReleaseEvent = lambda event: None
|
|
1105
|
+
full.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
1106
|
+
layout = QVBoxLayout(window)
|
|
1107
|
+
layout.setContentsMargins(12, 12, 12, 12)
|
|
1108
|
+
layout.addWidget(full)
|
|
1109
|
+
size = full.sizeHint()
|
|
1110
|
+
width, height = size.width() + 24, size.height() + 24
|
|
1111
|
+
screen = widget.screen().availableGeometry() if widget.screen() else None
|
|
1112
|
+
if screen is not None:
|
|
1113
|
+
scale = min(1.0, (screen.width() - 80) / width, (screen.height() - 80) / height)
|
|
1114
|
+
width, height = round(width * scale), round(height * scale)
|
|
1115
|
+
window.resize(width, height)
|
|
1116
|
+
window.setAttribute(Qt.WA_DeleteOnClose)
|
|
1117
|
+
window.show()
|
|
@@ -365,7 +365,7 @@ def svg(dots: Dots, title: str = "", unit: str = "Auto", width: int = 900) -> st
|
|
|
365
365
|
legend_rows = (min(len(dots.colour_values), 9) + 2) // 3
|
|
366
366
|
top = 34 + 18 * legend_rows
|
|
367
367
|
bottom, right = 44, 16
|
|
368
|
-
plot_h = min(max(n_rows * (16 if labelled else 0.5), 220),
|
|
368
|
+
plot_h = min(max(n_rows * (16 if labelled else 0.5), 220), 440) # landscape: it fits a side panel
|
|
369
369
|
plot_w = width - left - right
|
|
370
370
|
height = top + plot_h + bottom
|
|
371
371
|
x0, x1 = dots.x_min, dots.x_max
|
|
@@ -442,14 +442,40 @@ def svg(dots: Dots, title: str = "", unit: str = "Auto", width: int = 900) -> st
|
|
|
442
442
|
# Legend: what each colour means, with how many events.
|
|
443
443
|
items = [(CATEGORICAL_LIGHT[i], v, dots.colour_counts[v]) for i, v in enumerate(dots.colour_values[:8])]
|
|
444
444
|
rest = dots.colour_values[8:]
|
|
445
|
-
if rest:
|
|
446
|
-
|
|
445
|
+
if rest: # name the grey values when there are few, so none is hidden
|
|
446
|
+
name = "Other: " + ", ".join(rest) if len(rest) <= 3 else f"Other ({len(rest)} values)"
|
|
447
|
+
items.append((OTHER_LIGHT, name, sum(dots.colour_counts[v] for v in rest)))
|
|
447
448
|
column = (width - left - right) / 3
|
|
448
449
|
for i, (fill, value, count) in enumerate(items):
|
|
449
450
|
lx, ly = left + (i % 3) * column, 32 + (i // 3) * 18
|
|
450
|
-
name = (value or "–") if len(value) <=
|
|
451
|
+
name = (value or "–") if len(value) <= 48 else value[:47] + "…"
|
|
451
452
|
out.append(f'<circle cx="{lx + 5:.1f}" cy="{ly - 4}" r="4.5" fill="{fill}"/>')
|
|
452
453
|
out.append(f'<text x="{lx + 14:.1f}" y="{ly}" fill="#333">{_escape(name)} '
|
|
453
454
|
f'<tspan fill="#888">{count:,}</tspan></text>')
|
|
454
455
|
out.append("</svg>")
|
|
455
456
|
return "\n".join(out)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def how_to_read(settings: DotSettings, mode: int) -> str:
|
|
460
|
+
"""What the chart's axes mean and which patterns to look for, for the
|
|
461
|
+
x mode it was drawn in and its rows."""
|
|
462
|
+
by_case = settings.rows == "Case"
|
|
463
|
+
rows = ("Each row is a case and each dot one of its events" if by_case else
|
|
464
|
+
f"Each row is one value of {settings.rows} and each dot an event of it")
|
|
465
|
+
order = f"; rows are sorted by {SORT_MODES[settings.sort].lower()}" if by_case else ""
|
|
466
|
+
x = {
|
|
467
|
+
0: ", at the time it happened. "
|
|
468
|
+
+ ("The slope of the first dots is the arrival rate, vertical lines are events handled "
|
|
469
|
+
"together (batches), and horizontal gaps are cases waiting."
|
|
470
|
+
if by_case else
|
|
471
|
+
"Gaps are times it was not active (nights, weekends, days off), and vertical lines "
|
|
472
|
+
"are batches."),
|
|
473
|
+
1: ", at the time since its case began, so every case starts at 0. Compare how long each "
|
|
474
|
+
"step takes after the start; long horizontal gaps are waiting.",
|
|
475
|
+
2: ", at its share of the case's duration (0 % the first event, 100 % the last), so cases "
|
|
476
|
+
"of different lengths line up: a column shows where in a case something usually happens.",
|
|
477
|
+
3: ", at its place among all events of the log ordered by time: actual time without the gaps.",
|
|
478
|
+
4: ", at its position in the case (0 is the first event): which step comes where, whatever "
|
|
479
|
+
"the time.",
|
|
480
|
+
}[mode]
|
|
481
|
+
return f"{rows}{order}{x}"
|
|
@@ -1442,3 +1442,12 @@ def test_alignments_show_as_chevrons_and_on_the_model(app):
|
|
|
1442
1442
|
assert len(lists) == 1 and lists[0].model().rowCount() == 3
|
|
1443
1443
|
widget.resize(900, 900)
|
|
1444
1444
|
widget.grab()
|
|
1445
|
+
|
|
1446
|
+
|
|
1447
|
+
def test_a_figure_keeps_its_proportions_at_any_width(app):
|
|
1448
|
+
"""A figure in the Result panel is never stretched: its height follows its width."""
|
|
1449
|
+
from openprocess.gui.flow.viewers import SvgFigure
|
|
1450
|
+
figure = SvgFigure('<svg xmlns="http://www.w3.org/2000/svg" width="900" height="450" viewBox="0 0 900 450">'
|
|
1451
|
+
'<rect width="900" height="450" fill="white"/></svg>')
|
|
1452
|
+
assert figure.hasHeightForWidth()
|
|
1453
|
+
assert figure.heightForWidth(380) == 190 and figure.heightForWidth(900) == 450
|
|
@@ -86,6 +86,8 @@ def test_dotted_chart_draws_one_dot_per_event():
|
|
|
86
86
|
# Dots on the same spot in the same colour are drawn once: u1 creates all four orders on day 0.
|
|
87
87
|
by_user = dotted_chart(purchase_log(), rows="User", colour="Activity")
|
|
88
88
|
assert by_user.svg.count('r="3.0"') == 13 and ">u2</text>" in by_user.svg
|
|
89
|
+
# Five activities fit the palette; the caption says how to read the chart.
|
|
90
|
+
assert "Other" not in figure.svg and "arrival rate" in figure.caption
|
|
89
91
|
# Without timestamps the chart falls back to the position in the case.
|
|
90
92
|
untimed = dotted_chart(EventLog.from_simple_log(parse_simple_log("[<a,b,c>^2, <a,c>]")), x="Actual time")
|
|
91
93
|
assert "Event position in the case" in untimed.svg and untimed.svg.count('r="3.0"') == 8
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|