# 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
```javascript
// 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
```javascript
// 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
```javascript
// 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
```javascript
// Learned pattern for accessing feature properties in expressions
['get', 'propertyName']  // Retrieves property value from feature
```

### My Enhancements Beyond Web Source:

1. **Compound Filter Expressions**:
   - Used `all` operator to combine multiple filter conditions
   - Implemented range filtering with `>=` and `<=`
   - Multi-value filtering with `in` and `literal`

2. **Range Sliders**:
   - Extended beyond checkboxes to continuous controls
   - Real-time value display and updates
   - Multiple independent metric thresholds

3. **Filter Coordination**:
   - Mutual exclusivity for "All" vs specific regions
   - State management across 6 filter dimensions
   - Reset functionality restoring all defaults

4. **Statistics Calculation**:
   - Query rendered features after filtering
   - Aggregate calculations (sum, average)
   - Live dashboard updates

5. **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**:
```javascript
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**:
```javascript
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):
```javascript
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):
```javascript
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**:
```javascript
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

```javascript
{
    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):

```javascript
'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):

```javascript
'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:

```javascript
'circle-stroke-color': [
    'interpolate',
    ['linear'],
    ['get', 'researchScore'],
    55, '#ff4444',   // Red
    80, '#ffaa00',   // Orange
    95, '#00ffff'    // Cyan
]
```

## Globe Configuration

### Atmosphere Settings

```javascript
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

```javascript
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

```css
.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

- [x] Uses Mapbox GL JS v3.0.1
- [x] Globe projection enabled
- [x] Atmosphere effects configured
- [x] 120 universities with accurate coordinates
- [x] 6 data metrics per university
- [x] Region checkbox filters (7 options)
- [x] Ranking range slider
- [x] 4 metric threshold sliders
- [x] Compound filter expressions with `all`, `in`, `>=`, `<=`
- [x] Real-time statistics dashboard
- [x] Interactive popups with full details
- [x] Reset filters functionality
- [x] Pause/resume rotation control
- [x] Top 30 university labels
- [x] 8-stop color gradient for research scores
- [x] Inverse size scaling for rankings
- [x] Auto-rotation with interaction pause
- [x] Responsive design (desktop & mobile)
- [x] Web source attribution in README

## Learning Outcomes

**Completing this iteration demonstrates understanding of**:

1. **Filter Expressions**: Syntax and composition with Mapbox expressions
2. **Dynamic Filtering**: Real-time layer updates with `setFilter()`
3. **Compound Conditions**: Using `all`, `in`, `>=`, `<=` operators
4. **UI Controls**: Checkboxes and sliders for filter input
5. **Feature Querying**: `queryRenderedFeatures()` for statistics
6. **State Management**: Coordinating multiple filter dimensions
7. **Interactive Exploration**: User-driven data discovery
8. **Real-time Updates**: Synchronizing UI, filters, and statistics
9. **Filter Coordination**: Multiple layers with shared filter logic
10. **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

1. **Use `all` for AND logic**: Combine multiple conditions
2. **Use `in` for OR logic**: Match any of multiple values
3. **Use `literal` for arrays**: Wrap array values in filter expressions
4. **Use `get` for properties**: Access feature properties safely
5. **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

1. **index.html** - Main visualization with complete UI
2. **src/index.js** - Filtering logic and interactivity
3. **src/data/data.js** - 120 universities with 6 metrics each
4. **README.md** - Comprehensive documentation
5. **CLAUDE.md** - This development context file

## Local Development

### Running the Visualization

```bash
# 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.*
