viewinline 0.4.0__tar.gz → 0.5.0__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.
- {viewinline-0.4.0 → viewinline-0.5.0}/CITATION.cff +8 -7
- {viewinline-0.4.0 → viewinline-0.5.0}/PKG-INFO +8 -1
- {viewinline-0.4.0 → viewinline-0.5.0}/README.md +7 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/llms.txt +4 -1
- {viewinline-0.4.0 → viewinline-0.5.0}/pyproject.toml +1 -1
- {viewinline-0.4.0 → viewinline-0.5.0}/src/viewinline/viewinline.py +151 -5
- {viewinline-0.4.0 → viewinline-0.5.0/viewinline}/SKILL.md +1 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/.github/FUNDING.yml +0 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/.gitignore +0 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/LICENSE +0 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/context7.json +0 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/src/viewinline/__init__.py +0 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/viewinline_gif1.gif +0 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/viewinline_gif2.gif +0 -0
- {viewinline-0.4.0 → viewinline-0.5.0}/viewinline_gif2.jpg +0 -0
|
@@ -11,26 +11,27 @@ type: software
|
|
|
11
11
|
authors:
|
|
12
12
|
- given-names: Keiko
|
|
13
13
|
family-names: Nomura
|
|
14
|
-
|
|
14
|
+
orcid: "https://orcid.org/0000-0002-5218-3414"
|
|
15
15
|
- given-names: Filip
|
|
16
16
|
family-names: Kral
|
|
17
|
-
|
|
17
|
+
- given-names: Luis
|
|
18
|
+
family-names: Manrique Ruiz
|
|
18
19
|
repository-code: "https://github.com/nkeikon/inlineviewer"
|
|
19
20
|
url: "https://github.com/nkeikon/inlineviewer"
|
|
20
21
|
license: Apache-2.0
|
|
21
|
-
version: 0.
|
|
22
|
-
date-released: 2026-
|
|
22
|
+
version: 0.5.0
|
|
23
|
+
date-released: 2026-10-21
|
|
23
24
|
# ---------------------------------------------------------------------------
|
|
24
25
|
# The DOI below is the VERSION DOI for v0.3.2 (a specific archived snapshot).
|
|
25
26
|
# To make citations always resolve to your LATEST release, replace it with the
|
|
26
27
|
# Zenodo CONCEPT / "all versions" DOI, shown on the record under "Cite all
|
|
27
28
|
# versions". The version DOI stays useful in `identifiers` for reproducibility.
|
|
28
29
|
# ---------------------------------------------------------------------------
|
|
29
|
-
doi: "10.5281/zenodo.
|
|
30
|
+
doi: "10.5281/zenodo.19700943"
|
|
30
31
|
identifiers:
|
|
31
32
|
- type: doi
|
|
32
|
-
value: "10.5281/zenodo.
|
|
33
|
-
description: "Zenodo archive
|
|
33
|
+
value: "10.5281/zenodo.19700943"
|
|
34
|
+
description: "Zenodo archive"
|
|
34
35
|
keywords:
|
|
35
36
|
- geospatial
|
|
36
37
|
- raster
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: viewinline
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Quick look geospatial viewer for the terminal, with inline image previews
|
|
5
5
|
Project-URL: Homepage, https://github.com/nkeikon/viewinline
|
|
6
6
|
Project-URL: Repository, https://github.com/nkeikon/viewinline
|
|
@@ -86,6 +86,12 @@ viewinline path/to/file.tif --export out.png # save the rendered image as PNG
|
|
|
86
86
|
viewinline scene.tif --rgb 4 3 2 --export rgb.png
|
|
87
87
|
viewinline dem.tif --colormap terrain --display 1 --export dem.png # full-res with colormap
|
|
88
88
|
|
|
89
|
+
# Axis and grid overlay
|
|
90
|
+
viewinline path/to/file.tif --grid # ticks + grid in the raster's CRS units (5 divisions)
|
|
91
|
+
viewinline path/to/file.tif --grid 10 # 10 divisions instead of the default 5
|
|
92
|
+
viewinline boundaries.geoparquet --grid # ticks + grid in the vector's CRS units
|
|
93
|
+
viewinline photo.png --grid # pixel positions (no CRS)
|
|
94
|
+
|
|
89
95
|
# CSV and Parquet
|
|
90
96
|
viewinline data.csv # preview rows and columns
|
|
91
97
|
viewinline data.parquet --describe # summary statistics
|
|
@@ -222,6 +228,7 @@ General:
|
|
|
222
228
|
--display DISPLAY Resize only the displayed image (0.5=smaller, 2=bigger). Default: auto-fit to terminal.
|
|
223
229
|
--info Print file metadata and statistics as JSON, then exit (agent-facing). For NetCDF/HDF, lists variables; combine with --subset N to inspect one. Always returns JSON, including on error.
|
|
224
230
|
--export PATH Save the rendered image to PATH (.png/.jpg) and open it. Works with any display flag. Prints {"path": "..."} as the final line.
|
|
231
|
+
--grid [N] Overlay axis ticks and a light grid (N divisions, default 5). Labels are in the file's CRS units (degrees or metres) for georeferenced rasters and vectors; pixel positions for PNG/JPG, NetCDF, and non-georeferenced files.
|
|
225
232
|
|
|
226
233
|
Raster:
|
|
227
234
|
--band BAND Band number to display (single raster), or slice number for NetCDF. (default: 1)
|
|
@@ -53,6 +53,12 @@ viewinline path/to/file.tif --export out.png # save the rendered image as PNG
|
|
|
53
53
|
viewinline scene.tif --rgb 4 3 2 --export rgb.png
|
|
54
54
|
viewinline dem.tif --colormap terrain --display 1 --export dem.png # full-res with colormap
|
|
55
55
|
|
|
56
|
+
# Axis and grid overlay
|
|
57
|
+
viewinline path/to/file.tif --grid # ticks + grid in the raster's CRS units (5 divisions)
|
|
58
|
+
viewinline path/to/file.tif --grid 10 # 10 divisions instead of the default 5
|
|
59
|
+
viewinline boundaries.geoparquet --grid # ticks + grid in the vector's CRS units
|
|
60
|
+
viewinline photo.png --grid # pixel positions (no CRS)
|
|
61
|
+
|
|
56
62
|
# CSV and Parquet
|
|
57
63
|
viewinline data.csv # preview rows and columns
|
|
58
64
|
viewinline data.parquet --describe # summary statistics
|
|
@@ -189,6 +195,7 @@ General:
|
|
|
189
195
|
--display DISPLAY Resize only the displayed image (0.5=smaller, 2=bigger). Default: auto-fit to terminal.
|
|
190
196
|
--info Print file metadata and statistics as JSON, then exit (agent-facing). For NetCDF/HDF, lists variables; combine with --subset N to inspect one. Always returns JSON, including on error.
|
|
191
197
|
--export PATH Save the rendered image to PATH (.png/.jpg) and open it. Works with any display flag. Prints {"path": "..."} as the final line.
|
|
198
|
+
--grid [N] Overlay axis ticks and a light grid (N divisions, default 5). Labels are in the file's CRS units (degrees or metres) for georeferenced rasters and vectors; pixel positions for PNG/JPG, NetCDF, and non-georeferenced files.
|
|
192
199
|
|
|
193
200
|
Raster:
|
|
194
201
|
--band BAND Band number to display (single raster), or slice number for NetCDF. (default: 1)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- Command name: `viewinline`
|
|
8
8
|
- Requires: Python 3.9+
|
|
9
9
|
- License: Apache-2.0 © 2026 Keiko Nomura
|
|
10
|
-
- Latest release: v0.
|
|
10
|
+
- Latest release: v0.5.0 (2026-10-21)
|
|
11
11
|
- Combines the core display logic of `viewtif` and `viewgeom`, but is **non-interactive**: no zoom/pan/colormap-switching on the fly. Everything is controlled via CLI options (e.g. `--display`, `--color-by`, `--colormap`).
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
@@ -136,6 +136,8 @@ General:
|
|
|
136
136
|
- `--display DISPLAY` — resize only the displayed image (0.5 = smaller, 2 = bigger). Default: auto-fit to terminal.
|
|
137
137
|
- `--info` — print file metadata as JSON, then exit (no image drawn). Works with rasters (GeoTIFF, NetCDF, HDF) and vectors (GeoJSON, Shapefile, GeoPackage, GeoParquet). For NetCDF/HDF, lists variables; combine with `--subset N` to inspect one. Always returns JSON, including a `{"readable": false, "error": ...}` object on unreadable input. Aimed at AI coding agents.
|
|
138
138
|
- `--export PATH` — save the rendered image to PATH (`.png`/`.jpg`, chosen by extension) and open it; prints `{"path": "..."}` as the final line. Works with any display flag (`--rgb`, `--colormap`, `--band`, `--display`), saving exactly what viewinline would render. Useful for saving quick-looks and for AI agents inspecting outputs visually.
|
|
139
|
+
- `--grid [N]` — overlay axis ticks and a light grid (N divisions, default 5). Labels are in the file's CRS units (degrees or metres) for georeferenced rasters and vectors; pixel positions for PNG/JPG, NetCDF, and non-georeferenced files. Works with `--export`.
|
|
140
|
+
|
|
139
141
|
Raster:
|
|
140
142
|
- `--band BAND` — band number for a single raster, or slice number for NetCDF (default: 1).
|
|
141
143
|
- `--bands BANDS` — display multiple bands as a grid. Accepts ranges (`30-40`), lists (`3,4,5`), or mixed (`1,5,10-15`).
|
|
@@ -236,6 +238,7 @@ Optional: `chafa` (terminal coverage; system binary), `duckdb` (filter/sort/SQL)
|
|
|
236
238
|
- **v0.2.0 (2026-02-17):** Inline-only display (OSC 1337); removed ANSI fallback and /tmp save; DuckDB integration for `--where`/`--sort`/`--select`/`--limit`/`--sql`; license switched MIT → Apache-2.0.
|
|
237
239
|
- **v0.1.5 (2026-02-13):** Fixed duplicate band-display prints; optimized uint8 normalization; minor perf.
|
|
238
240
|
- **v0.4.0 (2026-08-23):** New agent-facing inspection commands: `--info` (file metadata + statistics as JSON, for rasters and vectors; lists variables for NetCDF/HDF with `--subset`; always returns JSON including structured errors) and `--export` (save the rendered image to PNG/JPEG, works with any display flag). Existing viewer behavior unchanged.
|
|
241
|
+
- **v0.5.0 (2026-10-21):** New `--grid [N]` flag: axis ticks and a light grid overlay. Georeferenced rasters and vectors are labelled in real CRS coordinates; photos, NetCDF, and non-georeferenced files in pixel positions. Grid contributed by @luismanriqueruiz.
|
|
239
242
|
|
|
240
243
|
## Support & links
|
|
241
244
|
|
|
@@ -35,7 +35,7 @@ warnings.filterwarnings("ignore", message="invalid scale_factor or add_offset at
|
|
|
35
35
|
_EXPORT_PATH = None
|
|
36
36
|
_EXPORT_RESULT = None
|
|
37
37
|
|
|
38
|
-
__version__ = "0.
|
|
38
|
+
__version__ = "0.5.0"
|
|
39
39
|
|
|
40
40
|
AVAILABLE_COLORMAPS = [
|
|
41
41
|
"viridis", "inferno", "magma", "plasma",
|
|
@@ -923,6 +923,123 @@ def normalize_to_uint8(band: np.ndarray, vmin=None, vmax=None, nodata=None) -> n
|
|
|
923
923
|
return (band * 255).astype(np.uint8)
|
|
924
924
|
|
|
925
925
|
|
|
926
|
+
# def add_axis_and_grid(img: np.ndarray, n_ticks: int = 5) -> np.ndarray:
|
|
927
|
+
# """Overlay pixel-coordinate axis ticks/labels and a light grid on an image.
|
|
928
|
+
|
|
929
|
+
# Operates on the final (already resized) array, right before display, so
|
|
930
|
+
# ticks reflect the pixel coordinates of the rendered image, not the
|
|
931
|
+
# source raster. Grid lines are alpha-blended so image content stays
|
|
932
|
+
# visible; ticks/labels live in an added margin along the left and
|
|
933
|
+
# bottom edges.
|
|
934
|
+
# """
|
|
935
|
+
# h, w = img.shape[:2]
|
|
936
|
+
# n_ticks = max(1, n_ticks)
|
|
937
|
+
|
|
938
|
+
# base = Image.fromarray(img).convert("RGBA")
|
|
939
|
+
# overlay = Image.new("RGBA", (w, h), (0, 0, 0, 0))
|
|
940
|
+
# odraw = ImageDraw.Draw(overlay)
|
|
941
|
+
# grid_color = (255, 255, 255, 110)
|
|
942
|
+
|
|
943
|
+
# xs = [min(int(round(i * w / n_ticks)), w - 1) for i in range(n_ticks + 1)]
|
|
944
|
+
# ys = [min(int(round(i * h / n_ticks)), h - 1) for i in range(n_ticks + 1)]
|
|
945
|
+
|
|
946
|
+
# for x in xs:
|
|
947
|
+
# odraw.line([(x, 0), (x, h - 1)], fill=grid_color, width=1)
|
|
948
|
+
# for y in ys:
|
|
949
|
+
# odraw.line([(0, y), (w - 1, y)], fill=grid_color, width=1)
|
|
950
|
+
|
|
951
|
+
# composed = Image.alpha_composite(base, overlay).convert("RGB")
|
|
952
|
+
|
|
953
|
+
# margin_l, margin_b, margin_r = 42, 22, 30
|
|
954
|
+
# canvas = Image.new("RGB", (w + margin_l + margin_r, h + margin_b), (24, 24, 24))
|
|
955
|
+
# canvas.paste(composed, (margin_l, 0))
|
|
956
|
+
# draw = ImageDraw.Draw(canvas)
|
|
957
|
+
|
|
958
|
+
# try:
|
|
959
|
+
# font = ImageFont.load_default()
|
|
960
|
+
# except Exception:
|
|
961
|
+
# font = None
|
|
962
|
+
|
|
963
|
+
# label_color = (255, 255, 0)
|
|
964
|
+
|
|
965
|
+
# for x in xs:
|
|
966
|
+
# px = margin_l + x
|
|
967
|
+
# draw.line([(px, h), (px, h + 3)], fill=label_color)
|
|
968
|
+
# draw.text((px + 2, h + 4), str(x), fill=label_color, font=font)
|
|
969
|
+
|
|
970
|
+
# for y in ys:
|
|
971
|
+
# label = str(y)
|
|
972
|
+
# tw = draw.textlength(label, font=font) if font else len(label) * 6
|
|
973
|
+
# draw.line([(margin_l - 3, y), (margin_l, y)], fill=label_color)
|
|
974
|
+
# draw.text((margin_l - 6 - tw, max(0, y - 5)), label, fill=label_color, font=font)
|
|
975
|
+
|
|
976
|
+
# return np.array(canvas)
|
|
977
|
+
|
|
978
|
+
def add_axis_and_grid(img: np.ndarray, n_ticks: int = 5, bounds=None) -> np.ndarray:
|
|
979
|
+
"""Overlay axis ticks/labels and a light grid on an image.
|
|
980
|
+
|
|
981
|
+
If ``bounds`` (left, bottom, right, top) is given, labels show real map
|
|
982
|
+
coordinates in the raster's CRS. Otherwise they show pixel positions of
|
|
983
|
+
the rendered image (used for plain photos and non-georeferenced files).
|
|
984
|
+
"""
|
|
985
|
+
h, w = img.shape[:2]
|
|
986
|
+
n_ticks = max(1, n_ticks)
|
|
987
|
+
fracs = [i / n_ticks for i in range(n_ticks + 1)]
|
|
988
|
+
|
|
989
|
+
xs = [min(int(round(f * w)), w - 1) for f in fracs]
|
|
990
|
+
ys = [min(int(round(f * h)), h - 1) for f in fracs]
|
|
991
|
+
|
|
992
|
+
if bounds is not None:
|
|
993
|
+
left, bottom, right, top = bounds
|
|
994
|
+
step = max(abs(right - left), abs(top - bottom)) / n_ticks
|
|
995
|
+
# Enough decimals to tell neighbouring ticks apart (0 for metres, ~2-4 for degrees)
|
|
996
|
+
decimals = 0 if step >= 10 else max(0, int(-np.floor(np.log10(step))) + 1)
|
|
997
|
+
x_labels = [f"{left + f * (right - left):.{decimals}f}" for f in fracs]
|
|
998
|
+
y_labels = [f"{top - f * (top - bottom):.{decimals}f}" for f in fracs]
|
|
999
|
+
else:
|
|
1000
|
+
x_labels = [str(x) for x in xs]
|
|
1001
|
+
y_labels = [str(y) for y in ys]
|
|
1002
|
+
|
|
1003
|
+
base = Image.fromarray(img).convert("RGBA")
|
|
1004
|
+
overlay = Image.new("RGBA", (w, h), (0, 0, 0, 0))
|
|
1005
|
+
odraw = ImageDraw.Draw(overlay)
|
|
1006
|
+
grid_color = (255, 255, 255, 110)
|
|
1007
|
+
for x in xs:
|
|
1008
|
+
odraw.line([(x, 0), (x, h - 1)], fill=grid_color, width=1)
|
|
1009
|
+
for y in ys:
|
|
1010
|
+
odraw.line([(0, y), (w - 1, y)], fill=grid_color, width=1)
|
|
1011
|
+
composed = Image.alpha_composite(base, overlay).convert("RGB")
|
|
1012
|
+
|
|
1013
|
+
try:
|
|
1014
|
+
font = ImageFont.load_default()
|
|
1015
|
+
except Exception:
|
|
1016
|
+
font = None
|
|
1017
|
+
probe = ImageDraw.Draw(Image.new("RGB", (1, 1)))
|
|
1018
|
+
|
|
1019
|
+
def text_w(s):
|
|
1020
|
+
return probe.textlength(s, font=font) if font else len(s) * 6
|
|
1021
|
+
|
|
1022
|
+
# Margins sized to the longest labels so nothing gets clipped
|
|
1023
|
+
margin_l = int(max(text_w(s) for s in y_labels)) + 10
|
|
1024
|
+
margin_r = int(text_w(x_labels[-1])) + 6
|
|
1025
|
+
margin_b = 22
|
|
1026
|
+
|
|
1027
|
+
canvas = Image.new("RGB", (w + margin_l + margin_r, h + margin_b), (24, 24, 24))
|
|
1028
|
+
canvas.paste(composed, (margin_l, 0))
|
|
1029
|
+
draw = ImageDraw.Draw(canvas)
|
|
1030
|
+
label_color = (255, 255, 0)
|
|
1031
|
+
|
|
1032
|
+
for x, label in zip(xs, x_labels):
|
|
1033
|
+
px = margin_l + x
|
|
1034
|
+
draw.line([(px, h), (px, h + 3)], fill=label_color)
|
|
1035
|
+
draw.text((px + 2, h + 4), label, fill=label_color, font=font)
|
|
1036
|
+
|
|
1037
|
+
for y, label in zip(ys, y_labels):
|
|
1038
|
+
draw.line([(margin_l - 3, y), (margin_l, y)], fill=label_color)
|
|
1039
|
+
draw.text((margin_l - 6 - text_w(label), max(0, y - 5)), label, fill=label_color, font=font)
|
|
1040
|
+
|
|
1041
|
+
return np.array(canvas)
|
|
1042
|
+
|
|
926
1043
|
def render_simple_image(filepath: str, args) -> None:
|
|
927
1044
|
"""Render a simple PNG/JPG image using PIL (no geospatial processing)."""
|
|
928
1045
|
try:
|
|
@@ -945,7 +1062,10 @@ def render_simple_image(filepath: str, args) -> None:
|
|
|
945
1062
|
else:
|
|
946
1063
|
img_array, scale = resize_to_terminal(img_array)
|
|
947
1064
|
print(f"[VIEW] Rendered image size → {img_array.shape[1]}×{img_array.shape[0]}px (size={scale:.2f})")
|
|
948
|
-
|
|
1065
|
+
|
|
1066
|
+
if getattr(args, "grid", None):
|
|
1067
|
+
img_array = add_axis_and_grid(img_array, n_ticks=args.grid)
|
|
1068
|
+
|
|
949
1069
|
show_image_auto(img_array, getattr(args, "display", None), is_vector=False)
|
|
950
1070
|
|
|
951
1071
|
except Exception as e:
|
|
@@ -1102,6 +1222,8 @@ def render_netcdf_via_netcdf4(path, args):
|
|
|
1102
1222
|
scale = max_dim / max(H, W)
|
|
1103
1223
|
new_w, new_h = int(W * scale), int(H * scale)
|
|
1104
1224
|
img = np.array(Image.fromarray(img).resize((new_w, new_h), Image.BILINEAR))
|
|
1225
|
+
if getattr(args, "grid", None):
|
|
1226
|
+
img = add_axis_and_grid(img, n_ticks=args.grid)
|
|
1105
1227
|
show_image_auto(img, getattr(args, "display", None), is_vector=False)
|
|
1106
1228
|
return
|
|
1107
1229
|
except ValueError as e:
|
|
@@ -1177,8 +1299,11 @@ def render_netcdf_via_netcdf4(path, args):
|
|
|
1177
1299
|
# (matches the width_pct logic in show_inline_image)
|
|
1178
1300
|
display_pct = args.display if args.display is not None else 0.33
|
|
1179
1301
|
|
|
1180
|
-
print(f"[VIEW] Rendered image size → {img.shape[1]}×{img.shape[0]}px (size={display_pct:.2f})")
|
|
1181
|
-
|
|
1302
|
+
print(f"[VIEW] Rendered image size → {img.shape[1]}×{img.shape[0]}px (size={display_pct:.2f})")
|
|
1303
|
+
|
|
1304
|
+
if getattr(args, "grid", None):
|
|
1305
|
+
img = add_axis_and_grid(img, n_ticks=args.grid)
|
|
1306
|
+
|
|
1182
1307
|
show_image_auto(img, getattr(args, "display", None), is_vector=False)
|
|
1183
1308
|
|
|
1184
1309
|
def render_raster(paths: list[str], args) -> None:
|
|
@@ -1255,6 +1380,7 @@ def render_raster(paths: list[str], args) -> None:
|
|
|
1255
1380
|
# Continue with normal raster opening
|
|
1256
1381
|
with rasterio.open(path) as ds:
|
|
1257
1382
|
H, W = ds.height, ds.width
|
|
1383
|
+
grid_bounds = tuple(ds.bounds) if ds.crs is not None else None
|
|
1258
1384
|
print(f"[DATA] Raster loaded: {os.path.basename(paths[0])} ({W}×{H})")
|
|
1259
1385
|
band_count = ds.count
|
|
1260
1386
|
|
|
@@ -1372,6 +1498,7 @@ def render_raster(paths: list[str], args) -> None:
|
|
|
1372
1498
|
for p in paths:
|
|
1373
1499
|
with rasterio.open(p) as ds:
|
|
1374
1500
|
bands.append(ds.read(1))
|
|
1501
|
+
grid_bounds = tuple(ds.bounds) if ds.crs is not None else None
|
|
1375
1502
|
shapes = {b.shape for b in bands}
|
|
1376
1503
|
if len(shapes) != 1:
|
|
1377
1504
|
print("[ERROR] Raster sizes do not match.")
|
|
@@ -1396,6 +1523,10 @@ def render_raster(paths: list[str], args) -> None:
|
|
|
1396
1523
|
img, scale = resize_to_terminal(img)
|
|
1397
1524
|
print(f"[VIEW] Rendered image size → {img.shape[1]}×{img.shape[0]}px (size={scale:.2f})")
|
|
1398
1525
|
|
|
1526
|
+
if getattr(args, "grid", None):
|
|
1527
|
+
# img = add_axis_and_grid(img, n_ticks=args.grid)
|
|
1528
|
+
img = add_axis_and_grid(img, n_ticks=args.grid, bounds=grid_bounds)
|
|
1529
|
+
|
|
1399
1530
|
# Use unified display
|
|
1400
1531
|
show_image_auto(img, getattr(args, "display", None), is_vector=False)
|
|
1401
1532
|
|
|
@@ -1648,7 +1779,18 @@ def render_vector(path, args):
|
|
|
1648
1779
|
# Figure setup
|
|
1649
1780
|
fig, ax = plt.subplots(figsize=(6, 6), dpi=150, facecolor="gray")
|
|
1650
1781
|
ax.set_facecolor("gray")
|
|
1651
|
-
|
|
1782
|
+
show_grid = getattr(args, "grid", None)
|
|
1783
|
+
if show_grid:
|
|
1784
|
+
# Keep axis on: real coordinate ticks (CRS units) plus a light grid,
|
|
1785
|
+
# instead of the pixel-based overlay used for raster images.
|
|
1786
|
+
ax.tick_params(colors="white", labelsize=6)
|
|
1787
|
+
for spine in ax.spines.values():
|
|
1788
|
+
spine.set_color("white")
|
|
1789
|
+
ax.locator_params(nbins=show_grid)
|
|
1790
|
+
ax.grid(True, color="white", alpha=0.3, linewidth=0.5)
|
|
1791
|
+
ax.ticklabel_format(style="plain", useOffset=False)
|
|
1792
|
+
else:
|
|
1793
|
+
ax.set_axis_off()
|
|
1652
1794
|
|
|
1653
1795
|
# Determine colormap
|
|
1654
1796
|
column = args.color_by if args.color_by in gdf.columns else None
|
|
@@ -1965,6 +2107,10 @@ def main() -> None:
|
|
|
1965
2107
|
|
|
1966
2108
|
general.add_argument("--export", metavar="PATH", default=None,
|
|
1967
2109
|
help="Also save the displayed image to PATH (.png/.jpg). Prints {\"path\": ...}.")
|
|
2110
|
+
general.add_argument(
|
|
2111
|
+
"--grid", nargs="?", type=int, const=5, default=None, metavar="N",
|
|
2112
|
+
help="Overlay coordinate axis ticks and a light grid on the image (N divisions, default 5)."
|
|
2113
|
+
)
|
|
1968
2114
|
|
|
1969
2115
|
# Raster options
|
|
1970
2116
|
raster = parser.add_argument_group("Raster")
|
|
@@ -62,6 +62,7 @@ Note: `--info` and `--export` report what a file *is* and what it *looks like*
|
|
|
62
62
|
**Inspection (JSON output, no image):**
|
|
63
63
|
- `--info` — print metadata + statistics as JSON, then exit (rasters and vectors; lists variables for NetCDF/HDF with `--subset N`)
|
|
64
64
|
- `--export PATH` — save the rendered image to PATH (`.png`/`.jpg`); prints `{"path": "..."}`
|
|
65
|
+
- `--grid [N]` — overlay axis ticks and a light grid (N divisions, default 5). Labels are in the file's CRS units for georeferenced rasters and vectors, pixel positions otherwise. Combine with `--export` to save a quick-look with readable coordinates, e.g. to check a file covers the expected area.
|
|
65
66
|
|
|
66
67
|
**Raster Display:**
|
|
67
68
|
- `--rgb R G B` — Specify band order for RGB (e.g., `--rgb 4 3 2`)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|