Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8cd9f14
refactor(gui): move shared widgets into components
holsam Nov 3, 2026
bb4ff53
refactor(gui): move dialogs into dialogs package
holsam Nov 3, 2026
1c7c930
refactor(gui): move panes into panes package
holsam Nov 3, 2026
7168926
refactor(gui): move tabs into tabs package
holsam Nov 3, 2026
37c5f06
pr: merge holsam/gui-refactor to holsam/v0.3.0-release
holsam Nov 4, 2026
60ff86b
feat(gui): add additional icons & tinted utility
holsam Nov 4, 2026
5f018b8
feat(gui): add status icons and badges
holsam Nov 4, 2026
b3a0a54
feat(gui): add toast notifications
holsam Nov 4, 2026
857edce
feat(gui): add two-handle range slider
holsam Nov 4, 2026
591ed2c
feat(config): add optional project name
holsam Nov 4, 2026
622c6ba
feat(gui): add name & tooltips in dialog
holsam Nov 4, 2026
2fc4a3d
feat(gui): add welcome pane
holsam Nov 4, 2026
9723c1c
feat(gui): show project name in window title
holsam Nov 4, 2026
0ec57f7
refactor: share pick and fit helpers between tabs
holsam Nov 4, 2026
107d424
feat(gui): add export tab
holsam Nov 4, 2026
b9f64ce
refactor(gui): move kinds tab into project tab
holsam Nov 4, 2026
f277ffe
feat(gui): add auto-saving settings pane
holsam Nov 4, 2026
8ba7200
refactor(gui): consolidate styling elements
holsam Nov 4, 2026
27a4e30
test(gui): update tests
holsam Nov 4, 2026
9736abc
feat(gui): add tomograms pane with status markers
holsam Nov 4, 2026
ab566bd
feat(gui): update project tab layout
holsam Nov 4, 2026
feb9d92
fix(gui): fix hotkeys when canvas not focused
holsam Nov 4, 2026
0b54ef0
fix(gui): fix tomogram jumping/search
holsam Nov 4, 2026
bc6f19c
refactor(gui): show the tomogram pane in pick tab
holsam Nov 4, 2026
afdb202
feat(gui): show estimate status in the pick table
holsam Nov 4, 2026
cb31b31
refactor(gui): rearrange pick settings pane
holsam Nov 4, 2026
a6000c9
feat(gui): update image controls
holsam Nov 4, 2026
6f19fbc
feat(gui): add fill button to the pick tab
holsam Nov 4, 2026
b5fd60b
feat(gui): restyle review tab
holsam Nov 4, 2026
a9f8876
feat(gui): update review table and show status
holsam Nov 4, 2026
8f0aa79
feat(gui): label review preview images
holsam Nov 4, 2026
9e2f67c
feat(export): add per-kind csv export
holsam Nov 4, 2026
af320fc
feat(average): record montage cell labels and geometry
holsam Nov 4, 2026
aba876b
feat(gui): draw montage labels and restyle the average pane
holsam Nov 4, 2026
168e35c
feat(gui): update export controls
holsam Nov 4, 2026
271e406
refactor(gui): add additional style utilities
holsam Nov 4, 2026
4aba087
feat(gui): polish project tab style
holsam Nov 4, 2026
91a0814
feat(gui): use quiet table styling throughout gui
holsam Nov 4, 2026
5acce17
style(gui): adjust kinds column spacing
holsam Nov 4, 2026
45c5b1f
feat(gui): polish pick tab style
holsam Nov 4, 2026
de512b7
feat(gui): size the window to the page
holsam Nov 4, 2026
17a4063
feat(gui): show a green tick before saved toasts
holsam Nov 4, 2026
c3c71a4
feat(gui): label the review crops and add a yz crop
holsam Nov 4, 2026
6f9c906
feat(average): label images with tomogram/pick
holsam Nov 4, 2026
9c85b4c
refactor(average): split saving from averaging
holsam Nov 4, 2026
410ee10
feat(gui): update average pane styling
holsam Nov 4, 2026
cdb9785
feat(gui): restyle export pane
holsam Nov 4, 2026
c5326dc
style(gui): update resize and tab bar
holsam Nov 4, 2026
eb56cf0
feat(gui): export tab restyling
holsam Nov 4, 2026
e7c3aa8
docs: update readme
holsam Nov 4, 2026
5f10e55
chore: update pyside6 dependency to essentials
holsam Nov 4, 2026
9781dd6
chore: update pickmix version to v0.3.0
holsam Nov 4, 2026
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
100 changes: 99 additions & 1 deletion NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,111 @@ add.svg
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #ffffff

cached.svg
Material Symbols "cached" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

check.svg
Material Symbols "check" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

close.svg
Material Symbols "close" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

create_new_folder.svg
Material Symbols "create_new_folder" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

delete.svg
Material Symbols "delete" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

edit.svg
Material Symbols "edit" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #ffffff

error.svg
Material Symbols "error" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

fit_screen.svg
Material Symbols "fit_screen" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

folder_open.svg
Material Symbols "folder_open" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

fullscreen.svg
Material Symbols "fullscreen" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

help.svg
Material Symbols "help" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

left_panel_close.svg
Material Symbols "left_panel_close" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

left_panel_open.svg
Material Symbols "left_panel_open" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

logout.svg
Material Symbols "logout" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

refresh.svg
Material Symbols "refresh" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a

visibility.svg
Material Symbols "visibiility" icon
Copyright (c) Google LLC
Expand All @@ -33,4 +124,11 @@ visibility_off.svg
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a
Modifications: fill colour set to #8a8a8a

warning.svg
Material Symbols "warning" icon
Copyright (c) Google LLC
Licensed under the Apache License, Version 2.0 (see src/pickmix/gui/icons/LICENSE in this directory)
Source: https://github.com/google/material-design-icons
Modifications: fill colour set to #8a8a8a
37 changes: 22 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,41 +26,48 @@ For development, use `uv sync` then `uv run pickmix`.
## How to use `pickmix`
### 1. Create a project

Launch pickmix using `pickmix`, which will open on the Project tab.
Launch pickmix using `pickmix`. The welcome page has two buttons for opening an existing project (also via `Ctrl/Cmd+O`) and creating a new project (also via `Ctrl/Cmd+N`).

![Project tab](docs/images/empty-project-tab.png)
![Welcome page](docs/images/welcome-page.png)

Click `[New project]`, and complete the fields in the dialog. Pickmix merges multiple runs into a single `tomograms.star` and writes `config.toml` in the project directory. Tomogram names get the run name as a prefix. Existing files are never overwritten.
Click `[New project]`, and complete the fields in the dialog. Hover over a field's `(?)` for further information about each field. Pickmix merges all the entered runs into a single `tomograms.star` and writes `config.toml` in the project directory. Tomogram names get the run name as a prefix. Existing files are never overwritten.

![New project dialog](docs/images/new-project.png)

Once created, the Project tab lists usable and rejected tomograms and the shared settings.
### 2. Check the project and define kinds

`pickmix` will now open to the Project tab, which contains the three columns described below.

![Project tab](docs/images/project-tab.png)

### 2. Define kinds
#### 2.1 Tomograms
This table lists every tomogram alongside its shape, pixel size and whether a matching denoised volume was identified. Yellow warning indicate usable tomograms with issues to be aware of (e.g. no denoised tomogram found, unusual pixel size), while a red error marks a rejected or unusable tomogram - hover over the error to see the reaon.

#### 2.2 Kinds
Each 'kind' is a type of pick and multiple can be added as required. Each kind has a marker size, an extraction box, an estimator (`ring` fits a circle to a pick, `none` passes the click straight through), a colour, an optional parent kind and an extraction pixel size. A kind with a parent takes its membrane-normal orientation from the nearest parent estimate.

Open the Kinds tab, and add additional 'kinds' (types of pick) as required. Each kind has a marker size, an extraction box, an estimator (`ring` fits a circle to a pick, `none` passes the click straight through), a colour, an optional parent kind and an extraction pixel size. The table order sets the `1` to `9` hotkeys. A kind with a parent takes its membrane-normal orientation from the nearest parent estimate.
![Kinds dialog](docs/images/kinds-dialog.png)

![Kinds tab](docs/images/kinds-tab.png)
#### 2.3 Settings
This pane controls general settings for the project, including which volume to use in the picking interface and which hotkeys map to which kinds. Parameters for the `ring` estimator can also be adjusted here as required.

### 3. Pick

Open the Pick tab and select a kind with `1` to `9`. Left-click adds or selects a pick; picks can be moved by selecting & dragging, or deleted using `Delete`. Right-click to pan across the current slice, and Ctrl/Cmd+Scroll to adjust zoom. Scrolling updates the current Z slice, and `Enter`/`Shift+Enter` steps forward/backward between tomograms. Fitted rings, boxes and normals can be toggled on/off as desired, and contrast sliders adjust the display.
Open the Pick tab. To the left is a a list of tomograms in the project, clicking a tomogram will jump there as will typing either its name or number into the search bar (the search bar automatically moves to the first match). If needed, the tomogram list can be hidden using the button next to the tomogram title. Select a kind using a hotkey or from the Kinds group, and left-click to add or select a pick. Picks can be moved by selecting & dragging, or deleted using the delete button (or `Delete` key). Right-click to pan across the current slice, and Ctrl/Cmd+Scroll to adjust zoom. Scrolling updates the current Z slice, and `Enter`/`Shift+Enter` steps forward/backward between tomograms. The settings pane has brightness/contrast controls, including `Auto` (the tomogram's own limits) and `Invert`, as well as auto-zoom functions `Fit` and `Fill`. The views group shows/hides fitted rings, boxes and normals. The pick table beneath shows each pick's estimate status: a green tick, a yellow warning (when flagged), a red error (when error occured during estimation), or a blue spinner (during processing).

![Pick tab](docs/images/pick-tab.png)

### 4. Average
### 4. Review

Return to the Kinds tab, and select a kind. Click `[Run averaging]` to extract a box around each pick and create a mean projection & montage.
Open the Review tab. Picks can be filtered by kind, tomogram, minimum SNR and whether they were flagged, with options to delete the selected pick or all currently shown. All picks can be queued for re-estimation here if required as well. Single-click a pick to view XY/XZ/YZ previews, or double-click to open that pick in the Pick tab.

![Average pane](docs/images/average-pane.png)
![Review tab](docs/images/review-tab.png)

### 5. Review and export
### 5. Average and export

Open the Review tab. Picks can be filtered by SNR and any flags, delete flagged picks, re-estimate, then **Export star files** to write `out/relion/<kind>/particles.star` plus one `NAME_coords.star` per tomogram. **Extract boxes** cuts the sub-volumes as MRC files. Kinds with a parent also write the subtomogram angles derived from it.
Open the Export tab. At the top, the averaging pane allows selection of a kind to build a mean projection and montage of the picks for that kind (optionally filterable by tomogram). The mean and montage images can be saved to `out/` from here, as well as per-tomogram extracted picks if desired. Below, a table summarises the collected data for all kinds and allow specification of a minimum SNR and whether to include flagged picks in exports. Click the checkboxes for the desired output filetype(s) and click `Export` to save. `Extract` alternatively generates a subvolume from each pick and saves as MRC files under `out/particles/<kind>`.

![Review tab](docs/images/review-tab.png)
![Export tab](docs/images/export-tab.png)

## Project layout

Expand All @@ -69,5 +76,5 @@ project/
config.toml settings and kinds
tomograms.star merged RELION tomogram table
tilt_series/ one star file per tomogram
out/ picks, estimates, averages, RELION export
out/ picks, estimates, averages, RELION & .csv exports
```
Binary file removed docs/images/average-pane.png
Binary file not shown.
Binary file removed docs/images/empty-project-tab.png
Binary file not shown.
Binary file added docs/images/export-tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/kinds-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/kinds-tab.png
Binary file not shown.
Binary file modified docs/images/new-project.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/pick-tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/project-tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/review-tab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/welcome-page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pickmix"
version = "0.2.0"
version = "0.3.0"
description = "Multi-kind particle picking GUI for cryo-ET sub-tomogram averaging workflows."
readme = "README.md"
authors = [
Expand All @@ -12,7 +12,7 @@ dependencies = [
"mrcfile>=1.5.4",
"numpy>=2.5.4",
"pydantic>=2.14.2",
"pyside6>6.9",
"pyside6-essentials>6.9",
"scikit-image>=0.26.0",
"scipy>=1.18.1",
"tomli-w>=1.2.0",
Expand Down
9 changes: 9 additions & 0 deletions src/pickmix/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
pickmix: entrypoint
'''

# Import external dependencies
from importlib.metadata import PackageNotFoundError, version

# __version__: installed version, 'unknown' when running from a bare checkout
try:
__version__: str = version('pickmix')
except PackageNotFoundError:
__version__ = 'unknown'

# main: launch the window, opening the config.toml given as the first argument
def main() -> None:
import sys
Expand Down
41 changes: 33 additions & 8 deletions src/pickmix/average.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
# _MONTAGE_MAX: most boxes shown in the montage, spread evenly over the picks
_MONTAGE_MAX: int = 64

# MONTAGE_PAD: pixels of padding around every cell of the montage
MONTAGE_PAD: int = 2

# AverageResult: normalised 2D images, ready to show; overall and per-tomogram means, and the montage
@dataclass(frozen=True)
class AverageResult:
Expand All @@ -28,8 +31,15 @@ class AverageResult:
montage: np.ndarray
per_tomogram: dict[str, np.ndarray]
folder: Path
# montage geometry and label
grid: int
pad: int
labels: list[str]
# boxes averaged per tomogram
counts: dict[str, int]


# average_kind: cut a box at every item, project the central slab of each along z, normalise it, and average per tomogram and overall; PNGs go to out_dir/average/<kind>/
# average_kind: cut a box at every item, project the central slab of each along z, normalise it, and average per tomogram and overall; nothing is written until save_average
def average_kind(
name: str, kind: Kind, items: list[Item], tomos: dict[str, Tomogram], config: Config,
*, log: Callable[[str], None] = lambda _: None,
Expand All @@ -42,6 +52,7 @@ def average_kind(
half = min(max(round(kind.marker_a / 2 / px), 1), box // 2)
centre = box // 2
images: dict[str, list[np.ndarray]] = {}
origins: list[str] = []
for tomogram in dict.fromkeys(p.tomogram for p, _ in items):
vol = load_volume(tomos[tomogram], source=config.source)
for p, f in items:
Expand All @@ -50,25 +61,39 @@ def average_kind(
cube = crop_box(vol, (round(f.z), round(f.y), round(f.x)), box)
img = cube[centre - half : centre + half + 1].mean(axis=0)
images.setdefault(tomogram, []).append((img - img.mean()) / (img.std() or 1.0))
origins.append(f'{len(images[tomogram])} ({tomogram})')
log(f'{name} {tomogram}: {len(images[tomogram])} boxes')
everything = [img for imgs in images.values() for img in imgs]
chosen = np.linspace(0, len(everything) - 1, min(len(everything), _MONTAGE_MAX)).astype(int)
grid = math.ceil(math.sqrt(len(chosen)))
result = AverageResult(
name, len(everything), box,
name,
len(everything),
box,
np.mean(everything, axis=0),
montage(np.stack([everything[i] for i in chosen]), grid_shape=(grid, grid), padding_width=2),
montage(np.stack([everything[i] for i in chosen]), grid_shape=(grid, grid), padding_width=MONTAGE_PAD),
{t: np.mean(imgs, axis=0) for t, imgs in images.items()},
config.out_dir / 'average' / name,
grid,
MONTAGE_PAD,
[origins[i] for i in chosen],
{t: len(imgs) for t, imgs in images.items()},
)
return result

# save_average: clear the kind's old PNGs and write the overall mean and montage, and each tomogram's mean when asked; returns the paths written
def save_average(result: AverageResult, *, per_tomogram: bool = False) -> list[Path]:
result.folder.mkdir(parents=True, exist_ok=True)
for stale in result.folder.glob('*.png'):
stale.unlink()
_save(result.folder / 'overall_mean.png', result.overall)
_save(result.folder / 'overall_montage.png', result.montage)
for tomogram, img in result.per_tomogram.items():
_save(result.folder / f'{tomogram}_mean.png', img)
return result
written = [result.folder / 'overall_mean.png', result.folder / 'overall_montage.png']
_save(written[0], result.overall)
_save(written[1], result.montage)
if per_tomogram:
for tomogram, img in result.per_tomogram.items():
written.append(result.folder / f'{tomogram}_mean.png')
_save(written[-1], img)
return written

# _save: write an image stretched between its 1st and 99th percentiles as an 8-bit PNG
def _save(path: Path, arr: np.ndarray) -> None:
Expand Down
8 changes: 8 additions & 0 deletions src/pickmix/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ def _default_kinds() -> dict[str, Kind]:

# Config: validated project settings
class Config(BaseModel):
# project name (shown on Project tab and in window title, None falls back to directory name)
name: str | None = None
# tomogram locations; denoised_dir None means raw only
raw_dir: Path
denoised_dir: Path | None = None
Expand All @@ -79,6 +81,12 @@ def replace(self, **changes: object) -> 'Config':
changes = {**changes, 'hotkeys': []}
return Config.model_validate({**self.model_dump(), **changes})

# _blank_name: a blank name is no name
@field_validator('name')
@classmethod
def _blank_name(cls, name: str | None) -> str | None:
return (name or '').strip() or None

# _names: kind names become folder names, so keep them plain
@field_validator('kinds')
@classmethod
Expand Down
32 changes: 31 additions & 1 deletion src/pickmix/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
'''

# Import external dependencies
import numpy as np
import csv, numpy as np
from dataclasses import dataclass
from pathlib import Path

Expand Down Expand Up @@ -31,6 +31,15 @@ class KindSummary:
box_px: int
folder: Path

# CsvSummary: what a csv export of one kind wrote
@dataclass(frozen=True)
class CsvSummary:
kind: str
written: int
below_snr: int
excluded_flagged: int
path: Path

# recommend_box: (box edge in Angstrom, in pixels at the kind's extraction pixel size rounded up to even); the kind's own box if set, else a percentile of the fits
def recommend_box(kind: Kind, items: list[Item], *, percentile: float = 95.0) -> tuple[float, int]:
if kind.box_a > 0:
Expand Down Expand Up @@ -80,3 +89,24 @@ def export_kind(
write_star_loop(folder / f'{tomogram}_coords.star', 'particles', columns, [r for r in rows if r[0] == tomogram])
box_a, box_px = recommend_box(kind, kept, percentile=percentile)
return KindSummary(name, len(kept), below, dropped, unmatched, box_a, box_px, folder)

# export_csv: write out_dir/csv/<kind>.csv, one row per pick passing the SNR and flag settings, with the pick and fitted centres in voxels, the fit's ring radius and box in Angstrom, SNR and flags
def export_csv(
name: str, items: list[Item], out_dir: Path, *, min_snr: float = 0.0, include_flagged: bool = True,
) -> CsvSummary:
kept = [(p, f) for p, f in items if f.snr >= min_snr and (include_flagged or not f.flag)]
below = sum(f.snr < min_snr for _, f in items)
excluded = 0 if include_flagged else sum(bool(f.flag) for _, f in items if f.snr >= min_snr)
if not kept:
raise ValueError(f'kind {name!r}: no picks left after filtering')
path = out_dir / 'csv' / f'{name}.csv'
path.parent.mkdir(parents=True, exist_ok=True)
with open(path, 'w', newline='') as handle:
writer = csv.writer(handle)
writer.writerow(['tomogram', 'kind', 'pick_x', 'pick_y', 'pick_z', 'fit_x', 'fit_y', 'fit_z', 'radius_a', 'box_a', 'snr', 'flag'])
for p, f in kept:
writer.writerow([
p.tomogram, p.kind, f'{p.x:.2f}', f'{p.y:.2f}', f'{p.z:.2f}', f'{f.x:.2f}', f'{f.y:.2f}', f'{f.z:.2f}',
f'{f.radius_a:.2f}', f'{f.box_a:.2f}', f'{f.snr:.3f}', f.flag,
])
return CsvSummary(name, len(kept), below, excluded, path)
Loading
Loading