Skip to main content

Open-source desktop tool for tree-ring cross-dating, measurement, and master chronology building.

This project has been archived.

The maintainers of this project have marked this project as archived. No new releases are expected.

Project description

Fritts — Dendrochronology Analysis Platform

Fritts Screenshot

An open-source desktop application for tree-ring cross-dating, measurement, and master chronology building. Built with Python, PyQt6, and PyQtGraph. Named in honor of Harold C. Fritts (1930–2024), author of Tree Rings and Climate and a pioneer of dendroclimatology.

Repository: GitHub · GitLab
Package: fritts-dendro on PyPI


Table of Contents

  1. Why Fritts?
  2. Features
  3. Quick Start
  4. Installation
  5. Supported Formats
  6. Dependencies
  7. Usage
  8. Cross-Dating Methods
  9. COFECHA-Style Quality Control
  10. Chronology Building
  11. Image Measurement
  12. Session Workspace
  13. ITRDB Integration
  14. Keyboard Shortcuts
  15. Sample Data
  16. Project Structure
  17. Development
  18. User Guide
  19. Target Users
  20. Tech Stack
  21. Known Issues
  22. License

Why Fritts?

Existing dendrochronology software is often dated, proprietary, Windows-only, or splits critical workflows across multiple applications. Fritts unifies format parsing, interactive visual plotting, statistical cross-dating, and chronology building into a single, modern, cross-platform interface.

Key differentiators:

  • All-in-one — Import, visualize, cross-date, detrend, build chronologies, and export in a single application.
  • Modern GUI — PyQtGraph-powered canvas with GPU-accelerated rendering, smooth zoom/pan, and multi-series overlay.
  • Standards-compliant — Full Tucson decadal read/write, TRiDaS read/write, Heidelberg read.
  • COFECHA-compatible QC — Sliding-window correlation with AR prewhitening and Spearman significance (matching dplR defaults).
  • ITRDB integration — Search and download data directly from the NOAA International Tree-Ring Data Bank.
  • Cross-platform — Linux, macOS, and Windows with optional standalone binaries.

Features

  • Multi-format import/export — Tucson (.rwl, .tuc, .crn), Heidelberg (.fh), TRiDaS (.xml).
  • Interactive plotting — PyQtGraph canvas with smooth zoom, pan, multi-series overlay, and skeleton plot mode.
  • Statistical cross-dating — Baillie-Pilcher t-value, Hollstein t-value, Gleichläufigkeit (GLK) with Buras-Wilmking 2015 correction, and sliding-window analysis.
  • COFECHA-style Quality Control — Leave-one-out master chronology, Yule-Walker AR(p) prewhitening (AIC order selection), segment correlation with Spearman's rho and p-value thresholding. Adjustable alpha via the QC dialog.
  • Detrending — Mean, negative exponential, Hugershoff, cubic spline, and Regional Curve Standardisation (RCS).
  • Chronology builder — Interactive master chronology with real-time EPS and R-bar metrics. Biweight robust mean averaging.
  • Classical ring detection — Projection-profile boundary detection on scanned wood-section images.
  • Geometric pith estimator — Adjustable concentric-circle overlay for estimating missing distance to pith.
  • Session workspace — Save and load complete project state to .fritts JSON files (all series, references, metadata).
  • ITRDB data search — Browse and download from the NOAA International Tree-Ring Data Bank.
  • R/dplR export — Generate companion .R scripts for advanced analysis in R's dplR package.
  • Preferences — DPI and theme settings persisted via QSettings.
  • Full undo/redo — Command-pattern architecture with 200-step undo history.
  • Sample data — Two synthetic 100-year series in sample_data/example.rwl for evaluation.

Quick Start

# Install from PyPI
pip install fritts-dendro

# Launch
fritts

Or from source:

git clone https://github.com/mabo-du/fritts.git
cd fritts
pip install -e ".[dev]"
fritts

First-run workflow

  1. Import data: File > Import (Ctrl+Shift+I) — select a .rwl, .fh, or .xml file.
  2. Explore: Click series in the Series List to view statistics. Toggle visibility with checkboxes.
  3. Cross-date: Right-click a floating series → "Cross-Date Series", or Tools > Cross-Date (Ctrl+D).
  4. Detrend: Tools > Detrend — remove biological growth trends before chronology building.
  5. Build chronology: Tools > Build Chronology (Ctrl+B) — create a master curve from reference series.
  6. QC: Tools > QC Report — run COFECHA-style quality control with adjustable alpha threshold.
  7. Save: File > Save Workspace (Ctrl+S) — save your session as a .fritts project file.
  8. Export: File > Export (Ctrl+E) — export as Tucson .rwl, TRiDaS .xml, or R/dplR script.

Installation

From PyPI (recommended)

pip install fritts-dendro
fritts

From source (development)

git clone https://github.com/mabo-du/fritts.git
cd fritts

# Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate  # Linux/macOS
# .venv\Scripts\activate   # Windows

# Install with dev dependencies
pip install -e ".[dev]"

# Launch
fritts

Standalone binaries

Pre-built executables are available from the GitHub Releases page:

Platform File Notes
Linux fritts-linux-x64 + Fritts-x86_64.AppImage AppImage is portable
macOS fritts-macos-arm64 Apple Silicon (M1+)
Windows fritts-windows-x64.exe Standalone executable

System dependencies

Ubuntu/Debian:

sudo apt install libxcb-cursor0 libegl1 libgl1

Fedora:

sudo dnf install qt6-qtbase-gui

Supported Formats

Format Extensions Read Write Description
Tucson Decadal .rwl, .tuc, .crn Most common tree-ring format. 0.01mm or 0.001mm precision, auto-detected from stop code (999 or -9999).
Heidelberg .fh German format with HEADER/DATA sections. Auto-detects single-column and decadal-block layouts.
TRiDaS XML .xml International standard (TRiDaS 1.2.2). Handles astronomical BCE convention.
Fritts Workspace .fritts JSON project file preserving all series, references, metadata, and format version.

Precision handling

  • Tucson: Stop code 999 → 0.01 mm precision (divide by 100). Stop code -9999 → 0.001 mm precision (divide by 1000). Mixed stop codes warn and use the dominant value as fallback.
  • TRiDaS: Unit attribute determines precision (1/100th millimetres → /100, micrometre → /1000, millimetre → /1).
  • Heidelberg: Values assumed in 1/100 mm (divide by 100).

Dependencies

Package Minimum Purpose
PyQt6 6.6 GUI framework
pyqtgraph 0.13 GPU-accelerated interactive plotting
pandas 2.1 Data manipulation and alignment
numpy 1.26 Numerical computation
scipy 1.12 Statistical algorithms (Pearson, Spearman, splines)
lxml 5.0 TRiDaS XML parsing
tifffile 2024.1 Memory-mapped TIFF loading for large images

All dependencies have explicit upper bounds in pyproject.toml to prevent breaking on future major releases.

Usage

Launching

fritts

Or directly:

python -m dendro.main

The Interface

The main window is divided into three panels:

Panel Location Content
Series List Left All loaded series with checkboxes, year ranges, visibility toggles. Right-click for context menu (Cross-Date, Set as Reference, Remove).
Plot Area Centre PyQtGraph canvas showing ring-width curves. Multi-series overlay with zoom/pan.
Stats Panel Right Selected series statistics: mean, standard deviation, min/max, year range, ring count. After cross-dating: t-values, GLK, overlap.

Series List operations

Action How
Select a series Left-click → shows stats in right panel
Toggle visibility Checkbox
Cross-date Right-click → "Cross-Date Series"
Set as reference Right-click → "Set as Reference"
Remove Right-click → "Remove Series" (undoable)
Shift in time Arrow keys (← →) with active selection. Clamped to ±10,000 years.
Snap to offset Click a proposed start year in the cross-date results panel

Plot controls

Control Action
Left-click + drag Pan
Scroll wheel Zoom in/out
Ctrl + scroll Zoom X-axis only
Shift + scroll Zoom Y-axis only
Right-click Context menu
F key Zoom to fit

Cross-Dating Methods

Fritts provides three complementary statistics for cross-dating:

Baillie-Pilcher t-value (t_bp)

A 5-year running mean is applied to both series before computing Pearson's r and converting to a t-statistic: t = r · √((n−6)/(1−r²)). This pre-smoothing reduces the influence of high-frequency noise and emphasises decadal-scale patterns.

  • Degrees of freedom: n−6 (4 lost to the running mean, 2 to bivariate correlation).
  • Reference: Baillie & Pilcher (1973), Tree-Ring Bulletin 33:7–14.
  • Typical significance: t > 3.5 for 50-year overlap.

Hollstein t-value (t_ho)

Each series is transformed to Wuchswerte (growth-change values) before correlation: Wᵢ = 100 · ln(xᵢ / xᵢ₋₁). This year-over-year ratio transform emphasises short-term growth changes. The canonical formula matches dendroNetwork::wuchswerte() (Hollstein 1980, pp 14–15).

  • Degrees of freedom: n−3 (1 lost to the lag, 2 to bivariate correlation).
  • Reference: Hollstein (1980), Mitteleuropäische Eichenchronologie.

Gleichläufigkeit (GLK)

GLK measures the percentage of years where both series show the same direction of change (up/up or down/down). Implemented with the Buras-Wilmking (2015) correction:

  • Year-pairs where both series show zero change count as a synchronous match.
  • Year-pairs where only one series shows zero change are excluded.
  • Z-score and p-value are computed using the exact binomial test (n < 30) or normal approximation (n ≥ 30).
  • Reference: Buras & Wilmking (2015), Dendrochronologia 33:42–48.

Interpreting results

Statistic Threshold Meaning
t_bp / t_ho > 3.5 Strong match, series likely correctly dated
t_bp / t_ho 2.5–3.5 Possible match, investigate further
t_bp / t_ho < 2.5 Weak match
GLK > 60% Good trend agreement
GLK > 70% Very strong trend agreement
p-value < 0.05 Statistically significant

Sliding window cross-dating

Tools > Cross-Date (Ctrl+D) runs crossdate_sliding() which slides the sample across the reference at every position where the overlap exceeds the minimum threshold (default 30 years). At each position, all three statistics (t_bp, t_ho, GLK) are computed on the overlapping segment. Results are displayed as a table ranked by t_bp.

COFECHA-Style Quality Control

Tools > QC Report runs a COFECHA-style analysis following dplR::corr.series.seg() conventions:

  1. Leave-one-out master: For each target series, a master chronology is built from the mean (or biweight robust mean) of all other series.
  2. AR prewhitening: Each full-length series is prewhitened via Yule-Walker AR(p) with AIC order selection (max order 5), removing autocorrelation that would inflate apparent significance. Matching dplR's normalize.xdate() behaviour.
  3. Sliding windows: Fixed-length segments (default 50 years, 25-year overlap) are correlated against the master.
  4. Spearman's rho with p-value: Segments are flagged when p > α (default α = 0.05). This adapts to varying segment lengths and df loss from prewhitening — unlike COFECHA's hardcoded r < 0.32 threshold which only applies to n=50.
  5. Adjustable alpha: The QC dialog provides an alpha spinbox (0.001–1.0) with a "Run QC" button to re-run at different thresholds.

Chronology Building

Tools > Build Chronology (Ctrl+B) creates a master chronology from selected reference series:

  1. Select reference series.
  2. Choose averaging method: Mean or Biweight robust mean (resistant to outliers, recommended).
  3. The chronology is built with EPS and R-bar calculated in real time:
    • R-bar: Mean inter-series correlation across all pairwise overlaps (Pearson r).
    • EPS (Expressed Population Signal): EPS = (n · r̄) / (1 + (n−1) · r̄). Threshold for a well-represented chronology: ≥ 0.85.
  4. The chronology appears in the Series List as CHRONOLOGY.
  5. Right-click → "Cross-Date Series" to date floating series against the master chronology.

Image Measurement

Tools > Image Measurement opens the wood-section image viewer:

  1. Load an image — JPEG, PNG, or TIFF. Files >500 MB use memory-mapped tifffile I/O for efficient loading.
  2. Set DPI — Calibrate the image resolution for accurate millimeter measurements.
  3. Detect rings — Click "Auto-Detect Rings" to run the classical projection-profile boundary detection algorithm.
  4. Manual markers — Left-click to place/adjust ring boundary markers.
  5. Extract series — Click "Extract Series" with ≥2 markers to export ring-width measurements. Series IDs are validated (≤8 alphanumeric characters).
  6. Pith estimator — Toggle concentric-circle overlay to estimate missing distance to pith.

The channel order for loaded images is RGB (matching pyqtgraph's makeARGB expectations). Grayscale images are automatically broadcast to 3-channel.

Session Workspace

File > Save Workspace (Ctrl+S) serialises the entire session (all series, detrended indices, reference flags, metadata) to a .fritts JSON file:

  • NaN values → JSON null for standard compliance.
  • format_version field for forward/backward compatibility.
  • File > Open Workspace (Ctrl+O) to reload.
  • File > Save As (Ctrl+Shift+S) for versioned saves.

ITRDB Integration

Tools > Search ITRDB connects to the NOAA International Tree-Ring Data Bank API:

  • Search: Keyword search across all published ITRDB studies (default limit 30 results to avoid API errors).
  • Download: Select a study and click "Download Selected" to fetch available .rwl series.
  • Security: SSRF guard (host whitelisted to ncei.noaa.gov), SSL context, 100 MB Content-Length cap.
  • User-Agent: Fritts/{version} for API identification.

API endpoint: https://www.ncei.noaa.gov/access/paleo-search/study/search.json

Keyboard Shortcuts

Shortcut Action
Ctrl+O Open Workspace
Ctrl+S Save Workspace
Ctrl+Shift+S Save Workspace As
Ctrl+Shift+I Import data
Ctrl+E Export data
Ctrl+, Preferences
Ctrl+Z Undo
Ctrl+Shift+Z / Ctrl+Y Redo
Ctrl+D Cross-Date
Ctrl+B Build Chronology
F Zoom to Fit
/ Shift active series ±1 year
Ctrl+Q Quit

Sample Data

The repository includes sample_data/example.rwl — two synthetic 100-year series (SAMPLEA, SAMPLEB) generated from an age-related exponential trend with AR(1) noise. These are suitable for:

  • Testing import/export workflows
  • Evaluating cross-dating statistics
  • Practicing chronology building
  • Familiarisation with the interface
fritts
# File > Import → select sample_data/example.rwl

Project Structure

fritts/
├── assets/                  # Static assets (screenshots, icons)
├── docs/
│   ├── USER_GUIDE.md        # Comprehensive user documentation
│   ├── scope.md             # Project scope and roadmap
│   └── research-papers/     # Reference papers
├── sample_data/             # Synthetic ring-width files
│   └── example.rwl          # 2 series, 100 years each
├── src/
│   └── dendro/
│       ├── io/              # Format parsers
│       │   ├── tucson.py    # Tucson decadal (.rwl) read/write
│       │   ├── heidelberg.py# Heidelberg (.fh) reader
│       │   ├── tridas.py    # TRiDaS XML read/write
│       │   ├── itrdb.py     # NOAA ITRDB API client
│       │   └── export_r.py  # dplR-compatible R script generator
│       ├── models/
│       │   ├── series.py    # RingWidthSeries (frozen dataclass)
│       │   ├── session.py   # SessionManager with serialization
│       │   └── commands.py  # Command pattern (undo/redo)
│       ├── stats/
│       │   ├── crossdate.py  # t_bp, t_ho, GLK, sliding cross-date
│       │   ├── chronology.py # Chronology builder, rbar, EPS
│       │   ├── detrend.py    # Mean, neg exp, spline, RCS
│       │   ├── quality_control.py  # COFECHA-style QC
│       │   └── ai_segmentation.py  # Classical ring detection
│       ├── ui/
│       │   ├── main_window.py      # Application window
│       │   ├── series_list.py      # Series list panel
│       │   ├── series_view.py      # Plot panel
│       │   ├── image_view.py       # Image measurement
│       │   ├── chronology_builder.py # Chronology dialog
│       │   ├── preferences_dialog.py # Settings dialog
│       │   └── qc_dialog.py        # QC report dialog
│       └── main.py           # Application entry point
├── tests/                    # Test suite (pytest)
│   ├── test_regression.py    # 35+ regression tests
│   ├── test_crossdate.py     # Cross-dating edge cases
│   ├── test_session_serialization.py  # Save/load round-trip
│   ├── test_io_formats.py    # Heidelberg, TRiDaS parsers
│   ├── test_ui_smoke.py      # UI smoke tests (pytest-qt)
│   └── ...
├── pyproject.toml            # Build configuration
└── README.md

Development

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests (95+ tests)
pytest

# Run linting
ruff check src/ tests/

# Format code
ruff format src/ tests/

Test organization

File Coverage
test_regression.py FR-specific regression tests (statistics, models, signals)
test_session_serialization.py .fritts save/load round-trip, version validation
test_commands.py Command pattern (DetrendCommand, undo/redo)
test_crossdate.py Cross-dating edge cases (no overlap, min_overlap, identical series)
test_tucson_parser.py Tucson read/write round-trip (BCE, non-decade starts)
test_io_formats.py Heidelberg and TRiDaS parser tests
test_detrend.py Detrending methods (mean, neg exp, spline)
test_itrdb.py ITRDB API client (mocked HTTP)
test_ui_smoke.py UI instantiation smoke tests (pytest-qt)

Contributing

  1. Fork the repository on GitHub or GitLab.
  2. Create a feature branch from master.
  3. Make your changes with tests.
  4. Run the full test suite: pytest.
  5. Submit a merge request / pull request.

User Guide

See docs/USER_GUIDE.md for comprehensive documentation covering:

  • Installation troubleshooting
  • Importing and exporting data
  • Cross-dating workflows
  • Detrending methods
  • Chronology building with EPS/R-bar interpretation
  • COFECHA-style Quality Control (prewhitening, alpha threshold)
  • ITRDB data search
  • Image measurement and ring detection
  • Keyboard shortcuts reference
  • Troubleshooting common issues

Target Users

  • Dendrochronologists dating archaeological timbers and historical structures.
  • Climate researchers building proxy records from tree rings.
  • Wood specialists in archaeology, heritage, and conservation.
  • Students learning tree-ring analysis methods.

Tech Stack

Component Technology
GUI PyQt6 (Qt 6.6+)
Visualization PyQtGraph (0.13.x, GPU-accelerated)
Data Pandas, NumPy
Statistics SciPy (Pearson r, Spearman rho, splines)
XML lxml (TRiDaS parsing)
Image I/O tifffile (large TIFF memory-mapped loading)
Testing pytest, pytest-qt, pytest-mock
Linting ruff
Build setuptools, PyInstaller, AppImage

Known Issues

NOAA ITRDB API limit

The ITRDB search API returns HTTP 500 errors when the limit parameter is 46 or higher. Fritts defaults to limit=30 to avoid this. If you need more results, run multiple searches with different keywords.

pyqtgraph version

Fritts requires pyqtgraph>=0.13,<0.14. Version 0.14 removed a method that pyqtgraph's own internal plotting code still calls, causing AttributeError spam on plot interactions. This is pinned in pyproject.toml. A warning is shown at startup if >=0.14 is detected.

TRiDaS NaN handling

The TRiDaS writer converts NaN ring-width values to 0. This is a known limitation of the current export implementation.

Large image loading

For TIFF files >500 MB, the QImage path has a 2× memory overhead (RGBA decode + numpy copy). Fritts automatically switches to tifffile memory-mapped I/O for files above this threshold, avoiding the double allocation. For extremely large files (>2 GB), ensure sufficient system memory for pyqtgraph's texture upload.

Undo stack

The undo stack is limited to 200 commands. When exceeded, the oldest commands are discarded. This prevents unbounded memory growth during long sessions.

License

MIT


Fritts — Named in honor of Harold C. Fritts (1930–2024), pioneer of dendroclimatology.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fritts_dendro-0.2.0.tar.gz (95.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fritts_dendro-0.2.0-py3-none-any.whl (85.2 kB view details)

Uploaded Python 3

File details

Details for the file fritts_dendro-0.2.0.tar.gz.

File metadata

  • Download URL: fritts_dendro-0.2.0.tar.gz
  • Upload date:
  • Size: 95.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fritts_dendro-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d525e24e5a00a529456dc0a64c6c0fce58fb31df5bc406ffecf8446e7cc92a0d
MD5 c4e9a053e76b9a007c4c5906dca08dab
BLAKE2b-256 c937c847ecfeed4fcc5d12805942c3b57a8eda6d4cfcdaf1b7fdd361ec446b09

See more details on using hashes here.

Provenance

The following attestation bundles were made for fritts_dendro-0.2.0.tar.gz:

Publisher: release.yml on mabo-du/fritts

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fritts_dendro-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fritts_dendro-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 85.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fritts_dendro-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1a0f6c222fd7cd6edff7ec5a5196a93ac057e8416132adea65768860b1950b9a
MD5 dda03ef7d233810443c940e40651121b
BLAKE2b-256 3374f59a398d29642b2f7227853ba2b675df118912d49ec484e7f8ddb867c857

See more details on using hashes here.

Provenance

The following attestation bundles were made for fritts_dendro-0.2.0-py3-none-any.whl:

Publisher: release.yml on mabo-du/fritts

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page