Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
378 changes: 372 additions & 6 deletions src/zyra/api/routers/cli.py

Large diffs are not rendered by default.

15 changes: 13 additions & 2 deletions src/zyra/api/workers/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,25 @@ def _args_dict_to_argv(stage: str, command: str, args: dict[str, Any]) -> list[s
argv.append(str(path))

# Remaining keys become long flags
negation_flags: dict[tuple[str, str], dict[str, str]] = {
("visualize", "globe"): {
"probe": "--no-probe",
"lighting": "--no-lighting",
"auto_rotate": "--no-auto-rotate",
}
}

for key, value in norm_args.items():
if value is None:
continue
flag = f"--{_to_kebab(key)}"
if isinstance(value, bool):
neg_flag = negation_flags.get((stage, command), {}).get(key)
if value:
argv.append(flag)
argv.append(f"--{_to_kebab(key)}")
elif neg_flag:
argv.append(neg_flag)
continue
flag = f"--{_to_kebab(key)}"
if isinstance(value, (list, tuple)):
for item in value:
argv.extend([flag, str(item)])
Expand Down
2 changes: 2 additions & 0 deletions src/zyra/assets/samples/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: Apache-2.0
"""Packaged sample datasets for quick-start demos."""
219 changes: 219 additions & 0 deletions src/zyra/assets/samples/age_of_seafloor_points.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
lat,lon,value,units
-60.00,-180.00,180.0,Ma
-60.00,-158.82,180.0,Ma
-60.00,-137.65,110.5,Ma
-60.00,-116.47,58.5,Ma
-60.00,-95.29,180.0,Ma
-60.00,-74.12,180.0,Ma
-60.00,-52.94,58.7,Ma
-60.00,-31.76,110.3,Ma
-60.00,-10.59,180.0,Ma
-60.00,10.59,180.0,Ma
-60.00,31.76,56.4,Ma
-60.00,52.94,30.2,Ma
-60.00,74.12,157.3,Ma
-60.00,95.29,180.0,Ma
-60.00,116.47,180.0,Ma
-60.00,137.65,180.0,Ma
-60.00,158.82,180.0,Ma
-60.00,180.00,180.0,Ma
-55.00,-150.00,180.0,Ma
-55.00,-141.11,136.5,Ma
-55.00,-132.22,83.2,Ma
-55.00,-123.33,29.8,Ma
-55.00,-114.44,62.0,Ma
-55.00,-105.56,115.3,Ma
-55.00,-96.67,168.7,Ma
-55.00,-27.73,125.8,Ma
-55.00,-21.82,161.2,Ma
-55.00,-15.91,180.0,Ma
-55.00,-10.00,180.0,Ma
-55.00,140.00,180.0,Ma
-55.00,145.57,180.0,Ma
-55.00,151.14,180.0,Ma
-55.00,156.71,180.0,Ma
-55.00,162.29,180.0,Ma
-55.00,167.86,180.0,Ma
-55.00,173.43,180.0,Ma
-55.00,179.00,180.0,Ma
-50.00,-180.00,180.0,Ma
-50.00,-158.82,180.0,Ma
-50.00,-137.65,121.4,Ma
-50.00,-116.47,40.6,Ma
-50.00,-95.29,167.7,Ma
-50.00,-10.59,180.0,Ma
-50.00,10.59,172.5,Ma
-50.00,20.00,116.1,Ma
-50.00,30.56,52.7,Ma
-50.00,31.76,45.5,Ma
-50.00,41.11,45.6,Ma
-50.00,51.67,23.8,Ma
-50.00,52.94,18.9,Ma
-50.00,62.22,74.6,Ma
-50.00,72.78,137.9,Ma
-50.00,74.12,145.9,Ma
-50.00,83.33,180.0,Ma
-50.00,93.89,180.0,Ma
-50.00,95.29,180.0,Ma
-50.00,104.44,180.0,Ma
-50.00,115.00,180.0,Ma
-50.00,116.47,180.0,Ma
-50.00,137.65,180.0,Ma
-50.00,158.82,180.0,Ma
-50.00,180.00,180.0,Ma
-43.12,-150.00,180.0,Ma
-43.12,-141.11,150.8,Ma
-43.12,-132.22,97.5,Ma
-43.12,-123.33,44.2,Ma
-43.12,-114.44,39.3,Ma
-43.12,-105.56,92.7,Ma
-43.12,-96.67,146.0,Ma
-42.14,156.71,180.0,Ma
-42.14,162.29,180.0,Ma
-42.14,167.86,180.0,Ma
-42.14,173.43,180.0,Ma
-42.14,179.00,180.0,Ma
-41.25,-27.73,97.0,Ma
-41.25,-21.82,132.4,Ma
-41.25,-15.91,167.9,Ma
-41.25,-10.00,180.0,Ma
-40.00,-180.00,180.0,Ma
-40.00,-158.82,180.0,Ma
-40.00,-137.65,134.2,Ma
-40.00,-116.47,20.8,Ma
-40.00,-95.29,147.9,Ma
-40.00,52.94,22.7,Ma
-40.00,74.12,132.3,Ma
-40.00,95.29,180.0,Ma
-40.00,158.82,180.0,Ma
-40.00,180.00,180.0,Ma
-37.50,41.11,52.1,Ma
-37.50,51.67,32.3,Ma
-37.50,62.22,57.3,Ma
-37.50,72.78,120.6,Ma
-37.50,83.33,180.0,Ma
-37.50,93.89,180.0,Ma
-37.50,104.44,180.0,Ma
-31.25,-150.00,180.0,Ma
-31.25,-141.11,167.4,Ma
-31.25,-132.22,114.0,Ma
-31.25,-123.33,60.7,Ma
-31.25,-114.44,14.5,Ma
-31.25,-105.56,67.8,Ma
-31.25,-96.67,121.2,Ma
-29.29,156.71,180.0,Ma
-29.29,162.29,180.0,Ma
-29.29,167.86,180.0,Ma
-29.29,173.43,180.0,Ma
-29.29,179.00,180.0,Ma
-27.50,-27.73,62.5,Ma
-27.50,-21.82,98.0,Ma
-25.00,41.11,59.9,Ma
-25.00,51.67,43.7,Ma
-25.00,62.22,37.1,Ma
-25.00,72.78,100.4,Ma
-25.00,83.33,163.8,Ma
-25.00,93.89,180.0,Ma
-25.00,104.44,180.0,Ma
-19.38,-150.00,180.0,Ma
-19.38,-141.11,180.0,Ma
-19.38,-132.22,131.9,Ma
-19.38,-123.33,78.5,Ma
-19.38,-114.44,25.2,Ma
-19.38,-105.56,41.7,Ma
-19.38,-96.67,95.0,Ma
-16.43,156.71,180.0,Ma
-16.43,162.29,180.0,Ma
-16.43,167.86,180.0,Ma
-16.43,173.43,180.0,Ma
-16.43,179.00,180.0,Ma
-13.75,-27.73,24.1,Ma
-13.75,-21.82,59.6,Ma
-12.50,41.11,68.4,Ma
-12.50,51.67,57.3,Ma
-12.50,62.22,14.8,Ma
-12.50,72.78,78.1,Ma
-12.50,83.33,141.4,Ma
-12.50,93.89,180.0,Ma
-12.50,104.44,180.0,Ma
-7.50,-150.00,180.0,Ma
-7.50,-141.11,180.0,Ma
-7.50,-132.22,150.1,Ma
-7.50,-123.33,96.7,Ma
-7.50,-114.44,43.4,Ma
-7.50,-105.56,15.2,Ma
-7.50,-96.67,68.5,Ma
-3.57,151.14,180.0,Ma
-3.57,156.71,180.0,Ma
-3.57,162.29,180.0,Ma
-3.57,167.86,180.0,Ma
-3.57,173.43,180.0,Ma
-3.57,179.00,180.0,Ma
0.00,-27.73,16.4,Ma
0.00,-21.82,19.1,Ma
0.00,41.11,77.1,Ma
0.00,51.67,72.2,Ma
0.00,62.22,8.8,Ma
0.00,72.78,54.5,Ma
0.00,83.33,117.8,Ma
0.00,93.89,180.0,Ma
0.00,104.44,180.0,Ma
0.00,115.00,180.0,Ma
4.38,-150.00,180.0,Ma
4.38,-141.11,180.0,Ma
4.38,-132.22,170.7,Ma
4.38,-123.33,117.4,Ma
4.38,-114.44,64.0,Ma
4.38,-105.56,10.7,Ma
4.38,-96.67,45.7,Ma
9.29,151.14,180.0,Ma
9.29,156.71,180.0,Ma
9.29,162.29,180.0,Ma
9.29,167.86,180.0,Ma
9.29,173.43,180.0,Ma
9.29,179.00,180.0,Ma
12.50,41.11,94.0,Ma
12.50,51.67,96.1,Ma
12.50,62.22,32.8,Ma
12.50,72.78,39.3,Ma
12.50,83.33,102.6,Ma
12.50,93.89,166.0,Ma
12.50,104.44,180.0,Ma
12.50,115.00,180.0,Ma
13.75,-27.73,56.8,Ma
13.75,-21.82,21.4,Ma
22.14,151.14,180.0,Ma
22.14,156.71,180.0,Ma
22.14,162.29,180.0,Ma
22.14,167.86,180.0,Ma
22.14,173.43,180.0,Ma
22.14,179.00,180.0,Ma
25.00,41.11,109.8,Ma
25.00,51.67,119.5,Ma
25.00,62.22,56.2,Ma
25.00,72.78,24.6,Ma
25.00,83.33,88.0,Ma
25.00,93.89,151.3,Ma
25.00,104.44,180.0,Ma
25.00,115.00,180.0,Ma
27.50,-45.45,180.0,Ma
27.50,-39.55,166.2,Ma
27.50,-33.64,130.7,Ma
27.50,-27.73,95.3,Ma
27.50,-21.82,59.8,Ma
35.00,151.14,180.0,Ma
35.00,156.71,180.0,Ma
35.00,162.29,180.0,Ma
35.00,167.86,180.0,Ma
35.00,173.43,180.0,Ma
35.00,179.00,180.0,Ma
41.25,-45.45,180.0,Ma
41.25,-39.55,180.0,Ma
41.25,-33.64,165.2,Ma
41.25,-27.73,129.7,Ma
41.25,-21.82,94.2,Ma
55.00,-45.45,180.0,Ma
55.00,-39.55,180.0,Ma
55.00,-33.64,180.0,Ma
55.00,-27.73,158.5,Ma
55.00,-21.82,123.0,Ma
19 changes: 19 additions & 0 deletions src/zyra/assets/samples/points.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
lat,lon,popup
51.5074,-0.1278,Buckingham Palace (London)
48.8566,2.3522,Eiffel Tower (Paris)
40.7128,-74.0060,Statue of Liberty (New York)
34.0522,-118.2437,Griffith Observatory (Los Angeles)
37.7749,-122.4194,Golden Gate Bridge (San Francisco)
19.4326,-99.1332,Zocalo (Mexico City)
-23.5505,-46.6333,Ibirapuera Park (Sao Paulo)
-34.6037,-58.3816,Obelisco (Buenos Aires)
-1.2921,36.8219,Kenyatta International (Nairobi)
35.6895,139.6917,Shinjuku Station (Tokyo)
37.5665,126.9780,Gyeongbokgung (Seoul)
31.2304,121.4737,The Bund (Shanghai)
-33.8688,151.2093,Sydney Opera House (Sydney)
1.3521,103.8198,Marina Bay Sands (Singapore)
28.6139,77.2090,India Gate (New Delhi)
55.7558,37.6176,Red Square (Moscow)
64.1265,-21.8174,Hallgrimskirkja (Reykjavik)
47.6062,-122.3321,Pike Place Market (Seattle)
67 changes: 67 additions & 0 deletions src/zyra/connectors/backends/vimeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,73 @@ def fetch_bytes(video_id: str) -> bytes: # pragma: no cover - placeholder
raise NotImplementedError("Ingest from Vimeo is not implemented yet")


def get_download_url(
video_id: str,
*,
token: str | None = None,
client_id: str | None = None,
client_secret: str | None = None,
) -> str | None:
"""Return a progressive download URL for the given Vimeo video.

Requires PyVimeo credentials (access token or client id/secret). When multiple
download renditions are available, the highest resolution progressive file is
returned.
"""

client = _get_client(token=token, client_id=client_id, client_secret=client_secret)
video_id = str(video_id).strip("/")
if not video_id.startswith("videos/"):
video_uri = f"/videos/{video_id}"
else:
video_uri = f"/{video_id}"
try:
response = client.get(video_uri)
except Exception as exc: # pragma: no cover - network/SDK dependent
raise RuntimeError(_summarize_exception(exc, operation="get")) from exc

data = None
if hasattr(response, "json"):
try:
data = response.json()
except Exception: # pragma: no cover - defensive
data = None
if not data:
data = getattr(response, "body", None)
if not isinstance(data, dict):
return None

downloads = data.get("download") or []
best_link = None
best_pixels = -1
for entry in downloads:
if not isinstance(entry, dict):
continue
link = entry.get("link")
if not link:
continue
if entry.get("quality") == "source":
return str(link)
width = entry.get("width") or 0
height = entry.get("height") or 0
pixels = width * height
if pixels > best_pixels:
best_pixels = pixels
best_link = str(link)
if best_link:
return best_link

files = data.get("files") or []
progressive = [
entry
for entry in files
if entry.get("quality") == "sd" or entry.get("quality") == "hd"
]
if progressive:
return str(progressive[0].get("link_secure") or progressive[0].get("link"))
return None


def upload_path(
video_path: str,
*,
Expand Down
5 changes: 5 additions & 0 deletions src/zyra/visualization/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Commands
- `animate` — Render animations from frames or datasets.
- `compose-video` — Compose image sequences into a video.
- `interactive` — Generate interactive maps.
- `globe` — Build interactive WebGL or Cesium globe bundles.

Common options (subset)
- `--input` / `--inputs` — single or batch inputs
Expand All @@ -21,3 +22,7 @@ Examples
- Heatmap: `zyra visualize heatmap --input data.nc --var T --extent -180 180 -90 90 --output heatmap.png`
- Vector: `zyra visualize vector --input data.nc --u U --v V --output wind.png`
- Animation: `zyra visualize animate --inputs frames/*.png --fps 24 --output anim.mp4`
- Globe (WebGL): ``zyra visualize globe --target webgl-sphere --texture earth.jpg --legend legend.png --output webgl_globe``
- Globe (Cesium): ``zyra visualize globe --target cesium-globe --tile-url https://tiledimageservices.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services/Seafloor_Age_02_WM/ImageServer --legend https://d3sik7mbbzunjo.cloudfront.net/land/sea_floor_age/colorbar_contour_en.png --output cesium_globe``

Globe bundles accept shared flags such as ``--title``/``--description`` for overlay copy, ``--legend`` for a title legend image, and ``--probe-gradient`` / ``--probe-lut`` / ``--probe-data`` so probe readouts can return color-decoded or dataset-backed values. Reusable color tables can be registered with ``--shared-gradient name=path`` when multiple layers or frame stacks should point at the same resource. Provide ``--video-source`` (local file, HTTP URL, or ``vimeo:ID``) together with ``--video-start`` and ``--video-fps`` to sample frames directly from video content—each extracted frame records an absolute timestamp based on the playback position. Textures and legends may reference local files, ``pkg:`` assets, or remote HTTP(S) URLs. Drag to rotate and use the mouse wheel or a touch pinch to zoom; ``--auto-rotate`` restores the legacy spin when desired. Use ``--lighting`` to opt back into shaded rendering—the viewer defaults to an unlit texture for clarity. The command writes an ``index.html`` alongside ``assets/`` that can be opened locally or published as static content.
Loading
Loading