diff --git a/tutorials/parquet_cesium.qmd b/tutorials/parquet_cesium.qmd index 0f271b2..8aa7e76 100644 --- a/tutorials/parquet_cesium.qmd +++ b/tutorials/parquet_cesium.qmd @@ -714,6 +714,7 @@ md`Retrieved ${pointdata.length} locations from ${parquet_path}.`; ```{ojs} //| echo: false +//| output: false // Center initial Cesium view on PKAP Survey Area and also set Home to PKAP! { const viewer = content.viewer; @@ -744,6 +745,7 @@ md`Retrieved ${pointdata.length} locations from ${parquet_path}.`; ```{ojs} //| echo: false +//| output: false // Handle geocode search: fly to location and trigger queries { if (searchGeoPid && searchGeoPid.trim() !== "") { @@ -782,78 +784,93 @@ md`Retrieved ${pointdata.length} locations from ${parquet_path}.`; ```{ojs} //| echo: false +//| output: false // Handle optional classification button: recolor dots by type { if (classifyDots !== null) { console.log("Classifying dots by type..."); performance.mark('classify-start'); - // Run the classification query - const query = ` - WITH geo_classification AS ( + try { + // Run the classification query + const query = ` + WITH geo_classification AS ( + SELECT + geo.pid, + MAX(CASE WHEN e.p = 'sample_location' THEN 1 ELSE 0 END) as is_sample_location, + MAX(CASE WHEN e.p = 'site_location' THEN 1 ELSE 0 END) as is_site_location + FROM nodes geo + JOIN nodes e ON (geo.row_id = e.o[1]) + WHERE geo.otype = 'GeospatialCoordLocation' + GROUP BY geo.pid + ) SELECT - geo.pid, - MAX(CASE WHEN e.p = 'sample_location' THEN 1 ELSE 0 END) as is_sample_location, - MAX(CASE WHEN e.p = 'site_location' THEN 1 ELSE 0 END) as is_site_location - FROM nodes geo - JOIN nodes e ON (geo.row_id = e.o[1]) - WHERE geo.otype = 'GeospatialCoordLocation' - GROUP BY geo.pid - ) - SELECT - pid, - CASE - WHEN is_sample_location = 1 AND is_site_location = 1 THEN 'both' - WHEN is_sample_location = 1 THEN 'sample_location_only' - WHEN is_site_location = 1 THEN 'site_location_only' - END as location_type - FROM geo_classification - `; - - const classifications = await db.query(query); - - // Build lookup map: pid -> location_type - const typeMap = new Map(); - for (const row of classifications) { - typeMap.set(row.pid, row.location_type); - } + pid, + CASE + WHEN is_sample_location = 1 AND is_site_location = 1 THEN 'both' + WHEN is_sample_location = 1 THEN 'sample_location_only' + WHEN is_site_location = 1 THEN 'site_location_only' + END as location_type + FROM geo_classification + `; + + const classifications = await db.query(query); + + // Build lookup map: pid -> location_type + const typeMap = new Map(); + for (const row of classifications) { + typeMap.set(row.pid, row.location_type); + } - // Color and size styling by location type - const styles = { - sample_location_only: { - color: Cesium.Color.fromCssColorString('#2E86AB'), - size: 3 - }, // Blue - field collection points - site_location_only: { - color: Cesium.Color.fromCssColorString('#A23B72'), - size: 6 - }, // Purple - administrative markers - both: { - color: Cesium.Color.fromCssColorString('#F18F01'), - size: 5 - } // Orange - dual-purpose - }; - - // Update colors of existing points - const points = content.points; - for (let i = 0; i < points.length; i++) { - const point = points.get(i); - const pid = point.id; - const locationType = typeMap.get(pid); - - if (locationType && styles[locationType]) { - point.color = styles[locationType].color; - point.pixelSize = styles[locationType].size; + // Color and size styling by location type + const styles = { + sample_location_only: { + color: Cesium.Color.fromCssColorString('#2E86AB'), + size: 3 + }, // Blue - field collection points + site_location_only: { + color: Cesium.Color.fromCssColorString('#A23B72'), + size: 6 + }, // Purple - administrative markers + both: { + color: Cesium.Color.fromCssColorString('#F18F01'), + size: 5 + } // Orange - dual-purpose + }; + + // Update colors of existing points + const points = content.points; + for (let i = 0; i < points.length; i++) { + const point = points.get(i); + const pid = point.id; + const locationType = typeMap.get(pid); + + if (locationType && styles[locationType]) { + point.color = styles[locationType].color; + point.pixelSize = styles[locationType].size; + } } - } - performance.mark('classify-end'); - performance.measure('classification', 'classify-start', 'classify-end'); - const classifyTime = performance.getEntriesByName('classification')[0].duration; - console.log(`Classification completed in ${classifyTime.toFixed(0)}ms - updated ${points.length} points`); - console.log(` - Blue (sample_location_only): field collection points`); - console.log(` - Purple (site_location_only): administrative markers`); - console.log(` - Orange (both): dual-purpose locations`); + performance.mark('classify-end'); + performance.measure('classification', 'classify-start', 'classify-end'); + const classifyTime = performance.getEntriesByName('classification')[0].duration; + console.log(`Classification completed in ${classifyTime.toFixed(0)}ms - updated ${points.length} points`); + console.log(` - Blue (sample_location_only): field collection points`); + console.log(` - Purple (site_location_only): administrative markers`); + console.log(` - Orange (both): dual-purpose locations`); + } catch (error) { + console.error("Classification failed:", error); + console.error("Error details:", error.message); + + // Show user-friendly message in browser console + console.warn("⚠️ Color-coding failed due to a data loading issue."); + console.warn("💡 Tip: This is an intermittent DuckDB-WASM issue with remote files."); + console.warn(" Try clicking the button again, or use a local cached file for better reliability."); + console.warn(" See the 'Using a local cached file' section above for instructions."); + + // Note: We don't show an alert() to avoid disrupting the user experience + // The page remains functional, just without the color-coding + } } } ``` @@ -914,6 +931,113 @@ ${JSON.stringify(testrecord, null, 2)} ` ``` +## Samples at Location via Sampling Event (Eric Kansa's Query) + +
| Thumbnail | +Sample | +Description | +Site | +Location | +
|---|---|---|---|---|
|
+ ${sample.has_thumbnail ?
+ html`
+ No image `
+ }
+ |
+
+
+ ${sample.sample_label}
+
+
+ |
+
+
+ ${sample.sample_description || 'No description'}
+
+ |
+
+
+ ${sample.sample_site_label}
+
+
+
+ View site
+
+
+ |
+
+ ${sample.latitude.toFixed(5)}°N + ${sample.longitude.toFixed(5)}°E + |
+
| Thumbnail | -Sample | -Description | -Site | -Location | -
|---|---|---|---|---|
|
- ${sample.has_thumbnail ?
- html`
- No image `
- }
- |
-
-
- ${sample.sample_label}
-
-
- |
-
-
- ${sample.sample_description || 'No description'}
-
- |
-
-
- ${sample.sample_site_label}
-
-
-
- View site
-
-
- |
-
- ${sample.latitude.toFixed(5)}°N - ${sample.longitude.toFixed(5)}°E - |
-