From 98b09cab690d62fed9d18acb5e9d49ed76acbc77 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Tue, 11 Aug 2026 20:52:24 +0200 Subject: chore: remove legacy chart rendering --- README.md | 13 ++------- chart/chart.go | 81 ---------------------------------------------------- cli/cli.go | 27 ------------------ go.mod | 9 ------ go.sum | 46 ------------------------------ ride/ride.go | 89 ---------------------------------------------------------- 6 files changed, 3 insertions(+), 262 deletions(-) delete mode 100644 chart/chart.go diff --git a/README.md b/README.md index aa55cca..f5f57df 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A Go toolkit for analyzing cycling rides from GPX exports: parse rides, detect c - **Similar-climb matching** — finds the same climb across rides by matching start/end coordinates, so times can be compared - **Mountain pass download** — imports French mountain passes from centcols.org into a SQLite database - **Pass crossing detection** — enriches passes with OSM coordinates, flags which passes a ride crosses, and names each climb after the pass it tops (e.g. "Col de Castellaras") -- **Plots** — renders elevation and score-profile charts as PNG +- **Interactive ride profiles** — explores elevation, climbs, and mountain-pass crossings in the web ride detail view - **Web ride library** — starts a local web server by default, imports Strava rides over a date range, stores metadata in SQLite, and keeps their GPX files on disk - **Materialized ride values** — computes Cotacol on import, stores its algorithm version in SQLite, and refreshes all computed values with `-backfill` - **Strava stream metrics** — preserves heart rate, cadence, and power in Garmin-compatible GPX files and in-memory ride columns @@ -49,9 +49,6 @@ mise watch dev-watch --restart --exts go,templ --ignore '*_templ.go' # Backfill OSM coordinates onto passes (needs -extract-osm run first) ./biking_home -enrich -# Render an elevation chart with climb highlights and pass markers -./biking_home -chart examples/2023-06-17.AlpesVerdonTour.gpx - ``` ## Options / Configuration @@ -64,7 +61,6 @@ mise watch dev-watch --restart --exts go,templ --ignore '*_templ.go' | `-extract-osm` | Extract mountain passes from a France OSM PBF | `""` | | `-enrich` | Backfill OSM coordinates onto passes | `false` | | `-backfill` | Recompute and persist all ride computed values | `false` | -| `-chart` | Render an elevation chart (climbs + passes) for a GPX file | `""` | Configuration is stored in `config.yaml`. Start from `config.example.yaml` and set the Strava credentials before launching the server. @@ -82,7 +78,7 @@ Standard apps are rate-limited to 100 calls per 15 minutes and 1,000 per day. ## Architecture -- Go 1.23; SQLite via `mattn/go-sqlite3`; charts via `gonum.org/v1/plot` +- Go 1.23; SQLite via `mattn/go-sqlite3` - `ride` — GPX parsing, climb detection, difficulty scores (KOM + Cotacol), similarity index - `mountain_pass` — centcols.org department CSV download into SQLite, with disk caching and retries - `osmpass` — OSM PBF extraction (`mountain_pass=yes` nodes) and pass coordinate enrichment @@ -90,8 +86,7 @@ Standard apps are rate-limited to 100 calls per 15 minutes and 1,000 per day. - `rides` — SQLite persistence for imported ride metadata and versioned computed values - `config` — typed YAML configuration and atomic persistence - `web` — HTTP server, OAuth callback, sync orchestration, and templ pages -- `cli` — legacy mountain-pass, OSM, and chart command handlers -- `chart` — elevation chart rendering +- `cli` — legacy mountain-pass and OSM command handlers - **Notable choices** — the difficulty score follows the Cotacol method: the ride is split into fixed 100 m segments and each scores `distance_km × slope²`, so steep sections weigh exponentially more than long flat ones ```mermaid @@ -108,14 +103,12 @@ flowchart TB config["config (YAML)"] web["web (HTTP + templ)"] cli["cli (legacy commands)"] - chart["chart (renderer)"] main --> cli cli --> ride cli --> mpass cli --> osmpass cli --> web - cli --> chart mpass --> ride web --> strava web --> rides diff --git a/chart/chart.go b/chart/chart.go deleted file mode 100644 index 7f5a4c7..0000000 --- a/chart/chart.go +++ /dev/null @@ -1,81 +0,0 @@ -package chart - -import ( - "fmt" - "image/color" - - "github.com/martinlehoux/biking_home/mountain_pass" - "github.com/martinlehoux/biking_home/ride" - "github.com/martinlehoux/kagamigo/kcore" - "gonum.org/v1/plot" - "gonum.org/v1/plot/plotter" - "gonum.org/v1/plot/vg" -) - -func Render(r ride.Ride, climbs []ride.Climb, crossings []mountain_pass.Crossing, output string) { - p := plot.New() - p.Title.Text = "Ride profile" - p.X.Label.Text = "Distance (km)" - p.Y.Label.Text = "Elevation (m)" - - maxElev := 0.0 - elevation := make(plotter.XYs, r.Len()) - for i := 0; i < r.Len(); i++ { - elevation[i].X = r.DistanceM(i) / 1000 - elevation[i].Y = r.ElevationM(i) - if r.ElevationM(i) > maxElev { - maxElev = r.ElevationM(i) - } - } - - for _, climb := range climbs { - x0 := climb.StartDistanceM() / 1000 - x1 := climb.EndDistanceM() / 1000 - fill, err := plotter.NewPolygon(plotter.XYs{ - {X: x0, Y: 0}, - {X: x1, Y: 0}, - {X: x1, Y: maxElev}, - {X: x0, Y: maxElev}, - }) - kcore.Expect(err, "failed to create climb band") - fill.Color = color.RGBA{R: 230, G: 160, B: 0, A: 70} - fill.LineStyle.Width = 0 - p.Add(fill) - p.Add(plotLabels(plotter.XY{X: (x0 + x1) / 2, Y: climb.TopElevationM() * 1.01}, climbLabel(climb))) - } - - for _, crossing := range crossings { - x := crossing.RideDistanceM / 1000 - line, err := plotter.NewLine(plotter.XYs{ - {X: x, Y: 0}, - {X: x, Y: maxElev}, - }) - kcore.Expect(err, "failed to create pass marker") - line.LineStyle.Dashes = []vg.Length{vg.Points(4), vg.Points(2)} - p.Add(line) - p.Add(plotLabels(plotter.XY{X: x, Y: maxElev * 0.96}, - fmt.Sprintf("%s %dm", crossing.Pass.Name, crossing.Pass.Elevation))) - } - - elevLine, err := plotter.NewLine(elevation) - kcore.Expect(err, "failed to create elevation line") - p.Add(elevLine) - - kcore.Expect(p.Save(10*vg.Inch, 4*vg.Inch, output), "failed to save chart") -} - -func climbLabel(climb ride.Climb) string { - if climb.Name != "" { - return climb.Name - } - return fmt.Sprintf("%s %d", ride.Category(climb.Score()), int(climb.Score())) -} - -func plotLabels(xy plotter.XY, label string) *plotter.Labels { - labels, err := plotter.NewLabels(plotter.XYLabels{ - XYs: plotter.XYs{xy}, - Labels: []string{label}, - }) - kcore.Expect(err, "failed to create labels") - return labels -} diff --git a/cli/cli.go b/cli/cli.go index 1d1b0f3..eb96356 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -5,15 +5,11 @@ import ( "database/sql" "flag" "log/slog" - "path/filepath" - "strings" "time" - "github.com/martinlehoux/biking_home/chart" "github.com/martinlehoux/biking_home/config" "github.com/martinlehoux/biking_home/mountain_pass" "github.com/martinlehoux/biking_home/osmpass" - "github.com/martinlehoux/biking_home/ride" "github.com/martinlehoux/biking_home/rides" "github.com/martinlehoux/biking_home/web" "github.com/martinlehoux/kagamigo/kcore" @@ -27,8 +23,6 @@ var ( extractOSM = flag.String("extract-osm", "", "extract mountain passes from an OSM PBF file into the database") enrich = flag.Bool("enrich", false, "backfill mountain pass coordinates from OSM data") backfill = flag.Bool("backfill", false, "recompute all stored ride values") - chartFile = flag.String("chart", "", "render a climb/pass chart for a GPX file") - parser = ride.GPXRideParser{} ) func Run(db *sql.DB, configPath string, appConfig config.Config) { @@ -52,8 +46,6 @@ func Run(db *sql.DB, configPath string, appConfig config.Config) { count, err := rides.Backfill(db) kcore.Expect(err, "failed to backfill ride values") slog.Info("Backfilled ride values", "rides", count) - case *chartFile != "": - runChart(db, *chartFile) default: runServer(db, configPath, appConfig) } @@ -64,22 +56,3 @@ func runServer(db *sql.DB, configPath string, appConfig config.Config) { slog.Info("Starting web server", "address", appConfig.Server.PublicURL) kcore.Expect(server.ListenAndServe(appConfig.Server.Address), "web server stopped") } - -func runChart(db *sql.DB, filename string) { - r, err := ride.ParseFile(parser, filename) - kcore.Expect(err, "failed to parse ride") - passes, err := mountain_pass.LoadMountainPasses(db) - kcore.Expect(err, "failed to load mountain passes") - - climbs := r.AllClimbs() - for i := range climbs { - if matched, ok := mountain_pass.MatchClimb(climbs[i], passes, 300, 50); ok { - climbs[i].Name = matched.Name - } - } - crossings := mountain_pass.DetectCrossings(r, passes, 100, 25) - - output := strings.TrimSuffix(filename, filepath.Ext(filename)) + "-chart.png" - chart.Render(r, climbs, crossings, output) - slog.Info("Chart written", "file", output) -} diff --git a/go.mod b/go.mod index f066362..54400c7 100644 --- a/go.mod +++ b/go.mod @@ -13,26 +13,19 @@ require ( github.com/stretchr/testify v1.10.0 github.com/tkrajina/gpxgo v1.4.0 golang.org/x/text v0.34.0 - gonum.org/v1/plot v0.16.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - codeberg.org/go-fonts/liberation v0.5.0 // indirect - codeberg.org/go-latex/latex v0.1.0 // indirect - codeberg.org/go-pdf/fpdf v0.10.0 // indirect - git.sr.ht/~sbinet/gg v0.6.0 // indirect github.com/BurntSushi/toml v1.4.0 // indirect github.com/ClickHouse/clickhouse-go v1.5.4 // indirect github.com/DataDog/czlib v0.0.0-20240814115052-86a9592b3985 // indirect github.com/PuerkitoBio/goquery v1.8.1 // indirect github.com/a-h/parse v0.0.0-20240121214402-3caf7543159a // indirect github.com/a-h/protocol v0.0.0-20240704131721-1e461c188041 // indirect - github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect github.com/amacneil/dbmate v1.16.2 // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/campoy/embedmd v1.0.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cli/browser v1.3.0 // indirect github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect @@ -42,7 +35,6 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect - github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/joho/godotenv v1.4.0 // indirect github.com/kataras/i18n v0.0.8 // indirect github.com/kr/pretty v0.1.0 // indirect @@ -67,7 +59,6 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/image v0.25.0 // indirect golang.org/x/mod v0.32.0 // indirect golang.org/x/net v0.51.0 // indirect golang.org/x/sync v0.19.0 // indirect diff --git a/go.sum b/go.sum index 0f5b5dc..89c2148 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,3 @@ -codeberg.org/go-fonts/dejavu v0.4.0 h1:2yn58Vkh4CFK3ipacWUAIE3XVBGNa0y1bc95Bmfx91I= -codeberg.org/go-fonts/dejavu v0.4.0/go.mod h1:abni088lmhQJvso2Lsb7azCKzwkfcnttl6tL1UTWKzg= -codeberg.org/go-fonts/latin-modern v0.4.0 h1:vkRCc1y3whKA7iL9Ep0fSGVuJfqjix0ica9UflHORO8= -codeberg.org/go-fonts/latin-modern v0.4.0/go.mod h1:BF68mZznJ9QHn+hic9ks2DaFl4sR5YhfM6xTYaP9vNw= -codeberg.org/go-fonts/liberation v0.5.0 h1:SsKoMO1v1OZmzkG2DY+7ZkCL9U+rrWI09niOLfQ5Bo0= -codeberg.org/go-fonts/liberation v0.5.0/go.mod h1:zS/2e1354/mJ4pGzIIaEtm/59VFCFnYC7YV6YdGl5GU= -codeberg.org/go-latex/latex v0.1.0 h1:hoGO86rIbWVyjtlDLzCqZPjNykpWQ9YuTZqAzPcfL3c= -codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9Dny04MHMw= -codeberg.org/go-pdf/fpdf v0.10.0 h1:u+w669foDDx5Ds43mpiiayp40Ov6sZalgcPMDBcZRd4= -codeberg.org/go-pdf/fpdf v0.10.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= -git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= -git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= -git.sr.ht/~sbinet/gg v0.6.0 h1:RIzgkizAk+9r7uPzf/VfbJHBMKUr0F5hRFxTUGMnt38= -git.sr.ht/~sbinet/gg v0.6.0/go.mod h1:uucygbfC9wVPQIfrmwM2et0imr8L7KQWywX0xpFMm94= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0= @@ -27,10 +12,6 @@ github.com/a-h/protocol v0.0.0-20240704131721-1e461c188041 h1:2enlC41iOwWklx9ZUq github.com/a-h/protocol v0.0.0-20240704131721-1e461c188041/go.mod h1:Gm0KywveHnkiIhqFSMZglXwWZRQICg3KDWLYdglv/d8= github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/amacneil/dbmate v1.16.2 h1:ovhzYRR2JT5EZbISNtg7MZmLM51ZrHLKoEKMPhiFz5E= github.com/amacneil/dbmate v1.16.2/go.mod h1:d+2u+wE7GpLepbKxi231FXoi7thXuI1AND5CRG18RcI= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= @@ -41,8 +22,6 @@ github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAK github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bradleyjkemp/cupaloy v1.3.0 h1:UJ0YJuhkMXEQcaoQNSCmK8og6GEVW/eDhAZuizvcpOY= github.com/bradleyjkemp/cupaloy v1.3.0/go.mod h1:Au1Xw1sgaJ5iSFktEhYsS0dbQiS1B0/XMXl+42y9Ilk= -github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= -github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= @@ -65,8 +44,6 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -79,7 +56,6 @@ github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kataras/i18n v0.0.8 h1:thiDRqq4fN2sQOK5CwR5Yh1yT7swP6B3wnadILhqjhk= github.com/kataras/i18n v0.0.8/go.mod h1:M/yRAqQ3Y7z2oSpotxG/+nPrgsJLas6t0kEJfIJk98E= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -136,7 +112,6 @@ github.com/urfave/cli/v2 v2.24.2 h1:q1VA+ofZ8SWfEKB9xXHUD4QZaeI9e+ItEqSbfH2JBXk= github.com/urfave/cli/v2 v2.24.2/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04 h1:qXafrlZL1WsJW5OokjraLLRURHiw0OzKHD/RNdspp4w= github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04/go.mod h1:FiwNQxz6hGoNFBC4nIx+CxZhI3nne5RmIOlT/MXcSD4= @@ -155,20 +130,13 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= -golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -177,15 +145,11 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -209,18 +173,11 @@ golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -gonum.org/v1/plot v0.16.0 h1:dK28Qx/Ky4VmPUN/2zeW0ELyM6ucDnBAj5yun7M9n1g= -gonum.org/v1/plot v0.16.0/go.mod h1:Xz6U1yDMi6Ni6aaXILqmVIb6Vro8E+K7Q/GeeH+Pn0c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= @@ -233,6 +190,3 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/ride/ride.go b/ride/ride.go index 52f95b8..5471535 100644 --- a/ride/ride.go +++ b/ride/ride.go @@ -13,10 +13,6 @@ import ( "github.com/jftuga/geodist" "github.com/martinlehoux/kagamigo/kcore" "github.com/tkrajina/gpxgo/gpx" - "gonum.org/v1/plot" - "gonum.org/v1/plot/plotter" - "gonum.org/v1/plot/plotutil" - "gonum.org/v1/plot/vg" ) const garminTrackPointExtensionNamespace = "http://www.garmin.com/xmlschemas/TrackPointExtension/v1" @@ -303,88 +299,3 @@ func (r *Ride) ClimbFromDist(startDist, endDist float64) Climb { } return Climb{ride: *r, rideStart: start, rideEnd: end} } - -func Plot(r *Ride, outputFile string) { - r.check() - - pts := make(plotter.XYs, r.Len()) - for i := 0; i < r.Len(); i++ { - pts[i].X = r.DistanceM(i) / 1000 // Convert distance to kilometers - pts[i].Y = r.ElevationM(i) - } - - p := plot.New() - p.Title.Text = "Ride Elevation Profile" - p.X.Label.Text = "Distance (km)" - p.Y.Label.Text = "Elevation (m)" - - line, err := plotter.NewLine(pts) - kcore.Expect(err, "failed to create line plot") - p.Add(line) - - err = p.Save(10*vg.Inch, 4*vg.Inch, outputFile) - kcore.Expect(err, "failed to save plot") -} - -func PlotScore(r *Ride, startKm, endKm float64, outputFile string) { - r.check() - - startIndex := 0 - for i := 0; i < r.Len(); i++ { - if r.DistanceM(i) >= startKm*1000 { - startIndex = i - break - } - } - - pts1 := make(plotter.XYs, 0) - endIndex := 0 - for i := startIndex + 1; i < r.Len(); i++ { - if r.DistanceM(i) > endKm*1000 { - endIndex = i - break - } - score1 := Score(*r, startIndex, i) - pts1 = append(pts1, plotter.XY{ - X: r.DistanceM(i) / 1000, // Convert distance to kilometers - Y: score1, - }) - } - pts2 := make(plotter.XYs, 0) - for i := startIndex; i < endIndex; i++ { - score2 := Score(*r, i, endIndex) - pts2 = append(pts2, plotter.XY{ - X: r.DistanceM(i) / 1000, // Convert distance to kilometers - Y: score2, - }) - } - - p := plot.New() - p.Title.Text = "Ride Score Profile" - p.X.Label.Text = "Distance (km)" - p.Y.Label.Text = "Score" - - line1, err := plotter.NewLine(pts1) - kcore.Expect(err, "failed to create line plot for score1") - line1.Color = plotutil.Color(0) // First line color - maxIndex := 0 - maxValue := pts1[0].Y - for i, pt := range pts1 { - if pt.Y > maxValue { - maxValue = pt.Y - maxIndex = i - } - } - println("Max value of line 1 is at distance:", pts1[maxIndex].X, "km") - - line2, err := plotter.NewLine(pts2) - kcore.Expect(err, "failed to create line plot for score2") - line2.Color = plotutil.Color(1) // Second line color - - p.Add(line1, line2) - p.Legend.Add("Score (start to i)", line1) - p.Legend.Add("Score (i to end)", line2) - - err = p.Save(10*vg.Inch, 4*vg.Inch, outputFile) - kcore.Expect(err, "failed to save plot") -} -- cgit v1.2.3