Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f58cc8d
Setup web app with uv
adjavon Aug 28, 2025
034f2be
style: :art: Change the aspect ratio of the population QuAC score
adjavon Sep 26, 2025
ca691d0
style: Improve the sidebar aspect ration
adjavon Sep 26, 2025
5607a1e
style: Move filtering into a side-bar
adjavon Sep 26, 2025
f05a384
style: Make side-bar collapsible
adjavon Sep 26, 2025
4d945af
style: Make panels re-sizeable
adjavon Sep 26, 2025
46e4451
style: Also re-size the sidebar
adjavon Sep 26, 2025
93c9a62
style: Make the toggle menu-style
adjavon Sep 26, 2025
c10b67c
fix: Show images
adjavon Sep 26, 2025
0e64d26
fix: Use absolute paths for images
adjavon Sep 26, 2025
89e4bf7
fix: Make mask overlay functional
adjavon Sep 26, 2025
8e864c9
style: Set mask with opacity
adjavon Sep 26, 2025
a1cd2a5
style: Match individual quac curve to expectations
adjavon Sep 26, 2025
ff5d731
style: Make filter a dual slider
adjavon Sep 27, 2025
eada751
style: Move population curve
adjavon Sep 27, 2025
05e494c
fix: Add a no explanation state
adjavon Sep 27, 2025
e7b471e
ux: Use window open for download
adjavon Sep 27, 2025
851c930
style: :card_file_box: Move filter info to metadata
adjavon Sep 27, 2025
e9b34c8
feat: :sparkles: Add blinding mode
adjavon Sep 28, 2025
7e2d9a2
refactor: :art: Split out report pane from front end
adjavon Sep 28, 2025
7c41cb6
refactor: :art: Split out the filtering
adjavon Sep 28, 2025
4958f57
refactor: :art: Split out explanation list
adjavon Sep 28, 2025
d1f9c57
refactor: :art: Split out the explanation viewer
adjavon Sep 28, 2025
6d2b4ed
style: :art: Remove whitespace
adjavon Sep 28, 2025
c32f1bc
feat: :sparkles: Add annotation
adjavon Sep 28, 2025
90ec785
refactor: :fire: Reduce redundant json encoding
adjavon Sep 28, 2025
b43e2c7
fix: :heavy_minus_sign: Remove funlib.learn dependency
adjavon Sep 28, 2025
c66aed7
fix: :white_check_mark: Fix vgg import
adjavon Sep 28, 2025
6005432
feat: :sparkles: Allow loading report from config
adjavon Sep 30, 2025
b8dd1cc
refactor: :art: Use Explanation to get images
adjavon Sep 30, 2025
c0f50be
fix: Use transform on images before serve
adjavon Sep 30, 2025
cbd5360
feat: :sparkles: Add a contour for mask
adjavon Sep 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ docs/_build
*.egg-info

# MacOS files
.DS_Store
.DS_Store

# data
web_app/test_example/
45 changes: 45 additions & 0 deletions UV_MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# UV Migration Guide

This project has been migrated from pixi to uv for dependency management.

## Installation

1. Install uv if not already installed:
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

2. Sync dependencies:
```bash
uv sync
```

3. Install the project in editable mode:
```bash
uv pip install -e .
```

## Common Commands

### Development
- Install dependencies: `uv sync`
- Add a dependency: `uv add package-name`
- Add a dev dependency: `uv add --dev package-name`
- Remove a dependency: `uv remove package-name`

### Running the project
- Activate virtual environment: `source .venv/bin/activate` (or use `uv run`)
- Run scripts with uv: `uv run python script.py`
- Run the visualizer: `uv run quac-visualizer` (replaces `pixi run visualizer`)

### Environments
The project supports different environments through optional dependencies:
- Development: `uv sync --extra dev` (installs pytest, black, mypy, etc.)
- Web: `uv sync --extra web` (installs flask, werkzeug)
- Docs: `uv sync --extra docs` (installs sphinx and related packages)

### Migration Notes
- Pixi's conda channels (nvidia, pytorch) are replaced by PyPI packages
- The `funlib.learn.torch` git dependency is handled via `[tool.uv.sources]`
- The pixi task `visualizer` is replaced by the `quac-visualizer` script
- Python version is constrained to `>=3.10,<3.13` for PyTorch compatibility
33 changes: 19 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ requires = ["setuptools", "wheel"]
name = "quac"
description = "Quantitative Attribution with Counterfactuals"
readme = "README.md"
requires-python = ">=3.10"
requires-python = ">=3.10,<3.13"
classifiers = ["Programming Language :: Python :: 3"]
keywords = []
license = { text = "BSD 3-Clause License" }
Expand All @@ -18,9 +18,8 @@ dynamic = ["version"]
dependencies = [
"captum",
"numpy>=2.0",
"torch==2.4.0",
"torchvision",
"funlib.learn.torch@git+https://github.com/funkelab/funlib.learn.torch",
"torch>=2.4.0,<2.5",
"torchvision>=0.19.0",
"opencv-python",
"pydantic",
"scipy",
Expand All @@ -33,6 +32,7 @@ dependencies = [

[project.optional-dependencies]
dev = ['pytest', 'black', 'mypy', 'pdoc', 'pre-commit']
web = ['flask>=2.0.0', 'werkzeug>=2.0.0']
docs = [
"ipykernel",
"jupyter_sphinx",
Expand All @@ -53,16 +53,21 @@ docs = [
homepage = "https://funkelab.github.io/quac/"
repository = "https://github.com/funkelab/quac"

[tool.pixi.project]
channels = ["nvidia/label/cuda-11.8.0", "nvidia", "conda-forge", "pytorch"]
platforms = ["linux-64"]
[tool.setuptools.dynamic]
version = { attr = "quac.__version__" }

[tool.pixi.pypi-dependencies]
quac = { path = ".", editable = true }
[tool.uv]
dev-dependencies = [
"pytest",
"black",
"mypy",
"pdoc",
"pre-commit"
]

[tool.pixi.environments]
default = { solve-group = "default" }
dev = { features = ["dev"], solve-group = "default" }
docs = { features = ["docs"], solve-group = "default" }
[tool.uv.sources]
# Handle the git dependency for funlib.learn.torch
funlib-learn-torch = { git = "https://github.com/funkelab/funlib.learn.torch" }

[tool.pixi.tasks]
[tool.mypy]
python_version = "3.10"
4 changes: 4 additions & 0 deletions src/quac/explanation.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def __init__(
score_changes: Optional[Union[list, np.ndarray]] = None,
optimal_threshold: Optional[float] = None,
method: Optional[str] = None,
annotation: str = "",
):
self._query_path = query_path
self._counterfactual_path = counterfactual_path
Expand All @@ -59,6 +60,7 @@ def __init__(
self._score_changes = score_changes
self._optimal_threshold = optimal_threshold
self._method = method
self.annotation = annotation

# Computed
self._query: Optional[torch.Tensor] = None
Expand All @@ -78,6 +80,7 @@ def __eq__(self, value):
and self.source_class == value.source_class
and self.target_class == value.target_class
and self.score == value.score
and self.annotation == value.annotation
)
# The other, optional, attributes are not checked for equality
return False
Expand Down Expand Up @@ -179,4 +182,5 @@ def explanation_encoder(explanation: Explanation):
"generated_prediction": serialize(explanation.generated_prediction),
"optimal_threshold": explanation._optimal_threshold,
"method": explanation._method,
"annotation": explanation.annotation,
}
8 changes: 3 additions & 5 deletions tests/test_evaluation.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import pytest
from quac.evaluation import Evaluator
from funlib.learn.torch.models import Vgg2D
from torchvision.models.resnet import resnet18
import numpy as np


@pytest.mark.skip("Skip test until we have usable data in CI/CD")
@pytest.mark.parametrize("input_shape", [(1, 128, 128)])
@pytest.mark.parametrize("input_shape", [(3, 224, 224)])
@pytest.mark.parametrize("num_thresholds", [50, 100])
def test_evaluator(input_shape, num_thresholds):
"""Checks that evaluator runs without errors"""
Expand All @@ -16,9 +16,7 @@ def test_evaluator(input_shape, num_thresholds):
attribution = np.random.rand(*input_shape)
vmin = -1
vmax = 1
classifier = Vgg2D(
(input_shape[1], input_shape[2]), output_classes=2, input_fmaps=input_shape[0]
)
classifier = resnet18(num_classes=2)

predictions = {
"original": np.random.rand(2),
Expand Down
Loading
Loading