fair-ca-visualization 0.4.0__py3-none-any.whl

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.
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.5
2
+ Name: fair-ca-visualization
3
+ Version: 0.4.0
4
+ Summary: Interactive visualization of the FAIR COMBINE Archive Indicators (FAIR-CA) for computational models.
5
+ Project-URL: Homepage, https://faircombine.streamlit.app
6
+ Project-URL: Documentation, https://matthiaskoenig.github.io/fair-ca-visualization
7
+ Project-URL: Repository, https://github.com/matthiaskoenig/fair-ca-visualization
8
+ Project-URL: Issues, https://github.com/matthiaskoenig/fair-ca-visualization/issues
9
+ Project-URL: Changelog, https://github.com/matthiaskoenig/fair-ca-visualization/tree/develop/release-notes
10
+ Project-URL: Download, https://pypi.org/project/fair-ca-visualization
11
+ Author-email: Matthias König <konigmatt@googlemail.com>
12
+ Maintainer-email: Matthias König <konigmatt@googlemail.com>
13
+ License-Expression: MIT
14
+ License-File: LICENSE
15
+ Keywords: COMBINE,FAIR,indicators,modeling,standardization,streamlit
16
+ Classifier: Development Status :: 4 - Beta
17
+ Classifier: Intended Audience :: Science/Research
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
23
+ Classifier: Topic :: Scientific/Engineering :: Visualization
24
+ Requires-Python: >=3.14
25
+ Requires-Dist: numpy>=2.4.3
26
+ Requires-Dist: openpyxl>=3.1.5
27
+ Requires-Dist: pandas<3,>=2.3.3
28
+ Requires-Dist: plotly>=6.6.0
29
+ Requires-Dist: pyarrow>=23.0.1
30
+ Requires-Dist: rich>=14.3.3
31
+ Requires-Dist: streamlit>=1.55.0
32
+ Description-Content-Type: text/markdown
33
+
34
+ ![fair-ca-visualization logo](https://github.com/matthiaskoenig/fair-ca-visualization/raw/develop/docs/images/fair-ca-logo.png)
35
+
36
+ # fair-ca-visualization
37
+
38
+ [![GitHub Actions CI/CD Status](https://github.com/matthiaskoenig/fair-ca-visualization/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/matthiaskoenig/fair-ca-visualization/actions/workflows/ci-cd.yml) [![Documentation](https://img.shields.io/badge/docs-fair--ca--visualization-008080.svg)](https://matthiaskoenig.github.io/fair-ca-visualization) [![Version](https://img.shields.io/pypi/v/fair-ca-visualization.svg)](https://pypi.org/project/fair-ca-visualization/) [![Python Versions](https://img.shields.io/pypi/pyversions/fair-ca-visualization.svg)](https://pypi.org/project/fair-ca-visualization/) [![MIT License](https://img.shields.io/pypi/l/fair-ca-visualization.svg)](https://opensource.org/licenses/MIT) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13755820.svg)](https://doi.org/10.5281/zenodo.13755820)
39
+
40
+ Computational models are essential tools for studying complex systems which, particularly in clinical settings, need to be quality-approved and transparent. A community-driven approach to enhance the transparency and communication of model features is adherence to the principles of Findability, Accessibility, Interoperability and Reusability (FAIR). The FAIR COMBINE Archive Indicators (FAIR-CA) adapt the FAIR indicators published by the Research Data Alliance to assess the FAIRness of models encoded in domain-specific standards, such as those established by [COMBINE](https://co.mbine.org).
41
+
42
+ The FAIR COMBINE Archive Indicators project is available from [https://github.com/FAIR-CA-indicators/FAIR-CA-indicators.github.io](https://github.com/FAIR-CA-indicators/FAIR-CA-indicators.github.io).
43
+
44
+ `fair-ca-visualization` visualizes FAIR-CA assessments interactively. The app is available from https://faircombine.streamlit.app, the documentation from https://matthiaskoenig.github.io/fair-ca-visualization.
45
+
46
+ [![The fair-ca-visualization app](https://github.com/matthiaskoenig/fair-ca-visualization/raw/develop/docs/images/fair-ca-example.png)](https://faircombine.streamlit.app)
47
+
48
+ # Installation
49
+
50
+ To run the app locally, install the package from [PyPI](https://pypi.org/project/fair-ca-visualization/) (python 3.14) and start it with `fairvis`:
51
+
52
+ ```bash
53
+ uv tool install fair-ca-visualization
54
+ fairvis
55
+ ```
56
+
57
+ See the [installation guide](https://matthiaskoenig.github.io/fair-ca-visualization/installation/) for pip and for running from a checkout, and [contributing](https://matthiaskoenig.github.io/fair-ca-visualization/development/) for the development setup.
58
+
59
+ # How to cite
60
+
61
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13755820.svg)](https://doi.org/10.5281/zenodo.13755820)
62
+
63
+ > König M. fair-ca-visualization: interactive visualization of the FAIR COMBINE Archive Indicators. Zenodo. [doi:10.5281/zenodo.13755820](https://doi.org/10.5281/zenodo.13755820)
64
+
65
+ ```bibtex
66
+ @software{fair_ca_visualization,
67
+ author = {König, Matthias},
68
+ title = {fair-ca-visualization: interactive visualization of the FAIR COMBINE Archive Indicators},
69
+ publisher = {Zenodo},
70
+ doi = {10.5281/zenodo.13755820},
71
+ url = {https://doi.org/10.5281/zenodo.13755820}
72
+ }
73
+ ```
74
+
75
+ # License
76
+
77
+ - Source Code: [MIT](https://opensource.org/license/MIT)
78
+ - Documentation: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
79
+
80
+ # Funding
81
+
82
+ Matthias König (MK) was supported by the Federal Ministry of Education and Research (BMBF, Germany) within the research network Systems Medicine of the Liver (LiSyM, grant number 031L0054). MK is supported by the Federal Ministry of Education and Research (BMBF, Germany) within ATLAS by grant number 031L0304B and by the German Research Foundation (DFG) within the Research Unit Program FOR 5151 QuaLiPerF (Quantifying Liver Perfusion-Function Relationship in Complex Resection - A Systems Medicine Approach) by grant number 436883643 and by grant number 465194077 (Priority Programme SPP 2311, Subproject SimLivA).
83
+
84
+ © 2024 - 2026 Matthias König
@@ -0,0 +1,26 @@
1
+ fairvis/__init__.py,sha256=QKec5mel6WuhYiJfip0L7zUSPROakL6gNrvqSFNK7W0,135
2
+ fairvis/__main__.py,sha256=nko_6M0jQuqHg4XRfaPcqSYzo7urXqA_yCIjQQwq8j8,115
3
+ fairvis/app.py,sha256=dv0NPANrVbnzun-yvRSfcfG1AW9bIlyCcmNhIEkHEu4,7942
4
+ fairvis/cli.py,sha256=_fp--nPtPuEF4ZudbhulCafQkDmLci3wqviJJtaDXy0,1517
5
+ fairvis/console.py,sha256=GaohtlJZurR4ExXRtL7GIHrj67_6-jFYTw2ai6QYVnQ,331
6
+ fairvis/data_io.py,sha256=nTCKUTvUai-XdxEx8ZYBpiZwaVD7X87GYJyz2nYXWdE,5208
7
+ fairvis/example.py,sha256=XPfjXfkMHlbPyaadSjhVHqpkBqr_lbZZqoUoswNLT_Q,417
8
+ fairvis/settings.py,sha256=yoajWwJ9SkNG8F4cwbCFqotx9uF7TpYH5jljYtKEf0s,589
9
+ fairvis/visualization.py,sha256=pPFi55209bd76TUsTN0XgnNUZ42fNTf42degrCkyJvA,3118
10
+ fairvis/data/FAIR_assessment_template.xlsx,sha256=-VzXMptkrXSgVktUEPN17898o8Coe5TgEsydDnHcU54,17011
11
+ fairvis/data/assessments/Alejandro2026_empagliflozin.xlsx,sha256=IXrMmyHaKuQ4uaf59_B1br5Swc-NZSFYE8q45jT-c9Y,67728
12
+ fairvis/data/assessments/BioModels_C19_curated.xlsx,sha256=meLgXWwnvH0q4rntdmtw2zZCSjfZuoStUpeHU8PVb5Y,18859
13
+ fairvis/data/assessments/BioModels_curated.xlsx,sha256=gcj8prxjigVI0Q21gh-3wprbFd3oEUpJJrGd0yel-pc,17585
14
+ fairvis/data/assessments/BioModels_non_curated.xlsx,sha256=o-H948t6T1GJcN0o_QRvel-Piz4fvFZdOqIrxNkEWGA,18896
15
+ fairvis/data/assessments/Casabianca2026_rivaroxaban.xlsx,sha256=9Rq9fz1RqFIthmo1E79lCRN-djiC8qPtBDzuQ5F0vzk,67726
16
+ fairvis/data/assessments/Elias2025_glimepiride.xlsx,sha256=8ghUfq29mvFjoqoPKM_td9I3GuzwgPnHLn25NRNU1EU,67724
17
+ fairvis/data/assessments/Nemitz2026_dapagliflozin.xlsx,sha256=2cawChl4OOQ7Q-uKPGrJ4Vvnjna62pYRXz64rKefr_Y,67191
18
+ fairvis/data/assessments/PMR_curated.xlsx,sha256=jv5nNGNwMw1Ygyja-WoNRDSfvs9tGcRG0vxMBWOrel0,18063
19
+ fairvis/data/assessments/PMR_non_curated.xlsx,sha256=AVRNTnu6-kVkNEYZ2EjRaY3d2PXnuRa5KEk5RSRd_LU,18385
20
+ fairvis/data/assessments/Tensil2026_losartan.xlsx,sha256=XqXSsu4lOZp2LvrPQOD6jxMQBXJHcFhHEC7iqF6RCHw,67724
21
+ fairvis/data/assessments/Tereshchuk2026_canagliflozin.xlsx,sha256=oaHDUthxVrrsFP4jubURX2-8ytiLnJQzWjwaAvw7ukY,67728
22
+ fair_ca_visualization-0.4.0.dist-info/METADATA,sha256=i5sRmKRKPi06te8EhL8OuGoVWrwC-BBUFYPtEzKBTNA,5673
23
+ fair_ca_visualization-0.4.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
24
+ fair_ca_visualization-0.4.0.dist-info/entry_points.txt,sha256=TGDUiYZ6BRCWrAu3umTEc4QuVQzNLyxYxKUBdoBv3eg,45
25
+ fair_ca_visualization-0.4.0.dist-info/licenses/LICENSE,sha256=-nDb-yPz_IzNCxwvh--aoEgFTIBZBpvjwVSsxPAgRUM,1064
26
+ fair_ca_visualization-0.4.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ fairvis = fairvis.cli:main
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2025-2026 Matthias König
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
fairvis/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ """fairvis: interactive visualization of the FAIR COMBINE Archive Indicators."""
2
+
3
+ __author__ = "Matthias König"
4
+ __version__ = "0.4.0"
fairvis/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Start the app with `python -m fairvis`."""
2
+
3
+ from fairvis.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
fairvis/app.py ADDED
@@ -0,0 +1,208 @@
1
+ """Streamlit app of the FAIR COMBINE Archive Indicators.
2
+
3
+ Run with `fairvis`, or from a checkout with `streamlit run src/fairvis/app.py`.
4
+ """
5
+
6
+ import pandas as pd
7
+ import streamlit as st
8
+
9
+ from fairvis.data_io import load_assessment, load_indicators, load_model_assessments
10
+ from fairvis.settings import TEMPLATE_PATH
11
+ from fairvis.visualization import visualize_barplot, visualize_polar_barplots
12
+
13
+ st.set_page_config(
14
+ page_title="FAIR-CA-Indicators",
15
+ page_icon="🧊",
16
+ layout="wide",
17
+ menu_items={
18
+ "Get help": "mailto:konigmatt@googlemail.com",
19
+ "Report a bug": "https://github.com/matthiaskoenig/fair-ca-visualization/issues/new",
20
+ "About": """
21
+ FAIR-CA-Indicators application.
22
+ """,
23
+ },
24
+ )
25
+ st.markdown(
26
+ """
27
+ <style>
28
+ .block-container {
29
+ padding-top: 2rem;
30
+ padding-bottom: 1rem;
31
+ padding-left: 5rem;
32
+ padding-right: 5rem;
33
+ }
34
+ </style>
35
+ """,
36
+ unsafe_allow_html=True,
37
+ )
38
+
39
+
40
+ @st.cache_data
41
+ def load_data() -> tuple[pd.DataFrame, dict[str, pd.DataFrame]]:
42
+ """Load the indicators and the example assessments.
43
+
44
+ Returns:
45
+ indicators with the counts of their assessments, and the assessments by
46
+ model id.
47
+ """
48
+ df_models = load_model_assessments()
49
+ df_indicators = load_indicators(df_models=df_models)
50
+
51
+ return df_indicators, df_models
52
+
53
+
54
+ df_indicators, models = load_data()
55
+
56
+
57
+ # --- Main ----------------------------------------------------------------------------
58
+ st.markdown(
59
+ """
60
+ # Visualize FAIR COMBINE Archive Indicators
61
+ """
62
+ )
63
+ tab_about, tab_assessment, tab_models, tab_indicators = st.tabs(
64
+ [
65
+ "About",
66
+ "Assess Model",
67
+ "Example Assessments",
68
+ "Indicators",
69
+ ]
70
+ )
71
+
72
+ with tab_about:
73
+ st.markdown(
74
+ """
75
+ ## Motivation
76
+ Computational models are essential tools for studying complex biological systems. In biomedical and clinical contexts in particular, models must be transparent, well-documented, and **reproducible** to ensure reliability and reuse.
77
+
78
+ A community-driven approach to improving transparency and communication of model characteristics is the adoption of the **FAIR principles**: *Findability, Accessibility, Interoperability, and Reusability*. Building on the FAIR indicators developed by the **Research Data Alliance (RDA)**, we propose an adaptation specifically designed for computational models encoded in domain standards developed within the **[COMBINE](https://co.mbine.org)** community.
79
+
80
+ The **FAIR COMBINE Archive Indicators** enable systematic assessment of the FAIRness of models packaged as COMBINE archives and support improved documentation, sharing, and reuse of computational models in the life sciences. More information is available from:
81
+
82
+ >*Balaur I., Nickerson D.P., Welter D., Wodke J.A.H., Ancien F., Gebhardt T., Grouès V., Hermjakob H., König M., Radde N., Rougny A., Schneider R., Malik-Sheriff R.S., Shiferaw K.B., Stefan M., Satagopam V., Waltemath D. (2025).*
83
+ >**FAIRification of computational models in biology.**
84
+ >bioRxiv 2025.03.21.644517 (preprint). doi: [10.1101/2025.03.21.644517](https://doi.org/10.1101/2025.03.21.644517)
85
+
86
+ ## Usage
87
+ This webpage provides an interactive visualization of the **FAIR COMBINE Archive Indicators**,
88
+
89
+ - Use the **Assess Model** tab to assess your own model (a template for the indicators is provided).
90
+ - Use the **Example Assessments** tab to explore FAIR indicator assessments for example models.
91
+ - Use the **Indicators** tab to browse the individual FAIR indicators.
92
+
93
+ ## How to cite the visualization tool
94
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13755820.svg)](https://doi.org/10.5281/zenodo.13755820)
95
+
96
+ ## Funding
97
+ Matthias König was supported by the **German Federal Ministry of Education and Research (BMBF)** within the ATLAS project (grant number 031L0304B) and by the **German Research Foundation (DFG)** within the Research Unit Program **FOR 5151 QuaLiPerF** (grant number 436883643) and the **Priority Programme SPP 2311 (Subproject SimLivA)** (grant number 465194077).
98
+
99
+ ## Example visualization
100
+ The example visualization demonstrates the **Model** and **Model Metadata** FAIR indicators using the *BioModels_C19_curated* example.
101
+ """
102
+ )
103
+ figs_example = visualize_polar_barplots(df_data=models["BioModels_C19_curated"])
104
+ col1a, col2a = st.columns(2)
105
+ with col1a:
106
+ st.plotly_chart(figs_example[0], key="pchart_example1")
107
+ with col2a:
108
+ st.plotly_chart(figs_example[1], key="pchart_example2")
109
+
110
+
111
+ with tab_indicators:
112
+ st.dataframe(
113
+ data=df_indicators,
114
+ width="stretch",
115
+ column_config={
116
+ "Assessment": st.column_config.BarChartColumn(
117
+ "FAIR Assessment",
118
+ help="Assessment of all models (NA, 0.0, 0.5, 1.0)",
119
+ ),
120
+ },
121
+ )
122
+
123
+
124
+ with tab_models:
125
+ col_select, col_fair, _ = st.columns(3)
126
+ with col_select:
127
+ model_id = st.selectbox(
128
+ "Select model",
129
+ index=0,
130
+ options=list(models.keys()),
131
+ )
132
+ df_model = models[model_id]
133
+
134
+ with col_fair:
135
+ fig_bar = visualize_barplot(df_data=df_model)
136
+ st.plotly_chart(fig_bar, width="content", key="pchart_models_bar1")
137
+
138
+ # plotly plot
139
+ figs = visualize_polar_barplots(df_data=df_model)
140
+ col1, col2 = st.columns(2)
141
+ with col1:
142
+ st.plotly_chart(figs[0], key="pchart_models_col1")
143
+ with col2:
144
+ st.plotly_chart(figs[1], key="pchart_models_col2")
145
+ col3, col4 = st.columns(2)
146
+ with col3:
147
+ st.plotly_chart(figs[2], key="pchart_models_col3")
148
+ with col4:
149
+ st.plotly_chart(figs[3], key="pchart_models_col4")
150
+
151
+ # show dataframe
152
+ st.dataframe(df_model, width="stretch")
153
+
154
+ with tab_assessment:
155
+ col_upload, col_template, col_fair_upload = st.columns(3, gap="medium")
156
+ with col_upload:
157
+ uploaded_xlsx = st.file_uploader(
158
+ "Upload FAIR model assessment",
159
+ type="xlsx",
160
+ accept_multiple_files=False,
161
+ )
162
+ df_model_upload: pd.DataFrame | None = None
163
+ if uploaded_xlsx is not None:
164
+ try:
165
+ df_model_upload = load_assessment(uploaded_xlsx)
166
+ except ValueError as err:
167
+ st.error(f"The uploaded file is no valid FAIR assessment: {err}")
168
+
169
+ with col_template:
170
+ st.html(
171
+ """
172
+ The template for assessment is available here:
173
+ """
174
+ )
175
+ st.download_button(
176
+ "Download FAIR Template",
177
+ TEMPLATE_PATH.read_bytes(),
178
+ file_name="FAIR_assessment_template.xlsx",
179
+ help="FAIR assessment template. Fill out and reupload for evaluation.",
180
+ )
181
+ with col_fair_upload:
182
+ if df_model_upload is not None:
183
+ fig_bar = visualize_barplot(df_data=df_model_upload)
184
+ st.plotly_chart(fig_bar, width="content")
185
+
186
+ if df_model_upload is not None:
187
+ # plotly plot
188
+ figs = visualize_polar_barplots(df_data=df_model_upload)
189
+ col1, col2 = st.columns(2)
190
+ with col1:
191
+ st.plotly_chart(figs[0], key="pchart_assessment_col1")
192
+ with col2:
193
+ st.plotly_chart(figs[1], key="pchart_assessment_col2")
194
+ col3, col4 = st.columns(2)
195
+ with col3:
196
+ st.plotly_chart(figs[2], key="pchart_assessment_col3")
197
+ with col4:
198
+ st.plotly_chart(figs[3], key="pchart_assessment_col4")
199
+
200
+ # show dataframe
201
+ st.dataframe(df_model_upload, width="stretch")
202
+
203
+ st.divider()
204
+ st.markdown(
205
+ """
206
+ © 2024-2026 [Matthias König](https://livermetabolism.com) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13755820.svg)](https://doi.org/10.5281/zenodo.13755820)
207
+ """
208
+ )
fairvis/cli.py ADDED
@@ -0,0 +1,46 @@
1
+ """Console script `fairvis`, starts the app with streamlit.
2
+
3
+ The options of `.streamlit/config.toml` of the repository are not read when the
4
+ app runs from an installed package, so they are passed on the command line.
5
+ Further arguments are passed to `streamlit run`, e.g. `fairvis --server.port 8502`.
6
+ """
7
+
8
+ import io
9
+ import sys
10
+
11
+ from streamlit.web import cli as stcli
12
+
13
+ from fairvis.settings import APP_PATH
14
+
15
+ STREAMLIT_OPTIONS: tuple[str, ...] = (
16
+ "--browser.gatherUsageStats=false",
17
+ "--theme.base=light",
18
+ )
19
+ """Default options of `streamlit run`, the same as in `.streamlit/config.toml`."""
20
+
21
+
22
+ def streamlit_argv(args: list[str]) -> list[str]:
23
+ """Command line of `streamlit run` for the app.
24
+
25
+ Args:
26
+ args: further arguments for `streamlit run`; they follow the defaults,
27
+ so they override them.
28
+
29
+ Returns:
30
+ the arguments, starting with the program name `streamlit`.
31
+ """
32
+ return ["streamlit", "run", str(APP_PATH), *STREAMLIT_OPTIONS, *args]
33
+
34
+
35
+ def main() -> None:
36
+ """Start the FAIR-CA visualization app.
37
+
38
+ The output is written as UTF-8: the messages of streamlit contain non ascii
39
+ characters, which the ansi code page of a redirected stdout on windows, e.g.
40
+ cp1252, cannot encode (UTF-8 is the default from python 3.15 on, PEP 686).
41
+ """
42
+ for stream in (sys.stdout, sys.stderr):
43
+ if isinstance(stream, io.TextIOWrapper):
44
+ stream.reconfigure(encoding="utf-8")
45
+ sys.argv = streamlit_argv(sys.argv[1:])
46
+ sys.exit(stcli.main())
fairvis/console.py ADDED
@@ -0,0 +1,17 @@
1
+ """Rich console for logging."""
2
+
3
+ from rich import pretty
4
+ from rich.console import Console
5
+ from rich.theme import Theme
6
+
7
+ pretty.install()
8
+ custom_theme = Theme(
9
+ {
10
+ "success": "green",
11
+ "info": "blue",
12
+ "warning": "orange3",
13
+ "error": "red",
14
+ }
15
+ )
16
+
17
+ console = Console(record=True, theme=custom_theme)
fairvis/data_io.py ADDED
@@ -0,0 +1,163 @@
1
+ """Loading and validation of FAIR assessments and the indicators."""
2
+
3
+ from numbers import Real
4
+ from pathlib import Path
5
+ from typing import BinaryIO
6
+
7
+ import numpy as np
8
+ import pandas as pd
9
+
10
+ from fairvis.console import console
11
+ from fairvis.settings import ASSESSMENTS_PATH, TEMPLATE_PATH
12
+
13
+ REQUIRED_COLUMNS: tuple[str, ...] = (
14
+ "ID",
15
+ "Short",
16
+ "Type",
17
+ "Category",
18
+ "Priority",
19
+ "Indicator",
20
+ "Description",
21
+ "Assessment details",
22
+ "Assessment",
23
+ )
24
+ """Columns of the template an assessment needs."""
25
+
26
+ ASSESSMENT_VALUES: tuple[float, ...] = (0.0, 0.5, 1.0)
27
+ """Allowed assessment values besides NA (not applicable, an empty cell)."""
28
+
29
+
30
+ def assessment_class(value: object) -> int:
31
+ """Class of an assessment value.
32
+
33
+ Args:
34
+ value: assessment of an indicator, NaN for NA.
35
+
36
+ Returns:
37
+ 0 for NA, 1 for 0.0, 2 for 0.5 and 3 for 1.0.
38
+
39
+ Raises:
40
+ ValueError: if the value is none of NA, 0, 0.5 and 1.
41
+ """
42
+ if isinstance(value, Real) and not isinstance(value, bool):
43
+ number = float(value)
44
+ if np.isnan(number):
45
+ return 0
46
+ for k, reference in enumerate(ASSESSMENT_VALUES, start=1):
47
+ if np.isclose(number, reference):
48
+ return k
49
+ if isinstance(value, str) and _is_number(value):
50
+ raise ValueError(
51
+ f"assessment value {value!r} is stored as text, enter it as a number"
52
+ )
53
+ raise ValueError(f"assessment value {value!r} is none of NA, 0, 0.5, 1")
54
+
55
+
56
+ def _is_number(text: str) -> bool:
57
+ try:
58
+ float(text)
59
+ except ValueError:
60
+ return False
61
+ return True
62
+
63
+
64
+ def validate_assessment(df: pd.DataFrame) -> None:
65
+ """Validate the structure and the values of a raw assessment.
66
+
67
+ Args:
68
+ df: assessment as read from the xlsx file, before the `ID` index is set.
69
+
70
+ Raises:
71
+ ValueError: if a column of the template is missing or an assessment value
72
+ is none of NA, 0, 0.5 and 1.
73
+ """
74
+ missing = [column for column in REQUIRED_COLUMNS if column not in df.columns]
75
+ if missing:
76
+ raise ValueError(
77
+ f"The assessment misses the columns {', '.join(missing)}. "
78
+ "Fill out the FAIR assessment template."
79
+ )
80
+ for indicator_id, value in zip(df["ID"], df["Assessment"], strict=True):
81
+ try:
82
+ assessment_class(value)
83
+ except ValueError as err:
84
+ raise ValueError(f"Indicator '{indicator_id}': {err}.") from err
85
+
86
+
87
+ def load_assessment(source: Path | BinaryIO) -> pd.DataFrame:
88
+ """Load an assessment from an xlsx file.
89
+
90
+ Args:
91
+ source: path of the xlsx file or an uploaded file.
92
+
93
+ Returns:
94
+ assessment indexed by the indicator `ID`, without the description columns
95
+ and without columns lacking a header (named `Unnamed: <n>` by pandas).
96
+
97
+ Raises:
98
+ ValueError: if the file is no readable xlsx file or no valid assessment.
99
+ """
100
+ try:
101
+ df = pd.read_excel(source, sheet_name=0)
102
+ except Exception as err:
103
+ raise ValueError(f"The file is no readable xlsx file: {err}") from err
104
+ validate_assessment(df)
105
+ unnamed = [column for column in df.columns if str(column).startswith("Unnamed")]
106
+ return df.set_index("ID").drop(
107
+ columns=["Description", "Assessment details", *unnamed]
108
+ )
109
+
110
+
111
+ def load_model_assessments(
112
+ assessment_dir: Path = ASSESSMENTS_PATH,
113
+ ) -> dict[str, pd.DataFrame]:
114
+ """Load all model assessments of a directory.
115
+
116
+ Args:
117
+ assessment_dir: directory with one xlsx file per model.
118
+
119
+ Returns:
120
+ assessments by model id (the file name without suffix), sorted by model id.
121
+ """
122
+ return {
123
+ path.stem: load_assessment(path)
124
+ for path in sorted(assessment_dir.glob("*.xlsx"))
125
+ }
126
+
127
+
128
+ def load_indicators(df_models: dict[str, pd.DataFrame]) -> pd.DataFrame:
129
+ """Load the indicators and count their assessments over all models.
130
+
131
+ Args:
132
+ df_models: assessments by model id, see `load_model_assessments`.
133
+
134
+ Returns:
135
+ indicators indexed by `ID`; the column `Assessment` holds the number of
136
+ models with NA, 0, 0.5 and 1 for the indicator.
137
+
138
+ Raises:
139
+ ValueError: if an assessment has other indicators than the template.
140
+ """
141
+ df_indicators = (
142
+ pd.read_excel(TEMPLATE_PATH, sheet_name=0)
143
+ .set_index("ID")
144
+ .drop(columns=["Description", "Assessment details", "Assessment", "Comment"])
145
+ )
146
+ assessments = [[0.0, 0.0, 0.0, 0.0] for _ in range(len(df_indicators))]
147
+ for model_id, df_model in df_models.items():
148
+ if not df_model.index.sort_values().equals(df_indicators.index.sort_values()):
149
+ raise ValueError(
150
+ f"The assessment '{model_id}' has other indicators than the template."
151
+ )
152
+ values = df_model["Assessment"].reindex(df_indicators.index).to_numpy()
153
+ for k, value in enumerate(values):
154
+ assessments[k][assessment_class(value)] += 1.0
155
+
156
+ df_indicators["Assessment"] = assessments
157
+ return df_indicators
158
+
159
+
160
+ if __name__ == "__main__":
161
+ df_indicators = load_indicators(load_model_assessments())
162
+ console.rule("Indicators", align="left", style="red")
163
+ console.print(df_indicators)
fairvis/example.py ADDED
@@ -0,0 +1,10 @@
1
+ """Example showing the figures of a bundled assessment in the browser."""
2
+
3
+ from fairvis.data_io import load_assessment
4
+ from fairvis.settings import ASSESSMENTS_PATH
5
+ from fairvis.visualization import visualize_barplot, visualize_polar_barplots
6
+
7
+ if __name__ == "__main__":
8
+ df = load_assessment(ASSESSMENTS_PATH / "BioModels_curated.xlsx")
9
+ visualize_barplot(df).show()
10
+ visualize_polar_barplots(df)[0].show()
fairvis/settings.py ADDED
@@ -0,0 +1,18 @@
1
+ """Paths of the app and of the data bundled with the package."""
2
+
3
+ from pathlib import Path
4
+
5
+ PACKAGE_PATH: Path = Path(__file__).parent
6
+ """Directory of the installed `fairvis` package."""
7
+
8
+ APP_PATH: Path = PACKAGE_PATH / "app.py"
9
+ """Streamlit script of the app."""
10
+
11
+ DATA_PATH: Path = PACKAGE_PATH / "data"
12
+ """Data bundled with the package."""
13
+
14
+ ASSESSMENTS_PATH: Path = DATA_PATH / "assessments"
15
+ """Example assessments, one xlsx file per model."""
16
+
17
+ TEMPLATE_PATH: Path = DATA_PATH / "FAIR_assessment_template.xlsx"
18
+ """Template of a FAIR assessment, also the definition of the indicators."""
@@ -0,0 +1,109 @@
1
+ """Plotly figures of a FAIR assessment."""
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ import plotly.express as px
6
+ import plotly.graph_objects as go
7
+
8
+ SUBSET_KEYS: tuple[str, ...] = (
9
+ "Model",
10
+ "Model metadata",
11
+ "Archive",
12
+ "Archive metadata",
13
+ )
14
+ """Types of indicators, one polar figure each."""
15
+
16
+ COLOR_DISCRETE_SEQUENCE: tuple[str, ...] = (
17
+ "#1f77b4", # muted blue
18
+ "#ff7f0e", # safety orange
19
+ "#2ca02c", # cooked asparagus green
20
+ "#d62728", # brick red
21
+ "#9467bd", # muted purple
22
+ "#8c564b", # chestnut brown
23
+ "#e377c2", # raspberry yogurt pink
24
+ "#7f7f7f", # middle gray
25
+ "#bcbd22", # curry yellow-green
26
+ "#17becf", # blue-teal
27
+ )
28
+ """Colors of the categories."""
29
+
30
+
31
+ def visualize_barplot(df_data: pd.DataFrame) -> go.Figure:
32
+ """Bar plot of the fraction of the indicators fulfilled per category.
33
+
34
+ Args:
35
+ df_data: assessment of a model, see `fairvis.data_io.load_assessment`.
36
+
37
+ Returns:
38
+ bar plot with the FAIR percentage per category.
39
+ """
40
+ # Count the fraction of indicators fullfilled per category
41
+ categories = df_data["Category"].unique()
42
+
43
+ values = dict.fromkeys(categories, 0.0)
44
+ totals = dict.fromkeys(categories, 0.0)
45
+ for _, row in df_data.iterrows():
46
+ category = row["Category"]
47
+ assessment = row["Assessment"]
48
+ totals[category] += 1.0
49
+ if not np.isnan(assessment):
50
+ values[category] += assessment
51
+
52
+ items = []
53
+ for category in categories:
54
+ items.append(
55
+ {
56
+ "category": category,
57
+ "value": values[category],
58
+ "total": totals[category],
59
+ "percentage": 100 * values[category] / totals[category],
60
+ }
61
+ )
62
+
63
+ df = pd.DataFrame(items)
64
+
65
+ # barplot
66
+ fig = px.bar(
67
+ df,
68
+ x="category",
69
+ y="percentage",
70
+ color="category", # title="FAIR assessment",
71
+ color_discrete_sequence=list(COLOR_DISCRETE_SEQUENCE),
72
+ labels={"category": "Category", "percentage": "FAIR [%]"},
73
+ )
74
+ fig.update_layout(
75
+ title="FAIR assessment",
76
+ yaxis_range=[0, 100],
77
+ showlegend=False,
78
+ height=250,
79
+ )
80
+
81
+ return fig
82
+
83
+
84
+ def visualize_polar_barplots(df_data: pd.DataFrame) -> list[go.Figure]:
85
+ """Polar bar plots of the indicators of a model, one per type of indicator.
86
+
87
+ Args:
88
+ df_data: assessment of a model, see `fairvis.data_io.load_assessment`.
89
+
90
+ Returns:
91
+ one polar bar plot per entry of `SUBSET_KEYS`, in that order.
92
+ """
93
+ figs = []
94
+ for key in SUBSET_KEYS:
95
+ df = df_data[df_data["Type"] == key]
96
+ fig = px.bar_polar(
97
+ df,
98
+ r="Assessment",
99
+ theta="Short",
100
+ color="Category",
101
+ hover_name="Indicator",
102
+ hover_data=["Indicator", "Category", "Priority"],
103
+ color_discrete_sequence=list(COLOR_DISCRETE_SEQUENCE),
104
+ )
105
+ fig.update_layout(title=key, showlegend=True)
106
+ fig.update_polars(radialaxis_tickvals=[0, 0.5, 1], angularaxis_showgrid=True)
107
+ figs.append(fig)
108
+
109
+ return figs