viewtif 0.2.4__tar.gz → 0.2.5__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.
- {viewtif-0.2.4 → viewtif-0.2.5}/PKG-INFO +14 -10
- {viewtif-0.2.4 → viewtif-0.2.5}/README.md +13 -9
- {viewtif-0.2.4 → viewtif-0.2.5}/pyproject.toml +1 -1
- viewtif-0.2.5/src/viewtif/__init__.py +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/src/viewtif/tif_viewer.py +25 -136
- {viewtif-0.2.4 → viewtif-0.2.5}/.gitignore +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/README.md +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/AG100.v003.13.-017.0001.h5 +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/ECOSTRESS_LST.tif +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/HLS_B02.tif +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/HLS_B03.tif +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/HLS_B04.tif +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/Zip_Codes.cpg +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/Zip_Codes.dbf +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/Zip_Codes.prj +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/Zip_Codes.shp +0 -0
- {viewtif-0.2.4 → viewtif-0.2.5}/examples/sample_data/Zip_Codes.shx +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: viewtif
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: Lightweight GeoTIFF, NetCDF, HDF/HDF5, and Esri File Geodatabase (.gdb) viewer with optional shapefile overlay. NetCDF and cartopy support available via pip install viewtif[netcdf].
|
|
5
5
|
Project-URL: Homepage, https://github.com/nkeikon/tifviewer
|
|
6
6
|
Project-URL: Source, https://github.com/nkeikon/tifviewer
|
|
@@ -26,6 +26,9 @@ Description-Content-Type: text/markdown
|
|
|
26
26
|
# viewtif
|
|
27
27
|
[](https://pepy.tech/project/viewtif)
|
|
28
28
|
[](https://pypi.org/project/viewtif/)
|
|
29
|
+
[](https://pypi.org/project/viewtif/)
|
|
30
|
+
|
|
31
|
+
|
|
29
32
|
|
|
30
33
|
A lightweight GeoTIFF viewer for quick visualization directly from the command line.
|
|
31
34
|
|
|
@@ -59,9 +62,9 @@ pip install GDAL
|
|
|
59
62
|
|
|
60
63
|
#### NetCDF support
|
|
61
64
|
```bash
|
|
62
|
-
|
|
65
|
+
pip install "viewtif[netcdf]"
|
|
63
66
|
```
|
|
64
|
-
> **Note:** For enhanced geographic visualization with map projections, coastlines, and borders, install with cartopy: `pip install "viewtif[netcdf]"` (cartopy is included in the netcdf extra). If cartopy is not available, netCDF files will still display with standard
|
|
67
|
+
> **Note:** For enhanced geographic visualization with map projections, coastlines, and borders, install with cartopy: `pip install "viewtif[netcdf]"` (cartopy is included in the netcdf extra). If cartopy is not available, netCDF files will still display with standard rendering.
|
|
65
68
|
## Quick Start
|
|
66
69
|
```bash
|
|
67
70
|
# View a GeoTIFF
|
|
@@ -114,12 +117,7 @@ If the dataset is very large (e.g., >20 million pixels), it will pause and warn
|
|
|
114
117
|
You can proceed manually or rerun with the `--scale` option for a smaller, faster preview.
|
|
115
118
|
|
|
116
119
|
### Update in v0.2.2: NetCDF support with optional cartopy visualization
|
|
117
|
-
`viewtif` now supports NetCDF (`.nc`) files
|
|
118
|
-
|
|
119
|
-
#### Installation with NetCDF support
|
|
120
|
-
```bash
|
|
121
|
-
pip install "viewtif[netcdf]"
|
|
122
|
-
```
|
|
120
|
+
`viewtif` now supports NetCDF (`.nc`) files via xarray, with optional cartopy-based geographic visualization. Use`[` / `]` to move forward or backward through time steps.
|
|
123
121
|
|
|
124
122
|
#### Examples
|
|
125
123
|
```bash
|
|
@@ -161,4 +159,10 @@ This project is released under the MIT License.
|
|
|
161
159
|
|
|
162
160
|
## Contributors
|
|
163
161
|
- [@HarshShinde0](https://github.com/HarshShinde0) — added mouse-wheel and trackpad zoom support; added NetCDF support with [@nkeikon](https://github.com/nkeikon)
|
|
164
|
-
- [@p-vdp](https://github.com/p-vdp) — added File Geodatabase (.gdb) raster support
|
|
162
|
+
- [@p-vdp](https://github.com/p-vdp) — added File Geodatabase (.gdb) raster support
|
|
163
|
+
|
|
164
|
+
## Useful links
|
|
165
|
+
- https://www.linkedin.com/posts/desmond-lartey_geospatial-analysts-heads-up-check-out-activity-7386336488050925568-G5bN?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA0INsBVIO1f6nS_NkKqFh4Na1ZpoYo2fc
|
|
166
|
+
- https://www.linkedin.com/posts/keiko-nomura-0231891_dont-you-sometimes-just-want-to-see-a-activity-7383409138296528896-sbRM?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA0INsBVIO1f6nS_NkKqFh4Na1ZpoYo2fc
|
|
167
|
+
- https://www.linkedin.com/posts/keiko-nomura-0231891_now-you-can-see-hdf-files-from-the-command-activity-7383963721561399296-F5i0?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA0INsBVIO1f6nS_NkKqFh4Na1ZpoYo2fc
|
|
168
|
+
- https://www.linkedin.com/posts/keiko-nomura-0231891_you-can-now-view-netcdf-files-nc-from-activity-7386189562072670208-3A0V?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA0INsBVIO1f6nS_NkKqFh4Na1ZpoYo2fc
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# viewtif
|
|
2
2
|
[](https://pepy.tech/project/viewtif)
|
|
3
3
|
[](https://pypi.org/project/viewtif/)
|
|
4
|
+
[](https://pypi.org/project/viewtif/)
|
|
5
|
+
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
A lightweight GeoTIFF viewer for quick visualization directly from the command line.
|
|
6
9
|
|
|
@@ -34,9 +37,9 @@ pip install GDAL
|
|
|
34
37
|
|
|
35
38
|
#### NetCDF support
|
|
36
39
|
```bash
|
|
37
|
-
|
|
40
|
+
pip install "viewtif[netcdf]"
|
|
38
41
|
```
|
|
39
|
-
> **Note:** For enhanced geographic visualization with map projections, coastlines, and borders, install with cartopy: `pip install "viewtif[netcdf]"` (cartopy is included in the netcdf extra). If cartopy is not available, netCDF files will still display with standard
|
|
42
|
+
> **Note:** For enhanced geographic visualization with map projections, coastlines, and borders, install with cartopy: `pip install "viewtif[netcdf]"` (cartopy is included in the netcdf extra). If cartopy is not available, netCDF files will still display with standard rendering.
|
|
40
43
|
## Quick Start
|
|
41
44
|
```bash
|
|
42
45
|
# View a GeoTIFF
|
|
@@ -89,12 +92,7 @@ If the dataset is very large (e.g., >20 million pixels), it will pause and warn
|
|
|
89
92
|
You can proceed manually or rerun with the `--scale` option for a smaller, faster preview.
|
|
90
93
|
|
|
91
94
|
### Update in v0.2.2: NetCDF support with optional cartopy visualization
|
|
92
|
-
`viewtif` now supports NetCDF (`.nc`) files
|
|
93
|
-
|
|
94
|
-
#### Installation with NetCDF support
|
|
95
|
-
```bash
|
|
96
|
-
pip install "viewtif[netcdf]"
|
|
97
|
-
```
|
|
95
|
+
`viewtif` now supports NetCDF (`.nc`) files via xarray, with optional cartopy-based geographic visualization. Use`[` / `]` to move forward or backward through time steps.
|
|
98
96
|
|
|
99
97
|
#### Examples
|
|
100
98
|
```bash
|
|
@@ -136,4 +134,10 @@ This project is released under the MIT License.
|
|
|
136
134
|
|
|
137
135
|
## Contributors
|
|
138
136
|
- [@HarshShinde0](https://github.com/HarshShinde0) — added mouse-wheel and trackpad zoom support; added NetCDF support with [@nkeikon](https://github.com/nkeikon)
|
|
139
|
-
- [@p-vdp](https://github.com/p-vdp) — added File Geodatabase (.gdb) raster support
|
|
137
|
+
- [@p-vdp](https://github.com/p-vdp) — added File Geodatabase (.gdb) raster support
|
|
138
|
+
|
|
139
|
+
## Useful links
|
|
140
|
+
- https://www.linkedin.com/posts/desmond-lartey_geospatial-analysts-heads-up-check-out-activity-7386336488050925568-G5bN?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA0INsBVIO1f6nS_NkKqFh4Na1ZpoYo2fc
|
|
141
|
+
- https://www.linkedin.com/posts/keiko-nomura-0231891_dont-you-sometimes-just-want-to-see-a-activity-7383409138296528896-sbRM?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA0INsBVIO1f6nS_NkKqFh4Na1ZpoYo2fc
|
|
142
|
+
- https://www.linkedin.com/posts/keiko-nomura-0231891_now-you-can-see-hdf-files-from-the-command-activity-7383963721561399296-F5i0?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA0INsBVIO1f6nS_NkKqFh4Na1ZpoYo2fc
|
|
143
|
+
- https://www.linkedin.com/posts/keiko-nomura-0231891_you-can-now-view-netcdf-files-nc-from-activity-7386189562072670208-3A0V?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAA0INsBVIO1f6nS_NkKqFh4Na1ZpoYo2fc
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "viewtif"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.5"
|
|
8
8
|
description = "Lightweight GeoTIFF, NetCDF, HDF/HDF5, and Esri File Geodatabase (.gdb) viewer with optional shapefile overlay. NetCDF and cartopy support available via pip install viewtif[netcdf]."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
File without changes
|
|
@@ -42,7 +42,7 @@ import matplotlib.cm as cm
|
|
|
42
42
|
import warnings
|
|
43
43
|
warnings.filterwarnings("ignore", category=RuntimeWarning, module="shapely")
|
|
44
44
|
|
|
45
|
-
__version__ = "0.2.
|
|
45
|
+
__version__ = "0.2.5"
|
|
46
46
|
|
|
47
47
|
# Optional overlay deps
|
|
48
48
|
try:
|
|
@@ -210,10 +210,31 @@ class TiffViewer(QMainWindow):
|
|
|
210
210
|
self.tif_path = self.tif_path or (os.path.commonprefix([red, green, blue]) or red)
|
|
211
211
|
|
|
212
212
|
elif tif_path:
|
|
213
|
-
|
|
213
|
+
# ---------------- Handle File Geodatabase (.gdb) ---------------- #
|
|
214
|
+
if tif_path and tif_path.lower().endswith(".gdb") and ":" not in tif_path:
|
|
215
|
+
import re, subprocess
|
|
216
|
+
gdb_path = tif_path # use full path to .gdb
|
|
217
|
+
try:
|
|
218
|
+
out = subprocess.check_output(["gdalinfo", "-norat", gdb_path], text=True)
|
|
219
|
+
rasters = re.findall(r"RASTER_DATASET=(\S+)", out)
|
|
220
|
+
if not rasters:
|
|
221
|
+
print(f"[WARN] No raster datasets found in {os.path.basename(gdb_path)}.")
|
|
222
|
+
sys.exit(0)
|
|
223
|
+
else:
|
|
224
|
+
print(f"Found {len(rasters)} raster dataset{'s' if len(rasters) > 1 else ''}:")
|
|
225
|
+
for i, r in enumerate(rasters):
|
|
226
|
+
print(f"[{i}] {r}")
|
|
227
|
+
print("\nUse one of these names to open. For example, to open the first raster:")
|
|
228
|
+
print(f'viewtif "OpenFileGDB:{gdb_path}:{rasters[0]}"')
|
|
229
|
+
sys.exit(0)
|
|
230
|
+
except subprocess.CalledProcessError as e:
|
|
231
|
+
print(f"[WARN] Could not inspect FileGDB: {e}")
|
|
232
|
+
sys.exit(0)
|
|
233
|
+
|
|
234
|
+
# --- Warn for large files before loading ---
|
|
214
235
|
warn_if_large(tif_path, scale=self._scale_arg)
|
|
215
236
|
|
|
216
|
-
|
|
237
|
+
# --------------------- Detect NetCDF --------------------- #
|
|
217
238
|
if tif_path and tif_path.lower().endswith((".nc", ".netcdf")):
|
|
218
239
|
try:
|
|
219
240
|
# Lazy-load NetCDF dependencies
|
|
@@ -359,26 +380,6 @@ class TiffViewer(QMainWindow):
|
|
|
359
380
|
except Exception as e:
|
|
360
381
|
raise RuntimeError(f"Error reading NetCDF file: {str(e)}")
|
|
361
382
|
|
|
362
|
-
# ---------------- Handle File Geodatabase (.gdb) ---------------- #
|
|
363
|
-
if tif_path and tif_path.lower().endswith(".gdb") and ":" not in tif_path:
|
|
364
|
-
import re, subprocess
|
|
365
|
-
gdb_path = tif_path # use full path to .gdb
|
|
366
|
-
try:
|
|
367
|
-
out = subprocess.check_output(["gdalinfo", "-norat", gdb_path], text=True)
|
|
368
|
-
rasters = re.findall(r"RASTER_DATASET=(\S+)", out)
|
|
369
|
-
if not rasters:
|
|
370
|
-
print(f"[WARN] No raster datasets found in {os.path.basename(gdb_path)}.")
|
|
371
|
-
sys.exit(0)
|
|
372
|
-
else:
|
|
373
|
-
print(f"Found {len(rasters)} raster dataset{'s' if len(rasters) > 1 else ''}:")
|
|
374
|
-
for i, r in enumerate(rasters):
|
|
375
|
-
print(f"[{i}] {r}")
|
|
376
|
-
print("\nUse one of these names to open. For example, to open the first raster:")
|
|
377
|
-
print(f'viewtif "OpenFileGDB:{gdb_path}:{rasters[0]}"')
|
|
378
|
-
sys.exit(0)
|
|
379
|
-
except subprocess.CalledProcessError as e:
|
|
380
|
-
print(f"[WARN] Could not inspect FileGDB: {e}")
|
|
381
|
-
sys.exit(0)
|
|
382
383
|
|
|
383
384
|
# # --- Universal size check before loading ---
|
|
384
385
|
# warn_if_large(tif_path, scale=self._scale_arg)
|
|
@@ -858,118 +859,6 @@ class TiffViewer(QMainWindow):
|
|
|
858
859
|
pass
|
|
859
860
|
|
|
860
861
|
return time_str
|
|
861
|
-
|
|
862
|
-
# def update_time_label(self):
|
|
863
|
-
# """Update the time label with the current time value"""
|
|
864
|
-
# if hasattr(self, '_has_time_dim') and self._has_time_dim:
|
|
865
|
-
# try:
|
|
866
|
-
# time_value = self._time_values[self._time_index]
|
|
867
|
-
# time_str = self.format_time_value(time_value)
|
|
868
|
-
|
|
869
|
-
# # Update time label if it exists
|
|
870
|
-
# if hasattr(self, 'time_label'):
|
|
871
|
-
# self.time_label.setText(f"Time: {time_str}")
|
|
872
|
-
|
|
873
|
-
# # Create a progress bar style display of time position
|
|
874
|
-
# total = len(self._time_values)
|
|
875
|
-
# position = self._time_index + 1
|
|
876
|
-
# bar_width = 20 # Width of the progress bar
|
|
877
|
-
# filled = int(bar_width * position / total)
|
|
878
|
-
# bar = "[" + "#" * filled + "-" * (bar_width - filled) + "]"
|
|
879
|
-
|
|
880
|
-
# # Show time info in status bar
|
|
881
|
-
# step_info = f"Time step: {position}/{total} {bar} {self.format_time_value(self._time_values[self._time_index])}"
|
|
882
|
-
|
|
883
|
-
# # Update status bar if it exists
|
|
884
|
-
# if hasattr(self, 'statusBar') and callable(self.statusBar):
|
|
885
|
-
# self.statusBar().showMessage(step_info)
|
|
886
|
-
# else:
|
|
887
|
-
# print(step_info)
|
|
888
|
-
# except Exception as e:
|
|
889
|
-
# print(f"Error updating time label: {e}")
|
|
890
|
-
|
|
891
|
-
# def toggle_play_pause(self):
|
|
892
|
-
# """Toggle play/pause animation of time steps"""
|
|
893
|
-
# if self._is_playing:
|
|
894
|
-
# self.stop_animation()
|
|
895
|
-
# else:
|
|
896
|
-
# self.start_animation()
|
|
897
|
-
|
|
898
|
-
# def start_animation(self):
|
|
899
|
-
# """Start the time animation"""
|
|
900
|
-
# from PySide6.QtCore import QTimer
|
|
901
|
-
|
|
902
|
-
# if not hasattr(self, '_play_timer') or self._play_timer is None:
|
|
903
|
-
# self._play_timer = QTimer(self)
|
|
904
|
-
# self._play_timer.timeout.connect(self.animation_step)
|
|
905
|
-
|
|
906
|
-
# # Set animation speed (milliseconds between frames)
|
|
907
|
-
# animation_speed = 500 # 0.5 seconds between frames
|
|
908
|
-
# self._play_timer.start(animation_speed)
|
|
909
|
-
|
|
910
|
-
# self._is_playing = True
|
|
911
|
-
# self.play_button.setText("⏸") # Pause symbol
|
|
912
|
-
# self.play_button.setToolTip("Pause animation")
|
|
913
|
-
|
|
914
|
-
# def stop_animation(self):
|
|
915
|
-
# """Stop the time animation"""
|
|
916
|
-
# if hasattr(self, '_play_timer') and self._play_timer is not None:
|
|
917
|
-
# self._play_timer.stop()
|
|
918
|
-
|
|
919
|
-
# self._is_playing = False
|
|
920
|
-
# self.play_button.setText("▶") # Play symbol
|
|
921
|
-
# self.play_button.setToolTip("Play animation")
|
|
922
|
-
|
|
923
|
-
# def animation_step(self):
|
|
924
|
-
# """Advance one frame in the animation"""
|
|
925
|
-
# # Go to next time step
|
|
926
|
-
# next_time = (self._time_index + 1) % len(self._time_values)
|
|
927
|
-
# self.time_slider.setValue(next_time)
|
|
928
|
-
|
|
929
|
-
# def closeEvent(self, event):
|
|
930
|
-
# """Clean up resources when the window is closed"""
|
|
931
|
-
# # Stop animation timer if it's running
|
|
932
|
-
# if hasattr(self, '_is_playing') and self._is_playing:
|
|
933
|
-
# self.stop_animation()
|
|
934
|
-
|
|
935
|
-
# # Call the parent class closeEvent
|
|
936
|
-
# super().closeEvent(event)
|
|
937
|
-
|
|
938
|
-
# def populate_date_combo(self):
|
|
939
|
-
# """Populate the date combo box with time values"""
|
|
940
|
-
# if hasattr(self, '_has_time_dim') and self._has_time_dim and hasattr(self, 'date_combo'):
|
|
941
|
-
# try:
|
|
942
|
-
# self.date_combo.clear()
|
|
943
|
-
|
|
944
|
-
# # Add a reasonable subset of dates if there are too many
|
|
945
|
-
# max_items = 100 # Maximum number of items to show in dropdown
|
|
946
|
-
|
|
947
|
-
# if len(self._time_values) <= max_items:
|
|
948
|
-
# # Add all time values
|
|
949
|
-
# for i, time_value in enumerate(self._time_values):
|
|
950
|
-
# time_str = self.format_time_value(time_value)
|
|
951
|
-
# self.date_combo.addItem(time_str, i)
|
|
952
|
-
# else:
|
|
953
|
-
# # Add a subset of time values
|
|
954
|
-
# step = len(self._time_values) // max_items
|
|
955
|
-
|
|
956
|
-
# # Always include first and last
|
|
957
|
-
# indices = list(range(0, len(self._time_values), step))
|
|
958
|
-
# if (len(self._time_values) - 1) not in indices:
|
|
959
|
-
# indices.append(len(self._time_values) - 1)
|
|
960
|
-
|
|
961
|
-
# for i in indices:
|
|
962
|
-
# time_str = self.format_time_value(self._time_values[i])
|
|
963
|
-
# self.date_combo.addItem(f"{time_str} [{i+1}/{len(self._time_values)}]", i)
|
|
964
|
-
# except Exception as e:
|
|
965
|
-
# print(f"Error populating date combo: {e}")
|
|
966
|
-
|
|
967
|
-
# def date_combo_changed(self, index):
|
|
968
|
-
# """Handle date combo box selection change"""
|
|
969
|
-
# if index >= 0:
|
|
970
|
-
# time_index = self.date_combo.itemData(index)
|
|
971
|
-
# if time_index is not None:
|
|
972
|
-
# self.time_slider.setValue(time_index)
|
|
973
862
|
|
|
974
863
|
def _render_rgb(self):
|
|
975
864
|
if self.rgb_mode:
|
|
@@ -1321,7 +1210,7 @@ def run_viewer(
|
|
|
1321
1210
|
import click
|
|
1322
1211
|
|
|
1323
1212
|
@click.command()
|
|
1324
|
-
@click.version_option("0.2.
|
|
1213
|
+
@click.version_option("0.2.5", prog_name="viewtif")
|
|
1325
1214
|
@click.argument("tif_path", required=False)
|
|
1326
1215
|
@click.option("--band", default=1, show_default=True, type=int, help="Band number to display")
|
|
1327
1216
|
@click.option("--scale", default=1.0, show_default=True, type=int, help="Scale factor for display")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|