From 71c42cd1ecbbb839350b6af8e764f6164b1795b3 Mon Sep 17 00:00:00 2001
From: XANTRONIX Industrial <xan@xantronix.com>
Date: Mon, 3 Mar 2025 10:43:18 -0500
Subject: [PATCH] Rename xmet-sounding-graph to -plot; add ability to plot
 hodographs

---
 bin/xmet-sounding-graph | 51 --------------------------
 bin/xmet-sounding-plot  | 79 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+), 51 deletions(-)
 delete mode 100755 bin/xmet-sounding-graph
 create mode 100755 bin/xmet-sounding-plot

diff --git a/bin/xmet-sounding-graph b/bin/xmet-sounding-graph
deleted file mode 100755
index 717316b..0000000
--- a/bin/xmet-sounding-graph
+++ /dev/null
@@ -1,51 +0,0 @@
-#! /usr/bin/env python3
-
-import argparse
-import cairo
-import shapely
-
-from xmet.db       import Database
-from xmet.sounding import Sounding
-from xmet.skew_t   import SkewTGraph, SkewTLegend
-
-IMAGE_WIDTH  = 800
-IMAGE_HEIGHT = 800
-
-GRAPH_WIDTH  = 800 - 128
-GRAPH_HEIGHT = 800 - 128
-
-parser = argparse.ArgumentParser(
-    description = 'Graph most recent valid sounding for location'
-)
-
-parser.add_argument('db',        help='XMET SQLite3 database')
-parser.add_argument('lat',       help='Latitude')
-parser.add_argument('lon',       help='Longitude')
-parser.add_argument('timestamp', help='Timestamp in YYYY-MM-DD HH:MM:SS (UTC)')
-parser.add_argument('output',    help='Output SVG file')
-
-args = parser.parse_args()
-
-db = Database.connect(args.db)
-
-location = shapely.Point(float(args.lon), float(args.lat))
-sounding = Sounding.valid_by_location(db, location, args.timestamp)
-
-print(f"Graphing {sounding.station} sounding at {sounding.timestamp_observed}")
-
-skew_t = SkewTGraph(GRAPH_WIDTH, GRAPH_HEIGHT)
-
-with cairo.SVGSurface(args.output, IMAGE_WIDTH, IMAGE_HEIGHT) as surface:
-    cr = cairo.Context(surface)
-
-    cr.set_source_rgb(1, 1, 1)
-    cr.rectangle(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT)
-    cr.fill()
-
-    skew_t.draw(cr, 64, 64, sounding)
-
-    cr.set_source_rgb(0, 0, 0)
-    cr.rectangle(64, 64, GRAPH_WIDTH, GRAPH_HEIGHT)
-    cr.stroke()
-
-    SkewTLegend.draw_for_graph(cr, skew_t, 64, 64)
diff --git a/bin/xmet-sounding-plot b/bin/xmet-sounding-plot
new file mode 100755
index 0000000..d05bb2e
--- /dev/null
+++ b/bin/xmet-sounding-plot
@@ -0,0 +1,79 @@
+#! /usr/bin/env python3
+
+import argparse
+import cairo
+import shapely
+
+from xmet.db        import Database
+from xmet.sounding  import Sounding
+from xmet.skew_t    import SkewTGraph, SkewTLegend
+from xmet.hodograph import Hodograph
+
+IMAGE_WIDTH  = 800
+IMAGE_HEIGHT = 800
+
+GRAPH_WIDTH  = 800 - 128
+GRAPH_HEIGHT = 800 - 128
+
+def plot_skew_t(sounding: Sounding, output: str):
+    print(f"Plotting Skew-T chart of {sounding.station} sounding at {sounding.timestamp_observed} to {output}")
+
+    with cairo.SVGSurface(output, IMAGE_WIDTH, IMAGE_HEIGHT) as surface:
+        cr = cairo.Context(surface)
+
+        cr.set_source_rgb(1, 1, 1)
+        cr.rectangle(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT)
+        cr.fill()
+
+        skew_t = SkewTGraph(GRAPH_WIDTH, GRAPH_HEIGHT)
+        skew_t.draw(cr, 64, 64, sounding)
+
+        cr.set_source_rgb(0, 0, 0)
+        cr.rectangle(64, 64, GRAPH_WIDTH, GRAPH_HEIGHT)
+        cr.stroke()
+
+        SkewTLegend.draw_for_graph(cr, skew_t, 64, 64)
+
+def plot_hodograph(sounding: Sounding, output: str):
+    print(f"Plotting hodograph of {sounding.station} sounding at {sounding.timestamp_observed} to {output}")
+
+    with cairo.SVGSurface(output, IMAGE_WIDTH, IMAGE_HEIGHT) as surface:
+        cr = cairo.Context(surface)
+
+        cr.save()
+        cr.set_source_rgb(1, 1, 1)
+        cr.rectangle(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT)
+        cr.fill()
+        cr.restore()
+
+        cr.set_source_rgb(0, 0, 0)
+        cr.rectangle(64, 64, GRAPH_WIDTH, GRAPH_HEIGHT)
+        cr.stroke()
+
+        hodograph = Hodograph(GRAPH_WIDTH, GRAPH_HEIGHT)
+        hodograph.draw(cr, 64, 64, sounding)
+
+parser = argparse.ArgumentParser(
+    description = 'Graph most recent valid sounding for location'
+)
+
+parser.add_argument('--skew-t',    type=str, help='Plot a Skew-T chart to the specified SVG file')
+parser.add_argument('--hodograph', type=str, help='Plot a hodograph to the specified SVG file')
+
+parser.add_argument('db',        help='XMET SQLite3 database')
+parser.add_argument('lat',       help='Latitude')
+parser.add_argument('lon',       help='Longitude')
+parser.add_argument('timestamp', help='Timestamp in YYYY-MM-DD HH:MM:SS (UTC)')
+
+args = parser.parse_args()
+
+db = Database.connect(args.db)
+
+location = shapely.Point(float(args.lon), float(args.lat))
+sounding = Sounding.valid_by_location(db, location, args.timestamp)
+
+if args.skew_t is not None:
+    plot_skew_t(sounding, args.skew_t)
+
+if args.hodograph is not None:
+    plot_hodograph(sounding, args.hodograph)