bigraph-viz
Advanced tools
@@ -1,26 +0,229 @@ | ||
| Metadata-Version: 2.1 | ||
| Metadata-Version: 2.4 | ||
| Name: bigraph-viz | ||
| Version: 0.1.10 | ||
| Summary: A graphviz-based plotting tool for compositional bigraph schema | ||
| Home-page: https://github.com/vivarium-collective/bigraph-viz | ||
| Author: Eran Agmon | ||
| Author-email: agmon.eran@gmail.com | ||
| License: UNKNOWN | ||
| Platform: UNKNOWN | ||
| Version: 0.1.15 | ||
| Summary: A visualization method for displaying the structure of process bigraphs | ||
| Author-email: Eran Agmon <agmon.eran@gmail.com> | ||
| Maintainer-email: Eran Agmon <agmon.eran@gmail.com> | ||
| License: Apache License | ||
| Version 2.0, January 2004 | ||
| http://www.apache.org/licenses/ | ||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||
| 1. Definitions. | ||
| "License" shall mean the terms and conditions for use, reproduction, | ||
| and distribution as defined by Sections 1 through 9 of this document. | ||
| "Licensor" shall mean the copyright owner or entity authorized by | ||
| the copyright owner that is granting the License. | ||
| "Legal Entity" shall mean the union of the acting entity and all | ||
| other entities that control, are controlled by, or are under common | ||
| control with that entity. For the purposes of this definition, | ||
| "control" means (i) the power, direct or indirect, to cause the | ||
| direction or management of such entity, whether by contract or | ||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||
| outstanding shares, or (iii) beneficial ownership of such entity. | ||
| "You" (or "Your") shall mean an individual or Legal Entity | ||
| exercising permissions granted by this License. | ||
| "Source" form shall mean the preferred form for making modifications, | ||
| including but not limited to software source code, documentation | ||
| source, and configuration files. | ||
| "Object" form shall mean any form resulting from mechanical | ||
| transformation or translation of a Source form, including but | ||
| not limited to compiled object code, generated documentation, | ||
| and conversions to other media types. | ||
| "Work" shall mean the work of authorship, whether in Source or | ||
| Object form, made available under the License, as indicated by a | ||
| copyright notice that is included in or attached to the work | ||
| (an example is provided in the Appendix below). | ||
| "Derivative Works" shall mean any work, whether in Source or Object | ||
| form, that is based on (or derived from) the Work and for which the | ||
| editorial revisions, annotations, elaborations, or other modifications | ||
| represent, as a whole, an original work of authorship. For the purposes | ||
| of this License, Derivative Works shall not include works that remain | ||
| separable from, or merely link (or bind by name) to the interfaces of, | ||
| the Work and Derivative Works thereof. | ||
| "Contribution" shall mean any work of authorship, including | ||
| the original version of the Work and any modifications or additions | ||
| to that Work or Derivative Works thereof, that is intentionally | ||
| submitted to Licensor for inclusion in the Work by the copyright owner | ||
| or by an individual or Legal Entity authorized to submit on behalf of | ||
| the copyright owner. For the purposes of this definition, "submitted" | ||
| means any form of electronic, verbal, or written communication sent | ||
| to the Licensor or its representatives, including but not limited to | ||
| communication on electronic mailing lists, source code control systems, | ||
| and issue tracking systems that are managed by, or on behalf of, the | ||
| Licensor for the purpose of discussing and improving the Work, but | ||
| excluding communication that is conspicuously marked or otherwise | ||
| designated in writing by the copyright owner as "Not a Contribution." | ||
| "Contributor" shall mean Licensor and any individual or Legal Entity | ||
| on behalf of whom a Contribution has been received by Licensor and | ||
| subsequently incorporated within the Work. | ||
| 2. Grant of Copyright License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| copyright license to reproduce, prepare Derivative Works of, | ||
| publicly display, publicly perform, sublicense, and distribute the | ||
| Work and such Derivative Works in Source or Object form. | ||
| 3. Grant of Patent License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| (except as stated in this section) patent license to make, have made, | ||
| use, offer to sell, sell, import, and otherwise transfer the Work, | ||
| where such license applies only to those patent claims licensable | ||
| by such Contributor that are necessarily infringed by their | ||
| Contribution(s) alone or by combination of their Contribution(s) | ||
| with the Work to which such Contribution(s) was submitted. If You | ||
| institute patent litigation against any entity (including a | ||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | ||
| or a Contribution incorporated within the Work constitutes direct | ||
| or contributory patent infringement, then any patent licenses | ||
| granted to You under this License for that Work shall terminate | ||
| as of the date such litigation is filed. | ||
| 4. Redistribution. You may reproduce and distribute copies of the | ||
| Work or Derivative Works thereof in any medium, with or without | ||
| modifications, and in Source or Object form, provided that You | ||
| meet the following conditions: | ||
| (a) You must give any other recipients of the Work or | ||
| Derivative Works a copy of this License; and | ||
| (b) You must cause any modified files to carry prominent notices | ||
| stating that You changed the files; and | ||
| (c) You must retain, in the Source form of any Derivative Works | ||
| that You distribute, all copyright, patent, trademark, and | ||
| attribution notices from the Source form of the Work, | ||
| excluding those notices that do not pertain to any part of | ||
| the Derivative Works; and | ||
| (d) If the Work includes a "NOTICE" text file as part of its | ||
| distribution, then any Derivative Works that You distribute must | ||
| include a readable copy of the attribution notices contained | ||
| within such NOTICE file, excluding those notices that do not | ||
| pertain to any part of the Derivative Works, in at least one | ||
| of the following places: within a NOTICE text file distributed | ||
| as part of the Derivative Works; within the Source form or | ||
| documentation, if provided along with the Derivative Works; or, | ||
| within a display generated by the Derivative Works, if and | ||
| wherever such third-party notices normally appear. The contents | ||
| of the NOTICE file are for informational purposes only and | ||
| do not modify the License. You may add Your own attribution | ||
| notices within Derivative Works that You distribute, alongside | ||
| or as an addendum to the NOTICE text from the Work, provided | ||
| that such additional attribution notices cannot be construed | ||
| as modifying the License. | ||
| You may add Your own copyright statement to Your modifications and | ||
| may provide additional or different license terms and conditions | ||
| for use, reproduction, or distribution of Your modifications, or | ||
| for any such Derivative Works as a whole, provided Your use, | ||
| reproduction, and distribution of the Work otherwise complies with | ||
| the conditions stated in this License. | ||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | ||
| any Contribution intentionally submitted for inclusion in the Work | ||
| by You to the Licensor shall be under the terms and conditions of | ||
| this License, without any additional terms or conditions. | ||
| Notwithstanding the above, nothing herein shall supersede or modify | ||
| the terms of any separate license agreement you may have executed | ||
| with Licensor regarding such Contributions. | ||
| 6. Trademarks. This License does not grant permission to use the trade | ||
| names, trademarks, service marks, or product names of the Licensor, | ||
| except as required for reasonable and customary use in describing the | ||
| origin of the Work and reproducing the content of the NOTICE file. | ||
| 7. Disclaimer of Warranty. Unless required by applicable law or | ||
| agreed to in writing, Licensor provides the Work (and each | ||
| Contributor provides its Contributions) on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
| implied, including, without limitation, any warranties or conditions | ||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||
| PARTICULAR PURPOSE. You are solely responsible for determining the | ||
| appropriateness of using or redistributing the Work and assume any | ||
| risks associated with Your exercise of permissions under this License. | ||
| 8. Limitation of Liability. In no event and under no legal theory, | ||
| whether in tort (including negligence), contract, or otherwise, | ||
| unless required by applicable law (such as deliberate and grossly | ||
| negligent acts) or agreed to in writing, shall any Contributor be | ||
| liable to You for damages, including any direct, indirect, special, | ||
| incidental, or consequential damages of any character arising as a | ||
| result of this License or out of the use or inability to use the | ||
| Work (including but not limited to damages for loss of goodwill, | ||
| work stoppage, computer failure or malfunction, or any and all | ||
| other commercial damages or losses), even if such Contributor | ||
| has been advised of the possibility of such damages. | ||
| 9. Accepting Warranty or Additional Liability. While redistributing | ||
| the Work or Derivative Works thereof, You may choose to offer, | ||
| and charge a fee for, acceptance of support, warranty, indemnity, | ||
| or other liability obligations and/or rights consistent with this | ||
| License. However, in accepting such obligations, You may act only | ||
| on Your own behalf and on Your sole responsibility, not on behalf | ||
| of any other Contributor, and only if You agree to indemnify, | ||
| defend, and hold each Contributor harmless for any liability | ||
| incurred by, or claims asserted against, such Contributor by reason | ||
| of your accepting any such warranty or additional liability. | ||
| END OF TERMS AND CONDITIONS | ||
| APPENDIX: How to apply the Apache License to your work. | ||
| To apply the Apache License to your work, attach the following | ||
| boilerplate notice, with the fields enclosed by brackets "[]" | ||
| replaced with your own identifying information. (Don't include | ||
| the brackets!) The text should be enclosed in the appropriate | ||
| comment syntax for the file format. We also recommend that a | ||
| file or class name and description of purpose be included on the | ||
| same "printed page" as the copyright notice for easier | ||
| identification within third-party archives. | ||
| Copyright 2023 Ryan Spangler and Eran Agmon | ||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| Keywords: visualization,systems biology,bigraph,graphviz,vivarium | ||
| Classifier: Development Status :: 3 - Alpha | ||
| Classifier: Intended Audience :: Developers | ||
| Classifier: Intended Audience :: Science/Research | ||
| Classifier: License :: OSI Approved :: MIT License | ||
| Classifier: Operating System :: OS Independent | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python :: 3.6 | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Programming Language :: Python :: 3 :: Only | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Programming Language :: Python :: 3.10 | ||
| Classifier: Programming Language :: Python :: 3.11 | ||
| Requires-Python: >=3.6 | ||
| Classifier: Programming Language :: Python :: 3.12 | ||
| Classifier: Topic :: Scientific/Engineering :: Visualization | ||
| Classifier: Topic :: Software Development :: Libraries | ||
| Requires-Python: >=3.9 | ||
| Description-Content-Type: text/markdown | ||
| License-File: LICENSE | ||
| License-File: AUTHORS.md | ||
| Requires-Dist: bigraph-schema | ||
| Requires-Dist: graphviz | ||
| Dynamic: license-file | ||
@@ -94,3 +297,1 @@ # Bigraph-viz | ||
| Bigraph-viz is open-source software released under the [Apache 2 License](https://github.com/vivarium-collective/bigraph-viz/blob/main/LICENSE). | ||
@@ -0,3 +1,2 @@ | ||
| bigraph-schema | ||
| graphviz | ||
| bigraph-schema>=0.0.51 | ||
| numpy |
@@ -5,3 +5,2 @@ AUTHORS.md | ||
| pyproject.toml | ||
| setup.py | ||
| bigraph_viz/__init__.py | ||
@@ -8,0 +7,0 @@ bigraph_viz/convert.py |
+487
-293
@@ -16,2 +16,3 @@ import os | ||
| # Utility: Label formatting | ||
@@ -22,2 +23,3 @@ def make_label(label): | ||
| def get_graph_wires(ports_schema, wires, graph_dict, schema_key, edge_path, bridge_wires=None): | ||
@@ -76,2 +78,3 @@ """ | ||
| # Append a single port wire connection to graph_dict | ||
@@ -108,2 +111,3 @@ | ||
| # Plot a labeled edge from a port to a process | ||
@@ -127,4 +131,14 @@ def plot_edges(graph, edge, port_labels, port_label_size, state_node_spec, constraint='false'): | ||
| # Add a node to the graph with optional value/type | ||
| def add_node_to_graph(graph, node, state_node_spec, show_values, show_types, significant_digits): | ||
| def add_node_to_graph( | ||
| graph, | ||
| node, | ||
| state_node_spec, | ||
| show_values, | ||
| show_types, | ||
| significant_digits, | ||
| value_char_limit, | ||
| type_char_limit, | ||
| ): | ||
| """ | ||
@@ -145,55 +159,88 @@ Add a state node to the Graphviz graph. | ||
| label_info = '' | ||
| value_char_limit = value_char_limit or 20 | ||
| type_char_limit = type_char_limit or 20 | ||
| rows = [label] # the node's name, already plain text | ||
| # Value row | ||
| if show_values and (val := node.get('value')) is not None: | ||
| if isinstance(val, float): | ||
| val = int(val) if val.is_integer() else round(val, significant_digits) | ||
| label_info += f":{val}" | ||
| val_str = str(val) | ||
| if len(val_str) > value_char_limit: | ||
| val_str = val_str[:value_char_limit] + "…" | ||
| rows.append(f"<FONT POINT-SIZE='10' COLOR='gray30'>value: {val_str}</FONT>") | ||
| # Type row | ||
| if show_types and (typ := node.get('type')): | ||
| label_info += f"<br/>[{typ if len(typ) <= 20 else '...'}]" | ||
| typ_str = str(typ) | ||
| if len(typ_str) > type_char_limit: | ||
| typ_str = typ_str[:type_char_limit] + "…" | ||
| rows.append(f"<FONT POINT-SIZE='10' COLOR='gray40'>type: {typ_str}</FONT>") | ||
| full_label = make_label(label + label_info) if label_info else make_label(label) | ||
| html_label = "<<TABLE BORDER='0' CELLBORDER='0' CELLSPACING='0'>" | ||
| for r in rows: | ||
| html_label += f"<TR><TD>{r}</TD></TR>" | ||
| html_label += "</TABLE>>" | ||
| # full_label = make_label(label + label_info) if label_info else make_label(label) | ||
| graph.attr('node', **state_node_spec) | ||
| graph.node(node_name, label=full_label) | ||
| graph.node(node_name, label=html_label) | ||
| return node_name | ||
| # make the Graphviz figure | ||
| import os | ||
| from collections import defaultdict | ||
| import graphviz | ||
| def get_graphviz_fig( | ||
| graph_dict, | ||
| label_margin='0.05', | ||
| node_label_size='12pt', | ||
| process_label_size=None, | ||
| size='16,10', | ||
| rankdir='TB', | ||
| aspect_ratio='auto', | ||
| dpi='70', | ||
| significant_digits=2, | ||
| undirected_edges=False, | ||
| show_values=False, | ||
| show_types=False, | ||
| port_labels=True, | ||
| port_label_size='10pt', | ||
| invisible_edges=None, | ||
| remove_process_place_edges=False, | ||
| node_border_colors=None, | ||
| node_fill_colors=None, | ||
| node_groups=None, | ||
| collapse_redundant_processes=False, | ||
| graph_dict, | ||
| label_margin='0.05', | ||
| node_label_size='12pt', | ||
| process_label_size=None, | ||
| size='16,10', | ||
| rankdir='TB', | ||
| aspect_ratio='auto', | ||
| dpi='70', | ||
| significant_digits=2, | ||
| undirected_edges=False, | ||
| show_values=False, | ||
| show_types=False, | ||
| value_char_limit=20, | ||
| type_char_limit=50, | ||
| port_labels=True, | ||
| port_label_size='10pt', | ||
| invisible_edges=None, | ||
| remove_process_place_edges=False, | ||
| node_border_colors=None, | ||
| node_fill_colors=None, | ||
| node_groups=None, | ||
| collapse_redundant_processes=False, | ||
| ): | ||
| """ | ||
| Generate a Graphviz Digraph from a graph_dict describing a simulation architecture. | ||
| Generate a Graphviz Digraph from a graph_dict describing a simulation bigraph. | ||
| Parameters: | ||
| graph_dict: dict | ||
| Dictionary describing nodes and edges of a simulation bigraph. | ||
| collapse_redundant_processes: bool | ||
| Collapse processes with identical port wiring into a single node. | ||
| All other parameters configure visual style. | ||
| Parameters | ||
| ---------- | ||
| graph_dict : dict | ||
| Dictionary describing nodes and edges of a simulation bigraph. | ||
| collapse_redundant_processes : bool | str | Iterable | dict | ||
| Controls collapsing of processes that share identical port wiring: | ||
| Returns: | ||
| graphviz.Digraph | ||
| Graphviz representation of the graph. | ||
| - False / None : collapse no processes | ||
| - True or "all" : collapse all redundant processes | ||
| - Iterable : collapse only processes matching the selectors | ||
| - {"exclude": it} : collapse all redundant processes except those | ||
| matching selectors in `it` | ||
| A selector can be: | ||
| * str : matches the leaf process name or str(path) | ||
| * tuple : matches the exact process path | ||
| Returns | ||
| ------- | ||
| graphviz.Digraph | ||
| """ | ||
| import difflib | ||
| from collections import defaultdict | ||
@@ -205,20 +252,35 @@ invisible_edges = invisible_edges or [] | ||
| graph = graphviz.Digraph(name='bigraph', engine='dot') | ||
| graph.attr(size=size, overlap='false', rankdir=rankdir, dpi=dpi, ratio=aspect_ratio, splines='true') | ||
| graph.attr(size=size, overlap='false', rankdir=rankdir, dpi=dpi, | ||
| ratio=aspect_ratio, splines='true') | ||
| # Define node styles | ||
| # Use the same label_margin parameter, but circles get a smaller | ||
| # effective margin so they don't balloon visually. | ||
| state_margin = str(float(label_margin) * 0.1) | ||
| process_margin = label_margin | ||
| # Node styles | ||
| state_node_spec = { | ||
| 'shape': 'circle', 'penwidth': '2', 'constraint': 'false', | ||
| 'margin': label_margin, 'fontsize': node_label_size | ||
| 'shape': 'circle', | ||
| 'penwidth': '2', | ||
| 'constraint': 'false', | ||
| 'margin': state_margin, | ||
| 'fontsize': node_label_size, | ||
| } | ||
| process_node_spec = { | ||
| 'shape': 'box', 'penwidth': '2', 'constraint': 'false', | ||
| 'margin': label_margin, 'fontsize': process_label_size | ||
| 'shape': 'box', | ||
| 'penwidth': '2', | ||
| 'constraint': 'false', | ||
| 'margin': process_margin, | ||
| 'fontsize': process_label_size, | ||
| } | ||
| # Define edge styles | ||
| # Edge styles | ||
| edge_styles = { | ||
| 'input': {'style': 'dashed', 'penwidth': '1', 'arrowhead': 'normal', 'arrowsize': '1.0', 'dir': 'forward'}, | ||
| 'output': {'style': 'dashed', 'penwidth': '1', 'arrowhead': 'normal', 'arrowsize': '1.0', 'dir': 'back'}, | ||
| 'bidirectional': {'style': 'dashed', 'penwidth': '1', 'arrowhead': 'normal', 'arrowsize': '1.0', 'dir': 'both'}, | ||
| 'place': {'arrowhead': 'none', 'penwidth': '2'} | ||
| 'input': {'style': 'dashed', 'penwidth': '1', 'arrowhead': 'normal', | ||
| 'arrowsize': '1.0', 'dir': 'forward'}, | ||
| 'output': {'style': 'dashed', 'penwidth': '1', 'arrowhead': 'normal', | ||
| 'arrowsize': '1.0', 'dir': 'back'}, | ||
| 'bidirectional': {'style': 'dashed', 'penwidth': '1', 'arrowhead': 'normal', | ||
| 'arrowsize': '1.0', 'dir': 'both'}, | ||
| 'place': {'arrowhead': 'none', 'penwidth': '2'}, | ||
| } | ||
@@ -231,11 +293,75 @@ if undirected_edges: | ||
| # -------- collapse configuration ---------------------------------------- | ||
| def normalize_collapse_arg(arg): | ||
| """ | ||
| Return (mode, selectors) where mode is: | ||
| 'none' : collapse nothing | ||
| 'all' : collapse all redundant processes | ||
| 'subset' : collapse only selected processes | ||
| 'all_except' : collapse all except selected processes | ||
| """ | ||
| if arg is False or arg is None: | ||
| return 'none', set() | ||
| if arg is True or arg == 'all': | ||
| return 'all', set() | ||
| if isinstance(arg, dict) and 'exclude' in arg: | ||
| try: | ||
| selectors = set(arg['exclude']) | ||
| except TypeError: | ||
| selectors = {arg['exclude']} | ||
| return 'all_except', selectors | ||
| # Iterable or single selector ⇒ subset | ||
| try: | ||
| selectors = set(arg) | ||
| except TypeError: | ||
| selectors = {arg} | ||
| return 'subset', selectors | ||
| collapse_mode, collapse_selectors = normalize_collapse_arg( | ||
| collapse_redundant_processes | ||
| ) | ||
| def process_matches_selector(entry, selector): | ||
| """Check if a process entry matches a single selector.""" | ||
| path, path_str, name = entry | ||
| if isinstance(selector, (tuple, list)): | ||
| return tuple(selector) == tuple(path) | ||
| return selector == name or selector == path_str | ||
| def process_is_selected(entry): | ||
| """Return True if this process is eligible to be collapsed.""" | ||
| if collapse_mode == 'all': | ||
| return True | ||
| if collapse_mode == 'none': | ||
| return False | ||
| if not collapse_selectors: | ||
| return collapse_mode == 'all' | ||
| matches = any( | ||
| process_matches_selector(entry, sel) | ||
| for sel in collapse_selectors | ||
| ) | ||
| if collapse_mode == 'subset': | ||
| return matches | ||
| if collapse_mode == 'all_except': | ||
| return not matches | ||
| return False | ||
| # -------- core helpers -------------------------------------------------- | ||
| def get_name_template(names): | ||
| """Create a generalized name with wildcards for collapsed process names.""" | ||
| """Create a generalized label for collapsed process names.""" | ||
| if len(names) == 1: | ||
| return names[0] | ||
| import re | ||
| prefix = os.path.commonprefix(names) | ||
| suffix = os.path.commonprefix([n[::-1] for n in names])[::-1] | ||
| wildcard_middle = '*' if prefix != names[0] or suffix != names[0] else '' | ||
| return f"{prefix}{wildcard_middle}{suffix}" | ||
| middle = '*' if prefix != names[0] or suffix != names[0] else '' | ||
| return f"{prefix}{middle}{suffix}" | ||
@@ -245,11 +371,18 @@ def add_state_nodes(): | ||
| for node in graph_dict['state_nodes']: | ||
| name = add_node_to_graph(graph, node, state_node_spec, show_values, show_types, significant_digits) | ||
| name = add_node_to_graph( | ||
| graph, node, state_node_spec, | ||
| show_values, show_types, significant_digits, | ||
| value_char_limit, type_char_limit, | ||
| ) | ||
| node_names.append(name) | ||
| def add_process_nodes(): | ||
| """Add process nodes to the graph, with optional collapse of redundant processes.""" | ||
| """ | ||
| Add process nodes, with optional collapse of redundant ones | ||
| according to collapse_mode and collapse_selectors. | ||
| """ | ||
| graph.attr('node', **process_node_spec) | ||
| process_fingerprints = defaultdict(list) | ||
| # Build fingerprints for each process based on edge connectivity | ||
| # Group processes by connectivity "fingerprint" | ||
| for node in graph_dict['process_nodes']: | ||
@@ -260,8 +393,12 @@ node_path = node['path'] | ||
| fingerprint = [] | ||
| for group, tag in [('input_edges', 'in'), ('output_edges', 'out'), ('bidirectional_edges', 'both')]: | ||
| fp = [] | ||
| for group, tag in [ | ||
| ('input_edges', 'in'), | ||
| ('output_edges', 'out'), | ||
| ('bidirectional_edges', 'both'), | ||
| ]: | ||
| for edge in graph_dict.get(group, []): | ||
| if edge['edge_path'] == node_path: | ||
| fingerprint.append((tag, edge['port'], str(edge.get('target_path')))) | ||
| fingerprint = tuple(sorted(fingerprint)) | ||
| fp.append((tag, edge['port'], str(edge.get('target_path')))) | ||
| fingerprint = tuple(sorted(fp)) | ||
| process_fingerprints[fingerprint].append((node_path, path_str, node_name)) | ||
@@ -271,18 +408,27 @@ | ||
| # Only collapse if flag is enabled | ||
| if collapse_redundant_processes: | ||
| for fingerprint, entries in process_fingerprints.items(): | ||
| names = [entry[2] for entry in entries] | ||
| template = get_name_template(names) | ||
| count = len(entries) | ||
| label = template if count == 1 else f"{template} (x{count})" | ||
| representative = str(entries[0][0]) | ||
| graph.node(representative, label=label) | ||
| node_names.append(representative) | ||
| for path, path_str, _ in entries: | ||
| if str(path) != representative: | ||
| collapse_map[str(path)] = representative | ||
| else: | ||
| # Add all process nodes without collapsing | ||
| for entries in process_fingerprints.values(): | ||
| # For each fingerprint group, possibly collapse some or all | ||
| for fingerprint, entries in process_fingerprints.items(): | ||
| selected = [e for e in entries if process_is_selected(e)] | ||
| if len(selected) > 1: | ||
| # Create collapsed representative | ||
| names = [e[2] for e in selected] | ||
| label = f"{get_name_template(names)} (x{len(selected)})" | ||
| rep_path = selected[0][0] | ||
| rep_str = str(rep_path) | ||
| graph.node(rep_str, label=label) | ||
| node_names.append(rep_str) | ||
| # Map collapsed entries (except representative) | ||
| for path, path_str, _ in selected[1:]: | ||
| collapse_map[str(path)] = rep_str | ||
| # Draw remaining (unselected) entries individually | ||
| remaining = [e for e in entries if e not in selected] | ||
| for path, path_str, name in remaining: | ||
| graph.node(path_str, label=name) | ||
| node_names.append(path_str) | ||
| else: | ||
| # No effective collapse here: draw all individually | ||
| for path, path_str, name in entries: | ||
@@ -292,11 +438,24 @@ graph.node(path_str, label=name) | ||
| return [entry[0] for entries in process_fingerprints.values() for entry in entries], collapse_map | ||
| # Return original process paths and collapse map | ||
| return [ | ||
| entry[0] | ||
| for entries in process_fingerprints.values() | ||
| for entry in entries | ||
| ], collapse_map | ||
| def rewrite_collapsed_edges(collapse_map): | ||
| """Update edge endpoints to point to collapsed representatives.""" | ||
| removed_keys = set(collapse_map.keys()) | ||
| for group in ['input_edges', 'output_edges', 'bidirectional_edges', 'disconnected_input_edges', | ||
| 'disconnected_output_edges']: | ||
| if not removed_keys: | ||
| return | ||
| for group in [ | ||
| 'input_edges', | ||
| 'output_edges', | ||
| 'bidirectional_edges', | ||
| 'disconnected_input_edges', | ||
| 'disconnected_output_edges', | ||
| ]: | ||
| edges = graph_dict.get(group, []) | ||
| new_edges = [] | ||
| seen = set() | ||
| new_edges, seen = [], set() | ||
| for edge in edges: | ||
@@ -307,3 +466,2 @@ key = str(edge['edge_path']) | ||
| if key not in removed_keys: | ||
| # Build a tuple that uniquely identifies this edge after collapse | ||
| edge_key = ( | ||
@@ -313,3 +471,3 @@ group, | ||
| edge.get('port'), | ||
| str(edge.get('target_path')) | ||
| str(edge.get('target_path')), | ||
| ) | ||
@@ -321,3 +479,3 @@ if edge_key not in seen: | ||
| # Remove any place_edges associated with collapsed processes | ||
| # Remove place edges involving removed processes | ||
| new_place_edges = [] | ||
@@ -342,13 +500,27 @@ for edge in graph_dict.get('place_edges', []): | ||
| graph.attr('edge', **edge_styles[style]) | ||
| plot_edges(graph, edge, port_labels, port_label_size, state_node_spec, constraint=constraint) | ||
| plot_edges( | ||
| graph, edge, port_labels, port_label_size, | ||
| state_node_spec, constraint=constraint, | ||
| ) | ||
| def add_place_edges(process_paths): | ||
| for edge in graph_dict['place_edges']: | ||
| visible = not ((remove_process_place_edges and edge['child'] in process_paths) or (edge in invisible_edges)) | ||
| for edge in graph_dict.get('place_edges', []): | ||
| visible = not ( | ||
| (remove_process_place_edges and edge['child'] in process_paths) | ||
| or (edge in invisible_edges) | ||
| ) | ||
| graph.attr('edge', style='filled' if visible else 'invis') | ||
| graph.edge(str(edge['parent']), str(edge['child']), **edge_styles['place'], constraint='true') | ||
| graph.edge( | ||
| str(edge['parent']), | ||
| str(edge['child']), | ||
| **edge_styles['place'], | ||
| constraint='true', | ||
| ) | ||
| def add_disconnected_edges(): | ||
| for direction, style_key in [('disconnected_input_edges', 'input'), ('disconnected_output_edges', 'output')]: | ||
| for edge in graph_dict[direction]: | ||
| for direction, style_key in [ | ||
| ('disconnected_input_edges', 'input'), | ||
| ('disconnected_output_edges', 'output'), | ||
| ]: | ||
| for edge in graph_dict.get(direction, []): | ||
| path = edge['edge_path'] | ||
@@ -361,3 +533,6 @@ port = edge['port'] | ||
| graph.attr('edge', **edge_styles[style_key]) | ||
| plot_edges(graph, edge, port_labels, port_label_size, state_node_spec, constraint='true') | ||
| plot_edges( | ||
| graph, edge, port_labels, port_label_size, | ||
| state_node_spec, constraint='true', | ||
| ) | ||
@@ -379,15 +554,25 @@ def rank_node_groups(): | ||
| def apply_custom_colors(): | ||
| state_paths = [entry['path'] for entry in graph_dict['state_nodes']] | ||
| process_paths = [entry['path'] for entry in graph_dict['process_nodes']] | ||
| if node_border_colors: | ||
| for name, color in node_border_colors.items(): | ||
| graph.node(str(name), color=color) | ||
| if name in state_paths or name in process_paths: | ||
| graph.node(str(name), color=color) | ||
| if node_fill_colors: | ||
| for name, color in node_fill_colors.items(): | ||
| graph.node(str(name), color=color, style='filled') | ||
| if name in state_paths or name in process_paths: | ||
| graph.node(str(name), color=color, style='filled') | ||
| # -------- build graph --------------------------------------------------- | ||
| add_state_nodes() | ||
| process_paths, collapse_map = add_process_nodes() | ||
| if collapse_redundant_processes: | ||
| rewrite_collapsed_edges(collapse_map) | ||
| rewrite_collapsed_edges(collapse_map) | ||
| add_place_edges(process_paths) | ||
| add_edges([('input_edges', 'input'), ('output_edges', 'output'), ('bidirectional_edges', 'bidirectional')]) | ||
| add_edges([ | ||
| ('input_edges', 'input'), | ||
| ('output_edges', 'output'), | ||
| ('bidirectional_edges', 'bidirectional'), | ||
| ]) | ||
| add_state_nodes() | ||
@@ -402,9 +587,9 @@ add_disconnected_edges() | ||
| def plot_bigraph( | ||
| state, | ||
| schema=None, | ||
| core=None, | ||
| out_dir=None, | ||
| filename=None, | ||
| file_format='png', | ||
| **kwargs | ||
| state, | ||
| schema=None, | ||
| core=None, | ||
| out_dir=None, | ||
| filename=None, | ||
| file_format='png', | ||
| **kwargs | ||
| ): | ||
@@ -477,4 +662,6 @@ """ | ||
| def graphviz_edge(core, schema, state, path, options, graph): | ||
| """Visualize a process node with input/output/bridge wiring.""" | ||
| schema = schema or {} | ||
| node_spec = { | ||
@@ -494,7 +681,11 @@ 'name': path[-1], | ||
| # Wiring | ||
| graph = get_graph_wires(schema.get('_inputs', {}), state.get('inputs', {}), graph, 'inputs', path, state.get('bridge', {}).get('inputs', {})) | ||
| graph = get_graph_wires(schema.get('_outputs', {}), state.get('outputs', {}), graph, 'outputs', path, state.get('bridge', {}).get('outputs', {})) | ||
| graph = get_graph_wires(schema.get('_inputs', {}), state.get('inputs', {}), graph, 'inputs', path, | ||
| state.get('bridge', {}).get('inputs', {})) | ||
| graph = get_graph_wires(schema.get('_outputs', {}), state.get('outputs', {}), graph, 'outputs', path, | ||
| state.get('bridge', {}).get('outputs', {})) | ||
| # Merge bidirectional edges | ||
| def key(edge): return (tuple(edge['edge_path']), tuple(edge['target_path']), edge['port']) | ||
| def key(edge): | ||
| return (tuple(edge['edge_path']), tuple(edge['target_path']), edge['port']) | ||
| input_set = {key(e): e for e in graph['input_edges']} | ||
@@ -589,3 +780,3 @@ output_set = {key(e): e for e in graph['output_edges']} | ||
| }, | ||
| 'map':{ | ||
| 'map': { | ||
| '_graphviz': graphviz_map, | ||
@@ -605,2 +796,3 @@ }, | ||
| # TODO: we want to visualize things that are not yet complete | ||
@@ -1097,2 +1289,3 @@ | ||
| def generate_spec_and_schema(n_rows, n_cols): | ||
@@ -1145,2 +1338,3 @@ spec = {'cells': {}} | ||
| def test_array_paths(): | ||
@@ -1163,3 +1357,3 @@ core = VisualizeTypes() | ||
| n_rows, n_cols = 6, 6 # or any desired shape | ||
| n_rows, n_cols = 6, 6 # or any desired shape | ||
| spec, schema = generate_spec_and_schema(n_rows, n_cols) | ||
@@ -1181,194 +1375,194 @@ | ||
| state = { | ||
| "particles": { | ||
| "rddyhz3IRHaZIKnpyROvGw": { | ||
| "id": "rddyhz3IRHaZIKnpyROvGw", | ||
| "position": ["1.6170202476993778", "2.6965198046441277"], | ||
| "size": "0.0", | ||
| "mass": "0.7708618958003092", | ||
| "local": { | ||
| "glucose": "2.1129479416859507", "acetate": "0.0"}, | ||
| "exchange": { | ||
| "glucose": "0.0", "acetate": "0.0"}, | ||
| "dFBA": { | ||
| "inputs": { | ||
| "substrates": ["local"], | ||
| "biomass": ["mass"]}, | ||
| "outputs": { | ||
| "substrates": ["exchange"], | ||
| "biomass": ["mass"]}, | ||
| "interval": 1.0, | ||
| "address": "local:DynamicFBA", | ||
| "config": { | ||
| "model_file": "textbook", | ||
| "kinetic_params": { | ||
| "glucose": ["0.5", "1.0"], | ||
| "acetate": ["0.5", "2.0"]}, | ||
| "substrate_update_reactions": { | ||
| "glucose": "EX_glc__D_e", | ||
| "acetate": "EX_ac_e"}, | ||
| "bounds": { | ||
| "EX_o2_e": { | ||
| "lower": "-2.0", | ||
| "upper": "!nil"}, | ||
| "ATPM": { | ||
| "lower": "1.0", | ||
| "upper": "1.0"}}}, | ||
| "shared": {} | ||
| } | ||
| }, | ||
| state = { | ||
| "particles": { | ||
| "rddyhz3IRHaZIKnpyROvGw": { | ||
| "id": "rddyhz3IRHaZIKnpyROvGw", | ||
| "position": ["1.6170202476993778", "2.6965198046441277"], | ||
| "size": "0.0", | ||
| "mass": "0.7708618958003092", | ||
| "local": { | ||
| "glucose": "2.1129479416859507", "acetate": "0.0"}, | ||
| "exchange": { | ||
| "glucose": "0.0", "acetate": "0.0"}, | ||
| "dFBA": { | ||
| "inputs": { | ||
| "substrates": ["local"], | ||
| "biomass": ["mass"]}, | ||
| "outputs": { | ||
| "substrates": ["exchange"], | ||
| "biomass": ["mass"]}, | ||
| "interval": 1.0, | ||
| "address": "local:DynamicFBA", | ||
| "config": { | ||
| "model_file": "textbook", | ||
| "kinetic_params": { | ||
| "glucose": ["0.5", "1.0"], | ||
| "acetate": ["0.5", "2.0"]}, | ||
| "substrate_update_reactions": { | ||
| "glucose": "EX_glc__D_e", | ||
| "acetate": "EX_ac_e"}, | ||
| "bounds": { | ||
| "EX_o2_e": { | ||
| "lower": "-2.0", | ||
| "upper": "!nil"}, | ||
| "ATPM": { | ||
| "lower": "1.0", | ||
| "upper": "1.0"}}}, | ||
| "shared": {} | ||
| } | ||
| }, | ||
| "global_time": "0.0", | ||
| "particle_movement": { | ||
| '_type': 'process', | ||
| "inputs": { | ||
| "particles": ["particles"], | ||
| "fields": ["fields"]}, | ||
| "outputs": { | ||
| "particles": ["particles"], | ||
| "fields": ["fields"]}, | ||
| "interval": 1.0, | ||
| "address": "local:Particles", | ||
| "config": {}, | ||
| }, | ||
| "fields": { | ||
| "glucose": { | ||
| "list": [ | ||
| [ | ||
| 6.682473038698228, | ||
| 6.138508047074471, | ||
| 5.932822055376635, | ||
| 1.2275655546440918, | ||
| 7.184289576021444, | ||
| 5.802540321285436, | ||
| 3.158370346023715, | ||
| 6.191878825605585, | ||
| 7.417057892118427, | ||
| 9.619194357104389 | ||
| ], | ||
| [ | ||
| 7.384059587748178, | ||
| 8.640811575012702, | ||
| 2.1129479416859507, | ||
| 3.1057148920618385, | ||
| 8.05289155553335, | ||
| 4.399086558257299, | ||
| 7.193948745260049, | ||
| 5.035688862165517, | ||
| 5.219923411699781, | ||
| 4.539653707209219 | ||
| ], | ||
| [ | ||
| 1.9082739815105203, | ||
| 8.99864529956811, | ||
| 6.5195511089756675, | ||
| 1.957101992521509, | ||
| 3.1907575508941806, | ||
| 4.5623876367245195, | ||
| 9.68212403622312, | ||
| 4.419905700021853, | ||
| 8.71921956750521, | ||
| 8.163620432115913 | ||
| ], | ||
| [ | ||
| 9.478709499822921, | ||
| 8.675323729741326, | ||
| 4.226239950967384, | ||
| 1.6634413475982608, | ||
| 4.2399161776694365, | ||
| 1.8032704088212483, | ||
| 8.029077191030485, | ||
| 3.5987760418726706, | ||
| 1.0827071604629657, | ||
| 4.939077862941639 | ||
| ], | ||
| [ | ||
| 2.2055610319311745, | ||
| 8.052040372657313, | ||
| 5.325939740703682, | ||
| 5.915877670139153, | ||
| 9.335157497844655, | ||
| 5.8973761480277584, | ||
| 7.503363745465629, | ||
| 1.2530328598811558, | ||
| 7.58703729093062, | ||
| 2.4382507126877866 | ||
| ] | ||
| }, | ||
| "global_time": "0.0", | ||
| "particle_movement": { | ||
| '_type': 'process', | ||
| "inputs": { | ||
| "particles": ["particles"], | ||
| "fields": ["fields"]}, | ||
| "outputs": { | ||
| "particles": ["particles"], | ||
| "fields": ["fields"]}, | ||
| "interval": 1.0, | ||
| "address": "local:Particles", | ||
| "config": {}, | ||
| }, | ||
| "fields": { | ||
| "glucose": { | ||
| "list": [ | ||
| [ | ||
| 6.682473038698228, | ||
| 6.138508047074471, | ||
| 5.932822055376635, | ||
| 1.2275655546440918, | ||
| 7.184289576021444, | ||
| 5.802540321285436, | ||
| 3.158370346023715, | ||
| 6.191878825605585, | ||
| 7.417057892118427, | ||
| 9.619194357104389 | ||
| ], | ||
| "data": "float", | ||
| "shape": [ | ||
| 5, | ||
| 10 | ||
| [ | ||
| 7.384059587748178, | ||
| 8.640811575012702, | ||
| 2.1129479416859507, | ||
| 3.1057148920618385, | ||
| 8.05289155553335, | ||
| 4.399086558257299, | ||
| 7.193948745260049, | ||
| 5.035688862165517, | ||
| 5.219923411699781, | ||
| 4.539653707209219 | ||
| ], | ||
| [ | ||
| 1.9082739815105203, | ||
| 8.99864529956811, | ||
| 6.5195511089756675, | ||
| 1.957101992521509, | ||
| 3.1907575508941806, | ||
| 4.5623876367245195, | ||
| 9.68212403622312, | ||
| 4.419905700021853, | ||
| 8.71921956750521, | ||
| 8.163620432115913 | ||
| ], | ||
| [ | ||
| 9.478709499822921, | ||
| 8.675323729741326, | ||
| 4.226239950967384, | ||
| 1.6634413475982608, | ||
| 4.2399161776694365, | ||
| 1.8032704088212483, | ||
| 8.029077191030485, | ||
| 3.5987760418726706, | ||
| 1.0827071604629657, | ||
| 4.939077862941639 | ||
| ], | ||
| [ | ||
| 2.2055610319311745, | ||
| 8.052040372657313, | ||
| 5.325939740703682, | ||
| 5.915877670139153, | ||
| 9.335157497844655, | ||
| 5.8973761480277584, | ||
| 7.503363745465629, | ||
| 1.2530328598811558, | ||
| 7.58703729093062, | ||
| 2.4382507126877866 | ||
| ] | ||
| }, | ||
| "acetate": { | ||
| "list": [ | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ], | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ], | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ], | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ], | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ] | ||
| ], | ||
| "data": "float", | ||
| "shape": [ | ||
| 5, | ||
| 10 | ||
| ] | ||
| }, | ||
| "acetate": { | ||
| "list": [ | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ], | ||
| "data": "float", | ||
| "shape": [ | ||
| 5, | ||
| 10 | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ], | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ], | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ], | ||
| [ | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0, | ||
| 0.0 | ||
| ] | ||
| } | ||
| ], | ||
| "data": "float", | ||
| "shape": [ | ||
| 5, | ||
| 10 | ||
| ] | ||
| } | ||
| } | ||
| } | ||
@@ -1375,0 +1569,0 @@ composition = { |
+217
-16
@@ -1,26 +0,229 @@ | ||
| Metadata-Version: 2.1 | ||
| Metadata-Version: 2.4 | ||
| Name: bigraph-viz | ||
| Version: 0.1.10 | ||
| Summary: A graphviz-based plotting tool for compositional bigraph schema | ||
| Home-page: https://github.com/vivarium-collective/bigraph-viz | ||
| Author: Eran Agmon | ||
| Author-email: agmon.eran@gmail.com | ||
| License: UNKNOWN | ||
| Platform: UNKNOWN | ||
| Version: 0.1.15 | ||
| Summary: A visualization method for displaying the structure of process bigraphs | ||
| Author-email: Eran Agmon <agmon.eran@gmail.com> | ||
| Maintainer-email: Eran Agmon <agmon.eran@gmail.com> | ||
| License: Apache License | ||
| Version 2.0, January 2004 | ||
| http://www.apache.org/licenses/ | ||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||
| 1. Definitions. | ||
| "License" shall mean the terms and conditions for use, reproduction, | ||
| and distribution as defined by Sections 1 through 9 of this document. | ||
| "Licensor" shall mean the copyright owner or entity authorized by | ||
| the copyright owner that is granting the License. | ||
| "Legal Entity" shall mean the union of the acting entity and all | ||
| other entities that control, are controlled by, or are under common | ||
| control with that entity. For the purposes of this definition, | ||
| "control" means (i) the power, direct or indirect, to cause the | ||
| direction or management of such entity, whether by contract or | ||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||
| outstanding shares, or (iii) beneficial ownership of such entity. | ||
| "You" (or "Your") shall mean an individual or Legal Entity | ||
| exercising permissions granted by this License. | ||
| "Source" form shall mean the preferred form for making modifications, | ||
| including but not limited to software source code, documentation | ||
| source, and configuration files. | ||
| "Object" form shall mean any form resulting from mechanical | ||
| transformation or translation of a Source form, including but | ||
| not limited to compiled object code, generated documentation, | ||
| and conversions to other media types. | ||
| "Work" shall mean the work of authorship, whether in Source or | ||
| Object form, made available under the License, as indicated by a | ||
| copyright notice that is included in or attached to the work | ||
| (an example is provided in the Appendix below). | ||
| "Derivative Works" shall mean any work, whether in Source or Object | ||
| form, that is based on (or derived from) the Work and for which the | ||
| editorial revisions, annotations, elaborations, or other modifications | ||
| represent, as a whole, an original work of authorship. For the purposes | ||
| of this License, Derivative Works shall not include works that remain | ||
| separable from, or merely link (or bind by name) to the interfaces of, | ||
| the Work and Derivative Works thereof. | ||
| "Contribution" shall mean any work of authorship, including | ||
| the original version of the Work and any modifications or additions | ||
| to that Work or Derivative Works thereof, that is intentionally | ||
| submitted to Licensor for inclusion in the Work by the copyright owner | ||
| or by an individual or Legal Entity authorized to submit on behalf of | ||
| the copyright owner. For the purposes of this definition, "submitted" | ||
| means any form of electronic, verbal, or written communication sent | ||
| to the Licensor or its representatives, including but not limited to | ||
| communication on electronic mailing lists, source code control systems, | ||
| and issue tracking systems that are managed by, or on behalf of, the | ||
| Licensor for the purpose of discussing and improving the Work, but | ||
| excluding communication that is conspicuously marked or otherwise | ||
| designated in writing by the copyright owner as "Not a Contribution." | ||
| "Contributor" shall mean Licensor and any individual or Legal Entity | ||
| on behalf of whom a Contribution has been received by Licensor and | ||
| subsequently incorporated within the Work. | ||
| 2. Grant of Copyright License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| copyright license to reproduce, prepare Derivative Works of, | ||
| publicly display, publicly perform, sublicense, and distribute the | ||
| Work and such Derivative Works in Source or Object form. | ||
| 3. Grant of Patent License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| (except as stated in this section) patent license to make, have made, | ||
| use, offer to sell, sell, import, and otherwise transfer the Work, | ||
| where such license applies only to those patent claims licensable | ||
| by such Contributor that are necessarily infringed by their | ||
| Contribution(s) alone or by combination of their Contribution(s) | ||
| with the Work to which such Contribution(s) was submitted. If You | ||
| institute patent litigation against any entity (including a | ||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | ||
| or a Contribution incorporated within the Work constitutes direct | ||
| or contributory patent infringement, then any patent licenses | ||
| granted to You under this License for that Work shall terminate | ||
| as of the date such litigation is filed. | ||
| 4. Redistribution. You may reproduce and distribute copies of the | ||
| Work or Derivative Works thereof in any medium, with or without | ||
| modifications, and in Source or Object form, provided that You | ||
| meet the following conditions: | ||
| (a) You must give any other recipients of the Work or | ||
| Derivative Works a copy of this License; and | ||
| (b) You must cause any modified files to carry prominent notices | ||
| stating that You changed the files; and | ||
| (c) You must retain, in the Source form of any Derivative Works | ||
| that You distribute, all copyright, patent, trademark, and | ||
| attribution notices from the Source form of the Work, | ||
| excluding those notices that do not pertain to any part of | ||
| the Derivative Works; and | ||
| (d) If the Work includes a "NOTICE" text file as part of its | ||
| distribution, then any Derivative Works that You distribute must | ||
| include a readable copy of the attribution notices contained | ||
| within such NOTICE file, excluding those notices that do not | ||
| pertain to any part of the Derivative Works, in at least one | ||
| of the following places: within a NOTICE text file distributed | ||
| as part of the Derivative Works; within the Source form or | ||
| documentation, if provided along with the Derivative Works; or, | ||
| within a display generated by the Derivative Works, if and | ||
| wherever such third-party notices normally appear. The contents | ||
| of the NOTICE file are for informational purposes only and | ||
| do not modify the License. You may add Your own attribution | ||
| notices within Derivative Works that You distribute, alongside | ||
| or as an addendum to the NOTICE text from the Work, provided | ||
| that such additional attribution notices cannot be construed | ||
| as modifying the License. | ||
| You may add Your own copyright statement to Your modifications and | ||
| may provide additional or different license terms and conditions | ||
| for use, reproduction, or distribution of Your modifications, or | ||
| for any such Derivative Works as a whole, provided Your use, | ||
| reproduction, and distribution of the Work otherwise complies with | ||
| the conditions stated in this License. | ||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | ||
| any Contribution intentionally submitted for inclusion in the Work | ||
| by You to the Licensor shall be under the terms and conditions of | ||
| this License, without any additional terms or conditions. | ||
| Notwithstanding the above, nothing herein shall supersede or modify | ||
| the terms of any separate license agreement you may have executed | ||
| with Licensor regarding such Contributions. | ||
| 6. Trademarks. This License does not grant permission to use the trade | ||
| names, trademarks, service marks, or product names of the Licensor, | ||
| except as required for reasonable and customary use in describing the | ||
| origin of the Work and reproducing the content of the NOTICE file. | ||
| 7. Disclaimer of Warranty. Unless required by applicable law or | ||
| agreed to in writing, Licensor provides the Work (and each | ||
| Contributor provides its Contributions) on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
| implied, including, without limitation, any warranties or conditions | ||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||
| PARTICULAR PURPOSE. You are solely responsible for determining the | ||
| appropriateness of using or redistributing the Work and assume any | ||
| risks associated with Your exercise of permissions under this License. | ||
| 8. Limitation of Liability. In no event and under no legal theory, | ||
| whether in tort (including negligence), contract, or otherwise, | ||
| unless required by applicable law (such as deliberate and grossly | ||
| negligent acts) or agreed to in writing, shall any Contributor be | ||
| liable to You for damages, including any direct, indirect, special, | ||
| incidental, or consequential damages of any character arising as a | ||
| result of this License or out of the use or inability to use the | ||
| Work (including but not limited to damages for loss of goodwill, | ||
| work stoppage, computer failure or malfunction, or any and all | ||
| other commercial damages or losses), even if such Contributor | ||
| has been advised of the possibility of such damages. | ||
| 9. Accepting Warranty or Additional Liability. While redistributing | ||
| the Work or Derivative Works thereof, You may choose to offer, | ||
| and charge a fee for, acceptance of support, warranty, indemnity, | ||
| or other liability obligations and/or rights consistent with this | ||
| License. However, in accepting such obligations, You may act only | ||
| on Your own behalf and on Your sole responsibility, not on behalf | ||
| of any other Contributor, and only if You agree to indemnify, | ||
| defend, and hold each Contributor harmless for any liability | ||
| incurred by, or claims asserted against, such Contributor by reason | ||
| of your accepting any such warranty or additional liability. | ||
| END OF TERMS AND CONDITIONS | ||
| APPENDIX: How to apply the Apache License to your work. | ||
| To apply the Apache License to your work, attach the following | ||
| boilerplate notice, with the fields enclosed by brackets "[]" | ||
| replaced with your own identifying information. (Don't include | ||
| the brackets!) The text should be enclosed in the appropriate | ||
| comment syntax for the file format. We also recommend that a | ||
| file or class name and description of purpose be included on the | ||
| same "printed page" as the copyright notice for easier | ||
| identification within third-party archives. | ||
| Copyright 2023 Ryan Spangler and Eran Agmon | ||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| Keywords: visualization,systems biology,bigraph,graphviz,vivarium | ||
| Classifier: Development Status :: 3 - Alpha | ||
| Classifier: Intended Audience :: Developers | ||
| Classifier: Intended Audience :: Science/Research | ||
| Classifier: License :: OSI Approved :: MIT License | ||
| Classifier: Operating System :: OS Independent | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python :: 3.6 | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Programming Language :: Python :: 3 :: Only | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Programming Language :: Python :: 3.10 | ||
| Classifier: Programming Language :: Python :: 3.11 | ||
| Requires-Python: >=3.6 | ||
| Classifier: Programming Language :: Python :: 3.12 | ||
| Classifier: Topic :: Scientific/Engineering :: Visualization | ||
| Classifier: Topic :: Software Development :: Libraries | ||
| Requires-Python: >=3.9 | ||
| Description-Content-Type: text/markdown | ||
| License-File: LICENSE | ||
| License-File: AUTHORS.md | ||
| Requires-Dist: bigraph-schema | ||
| Requires-Dist: graphviz | ||
| Dynamic: license-file | ||
@@ -94,3 +297,1 @@ # Bigraph-viz | ||
| Bigraph-viz is open-source software released under the [Apache 2 License](https://github.com/vivarium-collective/bigraph-viz/blob/main/LICENSE). | ||
+6
-2
@@ -7,6 +7,6 @@ [build-system] | ||
| name = "bigraph-viz" | ||
| version = "0.1.10" | ||
| version = "0.1.15" | ||
| description = "A visualization method for displaying the structure of process bigraphs" | ||
| readme = "README.md" | ||
| requires-python = "==3.12.9" | ||
| requires-python = ">=3.9" | ||
| license = { file = "LICENSE" } | ||
@@ -28,2 +28,6 @@ | ||
| "Programming Language :: Python :: 3", | ||
| "Programming Language :: Python :: 3 :: Only", | ||
| "Programming Language :: Python :: 3.9", | ||
| "Programming Language :: Python :: 3.10", | ||
| "Programming Language :: Python :: 3.11", | ||
| "Programming Language :: Python :: 3.12", | ||
@@ -30,0 +34,0 @@ "Topic :: Scientific/Engineering :: Visualization", |
-51
| import re | ||
| from setuptools import setup, find_packages | ||
| VERSION = '0.1.10' | ||
| with open("README.md", "r") as readme: | ||
| description = readme.read() | ||
| # Patch the relative links to absolute URLs that will work on PyPI. | ||
| description2 = re.sub( | ||
| r']\(([\w/.-]+\.png)\)', | ||
| r'](https://github.com/vivarium-collective/bigraph-viz/raw/main/\1)', | ||
| description) | ||
| long_description = re.sub( | ||
| r']\(([\w/.-]+)\)', | ||
| r'](https://github.com/vivarium-collective/bigraph-viz/blob /main/\1)', | ||
| description2) | ||
| setup( | ||
| name="bigraph-viz", | ||
| version=VERSION, | ||
| author="Eran Agmon", | ||
| author_email="agmon.eran@gmail.com", | ||
| description="A graphviz-based plotting tool for compositional bigraph schema", | ||
| long_description=long_description, | ||
| long_description_content_type="text/markdown", | ||
| url="https://github.com/vivarium-collective/bigraph-viz", | ||
| packages=find_packages(), | ||
| classifiers=[ | ||
| "Development Status :: 3 - Alpha", | ||
| "Intended Audience :: Developers", | ||
| "License :: OSI Approved :: MIT License", | ||
| "Operating System :: OS Independent", | ||
| "Programming Language :: Python", | ||
| "Programming Language :: Python :: 3", | ||
| "Programming Language :: Python :: 3.6", | ||
| "Programming Language :: Python :: 3.7", | ||
| "Programming Language :: Python :: 3.8", | ||
| "Programming Language :: Python :: 3.9", | ||
| "Programming Language :: Python :: 3.10", | ||
| "Programming Language :: Python :: 3.11", | ||
| ], | ||
| python_requires=">=3.6", | ||
| install_requires=[ | ||
| # List your package dependencies here | ||
| "graphviz", | ||
| "bigraph-schema>=0.0.51", | ||
| "numpy" | ||
| ], | ||
| ) |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
119550
32.09%1792
6.54%17
-5.56%