Skip to main content
Archived

This project has been archived by its maintainers, and is no longer receiving any updates.

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

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.

Metadata

Release files for fritts-dendro 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fritts-dendro 0.2.0
File Size Uploaded Provenance
fritts_dendro-0.2.0.tar.gz 95.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for fritts-dendro 0.2.0
File Interpreter ABI Platform
fritts_dendro-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 180.2 kB

Release files / fritts_dendro-0.2.0.tar.gz

Download URL fritts_dendro-0.2.0.tar.gz
Size 95.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d525e24e5a00a529456dc0a64c6c0fce58fb31df5bc406ffecf8446e7cc92a0d
BLAKE2b-256 checksum
How to use checksums
c937c847ecfeed4fcc5d12805942c3b57a8eda6d4cfcdaf1b7fdd361ec446b09
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.

Transparency log

Release files / fritts_dendro-0.2.0-py3-none-any.whl

Download URL fritts_dendro-0.2.0-py3-none-any.whl
Size 85.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1a0f6c222fd7cd6edff7ec5a5196a93ac057e8416132adea65768860b1950b9a
BLAKE2b-256 checksum
How to use checksums
3374f59a398d29642b2f7227853ba2b675df118912d49ec484e7f8ddb867c857
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.

Transparency log

Security for fritts-dendro 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for fritts_dendro-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page