Skip to content

📊 Advanced Visualization Techniques

🎨 Push the Boundaries of Building Height Visualization

Create stunning, professional-grade visualizations that tell compelling urban stories

🏗️ Advanced Isometric Building Views

Enhanced 3D Perspective Rendering

#### 🎯 **Custom Geometry Generator**
# 🏢 Advanced QGIS Python script for isometric buildings
layer = iface.activeLayer()

# 🎨 Create sophisticated 2.5D renderer
renderer = QgsRuleBasedRenderer(QgsSymbol.defaultSymbol(layer.geometryType()))
root_rule = renderer.rootRule()

# 🌟 Enhanced building symbol with gradients
symbol = QgsFillSymbol.createSimple({
    'color': '#b3b3b3',
    'outline_color': '#666666',
    'outline_width': '0.5'
})

# ⚡ Advanced geometry generator for realistic isometric effect
geom_generator = QgsGeometryGeneratorSymbolLayer.create({
    'geometryModifier': '''
        translate(
            extrude(
                $geometry, 
                cos(radians(135)) * 0.7, 
                sin(radians(135)) * 0.7, 
                CASE 
                    WHEN "height" IS NULL THEN 5
                    WHEN "height" < 1 THEN 5
                    ELSE "height" * 1.2
                END
            ),
            -0.3 * COALESCE("height", 5), 
            -0.3 * COALESCE("height", 5)
        )
    '''
})

# 🎨 Apply advanced styling
symbol.changeSymbolLayer(0, geom_generator)
renderer.rootRule().setSymbol(symbol)
layer.setRenderer(renderer)
layer.triggerRepaint()

print("🎉 Advanced isometric view applied!")

🔧 Advanced Features

  • 🎯 Smart Height Handling: Automatic fallback for NULL values
  • 📐 Perspective Correction: More realistic 3D angles
  • 🎨 Enhanced Shadows: Dynamic shadow positioning
  • 📊 Height Scaling: Adjustable vertical exaggeration

🌈 Sophisticated Height Categorization

🏙️ Multi-Criteria Building Classification

#### 📊 **Advanced Classification System**
🏢 Category 📏 Height Range 🎨 Color 🏗️ Description
🏠 Residential Low 0-5m #4CAF50 Single-story homes, shacks
🏘️ Residential Mid 5-10m #8BC34A 2-3 story houses
🏢 Commercial Low 10-20m #FFC107 4-6 story buildings
🏬 Commercial High 20-40m #FF9800 7-12 story towers
🏗️ Skyscrapers 40m+ #F44336 High-rise buildings

📊 QGIS Expression-Based Styling

#### 🎨 **Dynamic Color Expression**
-- 🎯 Advanced QGIS expression for dynamic building colors
CASE 
    WHEN "height" IS NULL OR "height" < 0 THEN '#CCCCCC'  -- Unknown
    WHEN "height" <= 5 THEN '#4CAF50'   -- Low residential
    WHEN "height" <= 10 THEN '#8BC34A'  -- Mid residential  
    WHEN "height" <= 20 THEN '#FFC107'  -- Commercial low
    WHEN "height" <= 40 THEN '#FF9800'  -- Commercial high
    ELSE '#F44336'                      -- Skyscrapers
END
#### ✨ **Advanced Height-Based Opacity**
-- 📊 Dynamic opacity based on building confidence
CASE 
    WHEN "building_presence" >= 0.8 THEN 255  -- High confidence: fully opaque
    WHEN "building_presence" >= 0.6 THEN 200  -- Medium confidence: semi-transparent
    WHEN "building_presence" >= 0.4 THEN 150  -- Low confidence: more transparent
    ELSE 100                                   -- Very low confidence: highly transparent
END

📈 Statistical Visualization Dashboard

📊 Create Height Distribution Charts

#### 📋 **Python Script for Advanced Analytics**
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from qgis.core import *

def create_building_analytics_dashboard(layer):
    """
    📊 Create comprehensive building height analytics dashboard
    """

    # 🎯 Extract building data
    features = [f for f in layer.getFeatures()]
    heights = [f['height'] for f in features if f['height'] is not None]
    areas = [f['area'] for f in features if f['area'] is not None]

    # 🎨 Set up dashboard style
    plt.style.use('dark_background')
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    fig.suptitle('🏙️ Building Heights Analytics Dashboard', 
                 fontsize=24, fontweight='bold', color='white')

    # 📊 Height distribution histogram
    ax1 = axes[0, 0]
    ax1.hist(heights, bins=30, color='#00ff7f', alpha=0.7, edgecolor='white')
    ax1.set_title('📊 Height Distribution', fontsize=14, color='white')
    ax1.set_xlabel('Height (m)', color='white')
    ax1.set_ylabel('Count', color='white')

    # 🥧 Building category pie chart
    ax2 = axes[0, 1]
    categories = ['Low (0-5m)', 'Mid (5-15m)', 'High (15-30m)', 'Very High (30m+)']
    counts = [
        sum(1 for h in heights if 0 <= h < 5),
        sum(1 for h in heights if 5 <= h < 15),
        sum(1 for h in heights if 15 <= h < 30),
        sum(1 for h in heights if h >= 30)
    ]
    colors = ['#4CAF50', '#FFC107', '#FF9800', '#F44336']
    ax2.pie(counts, labels=categories, colors=colors, autopct='%1.1f%%')
    ax2.set_title('🏢 Building Categories', fontsize=14, color='white')

    # 📈 Height vs Area scatter plot
    ax3 = axes[0, 2]
    if len(areas) == len(heights):
        ax3.scatter(areas, heights, alpha=0.6, c='#ff6b6b', s=30)
        ax3.set_title('📐 Height vs Area', fontsize=14, color='white')
        ax3.set_xlabel('Area (m²)', color='white')
        ax3.set_ylabel('Height (m)', color='white')

    # 📊 Statistical summary
    ax4 = axes[1, 0]
    stats_text = f"""
    📊 STATISTICS SUMMARY

    Total Buildings: {len(heights):,}

    🏗️ Height Statistics:
    Mean: {np.mean(heights):.1f}m
    Median: {np.median(heights):.1f}m  
    Max: {np.max(heights):.1f}m
    Min: {np.min(heights):.1f}m

    🏢 Height Categories:
    Low (0-5m): {counts[0]:,} ({counts[0]/len(heights)*100:.1f}%)
    Mid (5-15m): {counts[1]:,} ({counts[1]/len(heights)*100:.1f}%)
    High (15-30m): {counts[2]:,} ({counts[2]/len(heights)*100:.1f}%)
    Very High (30m+): {counts[3]:,} ({counts[3]/len(heights)*100:.1f}%)
    """
    ax4.text(0.1, 0.9, stats_text, transform=ax4.transAxes, 
             fontsize=12, color='white', verticalalignment='top',
             fontfamily='monospace')
    ax4.axis('off')

    # 📈 Cumulative distribution
    ax5 = axes[1, 1]
    sorted_heights = np.sort(heights)
    cumulative = np.arange(1, len(sorted_heights) + 1) / len(sorted_heights) * 100
    ax5.plot(sorted_heights, cumulative, color='#4facfe', linewidth=3)
    ax5.set_title('📈 Cumulative Distribution', fontsize=14, color='white')
    ax5.set_xlabel('Height (m)', color='white')
    ax5.set_ylabel('Cumulative %', color='white')
    ax5.grid(True, alpha=0.3)

    # 🎯 Box plot
    ax6 = axes[1, 2]
    bp = ax6.boxplot(heights, patch_artist=True)
    bp['boxes'][0].set_facecolor('#ff9a56')
    ax6.set_title('📊 Height Distribution Box Plot', fontsize=14, color='white')
    ax6.set_ylabel('Height (m)', color='white')

    plt.tight_layout()
    plt.savefig('building_analytics_dashboard.png', dpi=300, 
                bbox_inches='tight', facecolor='black')
    plt.show()

# 🚀 Execute the dashboard
layer = iface.activeLayer()
create_building_analytics_dashboard(layer)

🎮 Interactive Web Visualizations

🌐 3D Web Export with Enhanced Features

#### 🚀 **Advanced Qgis2threejs Configuration**
// 🎯 Custom JavaScript for enhanced web 3D viewer
{
    "title": "🏙️ Interactive Building Heights Explorer",
    "camera": {
        "position": [longitude, latitude, height],
        "target": [longitude, latitude, 0],
        "fov": 45
    },
    "lighting": {
        "ambient": 0.4,
        "directional": {
            "intensity": 0.8,
            "color": "#ffffff",
            "position": [1, 1, 1]
        }
    },
    "materials": {
        "building_low": {
            "color": "#4CAF50",
            "opacity": 0.9,
            "metalness": 0.1,
            "roughness": 0.8
        },
        "building_high": {
            "color": "#F44336", 
            "opacity": 0.9,
            "metalness": 0.3,
            "roughness": 0.6
        }
    },
    "controls": {
        "enableRotate": true,
        "enableZoom": true,
        "enablePan": true,
        "autoRotate": false,
        "autoRotateSpeed": 2.0
    }
}

📱 Mobile-Optimized 3D Views

#### 📲 **Responsive Design Settings**
/* 🎨 CSS for mobile-friendly 3D viewer */
@media (max-width: 768px) {
    .threejs-container {
        width: 100%;
        height: 70vh;
        touch-action: none;
    }

    .controls-panel {
        position: fixed;
        bottom: 20px;
        left: 50%;
        transform: translateX(-50%);
        background: rgba(0, 0, 0, 0.8);
        border-radius: 10px;
        padding: 15px;
    }

    .height-legend {
        font-size: 12px;
        line-height: 1.4;
        color: white;
    }
}

/* 🎯 Touch gestures optimization */
.building-tooltip {
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    padding: 10px;
    border-radius: 8px;
    font-family: 'Arial', sans-serif;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

🔥 Heat Map Visualizations

🌡️ Building Density Heat Maps

#### 📊 **QGIS Heat Map Creation** 1. **🎯 Vector → Analysis Tools → Heatmap (Kernel Density Estimation)** 2. **⚙️ Configuration**:
🔥 Heatmap Settings:
├── 📊 Input layer: Building polygons
├── 📏 Radius: 100 meters (adjust based on density)
├── 📐 Output raster size: 1000x1000 pixels
├── 📈 Weight field: "height" (for height-weighted density)
└── 🎨 Kernel shape: Quartic (smooth results)
3. **🎨 Styling**: - **Color Ramp**: Hot (black → red → yellow → white) - **Blending Mode**: Multiply or Screen - **Opacity**: 70-80% for overlay effect

🌈 Multi-Variable Heat Maps

🔥 Height Heat Map

  • Weight: Building height
  • Purpose: Show tall building clusters
  • Colors: Blue → Red
  • Applications: Urban planning, skyline analysis

📊 Density Heat Map

  • Weight: Building count
  • Purpose: Show building concentration
  • Colors: Purple → Yellow
  • Applications: Population estimation, infrastructure planning

🎭 Animation and Temporal Visualization

Time Series Animation

#### 🎬 **Create Building Growth Animation**
# 🎥 Python script for temporal building animation
import os
from datetime import datetime

def create_temporal_animation(base_layers, years, output_dir):
    """
    🎬 Create animated GIF showing building height changes over time
    """

    # 📁 Setup output directory
    os.makedirs(output_dir, exist_ok=True)
    frames = []

    for year in years:
        # 📊 Load data for specific year
        layer_path = f"building_heights_{year}.gpkg"
        layer = QgsVectorLayer(layer_path, f"Buildings_{year}", "ogr")

        # 🎨 Apply consistent styling
        apply_height_styling(layer, year)

        # 📷 Capture frame
        settings = QgsMapSettings()
        settings.setLayers([layer])
        settings.setBackgroundColor(QColor(0, 0, 0))

        # 💾 Save frame
        frame_path = f"{output_dir}/frame_{year}.png"
        export_frame(settings, frame_path)
        frames.append(frame_path)

    # 🎞️ Create animated GIF
    create_gif_from_frames(frames, f"{output_dir}/building_growth_animation.gif")
    print(f"🎉 Animation saved to: {output_dir}/building_growth_animation.gif")

def apply_height_styling(layer, year):
    """🎨 Apply consistent height-based styling"""
    # Implementation for consistent styling across years
    pass

def create_gif_from_frames(frames, output_path):
    """🎞️ Combine frames into animated GIF"""
    # Use PIL or similar library to create GIF
    pass

📈 Growth Pattern Visualization

#### 📊 **Building Height Change Detection**
-- 📈 SQL query for detecting height changes
SELECT 
    building_id,
    height_2019,
    height_2023,
    (height_2023 - height_2019) as height_change,
    CASE 
        WHEN (height_2023 - height_2019) > 10 THEN 'Major Growth'
        WHEN (height_2023 - height_2019) > 5 THEN 'Moderate Growth'
        WHEN (height_2023 - height_2019) > 0 THEN 'Minor Growth'
        WHEN (height_2023 - height_2019) = 0 THEN 'No Change'
        ELSE 'Decline/Demolition'
    END as change_category,
    ST_AsText(geometry) as location
FROM building_temporal_comparison
WHERE building_id IS NOT NULL
ORDER BY height_change DESC;
#### 🎨 **Change Visualization Symbology** | Change Type | Color | Symbol | Meaning | |-------------|--------|---------|---------| | **🚀 Major Growth (+10m)** | #FF0000 | ↗️ | Significant construction | | **📈 Moderate Growth (+5-10m)** | #FF9800 | ↗️ | Building additions | | **🔹 Minor Growth (+0-5m)** | #FFC107 | → | Small improvements | | **⭕ No Change** | #9E9E9E | ○ | Stable buildings | | **🔻 Decline** | #2196F3 | ↘️ | Demolition/damage |

🎯 Performance Optimization Tips

⚡ Rendering Speed

  • Use scale-dependent rendering for complex styles
  • Simplify geometries for overview displays
  • Cache styled layers as raster tiles
  • Enable feature caching in QGIS settings

💾 Memory Management

  • Process large datasets in chunks
  • Use virtual layers for on-the-fly calculations
  • Enable compression for exported files
  • Clear cache regularly during processing

🎨 Visual Quality

  • Use anti-aliasing for smooth edges
  • Apply appropriate transparency levels
  • Choose color schemes for accessibility
  • Test visualizations at different zoom levels

🎨 Advanced Visualization Mastery Achieved!

You now possess the skills to create world-class building height visualizations!