Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split out reports dependencies #977

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
30 changes: 15 additions & 15 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Generate environment
command: |
if [ ! -d /opt/conda/envs/tedana_py38 ]; then
conda create -yq -n tedana_py38 python=3.8
source activate tedana_py38
pip install -e .[tests]
pip install -e .[reports,tests]
fi
- save_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
paths:
- /opt/conda/envs/tedana_py38

Expand All @@ -34,7 +34,7 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Running unit tests
command: |
Expand All @@ -56,7 +56,7 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py39-v2-{{ checksum "pyproject.toml" }}
key: conda-py39-v3-{{ checksum "pyproject.toml" }}
- run:
name: Generate environment
command: |
Expand All @@ -65,7 +65,7 @@ jobs:
if [ ! -d /opt/conda/envs/tedana_py39 ]; then
conda create -yq -n tedana_py39 python=3.9
source activate tedana_py39
pip install .[tests]
pip install .[reports,tests]
fi
- run:
name: Running unit tests
Expand All @@ -75,7 +75,7 @@ jobs:
mkdir /tmp/src/coverage
mv /tmp/src/tedana/.coverage /tmp/src/coverage/.coverage.py39
- save_cache:
key: conda-py39-v2-{{ checksum "pyproject.toml" }}
key: conda-py39-v3-{{ checksum "pyproject.toml" }}
paths:
- /opt/conda/envs/tedana_py39
- persist_to_workspace:
Expand All @@ -99,7 +99,7 @@ jobs:
if [ ! -d /opt/conda/envs/tedana_py310 ]; then
conda create -yq -n tedana_py310 python=3.10
source activate tedana_py310
pip install .[tests]
pip install .[reports,tests]
fi
- run:
name: Running unit tests
Expand Down Expand Up @@ -192,7 +192,7 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Style check
command: |
Expand All @@ -208,7 +208,7 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Run integration tests
no_output_timeout: 40m
Expand All @@ -233,7 +233,7 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Run integration tests
no_output_timeout: 40m
Expand All @@ -258,7 +258,7 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Run integration tests
no_output_timeout: 40m
Expand All @@ -283,7 +283,7 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Run integration tests
no_output_timeout: 40m
Expand All @@ -308,7 +308,7 @@ jobs:
steps:
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Run integration tests
no_output_timeout: 40m
Expand All @@ -335,7 +335,7 @@ jobs:
at: /tmp
- checkout
- restore_cache:
key: conda-py38-v2-{{ checksum "pyproject.toml" }}
key: conda-py38-v3-{{ checksum "pyproject.toml" }}
- run:
name: Merge coverage files
command: |
Expand Down
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ classifiers = [
license = {file = "LICENSE"}
requires-python = ">=3.8"
dependencies = [
"bokeh>=1.0.0,<=3.4.1",
"mapca>=0.0.4,<=0.0.5",
"matplotlib",
"nibabel>=2.5.1,<=5.2.1",
Expand Down Expand Up @@ -50,7 +49,9 @@ doc = [
"sphinx-argparse",
"sphinxcontrib-bibtex",
]

reports = [
"bokeh>=1.0.0,<=3.4.1",
]
tests = [
"codecov",
"coverage",
Expand All @@ -69,7 +70,7 @@ tests = [
]

# Aliases
all = ["tedana[dev,doc,tests]"]
all = ["tedana[dev,doc,reports,tests]"]

[project.scripts]
ica_reclassify = "tedana.workflows.ica_reclassify:_main"
Expand Down
12 changes: 11 additions & 1 deletion tedana/reporting/dynamic_figures.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import numpy as np
import pandas as pd
from bokeh import events, models, plotting, transform
from sklearn.preprocessing import MinMaxScaler

color_mapping = {"accepted": "#2ecc71", "rejected": "#e74c3c", "ignored": "#3498db"}
Expand Down Expand Up @@ -67,6 +66,8 @@ def _create_data_struct(comptable_path, color_mapping=color_mapping):
cds : bokeh.models.ColumnDataSource
Data structure with all the fields to plot or hover over
"""
from bokeh import models

unused_cols = [
"normalized variance explained",
"countsigFT2",
Expand Down Expand Up @@ -152,6 +153,8 @@ def _create_kr_plt(comptable_cds, kappa_elbow=None, rho_elbow=None):
fig : bokeh.plotting.figure.Figure
Bokeh scatter plot of kappa vs. rho
"""
from bokeh import models, plotting

# Create Panel for the Kappa - Rho Scatter
kr_hovertool = models.HoverTool(
tooltips=[
Expand Down Expand Up @@ -272,6 +275,8 @@ def _create_sorted_plt(
fig : bokeh.plotting.figure.Figure
Bokeh plot of components ranked by a given feature
"""
from bokeh import models, plotting

hovertool = models.HoverTool(
tooltips=[
("Component ID", "@component"),
Expand Down Expand Up @@ -324,6 +329,7 @@ def _create_sorted_plt(


def _create_varexp_pie_plt(comptable_cds):
from bokeh import models, plotting, transform

pie_hovertool = models.HoverTool(
tooltips=[
Expand Down Expand Up @@ -383,6 +389,8 @@ def _tap_callback(comptable_cds, div_content, io_generator):
CustomJS : bokeh.models.CustomJS
Javascript function that adds the tapping functionality
"""
from bokeh import models

return models.CustomJS(
args=dict(
source_comp_table=comptable_cds,
Expand Down Expand Up @@ -419,5 +427,7 @@ def _link_figures(fig, comptable_ds, div_content, io_generator):
Same as input figure, but with a linked method to
its Tap event.
"""
from bokeh import events

fig.js_on_event(events.Tap, _tap_callback(comptable_ds, div_content, io_generator))
return fig
6 changes: 4 additions & 2 deletions tedana/reporting/html_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from string import Template

import pandas as pd
from bokeh import __version__ as bokehversion
from bokeh import embed, layouts, models
from pybtex.database.input import bibtex
from pybtex.plugin import find_plugin

Expand Down Expand Up @@ -189,6 +187,8 @@ def _save_as_html(body):
body : str
Body for HTML report with embedded figures
"""
from bokeh import __version__ as bokehversion

resource_path = Path(__file__).resolve().parent.joinpath("data", "html")
head_template_name = "report_head_template.html"
head_template_path = resource_path.joinpath(head_template_name)
Expand Down Expand Up @@ -238,6 +238,8 @@ def generate_report(io_generator: OutputGenerator) -> None:
-----
This writes out an HTML report to a file.
"""
from bokeh import embed, layouts, models

# Load the component time series
comp_ts_path = io_generator.get_name("ICA mixing tsv")
comp_ts_df = pd.read_csv(comp_ts_path, sep="\t", encoding="utf=8")
Expand Down
45 changes: 32 additions & 13 deletions tedana/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,9 @@

import nibabel as nib
import numpy as np
from bokeh import __version__ as bokeh_version
from mapca import __version__ as mapca_version
from matplotlib import __version__ as matplotlib_version
from nibabel import __version__ as nibabel_version
from nilearn import __version__ as nilearn_version
from nilearn._utils import check_niimg
from numpy import __version__ as numpy_version
from pandas import __version__ as pandas_version
from scipy import __version__ as scipy_version
from scipy import ndimage
from sklearn import __version__ as sklearn_version
from sklearn.utils import check_array
from threadpoolctl import __version__ as threadpoolctl_version

LGR = logging.getLogger("GENERAL")
RepLGR = logging.getLogger("REPORT")
Expand Down Expand Up @@ -555,9 +545,22 @@
return op.abspath(op.join(op.dirname(__file__), "resources") + op.sep)


def _check_report_dependencies():
"""Check if dependencies required for reports are installed."""
try:
import bokeh # noqa F401
import jinja2 # noqa F401
except ImportError:
raise ImportError(

Check warning on line 554 in tedana/utils.py

View check run for this annotation

Codecov / codecov/patch

tedana/utils.py#L553-L554

Added lines #L553 - L554 were not covered by tests
"Running tedana/ica_reclassify without the --no-reports flag requires extra "
"dependencies. "
"Please install tedana with the [reports] dependency group "
"(e.g., 'pip install tedana[reports]')."
)


def get_system_version_info():
"""
Return information about the system tedana is being run on.
"""Return information about the system tedana is being run on.

Returns
-------
Expand All @@ -566,10 +569,19 @@
and python and python library versioning info for key
modules used by tedana.
"""
from mapca import __version__ as mapca_version
from matplotlib import __version__ as matplotlib_version
from nibabel import __version__ as nibabel_version
from nilearn import __version__ as nilearn_version
from numpy import __version__ as numpy_version
from pandas import __version__ as pandas_version
from scipy import __version__ as scipy_version
from sklearn import __version__ as sklearn_version
from threadpoolctl import __version__ as threadpoolctl_version

system_info = platform.uname()

python_libraries = {
"bokeh": bokeh_version,
"matplotlib": matplotlib_version,
"mapca": mapca_version,
"nibabel": nibabel_version,
Expand All @@ -581,6 +593,13 @@
"threadpoolctl": threadpoolctl_version,
}

try:
from bokeh import __version__ as bokeh_version

python_libraries["bokeh"] = bokeh_version
except ImportError:
pass

return {
"System": system_info.system,
"Node": system_info.node,
Expand Down
14 changes: 8 additions & 6 deletions tedana/workflows/ica_reclassify.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,18 +247,17 @@ def ica_reclassify_workflow(
quiet=False,
reclassify_command=None,
):
"""
Run the post-tedana manual classification workflow.
"""Run the post-tedana manual classification workflow.

Please remember to cite [1]_.

Parameters
----------
registry : :obj:`str`
The previously run registry as a JSON file.
accept : :obj: `list`
accept : :obj:`list`
A list of integer values of components to accept in this workflow.
reject : :obj: `list`
reject : :obj:`list`
A list of integer values of components to reject in this workflow.
out_dir : :obj:`str`, optional
Output directory.
Expand All @@ -267,10 +266,10 @@ def ica_reclassify_workflow(
denoising. Default is False.
mir : :obj:`bool`, optional
Run minimum image regression after denoising. Default is False.
no_reports : obj:'bool', optional
no_reports : obj:`bool`, optional
Do not generate .html reports and .png plots. Default is false such
that reports are generated.
png_cmap : obj:'str', optional
png_cmap : obj:`str`, optional
Name of a matplotlib colormap to be used when generating figures.
Cannot be used with --no-png. Default is 'coolwarm'.
debug : :obj:`bool`, optional
Expand Down Expand Up @@ -298,6 +297,9 @@ def ica_reclassify_workflow(
TE-dependent analysis of multi-echo fMRI with tedana.
Journal of Open Source Software, 6(66), 3669. doi:10.21105/joss.03669.
"""
if not no_reports:
utils._check_report_dependencies()

out_dir = op.abspath(out_dir)
if not op.isdir(out_dir):
os.mkdir(out_dir)
Expand Down
3 changes: 3 additions & 0 deletions tedana/workflows/tedana.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,9 @@ def tedana_workflow(
----------
.. footbibliography::
"""
if not no_reports:
utils._check_report_dependencies()

out_dir = op.abspath(out_dir)
if not op.isdir(out_dir):
os.mkdir(out_dir)
Expand Down