15 KiB
CLAUDE.md - Globe Visualization 6 Development Context
Project Overview
This is Iteration 6 in a progressive Mapbox GL JS learning series. Each iteration builds upon previous learnings while introducing new techniques from web research. This iteration focuses on interactive filtering and UI controls for data exploration.
Development Assignment
Task: Create an interactive globe visualization demonstrating advanced filtering techniques learned from Mapbox documentation.
Theme: Global University Rankings & Research Output
- 120 top research universities worldwide
- Multi-dimensional data: ranking, publications, citations, funding, Nobel prizes
- Interactive filtering by region and research metrics
- Real-time statistics dashboard
Web Research Integration
Source: Mapbox GL JS Filter Markers Example URL: https://docs.mapbox.com/mapbox-gl-js/example/filter-markers/
Techniques Extracted from Web Source:
1. Core Filtering Method
// From web source - basic pattern
map.setLayoutProperty(layerID, 'visibility', checked ? 'visible' : 'none');
// Enhanced approach learned
map.setFilter('layer-id', filterExpression);
The web source demonstrated layer visibility toggling. I learned the more sophisticated setFilter() approach which filters features within a layer rather than hiding the entire layer.
2. Filter Expression Syntax
// From web source - equality filter
['==', 'icon', symbol]
// My applications
['==', 'region', selectedRegion] // Equality
['<=', ['get', 'ranking'], maxRank] // Less than or equal
['>=', ['get', 'publications'], minPubs] // Greater than or equal
['in', ['get', 'region'], ['literal', regions]] // Multiple values
3. Checkbox UI Pattern
// From web source
checkbox.addEventListener('change', (e) => {
map.setLayoutProperty(
layerID,
'visibility',
e.target.checked ? 'visible' : 'none'
);
});
// My adaptation
checkbox.addEventListener('change', () => {
updateFilterState();
applyFilters();
});
4. Feature Property Access
// Learned pattern for accessing feature properties in expressions
['get', 'propertyName'] // Retrieves property value from feature
My Enhancements Beyond Web Source:
-
Compound Filter Expressions:
- Used
alloperator to combine multiple filter conditions - Implemented range filtering with
>=and<= - Multi-value filtering with
inandliteral
- Used
-
Range Sliders:
- Extended beyond checkboxes to continuous controls
- Real-time value display and updates
- Multiple independent metric thresholds
-
Filter Coordination:
- Mutual exclusivity for "All" vs specific regions
- State management across 6 filter dimensions
- Reset functionality restoring all defaults
-
Statistics Calculation:
- Query rendered features after filtering
- Aggregate calculations (sum, average)
- Live dashboard updates
-
Multi-Layer Filtering:
- Coordinated filters across universities and labels layers
- Maintained label visibility rules while respecting filters
Technical Implementation Details
Filter Architecture
Filter State Object:
let currentFilters = {
regions: ['all'], // Selected regions
rankingRange: [1, 120], // Min/max ranking
minPublications: 0, // Publication threshold
minCitations: 0, // Citation threshold
minFunding: 0, // Funding threshold
minNobelPrizes: 0 // Nobel prize threshold
};
Filter Expression Builder:
function applyFilters() {
let filterExpression = ['all']; // AND combiner
// Region filter (OR within selected)
if (!selectedRegions.includes('all')) {
filterExpression.push([
'in',
['get', 'region'],
['literal', selectedRegions]
]);
}
// Ranking filter
filterExpression.push(['<=', ['get', 'ranking'], maxRank]);
// Metric thresholds
if (minPubs > 0) {
filterExpression.push(['>=', ['get', 'publications'], minPubs]);
}
// Apply to layer
map.setFilter('universities-layer', filterExpression);
// Update statistics
updateStatistics();
}
UI Control Implementation
Checkbox Filters (7 regions):
regions.forEach((region, index) => {
const checkbox = createElement('input', {
type: 'checkbox',
id: `region-${index}`,
value: region,
checked: region === 'All'
});
checkbox.addEventListener('change', () => {
// Handle "All" mutual exclusivity
if (region === 'All' && checkbox.checked) {
uncheckOtherRegions();
} else if (checkbox.checked) {
uncheckAll();
}
applyFilters();
});
});
Range Sliders (5 metrics):
slider.addEventListener('input', (e) => {
const value = parseInt(e.target.value);
currentFilters.metric = value;
displayElement.textContent = formatValue(value);
applyFilters(); // Immediate update
});
Statistics Dashboard
Query Filtered Features:
function updateStatistics() {
const features = map.queryRenderedFeatures({
layers: ['universities-layer']
});
const stats = {
count: features.length,
avgResearch: average(features, 'researchScore'),
totalPubs: sum(features, 'publications'),
totalCitations: sum(features, 'citations'),
totalNobel: sum(features, 'nobelPrizes')
};
updateDashboard(stats);
}
This queries only the currently visible (filtered) features, enabling real-time statistics that update with every filter change.
Data Structure
University Data Model
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [longitude, latitude]
},
properties: {
name: "University Name",
country: "Country",
region: "Region",
ranking: 1-120, // Global position
publications: 5500-19800, // Annual papers
citations: 122000-456000, // Total citations
funding: 400-4200, // Annual funding ($M)
nobelPrizes: 0-161, // Total Nobel laureates
researchScore: 55-99 // Composite score
}
}
Data Coverage
120 Universities Across 6 Regions:
- North America: 27 (USA, Canada)
- Europe: 25 (UK, Germany, France, Switzerland, etc.)
- Asia-Pacific: 42 (China, Japan, Singapore, Australia, India, etc.)
- Middle East: 9 (Israel, Qatar, UAE, Saudi Arabia, Turkey)
- Africa: 6 (South Africa, Egypt, Kenya, Nigeria)
- Latin America: 11 (Brazil, Argentina, Chile, Mexico, Colombia)
Data Realism:
- Rankings based on major global university rankings
- Publications scaled to realistic annual output
- Citations reflect cumulative academic impact
- Funding approximates actual research budgets
- Nobel prizes are historically accurate
Metric Distributions
- Research Score: 55-99 (composite excellence measure)
- Publications: 5,500-19,800 (annual research output)
- Citations: 122,000-456,000 (total academic citations)
- Funding: $400M-$4,200M (annual research funding)
- Nobel Prizes: 0-161 (total affiliated laureates)
Visual Design System
Color Scheme - Research Excellence
8-stop gradient from deep red (emerging) to royal blue (exceptional):
'circle-color': [
'interpolate',
['linear'],
['get', 'researchScore'],
55, '#8b0000', // Deep red
65, '#dc143c', // Crimson
75, '#ff6347', // Tomato
80, '#ffa500', // Orange
85, '#ffd700', // Gold
90, '#32cd32', // Lime green
95, '#00bfff', // Deep sky blue
99, '#0066ff' // Royal blue
]
Size Encoding - Ranking Position
Inverse relationship (better rank = larger circle):
'circle-radius': [
'interpolate',
['linear'],
['get', 'ranking'],
1, 18, // Top rank
10, 14,
25, 11,
50, 9,
75, 7,
100, 5,
120, 4 // Lower rank
]
Stroke Styling
Dynamic stroke color matches research score:
'circle-stroke-color': [
'interpolate',
['linear'],
['get', 'researchScore'],
55, '#ff4444', // Red
80, '#ffaa00', // Orange
95, '#00ffff' // Cyan
]
Globe Configuration
Atmosphere Settings
map.setFog({
color: 'rgba(8, 16, 32, 0.95)', // Dark base
'high-color': 'rgba(25, 60, 120, 0.5)', // Blue horizon
'horizon-blend': 0.3, // Blend distance
'space-color': '#000510', // Deep space
'star-intensity': 0.7 // Star brightness
});
Auto-Rotation
let userInteracting = false;
function rotateGlobe() {
if (!userInteracting && !rotationPaused) {
const center = map.getCenter();
center.lng += 0.05; // Slow rotation
map.setCenter(center);
}
requestAnimationFrame(rotateGlobe);
}
Pauses during user interaction, resumes when idle.
UI/UX Design Patterns
Glassmorphism Theme
.panel {
background: rgba(0, 0, 0, 0.9);
backdrop-filter: blur(15px);
border: 1px solid rgba(255, 255, 255, 0.15);
}
Creates semi-transparent panels with blur effect for modern aesthetic.
Responsive Layout
Desktop:
- Controls panel: Right side
- Statistics: Bottom left
- Legend: Bottom right
- Title: Top center
Mobile (< 768px):
- Controls: Bottom overlay (scrollable)
- Statistics: Top left (compact)
- Legend: Hidden
- Title: Reduced size
Interactive Feedback
- Slider values update in real-time
- Statistics dashboard refreshes with filters
- Hover popups show detailed metrics
- Cursor changes on interactive elements
- Smooth transitions on all updates
Performance Considerations
Efficient Filtering
- No data reloading: Filters operate on existing source
- Expression-based: Computed on GPU where possible
- Debounced updates: Statistics calculated after filter application
- Feature querying: Only visible features processed
Optimized Rendering
- Single data source: All 120 universities in one GeoJSON
- Layer reuse: Same source for circles and labels
- Conditional labels: Only top 30 show text
- Stroke width: Modest 2px to reduce overdraw
Memory Management
- Static data: Universities loaded once
- No data duplication: Filters reference same source
- Minimal DOM: Controls generated once
- Event delegation: Where possible
Validation Checklist
- Uses Mapbox GL JS v3.0.1
- Globe projection enabled
- Atmosphere effects configured
- 120 universities with accurate coordinates
- 6 data metrics per university
- Region checkbox filters (7 options)
- Ranking range slider
- 4 metric threshold sliders
- Compound filter expressions with
all,in,>=,<= - Real-time statistics dashboard
- Interactive popups with full details
- Reset filters functionality
- Pause/resume rotation control
- Top 30 university labels
- 8-stop color gradient for research scores
- Inverse size scaling for rankings
- Auto-rotation with interaction pause
- Responsive design (desktop & mobile)
- Web source attribution in README
Learning Outcomes
Completing this iteration demonstrates understanding of:
- Filter Expressions: Syntax and composition with Mapbox expressions
- Dynamic Filtering: Real-time layer updates with
setFilter() - Compound Conditions: Using
all,in,>=,<=operators - UI Controls: Checkboxes and sliders for filter input
- Feature Querying:
queryRenderedFeatures()for statistics - State Management: Coordinating multiple filter dimensions
- Interactive Exploration: User-driven data discovery
- Real-time Updates: Synchronizing UI, filters, and statistics
- Filter Coordination: Multiple layers with shared filter logic
- Practical Application: Adapting web examples to complex use cases
Progressive Learning Demonstrated
Building on Previous Iterations:
- Iter 1: Basic globe setup, circle layers
- Iter 2: Color gradients, visual styling
- Iter 3: Data-driven expressions
- Iter 4: Multi-layer composition
- Iter 6: Interactive filtering & exploration ← Current
New Capabilities Added:
- Multi-criteria filtering system
- Checkbox and slider UI controls
- Compound filter expressions
- Real-time statistics calculation
- Coordinated filter state management
- Reset and rotation control
Synthesis Achievement: Combines visual techniques (Iter 1-3), layer composition (Iter 4), and interactive controls (Iter 6) into a comprehensive data exploration tool.
Development Notes
Filter Expression Best Practices
- Use
allfor AND logic: Combine multiple conditions - Use
infor OR logic: Match any of multiple values - Use
literalfor arrays: Wrap array values in filter expressions - Use
getfor properties: Access feature properties safely - Order matters: Put most selective filters first for performance
Common Pitfalls Avoided
-
❌ Reloading data on filter change (inefficient)
-
✅ Using
setFilter()on existing source (efficient) -
❌ Hiding entire layer with visibility (limited flexibility)
-
✅ Filtering features within layer (precise control)
-
❌ Calculating statistics from raw data (inaccurate)
-
✅ Querying rendered features (matches visible state)
-
❌ Conflicting filter states (confusing UX)
-
✅ Coordinated state management (clear behavior)
Extension Opportunities
Future enhancements:
- Animated transitions between filter states
- Saved filter presets (e.g., "Elite Tier", "High Impact")
- Export filtered data to CSV/JSON
- Comparison mode (before/after filtering)
- URL parameters for shareable filtered views
- Multi-map views showing different filter perspectives
- 3D extrusions for research output metrics
- Connection lines between collaborating institutions
Files Created
- index.html - Main visualization with complete UI
- src/index.js - Filtering logic and interactivity
- src/data/data.js - 120 universities with 6 metrics each
- README.md - Comprehensive documentation
- CLAUDE.md - This development context file
Local Development
Running the Visualization
# Option 1: Python 3
python3 -m http.server 8000
# Option 2: Python 2
python -m SimpleHTTPServer 8000
# Option 3: Node.js
npx http-server -p 8000
# Option 4: PHP
php -S localhost:8000
Then open: http://localhost:8000
Browser Requirements
- Modern browser with WebGL support
- Recommended: Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
- Minimum screen resolution: 1024x768
Testing Checklist
- Globe renders with atmosphere
- 120 universities visible on load
- Region checkboxes filter correctly
- "All" checkbox mutual exclusivity works
- All 5 sliders update filters in real-time
- Statistics dashboard shows correct values
- Hover popups display university details
- Labels appear for top 30 only
- Reset button restores all defaults
- Pause rotation button toggles correctly
- Auto-rotation works and pauses on interaction
- Responsive layout on mobile (< 768px)
This iteration successfully demonstrates mastery of Mapbox filtering techniques learned from official documentation, applied to a comprehensive research dataset with sophisticated multi-dimensional exploration capabilities.