{"id":50197056,"url":"https://github.com/aplgr/grovegrid","last_synced_at":"2026-05-25T18:33:14.575Z","repository":{"id":314676993,"uuid":"1056289106","full_name":"aplgr/grovegrid","owner":"aplgr","description":"Interactive growth maps for rows of trees. CSV in; single HTML out.","archived":false,"fork":false,"pushed_at":"2026-04-28T23:39:33.000Z","size":948,"stargazers_count":0,"open_issues_count":10,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-29T01:23:35.759Z","etag":null,"topics":["alpinejs","cli","csv","data-visualization","echarts","forestry","go","heatmap"],"latest_commit_sha":null,"homepage":"https://aplgr.github.io/grovegrid/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aplgr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-13T19:17:16.000Z","updated_at":"2026-04-28T23:38:40.000Z","dependencies_parsed_at":"2025-09-14T03:10:24.573Z","dependency_job_id":"72544336-973f-4963-b7b9-a819ce52022f","html_url":"https://github.com/aplgr/grovegrid","commit_stats":null,"previous_names":["aplgr/grovegrid"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/aplgr/grovegrid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aplgr%2Fgrovegrid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aplgr%2Fgrovegrid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aplgr%2Fgrovegrid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aplgr%2Fgrovegrid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aplgr","download_url":"https://codeload.github.com/aplgr/grovegrid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aplgr%2Fgrovegrid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33488928,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-25T14:31:05.219Z","status":"ssl_error","status_checked_at":"2026-05-25T14:31:02.878Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpinejs","cli","csv","data-visualization","echarts","forestry","go","heatmap"],"created_at":"2026-05-25T18:33:10.800Z","updated_at":"2026-05-25T18:33:14.559Z","avatar_url":"https://github.com/aplgr.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GroveGrid\n\n[![Live demo](https://img.shields.io/badge/demo-GitHub%20Pages-2ea44f)](https://aplgr.github.io/grovegrid/)\n[![Release](https://img.shields.io/github/v/release/aplgr/grovegrid)](https://github.com/aplgr/grovegrid/releases)\n![Status](https://img.shields.io/badge/status-alpha-orange)\n![Scope](https://img.shields.io/badge/scope-personal%20tool-blue)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\n[![Tests](https://github.com/aplgr/grovegrid/actions/workflows/test.yml/badge.svg)](https://github.com/aplgr/grovegrid/actions/workflows/test.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/aplgr/grovegrid.svg)](https://pkg.go.dev/github.com/aplgr/grovegrid)\n[![Go Report Card](https://goreportcard.com/badge/github.com/aplgr/grovegrid)](https://goreportcard.com/report/github.com/aplgr/grovegrid)\n[![Go](https://img.shields.io/badge/Go-1.22%2B-00ADD8?logo=go)](#)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/aplgr/grovegrid/issues)\n\n\n**CSV → interactive heatmaps \u0026 timeline for tree rows** (Go CLI · Alpine.js · ECharts)\n\nI keep snapshots of a small, planned grove: rows of trees, each with a position, a numeric condition (0 = dead, higher = better), height in cm, and a short species code. I first rendered static PNGs in Python, but that felt rigid. **GroveGrid** is my tiny CLI tool that turns those CSVs into one self-contained HTML: a calm heatmap with a time slider. It helps me review growth at a glance — and if you track rows of plants or orchards, it might be useful to you as well.\n\n## What it does\n\n* **Color-coded grid** for your rows (row × tree number). Numeric condition is shown as color; missing cells render as *no data* (dark grey), condition **0** as grey.\n* **Size-coded points** for height (cm) with helpful tooltips (species, exact values).\n* **Switch time slices** (one CSV per slice) via dropdown or slider — no page reloads.\n* **Ragged rows** are fine: each row can have a different length.\n* **Single, offline HTML** you can open anywhere.\n\n## Quickstart\n\n```bash\n# Build\ngo build -o ./bin/grovegrid ./cmd/grovegrid\n\n# Run (reads all *.csv in the folder)\n./bin/grovegrid -in ./data -out ./out -title \"GroveGrid\"\n\n# Open the result in your browser\n# -\u003e ./out/index.html\n```\n\n\u003e **Tip:** `data/` can contain multiple files like `2023-04.csv`, `2023-05.csv` etc.\n\u003e Every file becomes one time slice. It ships with sample inputs so you can play immediately.\n\n## Data model\n\n**CSV columns (case-insensitive; German header variants are accepted):**\n\n* `row` *(int)* — row index (1..X)\n* `position` *(int)* — position in row (1..Y)\n* `condition` *(float)* — **0 = dead**, **\u003e 0 = better**; empty/unknown → *no data* (internally `-1`)\n* `height` *(float, cm)*\n* `species` *(string, short code)* — e.g. `Y`, `Cu`, `P`\n\n**Example**\n\n```csv\nrow;position;condition;height;species;notes\n1;1;3.2;35;Y;new planting 2023-03\n1;2;0;28;Y;storm damage (May)\n1;3;1.4;15;Cu;\n2;1;4.0;42;P;shaded area\n```\n\n## Design notes\n\n* **Chart mapping**: ECharts heatmap encodes *condition*; scatter encodes *height* via `symbolSize`.\n* **Color logic**: piecewise mapping on the heatmap — `-1` (*no data*), `0` (*dead*, `ZeroColor`), and a red → yellow → green gradient (`GradColors`) for values `\u003e 0`.\n* **Stable timeline**: points are keyed by `(row, position)` across months; updates use ECharts’ merge behavior (`setOption(..., false)`), so points don’t jump — only size/color change with a short linear animation.\n* **Alpine glue**: the ECharts instance lives outside Alpine’s proxy to avoid recursion and keep reactivity simple.\n* **CSV parsing**: delimiter autodetection (`;`, `,`, tab), header normalization (umlauts, dashes/underscores), robust float parsing (`,` and `.`), and optional mapping from legacy text labels to numeric condition.\n* **Ragged rows handling**: the full grid is rendered; missing coordinates are filled as *no data*.\n\n## CLI Flags\n\n| Flag     | Default     | Description                                            |\n| -------- | ----------- | ------------------------------------------------------ |\n| `-in`    | `./data`    | Input directory with CSV files (each file = one slice) |\n| `-out`   | `./out`     | Output directory (will be created)                     |\n| `-title` | `GroveGrid` | Page title for the generated HTML                      |\n| `-json-out` | *(empty)* | If set, also writes the raw data as JSON to this path |\n\n## Development\n\n```bash\ngo test ./...\nnpm install\nnpm run vendor:sync\n```\n\nAfter Dependabot updates, run the local tests. For JavaScript updates, also regenerate the HTML and briefly check the output in a browser.\n\n## License\n\nMIT — see `LICENSE`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faplgr%2Fgrovegrid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faplgr%2Fgrovegrid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faplgr%2Fgrovegrid/lists"}