Skip to content

Commit 55ae9d3

Browse files
rdhyeeclaude
andcommitted
Add error handling for classification query failures
Wraps the color-coding classification query in try-catch to handle intermittent DuckDB-WASM HTTP range request errors when querying large remote parquet files. Changes: - Added try-catch around classification query execution - Logs user-friendly error messages to console instead of crashing - Page remains functional even if classification fails - Provides helpful tips about retrying or using local cached file Fixes occasional "Range request...offset is out of bounds" errors that occur due to DuckDB-WASM limitations with remote files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 87fdcea commit 55ae9d3

File tree

1 file changed

+76
-62
lines changed

1 file changed

+76
-62
lines changed

tutorials/parquet_cesium.qmd

Lines changed: 76 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -788,72 +788,86 @@ md`Retrieved ${pointdata.length} locations from ${parquet_path}.`;
788788
console.log("Classifying dots by type...");
789789
performance.mark('classify-start');
790790
791-
// Run the classification query
792-
const query = `
793-
WITH geo_classification AS (
791+
try {
792+
// Run the classification query
793+
const query = `
794+
WITH geo_classification AS (
795+
SELECT
796+
geo.pid,
797+
MAX(CASE WHEN e.p = 'sample_location' THEN 1 ELSE 0 END) as is_sample_location,
798+
MAX(CASE WHEN e.p = 'site_location' THEN 1 ELSE 0 END) as is_site_location
799+
FROM nodes geo
800+
JOIN nodes e ON (geo.row_id = e.o[1])
801+
WHERE geo.otype = 'GeospatialCoordLocation'
802+
GROUP BY geo.pid
803+
)
794804
SELECT
795-
geo.pid,
796-
MAX(CASE WHEN e.p = 'sample_location' THEN 1 ELSE 0 END) as is_sample_location,
797-
MAX(CASE WHEN e.p = 'site_location' THEN 1 ELSE 0 END) as is_site_location
798-
FROM nodes geo
799-
JOIN nodes e ON (geo.row_id = e.o[1])
800-
WHERE geo.otype = 'GeospatialCoordLocation'
801-
GROUP BY geo.pid
802-
)
803-
SELECT
804-
pid,
805-
CASE
806-
WHEN is_sample_location = 1 AND is_site_location = 1 THEN 'both'
807-
WHEN is_sample_location = 1 THEN 'sample_location_only'
808-
WHEN is_site_location = 1 THEN 'site_location_only'
809-
END as location_type
810-
FROM geo_classification
811-
`;
812-
813-
const classifications = await db.query(query);
814-
815-
// Build lookup map: pid -> location_type
816-
const typeMap = new Map();
817-
for (const row of classifications) {
818-
typeMap.set(row.pid, row.location_type);
819-
}
805+
pid,
806+
CASE
807+
WHEN is_sample_location = 1 AND is_site_location = 1 THEN 'both'
808+
WHEN is_sample_location = 1 THEN 'sample_location_only'
809+
WHEN is_site_location = 1 THEN 'site_location_only'
810+
END as location_type
811+
FROM geo_classification
812+
`;
813+
814+
const classifications = await db.query(query);
815+
816+
// Build lookup map: pid -> location_type
817+
const typeMap = new Map();
818+
for (const row of classifications) {
819+
typeMap.set(row.pid, row.location_type);
820+
}
820821
821-
// Color and size styling by location type
822-
const styles = {
823-
sample_location_only: {
824-
color: Cesium.Color.fromCssColorString('#2E86AB'),
825-
size: 3
826-
}, // Blue - field collection points
827-
site_location_only: {
828-
color: Cesium.Color.fromCssColorString('#A23B72'),
829-
size: 6
830-
}, // Purple - administrative markers
831-
both: {
832-
color: Cesium.Color.fromCssColorString('#F18F01'),
833-
size: 5
834-
} // Orange - dual-purpose
835-
};
836-
837-
// Update colors of existing points
838-
const points = content.points;
839-
for (let i = 0; i < points.length; i++) {
840-
const point = points.get(i);
841-
const pid = point.id;
842-
const locationType = typeMap.get(pid);
843-
844-
if (locationType && styles[locationType]) {
845-
point.color = styles[locationType].color;
846-
point.pixelSize = styles[locationType].size;
822+
// Color and size styling by location type
823+
const styles = {
824+
sample_location_only: {
825+
color: Cesium.Color.fromCssColorString('#2E86AB'),
826+
size: 3
827+
}, // Blue - field collection points
828+
site_location_only: {
829+
color: Cesium.Color.fromCssColorString('#A23B72'),
830+
size: 6
831+
}, // Purple - administrative markers
832+
both: {
833+
color: Cesium.Color.fromCssColorString('#F18F01'),
834+
size: 5
835+
} // Orange - dual-purpose
836+
};
837+
838+
// Update colors of existing points
839+
const points = content.points;
840+
for (let i = 0; i < points.length; i++) {
841+
const point = points.get(i);
842+
const pid = point.id;
843+
const locationType = typeMap.get(pid);
844+
845+
if (locationType && styles[locationType]) {
846+
point.color = styles[locationType].color;
847+
point.pixelSize = styles[locationType].size;
848+
}
847849
}
848-
}
849850
850-
performance.mark('classify-end');
851-
performance.measure('classification', 'classify-start', 'classify-end');
852-
const classifyTime = performance.getEntriesByName('classification')[0].duration;
853-
console.log(`Classification completed in ${classifyTime.toFixed(0)}ms - updated ${points.length} points`);
854-
console.log(` - Blue (sample_location_only): field collection points`);
855-
console.log(` - Purple (site_location_only): administrative markers`);
856-
console.log(` - Orange (both): dual-purpose locations`);
851+
performance.mark('classify-end');
852+
performance.measure('classification', 'classify-start', 'classify-end');
853+
const classifyTime = performance.getEntriesByName('classification')[0].duration;
854+
console.log(`Classification completed in ${classifyTime.toFixed(0)}ms - updated ${points.length} points`);
855+
console.log(` - Blue (sample_location_only): field collection points`);
856+
console.log(` - Purple (site_location_only): administrative markers`);
857+
console.log(` - Orange (both): dual-purpose locations`);
858+
} catch (error) {
859+
console.error("Classification failed:", error);
860+
console.error("Error details:", error.message);
861+
862+
// Show user-friendly message in browser console
863+
console.warn("⚠️ Color-coding failed due to a data loading issue.");
864+
console.warn("💡 Tip: This is an intermittent DuckDB-WASM issue with remote files.");
865+
console.warn(" Try clicking the button again, or use a local cached file for better reliability.");
866+
console.warn(" See the 'Using a local cached file' section above for instructions.");
867+
868+
// Note: We don't show an alert() to avoid disrupting the user experience
869+
// The page remains functional, just without the color-coding
870+
}
857871
}
858872
}
859873
```

0 commit comments

Comments
 (0)