Skip to content

Commit 434ed9a

Browse files
Improve UI/UX and fix bugs (#1)
* Add plugin source and improve UI/UX - Show readable event names in dropdown instead of JSON URLs - Fix blank white canvas by transforming extents to canvas CRS - Make table columns resizable and headers clickable to sort - Show pre/post phase footprints in different outline colors (#3388ff/red) - Add semi-transparent yellow highlight for selected footprints via rubber band - Clear highlight on visualize; remove on deselect - Add byte-level download progress with cancel button - Use dark-mode-friendly status label colors - Fix RuntimeError on plugin unload (sip.isdeleted guard) - Fix phase filter to handle both "pre"/"post" and "pre-event"/"post-event" * Improve layer checking * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 6c74a5d commit 434ed9a

19 files changed

Lines changed: 4203 additions & 3 deletions

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,9 @@ cython_debug/
182182
.abstra/
183183

184184
# Visual Studio Code
185-
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
185+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186186
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187-
# and can be added to the global gitignore or merged into this file. However, if you prefer,
187+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
188188
# you could uncomment the following to ignore the entire vscode folder
189189
# .vscode/
190190

.pre-commit-config.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v6.0.0
4+
hooks:
5+
- id: check-toml
6+
- id: check-yaml
7+
- id: end-of-file-fixer
8+
types: [python]
9+
- id: trailing-whitespace
10+
- id: requirements-txt-fixer
11+
- id: check-added-large-files
12+
args: ["--maxkb=500"]
13+
14+
- repo: https://github.com/psf/black-pre-commit-mirror
15+
rev: 26.1.0
16+
hooks:
17+
- id: black-jupyter
18+
19+
- repo: https://github.com/codespell-project/codespell
20+
rev: v2.4.1
21+
hooks:
22+
- id: codespell
23+
args:
24+
[
25+
"--ignore-words-list=aci,acount,acounts,fallow,ges,hart,hist,nd,ned,ois,wqs,watermask,tre,mape",
26+
"--skip=*.csv,*.geojson,*.json,*.yml*.js,*.html,*cff,*.pdf",
27+
]
28+
29+
- repo: https://github.com/kynan/nbstripout
30+
rev: 0.9.1
31+
hooks:
32+
- id: nbstripout

README.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,53 @@
11
# qgis-vantor-plugin
2-
A QGIS plugin for searching and visualizing Vantor Open Data
2+
3+
A QGIS plugin for searching, visualizing, and downloading data from the [Vantor Open Data](https://vantor-opendata.s3.amazonaws.com/events/catalog.json) STAC catalog.
4+
5+
## Features
6+
7+
- Browse disaster event collections from the Vantor STAC catalog
8+
- Search imagery by map extent or drawn bounding box
9+
- Filter by event and pre/post-event phase
10+
- Visualize Cloud-Optimized GeoTIFF (COG) imagery directly in QGIS
11+
- Download selected imagery to disk
12+
- Interactive footprint display with bidirectional table/map selection
13+
- One-click dependency installer using uv for fast cross-platform package management
14+
15+
## Installation
16+
17+
### From Source
18+
19+
```bash
20+
git clone https://github.com/opengeos/qgis-vantor-plugin.git
21+
cd qgis-vantor-plugin
22+
python install.py
23+
```
24+
25+
Then restart QGIS and enable the **Vantor** plugin in **Plugins > Manage and Install Plugins**.
26+
27+
### First Run
28+
29+
1. Open the **Settings** panel from the Vantor toolbar
30+
2. Go to the **Dependencies** tab
31+
3. Click **Install Dependencies** to install `pystac`
32+
4. Restart QGIS
33+
34+
## Usage
35+
36+
1. Open the **Vantor Panel** from the toolbar
37+
2. Select an event from the dropdown (events are fetched live from the catalog)
38+
3. Optionally filter by phase (Pre-event / Post-event) and spatial extent
39+
4. Click **Search** to fetch items and display footprints on the map
40+
5. Click on a table row to highlight the footprint on the map (and vice versa)
41+
6. Check items and click **Visualize** to stream COG imagery or **Download** to save to disk
42+
43+
## Packaging
44+
45+
```bash
46+
python package_plugin.py
47+
```
48+
49+
This creates a `vantor-{version}.zip` file ready for upload to the QGIS plugin repository.
50+
51+
## License
52+
53+
[MIT](LICENSE)

install.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Cross-platform installation script for Vantor QGIS Plugin.
4+
5+
Usage:
6+
python install.py # Install the plugin
7+
python install.py --remove # Remove the plugin
8+
"""
9+
10+
import os
11+
import sys
12+
import shutil
13+
import argparse
14+
from pathlib import Path
15+
16+
17+
def get_qgis_plugin_dir() -> Path:
18+
"""Get the QGIS plugin directory based on the current platform.
19+
20+
Returns:
21+
Path to the QGIS plugins directory.
22+
"""
23+
home = Path.home()
24+
25+
if sys.platform == "linux" or sys.platform == "linux2":
26+
plugin_dir = home / ".local/share/QGIS/QGIS3/profiles/default/python/plugins"
27+
elif sys.platform == "darwin":
28+
plugin_dir = (
29+
home
30+
/ "Library/Application Support/QGIS/QGIS3/profiles/default/python/plugins"
31+
)
32+
elif sys.platform == "win32":
33+
appdata = os.environ.get("APPDATA", "")
34+
if appdata:
35+
plugin_dir = Path(appdata) / "QGIS/QGIS3/profiles/default/python/plugins"
36+
else:
37+
plugin_dir = (
38+
home / "AppData/Roaming/QGIS/QGIS3/profiles/default/python/plugins"
39+
)
40+
else:
41+
raise RuntimeError(f"Unsupported platform: {sys.platform}")
42+
43+
return plugin_dir
44+
45+
46+
def install_plugin(
47+
source_dir: Path, plugin_dir: Path, plugin_name: str = "vantor"
48+
) -> bool:
49+
"""Install the plugin to the QGIS plugins directory.
50+
51+
Args:
52+
source_dir: Path to the plugin source directory.
53+
plugin_dir: Path to the QGIS plugins directory.
54+
plugin_name: Name of the plugin folder in QGIS plugins directory.
55+
56+
Returns:
57+
True if installation was successful, False otherwise.
58+
"""
59+
target_dir = plugin_dir / plugin_name
60+
61+
# Create plugin directory if it doesn't exist
62+
plugin_dir.mkdir(parents=True, exist_ok=True)
63+
64+
# Remove existing installation
65+
if target_dir.exists():
66+
print(f"Removing existing installation: {target_dir}")
67+
shutil.rmtree(target_dir)
68+
69+
# Copy plugin
70+
print(f"Installing plugin to: {target_dir}")
71+
shutil.copytree(source_dir, target_dir)
72+
73+
return True
74+
75+
76+
def remove_plugin(plugin_dir: Path, plugin_name: str = "vantor") -> bool:
77+
"""Remove the plugin from the QGIS plugins directory.
78+
79+
Args:
80+
plugin_dir: Path to the QGIS plugins directory.
81+
plugin_name: Name of the plugin folder in QGIS plugins directory.
82+
83+
Returns:
84+
True if removal was successful, False otherwise.
85+
"""
86+
target_dir = plugin_dir / plugin_name
87+
88+
if target_dir.exists():
89+
print(f"Removing plugin: {target_dir}")
90+
shutil.rmtree(target_dir)
91+
print("Plugin removed successfully.")
92+
return True
93+
else:
94+
print("Plugin not found. Nothing to remove.")
95+
return False
96+
97+
98+
def main():
99+
parser = argparse.ArgumentParser(description="Install or remove Vantor QGIS Plugin")
100+
parser.add_argument(
101+
"--remove",
102+
action="store_true",
103+
help="Remove the plugin instead of installing",
104+
)
105+
parser.add_argument(
106+
"--plugin-dir",
107+
type=str,
108+
default=None,
109+
help="Custom QGIS plugin directory (optional)",
110+
)
111+
parser.add_argument(
112+
"--name",
113+
type=str,
114+
default="vantor",
115+
help="Plugin folder name in QGIS plugins directory (default: vantor)",
116+
)
117+
args = parser.parse_args()
118+
119+
# Get script directory
120+
script_dir = Path(__file__).parent.resolve()
121+
source_dir = script_dir / "vantor"
122+
123+
if not source_dir.exists():
124+
print(f"Error: Plugin source directory not found: {source_dir}")
125+
sys.exit(1)
126+
127+
# Get plugin directory
128+
if args.plugin_dir:
129+
plugin_dir = Path(args.plugin_dir)
130+
else:
131+
try:
132+
plugin_dir = get_qgis_plugin_dir()
133+
except RuntimeError as e:
134+
print(f"Error: {e}")
135+
print("Please specify the plugin directory with --plugin-dir")
136+
sys.exit(1)
137+
138+
print(f"Platform: {sys.platform}")
139+
print(f"Plugin directory: {plugin_dir}")
140+
print(f"Plugin name: {args.name}")
141+
print()
142+
143+
if args.remove:
144+
success = remove_plugin(plugin_dir, args.name)
145+
else:
146+
success = install_plugin(source_dir, plugin_dir, args.name)
147+
148+
if success:
149+
print()
150+
print("=" * 60)
151+
print("Installation complete!")
152+
print("=" * 60)
153+
print()
154+
print("To use the plugin:")
155+
print(" 1. Restart QGIS")
156+
print(" 2. Go to Plugins -> Manage and Install Plugins...")
157+
print(f" 3. Enable '{args.name}'")
158+
print()
159+
160+
sys.exit(0 if success else 1)
161+
162+
163+
if __name__ == "__main__":
164+
main()

0 commit comments

Comments
 (0)