rsplot 0.2.7__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. {rsplot-0.2.7 → rsplot-0.3.1}/PKG-INFO +115 -12
  2. rsplot-0.3.1/README.md +250 -0
  3. {rsplot-0.2.7 → rsplot-0.3.1}/pyproject.toml +9 -2
  4. rsplot-0.3.1/src/rsplot/__init__.py +10 -0
  5. rsplot-0.3.1/src/rsplot/cli.py +937 -0
  6. rsplot-0.3.1/src/rsplot/commands/__init__.py +1 -0
  7. rsplot-0.3.1/src/rsplot/commands/common.py +112 -0
  8. rsplot-0.3.1/src/rsplot/commands/fnr.py +262 -0
  9. rsplot-0.3.1/src/rsplot/commands/forecast.py +349 -0
  10. rsplot-0.3.1/src/rsplot/commands/meteo.py +381 -0
  11. rsplot-0.3.1/src/rsplot/commands/overlay.py +267 -0
  12. rsplot-0.3.1/src/rsplot/commands/raster.py +386 -0
  13. rsplot-0.3.1/src/rsplot/commands/recent.py +164 -0
  14. rsplot-0.3.1/src/rsplot/commands/reconstruct.py +220 -0
  15. rsplot-0.3.1/src/rsplot/commands/station.py +135 -0
  16. rsplot-0.3.1/src/rsplot/commands/station_trend.py +317 -0
  17. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/config.py +46 -0
  18. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/fnr.py +66 -159
  19. rsplot-0.3.1/src/rsplot/geo/boundaries.py +474 -0
  20. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/geo/gridding.py +12 -4
  21. rsplot-0.3.1/src/rsplot/geo/processing.py +120 -0
  22. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/plotting/fnr.py +18 -91
  23. rsplot-0.2.7/src/rsplot/plotting/raster.py → rsplot-0.3.1/src/rsplot/plotting/map_frame.py +116 -119
  24. rsplot-0.3.1/src/rsplot/plotting/meteo.py +158 -0
  25. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/plotting/overlay.py +30 -101
  26. rsplot-0.3.1/src/rsplot/plotting/raster.py +103 -0
  27. rsplot-0.3.1/src/rsplot/plotting/station.py +172 -0
  28. rsplot-0.3.1/src/rsplot/plotting/station_trend.py +320 -0
  29. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/plotting/styles.py +7 -6
  30. rsplot-0.3.1/src/rsplot/plotting/wind.py +80 -0
  31. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/readers/__init__.py +3 -1
  32. rsplot-0.3.1/src/rsplot/readers/_tropomi.py +130 -0
  33. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/readers/base.py +66 -0
  34. rsplot-0.3.1/src/rsplot/readers/era5.py +201 -0
  35. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/readers/era5_wind.py +21 -70
  36. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/readers/forecast.py +61 -27
  37. rsplot-0.3.1/src/rsplot/readers/guokong.py +451 -0
  38. rsplot-0.3.1/src/rsplot/readers/reconstruct.py +436 -0
  39. rsplot-0.3.1/src/rsplot/readers/tropomi_hcho.py +32 -0
  40. rsplot-0.3.1/src/rsplot/readers/tropomi_no2.py +33 -0
  41. rsplot-0.3.1/src/rsplot/readers/tropomi_o3.py +35 -0
  42. rsplot-0.3.1/src/rsplot/readers/tropomi_o3pr.py +33 -0
  43. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/recent.py +43 -61
  44. rsplot-0.3.1/src/rsplot/result_builders/__init__.py +25 -0
  45. rsplot-0.3.1/src/rsplot/result_builders/common.py +138 -0
  46. rsplot-0.3.1/src/rsplot/result_builders/fnr.py +189 -0
  47. rsplot-0.3.1/src/rsplot/result_builders/forecast.py +113 -0
  48. rsplot-0.3.1/src/rsplot/result_builders/meteo.py +171 -0
  49. rsplot-0.3.1/src/rsplot/result_builders/overlay.py +75 -0
  50. rsplot-0.3.1/src/rsplot/result_builders/raster.py +72 -0
  51. rsplot-0.3.1/src/rsplot/result_builders/reconstruct.py +85 -0
  52. rsplot-0.3.1/src/rsplot/result_builders/station.py +221 -0
  53. rsplot-0.3.1/src/rsplot/result_builders/station_trend.py +229 -0
  54. rsplot-0.3.1/src/rsplot/results.py +45 -0
  55. rsplot-0.3.1/src/rsplot/stats.py +36 -0
  56. rsplot-0.3.1/src/rsplot/temporal.py +224 -0
  57. rsplot-0.2.7/README.md +0 -147
  58. rsplot-0.2.7/src/rsplot/__init__.py +0 -3
  59. rsplot-0.2.7/src/rsplot/cli.py +0 -1939
  60. rsplot-0.2.7/src/rsplot/geo/boundaries.py +0 -281
  61. rsplot-0.2.7/src/rsplot/plotting/station.py +0 -329
  62. rsplot-0.2.7/src/rsplot/readers/guokong.py +0 -143
  63. rsplot-0.2.7/src/rsplot/readers/tropomi_hcho.py +0 -126
  64. rsplot-0.2.7/src/rsplot/readers/tropomi_no2.py +0 -102
  65. rsplot-0.2.7/src/rsplot/readers/tropomi_o3.py +0 -104
  66. rsplot-0.2.7/src/rsplot/readers/tropomi_o3pr.py +0 -103
  67. rsplot-0.2.7/src/rsplot/results.py +0 -793
  68. {rsplot-0.2.7 → rsplot-0.3.1}/.gitignore +0 -0
  69. {rsplot-0.2.7 → rsplot-0.3.1}/LICENSE +0 -0
  70. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/__main__.py +0 -0
  71. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/geo/__init__.py +0 -0
  72. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/plotting/__init__.py +0 -0
  73. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/plotting/colormaps.py +0 -0
  74. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/tiles/__init__.py +0 -0
  75. {rsplot-0.2.7 → rsplot-0.3.1}/src/rsplot/tiles/tianditu.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: rsplot
3
- Version: 0.2.7
3
+ Version: 0.3.1
4
4
  Summary: CLI tool for plotting Remote Sensing data, designed for Agent.
5
5
  Project-URL: Repository, https://git.lug.ustc.edu.cn/yaoyhu/rsplot
6
6
  Project-URL: GitHub, https://github.com/yaoyhu/rsplot
@@ -227,8 +227,8 @@ Description-Content-Type: text/markdown
227
227
 
228
228
  # rsplot
229
229
 
230
- `rsplot` is an Agent-oriented command-line tool for plotting remote-sensing and
231
- air-quality data. It is designed to provide a small, stable CLI surface for
230
+ `rsplot` is an Agent-oriented command-line tool for plotting remote-sensing,
231
+ reconstructed, and air-quality data. It provides a small, stable CLI surface for
232
232
  [tianpu-agent](https://git.lug.ustc.edu.cn/yaoyhu/tianpu-agent).
233
233
 
234
234
 
@@ -247,6 +247,19 @@ uv add rsplot
247
247
  uv run rsplot --help
248
248
  ```
249
249
 
250
+ ### Development releases
251
+
252
+ Every push to `main` publishes a PEP 440 development release such as
253
+ `0.3.1.dev4`. Stable installs continue to ignore these releases. To follow the
254
+ latest development build, opt in once:
255
+
256
+ ```bash
257
+ uv tool install rsplot --prerelease allow
258
+ uv tool upgrade rsplot
259
+ ```
260
+
261
+ The prerelease setting is retained by later `uv tool upgrade` commands.
262
+
250
263
  For local development:
251
264
 
252
265
  ```bash
@@ -282,6 +295,13 @@ hcho = "/path/to/HCHO"
282
295
  guokong = "/path/to/guokong_combine"
283
296
  era5 = "/path/to/era5"
284
297
  forecast = "/path/to/forecast"
298
+ reconstruct = "/path/to/reconstruct"
299
+
300
+ # Optional lower-level boundary override for a direct-administered city.
301
+ # [subdivision_overrides."中山市"]
302
+ # path = "/path/to/中山市镇街界线.shp"
303
+ # name_field = "镇街名称"
304
+ # level = "township"
285
305
 
286
306
  # Optional satellite basemap key. Leave commented unless you have a real key.
287
307
  # [tianditu]
@@ -307,6 +327,7 @@ export RSPLOT_DATA_DIR_HCHO="/path/to/HCHO"
307
327
  export RSPLOT_DATA_DIR_GUOKONG="/path/to/guokong_combine"
308
328
  export RSPLOT_DATA_DIR_ERA5="/path/to/era5"
309
329
  export RSPLOT_DATA_DIR_FORECAST="/path/to/forecast"
330
+ export RSPLOT_DATA_DIR_RECONSTRUCT="/path/to/reconstruct"
310
331
  export RSPLOT_HCHO_CMAP_FILE="/path/to/256x3_rgb_table.txt"
311
332
  ```
312
333
 
@@ -314,6 +335,11 @@ Command-line directory options, such as `--data-dir`, take precedence for the
314
335
  command being run. If no TianDiTu API key is configured, use `--basemap none`
315
336
  to avoid requesting satellite tiles.
316
337
 
338
+ City subdivision overrides replace the county layer only for the configured
339
+ city. Their source CRS is converted to the CRS of the standard city boundary.
340
+ This lets direct-administered towns or streets appear in maps and spatial
341
+ summaries, and makes qualified inputs such as `中山/板芙` resolvable.
342
+
317
343
  ## Usage
318
344
 
319
345
  The examples below assume data paths are configured and readable.
@@ -334,24 +360,63 @@ rsplot raster 安徽 20260227 -p o3pr -o o3pr_anhui_20260227.png
334
360
  # Plot an explicit TROPOMI date range.
335
361
  rsplot raster 长三角 20260101-20260131 -p no2 -o no2_yrd_202601.png
336
362
 
337
- # Plot gridded air-quality forecast initialized at a specific hour.
363
+ # Reconstructed-grid input is China standard time; rsplot converts it to the
364
+ # matching UTC archive filename. This reads 2026051100.nc.
365
+ rsplot reconstruct 安徽 2026051108 --var PM2.5 \
366
+ -o reconstruct_anhui_pm25.png
367
+
368
+ # Date-only input selects the latest complete hour in that China-time day.
369
+ rsplot reconstruct 合肥 20260511 --var O3 --res 0.01 \
370
+ -o reconstruct_hefei_o3.png
371
+
372
+ # Forecast input is China standard time; rsplot converts it
373
+ # to the matching UTC archive initialization hour before reading.
338
374
  rsplot forecast 安徽 2026063000 --lead 24 --var O3 -o forecast_anhui_o3.png
339
375
 
340
- # Date-only forecast input automatically selects the latest initialized hour.
376
+ # Date-only input selects the latest initialization within that China-time day.
341
377
  rsplot forecast 合肥 20260630 --lead 72 --var PM2.5 -o forecast_hefei_pm25.png
342
378
 
343
379
  # Overlay station observations on the forecast valid time.
344
380
  rsplot forecast 合肥 2026041409 --lead 6 --var O3 --station-overlay -o forecast_station_hefei_o3.png
345
381
 
382
+ # Plot ERA5 2 m temperature. Input hours are China standard time; rsplot
383
+ # converts them to the matching UTC archive day and hour automatically.
384
+ rsplot meteo 南京 2026051115 --temp-level 2m -o meteo_nanjing_t2m.png
385
+
386
+ # Plot black 850 hPa wind arrows; length represents speed and no wind
387
+ # colorbar is drawn. The reference arrow gives the speed scale.
388
+ rsplot meteo 南京 2026051115 --wind-level 850 -o meteo_nanjing_wind850.png
389
+
390
+ # Overlay black wind arrows on a temperature background. Only the temperature
391
+ # colorbar is drawn.
392
+ rsplot meteo 南京 2026051115 --temp-level 850 \
393
+ --wind-level 850 -o meteo_nanjing_t850_wind850.png
394
+
395
+ # Overlay station observations with black wind arrows.
396
+ rsplot meteo 南京 2026051115 --station-var O3 \
397
+ --wind-level 850 -o meteo_nanjing_o3_wind850.png
398
+
399
+ # Temperature, stations, and wind can be combined. The two colorbars describe
400
+ # temperature and station concentration; wind magnitude is encoded by length.
401
+ rsplot meteo 南京 2026051115 --temp-level 850 --station-var O3 \
402
+ --wind-level 850 -o meteo_nanjing_t850_o3_wind850.png
403
+
346
404
  # Plot national monitoring station observations.
347
405
  rsplot station 合肥 2026041415 --var O3 -o station_hefei_o3.png
348
406
 
349
- # Overlay hourly ERA5 10 m wind vectors on station observations.
350
- # Station timestamps default to Asia/Shanghai and are matched to ERA5 UTC.
351
- rsplot station 合肥 2026041415 --var O3 --wind-level 10m -o station_wind_hefei_o3.png
407
+ # Plot one station's hourly observations over the latest seven days.
408
+ rsplot trend 3347A 20260520 --days 7 --var O3 -o trend_3347A_o3_7d.png
352
409
 
353
- # Pressure-level wind is also supported (1000/925/850/700/500 hPa).
354
- rsplot station 安徽 2026041415 --var PM2.5 --wind-level 850 -o station_wind_anhui_pm25.png
410
+ # A single day and an explicit date range are also supported.
411
+ rsplot trend 3347A 20260520 --days 1 --var O3 -o trend_3347A_o3_day.png
412
+ rsplot trend 3347A 20260501-20260507 --var PM2.5 -o trend_3347A_pm25.png
413
+
414
+ # Plot all regional stations as grey lines plus the hourly station mean.
415
+ rsplot trend 重庆 20260520 --days 7 --var O3 --region -o trend_chongqing_o3.png
416
+
417
+ # Plot only the regional mean and highlight one or more explicit stations.
418
+ rsplot trend 重庆 20260520 --days 7 --var O3 --region --view mean \
419
+ --focus-station 3347A --threshold 200 -o trend_chongqing_focus.png
355
420
 
356
421
  # Overlay satellite raster data and station observations.
357
422
  rsplot overlay 合肥 2026041415 -p no2 --var NO2 -o overlay_hefei_no2.png
@@ -367,8 +432,46 @@ rsplot fnr 合肥 20260114 --voc-threshold 0.8 --nox-threshold 1.8 --display-max
367
432
  ```
368
433
 
369
434
  When `-o/--output` is provided, `rsplot` writes the image to that path and also
370
- writes a JSON sidecar with the same base name.
435
+ writes a JSON sidecar with the same base name. Reconstructed-grid JSON records
436
+ both the China-time input and matched UTC archive hour, source file, native and
437
+ output resolution, regional statistics, administrative summaries, and hotspots.
371
438
 
372
439
  ## License
373
440
 
374
441
  This project is distributed under the license in `LICENSE`.
442
+
443
+ ## Publishing
444
+
445
+ The package version is derived from Git by `hatch-vcs`; do not add a static
446
+ `project.version` or make version-bump commits. The latest `vX.Y.Z` tag is the
447
+ stable version. Commits after it build as the next patch development series:
448
+
449
+ ```text
450
+ v0.3.0 -> 0.3.0
451
+ first commit -> 0.3.1.dev1
452
+ second commit -> 0.3.1.dev2
453
+ v0.3.1 -> 0.3.1
454
+ ```
455
+
456
+ GitHub Actions publishes every `main` push through the `pypi-dev` environment
457
+ and every `v*` tag through `pypi`. Configure two PyPI Trusted Publishers with
458
+ the same owner, repository, and workflow, differing only by environment:
459
+
460
+ ```text
461
+ Owner: yaoyhu
462
+ Repository: rsplot
463
+ Workflow: publish.yml
464
+ Environment: pypi-dev
465
+ Environment: pypi
466
+ ```
467
+
468
+ Leave `pypi-dev` automatic for continuous development uploads. Protect the
469
+ `pypi` GitHub environment with required reviewers so stable releases need an
470
+ explicit approval.
471
+
472
+ To make a stable release after the desired commit is on GitHub:
473
+
474
+ ```bash
475
+ git tag -a v0.3.1 -m v0.3.1
476
+ git push github v0.3.1
477
+ ```
rsplot-0.3.1/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # rsplot
2
+
3
+ `rsplot` is an Agent-oriented command-line tool for plotting remote-sensing,
4
+ reconstructed, and air-quality data. It provides a small, stable CLI surface for
5
+ [tianpu-agent](https://git.lug.ustc.edu.cn/yaoyhu/tianpu-agent).
6
+
7
+
8
+ ## Installation
9
+
10
+ Run directly with `uvx`:
11
+
12
+ ```bash
13
+ uvx rsplot --help
14
+ ```
15
+
16
+ Or install it in a project environment:
17
+
18
+ ```bash
19
+ uv add rsplot
20
+ uv run rsplot --help
21
+ ```
22
+
23
+ ### Development releases
24
+
25
+ Every push to `main` publishes a PEP 440 development release such as
26
+ `0.3.1.dev4`. Stable installs continue to ignore these releases. To follow the
27
+ latest development build, opt in once:
28
+
29
+ ```bash
30
+ uv tool install rsplot --prerelease allow
31
+ uv tool upgrade rsplot
32
+ ```
33
+
34
+ The prerelease setting is retained by later `uv tool upgrade` commands.
35
+
36
+ For local development:
37
+
38
+ ```bash
39
+ git clone https://github.com/yaoyhu/rsplot.git
40
+ cd rsplot
41
+ uv sync
42
+ uv run rsplot --help
43
+ ```
44
+
45
+ ## Configuration
46
+
47
+ `rsplot` does not ship site-specific data paths. Configure local satellite,
48
+ station, boundary, and font paths with a TOML file:
49
+
50
+ ```bash
51
+ mkdir -p ~/.config/rsplot
52
+ cp config.example.toml ~/.config/rsplot/config.toml
53
+ ```
54
+
55
+ Then edit `~/.config/rsplot/config.toml`:
56
+
57
+ ```toml
58
+ [paths]
59
+ geojson_dir = "/path/to/geojson"
60
+ font_dir = "/path/to/fonts"
61
+ # hcho_cmap_file = "/path/to/256x3_rgb_table.txt"
62
+
63
+ [paths.data_dirs]
64
+ no2 = "/path/to/NO2"
65
+ o3 = "/path/to/O3"
66
+ o3pr = "/path/to/O3PR"
67
+ hcho = "/path/to/HCHO"
68
+ guokong = "/path/to/guokong_combine"
69
+ era5 = "/path/to/era5"
70
+ forecast = "/path/to/forecast"
71
+ reconstruct = "/path/to/reconstruct"
72
+
73
+ # Optional lower-level boundary override for a direct-administered city.
74
+ # [subdivision_overrides."中山市"]
75
+ # path = "/path/to/中山市镇街界线.shp"
76
+ # name_field = "镇街名称"
77
+ # level = "township"
78
+
79
+ # Optional satellite basemap key. Leave commented unless you have a real key.
80
+ # [tianditu]
81
+ # api_key = "your-real-key"
82
+ ```
83
+
84
+ You can also point to a different config file:
85
+
86
+ ```bash
87
+ export RSPLOT_CONFIG="/path/to/rsplot.toml"
88
+ ```
89
+
90
+ Environment variables override TOML values:
91
+
92
+ ```bash
93
+ export TIANDITU_API_KEY="your-key"
94
+ export RSPLOT_GEOJSON_DIR="/path/to/geojson"
95
+ export RSPLOT_FONT_DIR="/path/to/fonts"
96
+ export RSPLOT_DATA_DIR_NO2="/path/to/NO2"
97
+ export RSPLOT_DATA_DIR_O3="/path/to/O3"
98
+ export RSPLOT_DATA_DIR_O3PR="/path/to/O3PR"
99
+ export RSPLOT_DATA_DIR_HCHO="/path/to/HCHO"
100
+ export RSPLOT_DATA_DIR_GUOKONG="/path/to/guokong_combine"
101
+ export RSPLOT_DATA_DIR_ERA5="/path/to/era5"
102
+ export RSPLOT_DATA_DIR_FORECAST="/path/to/forecast"
103
+ export RSPLOT_DATA_DIR_RECONSTRUCT="/path/to/reconstruct"
104
+ export RSPLOT_HCHO_CMAP_FILE="/path/to/256x3_rgb_table.txt"
105
+ ```
106
+
107
+ Command-line directory options, such as `--data-dir`, take precedence for the
108
+ command being run. If no TianDiTu API key is configured, use `--basemap none`
109
+ to avoid requesting satellite tiles.
110
+
111
+ City subdivision overrides replace the county layer only for the configured
112
+ city. Their source CRS is converted to the CRS of the standard city boundary.
113
+ This lets direct-administered towns or streets appear in maps and spatial
114
+ summaries, and makes qualified inputs such as `中山/板芙` resolvable.
115
+
116
+ ## Usage
117
+
118
+ The examples below assume data paths are configured and readable.
119
+
120
+ ```bash
121
+ # Show available commands and options.
122
+ rsplot --help
123
+
124
+ # Plot a single-day TROPOMI raster.
125
+ rsplot raster 合肥 20260115 -p no2 -o ./logs/hcho/raster_city_jiujiang_hcho.png
126
+
127
+ # Plot a 30-day TROPOMI window mean.
128
+ rsplot raster 安徽 20260131 -p hcho --days 30 -o hcho_anhui_202601.png
129
+
130
+ # Plot a TROPOMI ozone-profile tropospheric column raster.
131
+ rsplot raster 安徽 20260227 -p o3pr -o o3pr_anhui_20260227.png
132
+
133
+ # Plot an explicit TROPOMI date range.
134
+ rsplot raster 长三角 20260101-20260131 -p no2 -o no2_yrd_202601.png
135
+
136
+ # Reconstructed-grid input is China standard time; rsplot converts it to the
137
+ # matching UTC archive filename. This reads 2026051100.nc.
138
+ rsplot reconstruct 安徽 2026051108 --var PM2.5 \
139
+ -o reconstruct_anhui_pm25.png
140
+
141
+ # Date-only input selects the latest complete hour in that China-time day.
142
+ rsplot reconstruct 合肥 20260511 --var O3 --res 0.01 \
143
+ -o reconstruct_hefei_o3.png
144
+
145
+ # Forecast input is China standard time; rsplot converts it
146
+ # to the matching UTC archive initialization hour before reading.
147
+ rsplot forecast 安徽 2026063000 --lead 24 --var O3 -o forecast_anhui_o3.png
148
+
149
+ # Date-only input selects the latest initialization within that China-time day.
150
+ rsplot forecast 合肥 20260630 --lead 72 --var PM2.5 -o forecast_hefei_pm25.png
151
+
152
+ # Overlay station observations on the forecast valid time.
153
+ rsplot forecast 合肥 2026041409 --lead 6 --var O3 --station-overlay -o forecast_station_hefei_o3.png
154
+
155
+ # Plot ERA5 2 m temperature. Input hours are China standard time; rsplot
156
+ # converts them to the matching UTC archive day and hour automatically.
157
+ rsplot meteo 南京 2026051115 --temp-level 2m -o meteo_nanjing_t2m.png
158
+
159
+ # Plot black 850 hPa wind arrows; length represents speed and no wind
160
+ # colorbar is drawn. The reference arrow gives the speed scale.
161
+ rsplot meteo 南京 2026051115 --wind-level 850 -o meteo_nanjing_wind850.png
162
+
163
+ # Overlay black wind arrows on a temperature background. Only the temperature
164
+ # colorbar is drawn.
165
+ rsplot meteo 南京 2026051115 --temp-level 850 \
166
+ --wind-level 850 -o meteo_nanjing_t850_wind850.png
167
+
168
+ # Overlay station observations with black wind arrows.
169
+ rsplot meteo 南京 2026051115 --station-var O3 \
170
+ --wind-level 850 -o meteo_nanjing_o3_wind850.png
171
+
172
+ # Temperature, stations, and wind can be combined. The two colorbars describe
173
+ # temperature and station concentration; wind magnitude is encoded by length.
174
+ rsplot meteo 南京 2026051115 --temp-level 850 --station-var O3 \
175
+ --wind-level 850 -o meteo_nanjing_t850_o3_wind850.png
176
+
177
+ # Plot national monitoring station observations.
178
+ rsplot station 合肥 2026041415 --var O3 -o station_hefei_o3.png
179
+
180
+ # Plot one station's hourly observations over the latest seven days.
181
+ rsplot trend 3347A 20260520 --days 7 --var O3 -o trend_3347A_o3_7d.png
182
+
183
+ # A single day and an explicit date range are also supported.
184
+ rsplot trend 3347A 20260520 --days 1 --var O3 -o trend_3347A_o3_day.png
185
+ rsplot trend 3347A 20260501-20260507 --var PM2.5 -o trend_3347A_pm25.png
186
+
187
+ # Plot all regional stations as grey lines plus the hourly station mean.
188
+ rsplot trend 重庆 20260520 --days 7 --var O3 --region -o trend_chongqing_o3.png
189
+
190
+ # Plot only the regional mean and highlight one or more explicit stations.
191
+ rsplot trend 重庆 20260520 --days 7 --var O3 --region --view mean \
192
+ --focus-station 3347A --threshold 200 -o trend_chongqing_focus.png
193
+
194
+ # Overlay satellite raster data and station observations.
195
+ rsplot overlay 合肥 2026041415 -p no2 --var NO2 -o overlay_hefei_no2.png
196
+
197
+ # Plot an FNR regime map with the default 7-day window.
198
+ rsplot fnr 合肥 20260114 -o fnr_hefei.png
199
+
200
+ # Plot an FNR regime map with an explicit date range.
201
+ rsplot fnr 长三角 20260101-20260130 -o fnr_yrd_202601.png
202
+
203
+ # Override FNR regime thresholds for agent-driven sensitivity tests.
204
+ rsplot fnr 合肥 20260114 --voc-threshold 0.8 --nox-threshold 1.8 --display-max 5 -o fnr_hefei_sensitivity.png
205
+ ```
206
+
207
+ When `-o/--output` is provided, `rsplot` writes the image to that path and also
208
+ writes a JSON sidecar with the same base name. Reconstructed-grid JSON records
209
+ both the China-time input and matched UTC archive hour, source file, native and
210
+ output resolution, regional statistics, administrative summaries, and hotspots.
211
+
212
+ ## License
213
+
214
+ This project is distributed under the license in `LICENSE`.
215
+
216
+ ## Publishing
217
+
218
+ The package version is derived from Git by `hatch-vcs`; do not add a static
219
+ `project.version` or make version-bump commits. The latest `vX.Y.Z` tag is the
220
+ stable version. Commits after it build as the next patch development series:
221
+
222
+ ```text
223
+ v0.3.0 -> 0.3.0
224
+ first commit -> 0.3.1.dev1
225
+ second commit -> 0.3.1.dev2
226
+ v0.3.1 -> 0.3.1
227
+ ```
228
+
229
+ GitHub Actions publishes every `main` push through the `pypi-dev` environment
230
+ and every `v*` tag through `pypi`. Configure two PyPI Trusted Publishers with
231
+ the same owner, repository, and workflow, differing only by environment:
232
+
233
+ ```text
234
+ Owner: yaoyhu
235
+ Repository: rsplot
236
+ Workflow: publish.yml
237
+ Environment: pypi-dev
238
+ Environment: pypi
239
+ ```
240
+
241
+ Leave `pypi-dev` automatic for continuous development uploads. Protect the
242
+ `pypi` GitHub environment with required reviewers so stable releases need an
243
+ explicit approval.
244
+
245
+ To make a stable release after the desired commit is on GitHub:
246
+
247
+ ```bash
248
+ git tag -a v0.3.1 -m v0.3.1
249
+ git push github v0.3.1
250
+ ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "rsplot"
3
- version = "0.2.7"
3
+ dynamic = ["version"]
4
4
  description = "CLI tool for plotting Remote Sensing data, designed for Agent."
5
5
  authors = [
6
6
  { name = "Yaoyao Hu", email = "yaoyhu@mail.ustc.edu.cn" },
@@ -37,9 +37,16 @@ GitHub = "https://github.com/yaoyhu/rsplot"
37
37
  rsplot = "rsplot.__main__:app"
38
38
 
39
39
  [build-system]
40
- requires = ["hatchling"]
40
+ requires = ["hatchling", "hatch-vcs>=0.5,<0.6"]
41
41
  build-backend = "hatchling.build"
42
42
 
43
+ [tool.hatch.version]
44
+ source = "vcs"
45
+
46
+ [tool.hatch.version.raw-options]
47
+ version_scheme = "guess-next-dev"
48
+ local_scheme = "no-local-version"
49
+
43
50
  [tool.hatch.build.targets.sdist]
44
51
  only-include = ["src/rsplot"]
45
52
 
@@ -0,0 +1,10 @@
1
+ """rsplot — CLI tool for plotting Remote Sensing data, designed for agent."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("rsplot")
7
+ except PackageNotFoundError: # pragma: no cover - source tree without install
8
+ __version__ = "unknown"
9
+
10
+ __all__ = ["__version__"]