📊 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**
📊 QGIS Expression-Based Styling¶
#### 🎨 **Dynamic Color Expression**
#### ✨ **Advanced Height-Based Opacity**
-- 🎯 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
-- 📊 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**:
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**
#### 🎨 **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 |
-- 📈 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;
🎯 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!