Skip to content

Commit 82727a6

Browse files
rdhyeeclaude
andcommitted
Revert performance optimization: restore automatic color-coded dots
The optional classification button approach (from commit 4612339) never rendered properly in the browser. Reverting to the working automatic color-classification from commit 4a4b527 (PR isamplesorg#33). **Reverted changes**: - Removed non-functional classification button - Restored automatic CTE query with JOIN + GROUP BY - Dots now color-code automatically on load: - Blue (small): sample_location_only - field collection points - Purple (large): site_location_only - administrative markers - Orange (medium): both - dual-purpose locations **Trade-off**: Slower initial load (~7s vs ~2s) but WORKING feature. The button was never rendering due to Observable/Quarto interaction issues. Rather than debug further, restoring proven working behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 591b664 commit 82727a6

File tree

1 file changed

+51
-174
lines changed

1 file changed

+51
-174
lines changed

tutorials/parquet_cesium.qmd

Lines changed: 51 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,6 @@ viewof searchGeoPid = Inputs.text({
4747
});
4848
```
4949

50-
```{ojs}
51-
//| echo: fenced
52-
viewof classifyDots = Inputs.button("Color-code by type (sample/site/both)", {
53-
value: null,
54-
reduce: () => Date.now()
55-
})
56-
```
57-
5850
::: {.callout-tip collapse="true"}
5951
#### Using a local cached file for faster performance
6052

@@ -137,91 +129,69 @@ async function loadData(query, params = [], waiting_id = null, key = "default")
137129
}
138130
139131
locations = {
140-
// Performance telemetry
141-
performance.mark('locations-start');
142-
143-
// Get loading indicator element for progress updates
144-
const loadingDiv = document.getElementById('loading_1');
145-
if (loadingDiv) {
146-
loadingDiv.hidden = false;
147-
loadingDiv.innerHTML = 'Loading geocodes...';
148-
}
149-
150-
// Fast query: just get all distinct geocodes (no classification!)
132+
// Get geographic locations with classification by usage type
151133
const query = `
152-
SELECT DISTINCT
134+
WITH geo_classification AS (
135+
SELECT
136+
geo.pid,
137+
geo.latitude,
138+
geo.longitude,
139+
MAX(CASE WHEN e.p = 'sample_location' THEN 1 ELSE 0 END) as is_sample_location,
140+
MAX(CASE WHEN e.p = 'site_location' THEN 1 ELSE 0 END) as is_site_location
141+
FROM nodes geo
142+
JOIN nodes e ON (geo.row_id = e.o[1])
143+
WHERE geo.otype = 'GeospatialCoordLocation'
144+
GROUP BY geo.pid, geo.latitude, geo.longitude
145+
)
146+
SELECT
153147
pid,
154148
latitude,
155-
longitude
156-
FROM nodes
157-
WHERE otype = 'GeospatialCoordLocation'
149+
longitude,
150+
CASE
151+
WHEN is_sample_location = 1 AND is_site_location = 1 THEN 'both'
152+
WHEN is_sample_location = 1 THEN 'sample_location_only'
153+
WHEN is_site_location = 1 THEN 'site_location_only'
154+
END as location_type
155+
FROM geo_classification
158156
`;
159-
160-
performance.mark('query-start');
161157
const data = await loadData(query, [], "loading_1", "locations");
162-
performance.mark('query-end');
163-
performance.measure('locations-query', 'query-start', 'query-end');
164-
const queryTime = performance.getEntriesByName('locations-query')[0].duration;
165-
console.log(`Query executed in ${queryTime.toFixed(0)}ms - retrieved ${data.length} locations`);
166158
167159
// Clear the existing PointPrimitiveCollection
168160
content.points.removeAll();
169161
170-
// Single color for all points (blue)
171-
const defaultColor = Cesium.Color.fromCssColorString('#2E86AB');
172-
const defaultSize = 4;
162+
// Color and size styling by location type
163+
const styles = {
164+
sample_location_only: {
165+
color: Cesium.Color.fromCssColorString('#2E86AB'),
166+
size: 3
167+
}, // Blue - field collection points
168+
site_location_only: {
169+
color: Cesium.Color.fromCssColorString('#A23B72'),
170+
size: 6
171+
}, // Purple - administrative markers
172+
both: {
173+
color: Cesium.Color.fromCssColorString('#F18F01'),
174+
size: 5
175+
} // Orange - dual-purpose
176+
};
173177
174-
// Render points in chunks to keep UI responsive
175-
const CHUNK_SIZE = 500;
178+
// Create point primitives for cesium display
176179
const scalar = new Cesium.NearFarScalar(1.5e2, 2, 8.0e6, 0.2);
177-
178-
performance.mark('render-start');
179-
for (let i = 0; i < data.length; i += CHUNK_SIZE) {
180-
const chunk = data.slice(i, i + CHUNK_SIZE);
181-
const endIdx = Math.min(i + CHUNK_SIZE, data.length);
182-
183-
// Update progress indicator
184-
if (loadingDiv) {
185-
const pct = Math.round((endIdx / data.length) * 100);
186-
loadingDiv.innerHTML = `Rendering geocodes... ${endIdx.toLocaleString()}/${data.length.toLocaleString()} (${pct}%)`;
187-
}
188-
189-
// Add points for this chunk
190-
for (const row of chunk) {
191-
content.points.add({
192-
id: row.pid,
193-
position: Cesium.Cartesian3.fromDegrees(
194-
row.longitude, //longitude
195-
row.latitude, //latitude
196-
0 //elevation, m
197-
),
198-
pixelSize: defaultSize,
199-
color: defaultColor,
200-
scaleByDistance: scalar,
201-
});
202-
}
203-
204-
// Yield to browser between chunks to keep UI responsive
205-
if (i + CHUNK_SIZE < data.length) {
206-
await new Promise(resolve => setTimeout(resolve, 0));
207-
}
208-
}
209-
performance.mark('render-end');
210-
performance.measure('locations-render', 'render-start', 'render-end');
211-
const renderTime = performance.getEntriesByName('locations-render')[0].duration;
212-
213-
// Hide loading indicator
214-
if (loadingDiv) {
215-
loadingDiv.hidden = true;
180+
for (const row of data) {
181+
const style = styles[row.location_type] || styles.both; // fallback to orange
182+
content.points.add({
183+
id: row.pid,
184+
// https://cesium.com/learn/cesiumjs/ref-doc/Cartesian3.html#.fromDegrees
185+
position: Cesium.Cartesian3.fromDegrees(
186+
row.longitude, //longitude
187+
row.latitude, //latitude
188+
0,//randomCoordinateJitter(10.0, 10.0), //elevation, m
189+
),
190+
pixelSize: style.size,
191+
color: style.color,
192+
scaleByDistance: scalar,
193+
});
216194
}
217-
218-
performance.mark('locations-end');
219-
performance.measure('locations-total', 'locations-start', 'locations-end');
220-
const totalTime = performance.getEntriesByName('locations-total')[0].duration;
221-
222-
console.log(`Rendering completed in ${renderTime.toFixed(0)}ms`);
223-
console.log(`Total time (query + render): ${totalTime.toFixed(0)}ms`);
224-
225195
content.enableTracking();
226196
return data;
227197
}
@@ -376,12 +346,7 @@ async function get_samples_1(pid) {
376346
AND geo.otype = 'GeospatialCoordLocation'
377347
ORDER BY has_thumbnail DESC
378348
`;
379-
performance.mark('samples1-start');
380349
const result = await loadData(q, [pid], "loading_s1", "samples_1");
381-
performance.mark('samples1-end');
382-
performance.measure('samples1-query', 'samples1-start', 'samples1-end');
383-
const queryTime = performance.getEntriesByName('samples1-query')[0].duration;
384-
console.log(`Path 1 query executed in ${queryTime.toFixed(0)}ms - retrieved ${result?.length || 0} samples`);
385350
return result ?? [];
386351
}
387352
@@ -438,12 +403,7 @@ async function get_samples_2(pid) {
438403
AND geo.otype = 'GeospatialCoordLocation'
439404
ORDER BY has_thumbnail DESC
440405
`;
441-
performance.mark('samples2-start');
442406
const result = await loadData(q, [pid], "loading_s2", "samples_2");
443-
performance.mark('samples2-end');
444-
performance.measure('samples2-query', 'samples2-start', 'samples2-end');
445-
const queryTime = performance.getEntriesByName('samples2-query')[0].duration;
446-
console.log(`Path 2 query executed in ${queryTime.toFixed(0)}ms - retrieved ${result?.length || 0} samples`);
447407
return result ?? [];
448408
}
449409
@@ -500,12 +460,7 @@ async function get_samples_at_geo_cord_location_via_sample_event(pid) {
500460
AND geo.otype = 'GeospatialCoordLocation'
501461
ORDER BY has_thumbnail DESC
502462
`;
503-
performance.mark('eric-query-start');
504463
const result = await loadData(q, [pid], "loading_combined", "samples_combined");
505-
performance.mark('eric-query-end');
506-
performance.measure('eric-query', 'eric-query-start', 'eric-query-end');
507-
const queryTime = performance.getEntriesByName('eric-query')[0].duration;
508-
console.log(`Eric's query executed in ${queryTime.toFixed(0)}ms - retrieved ${result?.length || 0} samples`);
509464
return result ?? [];
510465
}
511466
@@ -766,84 +721,6 @@ md`Retrieved ${pointdata.length} locations from ${parquet_path}.`;
766721
}
767722
```
768723

769-
```{ojs}
770-
//| echo: false
771-
// Handle optional classification button: recolor dots by type
772-
{
773-
if (classifyDots !== null) {
774-
console.log("Classifying dots by type...");
775-
performance.mark('classify-start');
776-
777-
// Run the classification query
778-
const query = `
779-
WITH geo_classification AS (
780-
SELECT
781-
geo.pid,
782-
MAX(CASE WHEN e.p = 'sample_location' THEN 1 ELSE 0 END) as is_sample_location,
783-
MAX(CASE WHEN e.p = 'site_location' THEN 1 ELSE 0 END) as is_site_location
784-
FROM nodes geo
785-
JOIN nodes e ON (geo.row_id = e.o[1])
786-
WHERE geo.otype = 'GeospatialCoordLocation'
787-
GROUP BY geo.pid
788-
)
789-
SELECT
790-
pid,
791-
CASE
792-
WHEN is_sample_location = 1 AND is_site_location = 1 THEN 'both'
793-
WHEN is_sample_location = 1 THEN 'sample_location_only'
794-
WHEN is_site_location = 1 THEN 'site_location_only'
795-
END as location_type
796-
FROM geo_classification
797-
`;
798-
799-
const classifications = await db.query(query);
800-
801-
// Build lookup map: pid -> location_type
802-
const typeMap = new Map();
803-
for (const row of classifications) {
804-
typeMap.set(row.pid, row.location_type);
805-
}
806-
807-
// Color and size styling by location type
808-
const styles = {
809-
sample_location_only: {
810-
color: Cesium.Color.fromCssColorString('#2E86AB'),
811-
size: 3
812-
}, // Blue - field collection points
813-
site_location_only: {
814-
color: Cesium.Color.fromCssColorString('#A23B72'),
815-
size: 6
816-
}, // Purple - administrative markers
817-
both: {
818-
color: Cesium.Color.fromCssColorString('#F18F01'),
819-
size: 5
820-
} // Orange - dual-purpose
821-
};
822-
823-
// Update colors of existing points
824-
const points = content.points;
825-
for (let i = 0; i < points.length; i++) {
826-
const point = points.get(i);
827-
const pid = point.id;
828-
const locationType = typeMap.get(pid);
829-
830-
if (locationType && styles[locationType]) {
831-
point.color = styles[locationType].color;
832-
point.pixelSize = styles[locationType].size;
833-
}
834-
}
835-
836-
performance.mark('classify-end');
837-
performance.measure('classification', 'classify-start', 'classify-end');
838-
const classifyTime = performance.getEntriesByName('classification')[0].duration;
839-
console.log(`Classification completed in ${classifyTime.toFixed(0)}ms - updated ${points.length} points`);
840-
console.log(` - Blue (sample_location_only): field collection points`);
841-
console.log(` - Purple (site_location_only): administrative markers`);
842-
console.log(` - Orange (both): dual-purpose locations`);
843-
}
844-
}
845-
```
846-
847724
::: {.panel-tabset}
848725

849726
## Map

0 commit comments

Comments
 (0)