Metadata-Version: 2.4
Name: chronojson
Version: 0.1.0b2
Summary: Temporal extension framework for GeoJSON.
Author: Ahmet Koçyiğit
License: MIT
Project-URL: Homepage, https://github.com/AhmetBeratKocyigit/chronojson
Project-URL: Repository, https://github.com/AhmetBeratKocyigit/chronojson
Project-URL: Issues, https://github.com/AhmetBeratKocyigit/chronojson/issues
Keywords: geojson,gis,history,digital-humanities,temporal,mapping
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

<div align="center">

# ChronoJSON

**A time-aware extension of the GeoJSON specification.**

GeoJSON answers *where*. ChronoJSON answers *where — and when*.

[![PyPI version](https://img.shields.io/pypi/v/chronojson.svg)](https://pypi.org/project/chronojson/)
[![Python versions](https://img.shields.io/pypi/pyversions/chronojson.svg)](https://pypi.org/project/chronojson/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Spec Status](https://img.shields.io/badge/spec-draft--0.1-orange.svg)](#specification)

[Documentation](#table-of-contents) · [Quick Start](#-quick-start) · [Specification](#-specification-overview) · [Roadmap](#-roadmap) · [Contributing](#-contributing)

</div>

---

## Table of Contents

- [Overview](#-overview)
- [Motivation](#-motivation)
- [Why ChronoJSON?](#-why-chronojson)
- [Timeline Inheritance Model](#-timeline-inheritance-model)
- [Features](#-features)
- [Installation](#-installation)
- [Quick Start](#-quick-start)
- [Data Model](#-data-model)
- [Milestone Types](#-milestone-types)
- [Metadata](#-metadata)
- [GeoJSON vs ChronoJSON](#-geojson-vs-chronojson)
- [Project Structure](#-project-structure)
- [Architecture](#-architecture)
- [API Overview](#-api-overview)
- [Specification Overview](#-specification-overview)
- [Roadmap](#-roadmap)
- [Contributing](#-contributing)
- [License](#-license)
- [Author](#-author)
- [Acknowledgements](#-acknowledgements)

---

## 🌍 Overview

**ChronoJSON** is an open specification and reference Python implementation for representing **time-aware geographic data**. It extends the GeoJSON ecosystem with a temporal dimension, while remaining fully interoperable with existing GIS tooling.

It targets any domain where geography changes over time:

| Domain | Example use case |
|---|---|
| 🏛️ Historical GIS | Empire and border evolution |
| 📜 Digital Humanities | Annotated historical narratives |
| 🗺️ Historical Atlases | Interactive time-sliced maps |
| ⛏️ Archaeology | Site occupation timelines |
| 🏺 Cultural Heritage | Monument and site lifecycle tracking |
| 🧭 Historical Cartography | Map digitization over eras |
| 🎓 Education & Research | Teaching historical change spatially |
| 🎮 Strategy Games | Territory control over turns/time |
| 🛰️ UAV / Live Tracking | Flight paths, live vehicle location |

> **In one sentence:** ChronoJSON stores *change*, not *repetition*.

---

## 💡 Motivation

GIS formats are excellent at describing space. They are not designed to describe **change over time**.

When a country's borders shift every few decades, the conventional workaround is to create a **new, complete GeoJSON file for every date**. This approach seems simple, but it does not scale:

- 📁 Duplicated geometries across every snapshot
- 🧾 Duplicated properties, repeated for every version
- 💾 Growing file sizes as history accumulates
- 🔧 Painful maintenance — one change means editing N files

ChronoJSON was designed to solve this at the format level, not with external tooling bolted on afterward.

---

## ❓ Why ChronoJSON?

- **Single source of truth per feature.** One entity, one file, full history.
- **Inheritance, not duplication.** Only *changes* are recorded; everything else is inherited automatically.
- **GeoJSON-compatible core.** Familiar `Feature` / `FeatureCollection` structures, extended — not replaced.
- **Point-in-time queries.** Ask "what did this feature look like in year *X*?" and get a resolved, immutable state.
- **Tool-agnostic.** Plays well with existing GIS and mapping ecosystems by design.

### Why not plain GeoJSON?

GeoJSON has no concept of time. Any temporal modeling on top of it is a convention your team invents and maintains by hand — multiple files, naming schemes, manual diffing. ChronoJSON turns that convention into a first-class, validated data model.

---

## ⏳ Timeline Inheritance Model

Instead of repeating an entire feature for every date, ChronoJSON stores a **base feature** plus an ordered list of **milestones**. Any property or geometry not explicitly changed at a milestone is inherited from the previous state.

**Example — Ottoman Beylik → Ottoman Empire**

| Year | Event | Result |
|---|---|---|
| 1299 | `creation` | Beylik founded, capital: Söğüt |
| 1326 | `property_change` | Capital becomes Bursa |
| 1365 | `property_change` | Capital becomes Edirne |
| 1453 | `geometry_change` + `property_change` | Geometry updated, capital → Istanbul, name → "Ottoman Empire" |
| 1699 | `geometry_change` | Territorial contraction after treaty |
| 1922 | `deletion` | State dissolved |

```mermaid
timeline
    title Ottoman Beylik → Ottoman Empire
    1299 : Creation (Capital: Söğüt)
    1326 : Capital → Bursa
    1365 : Capital → Edirne
    1453 : Geometry change, Capital → Istanbul, Name → Ottoman Empire
    1699 : Geometry change
    1922 : Deletion
```

Querying `feature.at(1500)` resolves every property and geometry by walking the timeline up to that date — no duplication, no manual bookkeeping.

---

## ✨ Features

**Implemented**

- ✅ GeoJSON-compatible format
- ✅ `FeatureCollection` and `Feature` objects
- ✅ Dataset-level metadata support
- ✅ `Chrono` and `Milestone` objects
- ✅ `TimeRange` support
- ✅ Multiple milestone types
- ✅ JSON loading and saving
- ✅ Timeline resolution engine
- ✅ Property inheritance
- ✅ Geometry inheritance
- ✅ Immutable resolved state
- ✅ `Feature.at(year)` point-in-time queries
- ✅ Internal resolution cache

**Planned** — see [Roadmap](#-roadmap)

---

## 📦 Installation

```bash
pip install chronojson
```

Requires Python 3.9+.

---

## 🚀 Quick Start

```python
import chronojson

# Load a ChronoJSON dataset
collection = chronojson.load("ottoman.geojson")

# Pick a feature from the collection
feature = collection.features[0]

# Resolve its state at a specific point in time
state = feature.at(1500)

print(state.properties["capital"])  # Istanbul
print(state.properties["name"])     # Ottoman Empire
```

Every call to `.at(year)` returns an **immutable, fully-resolved snapshot** — geometry and properties included — computed by walking the feature's milestone timeline.

---

## 🧬 Data Model

```mermaid
classDiagram
    class FeatureCollection {
        +metadata: Metadata
        +features: List~Feature~
    }
    class Feature {
        +id: str
        +base_properties: dict
        +base_geometry: Geometry
        +chrono: Chrono
        +at(year) FeatureState
    }
    class Chrono {
        +milestones: List~Milestone~
    }
    class Milestone {
        +type: MilestoneType
        +date: TimeRange
        +properties: dict
        +geometry: Geometry
    }
    class FeatureState {
        +properties: dict
        +geometry: Geometry
        +year: int
    }

    FeatureCollection "1" --> "*" Feature
    Feature "1" --> "1" Chrono
    Chrono "1" --> "*" Milestone
    Feature ..> FeatureState : resolves to
```

---

## 🏷️ Milestone Types

| Type | Status | Description |
|---|---|---|
| `creation` | ✅ Stable | Marks the start of a feature's existence |
| `deletion` | ✅ Stable | Marks the end of a feature's existence |
| `property_change` | ✅ Stable | Updates one or more properties |
| `geometry_change` | ✅ Stable | Replaces the feature's geometry |
| `event` | ✅ Stable | Non-structural annotation (e.g. a battle, a treaty) |
| `merge` | 🚧 Planned | Combines two or more features into one |
| `split` | 🚧 Planned | Divides a feature into multiple features |

---

## 🗂️ Metadata

Every ChronoJSON dataset can declare descriptive metadata alongside its features:

```json
{
  "metadata": {
    "title": "Ottoman Empire",
    "description": "Territorial evolution of the Ottoman state, 1299–1922.",
    "author": "Jane Doe",
    "license": "CC-BY-4.0",
    "created": "2024-01-01",
    "updated": "2024-06-01",
    "version": "1.0.0"
  }
}
```

---

## ⚖️ GeoJSON vs ChronoJSON

| Aspect | GeoJSON | ChronoJSON |
|---|---|---|
| Spatial representation | ✅ Yes | ✅ Yes |
| Temporal representation | ❌ No | ✅ Yes |
| Change over time | Requires separate files | Native, via milestones |
| Duplication | High (one file per date) | Minimal (inheritance-based) |
| Point-in-time queries | Manual / external tooling | `Feature.at(year)` built-in |
| Backward compatibility | — | Fully compatible superset |
| File size at scale | Grows linearly with snapshots | Grows with actual changes only |

---

## 📁 Project Structure

```
chronojson/
├── __init__.py
├── schema.py          # Core schema definitions
├── enums.py           # Milestone types and enums
├── io.py              # Load / save operations
├── timeline.py        # Timeline resolution engine
├── validation.py       # Schema and data validation
├── query.py           # Query API (in progress)
├── geometry.py         # Geometry inheritance logic
├── fuzzy.py            # Fuzzy / uncertain date handling
├── exceptions.py       # Custom exception types
│
├── converters/
│   ├── geojson.py      # GeoJSON <-> ChronoJSON conversion
│   ├── csv.py           # CSV import/export
│   └── pandas.py        # pandas DataFrame integration
│
└── utils/
    ├── cache.py         # Resolution caching
    ├── dates.py         # Date/time parsing utilities
    └── ids.py            # Feature ID generation
```

---

## 🏗️ Architecture

```mermaid
flowchart LR
    A[ChronoJSON File] --> B[io.py<br/>Load]
    B --> C[schema.py<br/>Parse into Feature/Chrono objects]
    C --> D[validation.py<br/>Validate structure]
    C --> E[timeline.py<br/>Resolution Engine]
    E --> F[geometry.py<br/>Geometry inheritance]
    E --> G[Property inheritance]
    F --> H[utils/cache.py]
    G --> H
    H --> I[Feature.at year]
    I --> J[Resolved FeatureState]
```

---

## 🧩 API Overview

```python
# Loading and saving
collection = chronojson.load("path/to/file.geojson")
chronojson.save(collection, "output.geojson")

# Accessing features
feature = collection.features[0]

# Resolving state at a point in time
state = feature.at(1453)
state.properties   # dict of resolved properties
state.geometry     # resolved geometry object

# Inspecting the timeline directly
for milestone in feature.chrono.milestones:
    print(milestone.type, milestone.date)
```

> 📘 A full API reference will be published alongside the [Query API](#-roadmap) release.

---

## 📐 Specification Overview

ChronoJSON is designed as an **open specification**, not just a Python library. The reference implementation in this repository is one conformant implementation; others (e.g. a future JavaScript SDK) are expected to follow the same document model:

- `FeatureCollection` → `Feature` → `Chrono` → `Milestone`
- All coordinate and geometry structures remain RFC 7946 (GeoJSON) compatible
- Temporal resolution is deterministic and order-dependent on milestone dates

A formal specification document is tracked under [Roadmap](#-roadmap).

---

## 🗺️ Roadmap

- [ ] Validation Engine (schema + semantic validation)
- [ ] `merge` and `split` milestone support
- [ ] Query API (filter features by time range, property, region)
- [ ] JavaScript SDK
- [ ] Complete formal specification document
- [ ] CLI tool
- [ ] GeoPandas integration
- [ ] Leaflet integration
- [ ] OpenLayers integration
- [ ] MapLibre integration
- [ ] Temporal GIS utility functions

---

## 🤝 Contributing

Contributions are welcome, whether you're fixing a bug, improving documentation, or proposing an addition to the specification.

<details>
<summary><strong>How to contribute</strong></summary>

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-feature`
3. Make your changes and add tests where applicable
4. Run the test suite: `pytest`
5. Open a pull request with a clear description of the change

</details>

Please open an issue first for significant changes, especially anything touching the core specification, so it can be discussed before implementation work begins.

---

## 📄 License

This project is licensed under the **MIT License**. See [LICENSE](LICENSE) for details.

---

## 👤 Author

Maintained by Ahmet Koçyiğit.
Feel free to open an issue or start a discussion for questions, ideas, or feedback.

---

## 🙏 Acknowledgements

- The [GeoJSON](https://geojson.org/) specification, for the spatial foundation this project builds on
- The broader GIS and Digital Humanities communities whose use cases shaped this project's direction

---

<div align="center">

**ChronoJSON** — *because geography has a history.*

</div>
