Skip to content

πŸ› οΈ Troubleshooting & Tips

πŸ”§ Master Problem-Solving Guide

Overcome common challenges and optimize your building height extraction workflow

🚨 Common Issues and Solutions

πŸ—οΈ Building Visualization Problems

#### ⚠️ **Buildings appear stretched or distorted in 2.5D view**

🎯 Root Causes

  • Coordinate System Issues: Data in geographic (lat/lon) instead of projected coordinates
  • Height Unit Mismatch: Heights in feet instead of meters
  • Scale Factor Problems: Vertical exaggeration set incorrectly
  • CRS Inconsistency: Layers using different coordinate reference systems

βœ… Solutions

**πŸ—ΊοΈ Fix Coordinate System:**
-- In QGIS, reproject to local UTM zone
Project β†’ Properties β†’ CRS β†’ Search for "UTM Zone [XX]N"
-- Example for Ghana: EPSG:32630 (UTM Zone 30N)
**πŸ“ Verify Height Units:**
# Check height statistics in Python console
layer = iface.activeLayer()
heights = [f['height'] for f in layer.getFeatures() if f['height'] is not None]
print(f"Min height: {min(heights):.2f}")
print(f"Max height: {max(heights):.2f}")
print(f"Average height: {sum(heights)/len(heights):.2f}")
# Typical residential buildings: 3-15m
# If values are 10-50, might be in feet
**βš™οΈ Adjust Vertical Scale:** - In 2.5D symbology, set height scale factor to 0.3048 if data is in feet - For dramatic effect, use scale factor 2-3x - For realistic view, use scale factor 1.0x

πŸ“Š Data Quality Issues

#### ⚠️ **Missing or NULL height values**

πŸ” Diagnosis Steps

1. **πŸ“Š Check Attribute Table:**
Right-click layer β†’ Open Attribute Table
Look for NULL, 0, or negative values in height column
2. **🎯 Verify Building Presence:**
-- Filter by confidence in Field Calculator
"building_presence" > 0.5 AND "height" IS NOT NULL
3. **πŸ“ˆ Statistical Analysis:**
# Python console analysis
layer = iface.activeLayer()
total_features = layer.featureCount()
valid_heights = sum(1 for f in layer.getFeatures() 
                   if f['height'] is not None and f['height'] > 0)
print(f"Valid heights: {valid_heights}/{total_features} "
      f"({valid_heights/total_features*100:.1f}%)")

πŸ› οΈ Fix Strategies

**πŸ”§ Method 1: Default Value Assignment**
-- In Field Calculator, create new field 'height_clean'
COALESCE("height", 5)  -- Use 5m default for NULL values
**πŸ”§ Method 2: Conditional Defaults**
CASE 
    WHEN "height" IS NULL OR "height" <= 0 THEN 
        CASE 
            WHEN "area" > 200 THEN 8    -- Large building = 8m
            WHEN "area" > 100 THEN 6    -- Medium building = 6m  
            ELSE 4                      -- Small building = 4m
        END
    ELSE "height"
END
**πŸ”§ Method 3: Spatial Interpolation**
# Use nearby buildings to estimate height
# Processing Toolbox β†’ Interpolation β†’ IDW Interpolation
# Input: Buildings with valid heights
# Output: Height surface for estimation

🌍 Earth Engine and Download Issues

#### ⚠️ **Google Earth Engine timeout or memory errors**

🚫 Common Error Messages

  • User memory limit exceeded
  • Computation timed out
  • Too many concurrent aggregations
  • Image.reduceRegions: Tile error

πŸ’‘ Optimization Solutions

**🎯 Reduce Processing Scale:**
// Instead of scale: 4, try larger values
Export.image.toDrive({
  image: buildingHeights.clip(geometry),
  scale: 8,        // or 16 for testing
  maxPixels: 1e9,  // Increase pixel limit
  tileScale: 16    // Reduce memory per tile
});
**πŸ“ Process Smaller Areas:**
// Split large areas into smaller chunks
var bounds = geometry.bounds();
var xSize = bounds.coordinates().get(0).get(2).get(0)
             .subtract(bounds.coordinates().get(0).get(0).get(0));
var ySize = bounds.coordinates().get(0).get(2).get(1)
             .subtract(bounds.coordinates().get(0).get(0).get(1));

// Create grid of smaller areas
var gridSize = 0.01; // Degrees
// Process each grid cell separately
**⚑ Use Pyramid Policy:**
var buildingHeights = buildingsMosaic
  .select('building_height')
  .setDefaultProjection('EPSG:4326', null, 4)
  .pyramidingPolicy('mean');  // Smooth aggregation

🐍 Python Download and Processing Issues

#### ⚠️ **gsutil authentication and download problems**

πŸ” Authentication Issues

**Error:** `AccessDeniedException: 403 Forbidden` **Solutions:**
# 1. Login with Google account
gcloud auth login

# 2. Set up application default credentials
gcloud auth application-default login

# 3. Check authentication status
gcloud auth list

# 4. Set active account if multiple accounts
gcloud config set account your-email@gmail.com
**Error:** `gsutil: command not found` **Solutions:**
# Install Google Cloud SDK
# For Ubuntu/Debian:
curl https://sdk.cloud.google.com | bash
exec -l $SHELL

# For macOS:
brew install google-cloud-sdk

# For Windows: Download installer from cloud.google.com

πŸ“¦ Python Package Issues

**Error:** `ModuleNotFoundError: No module named 'rasterio'` **Solutions:**
# Create isolated environment
python -m venv building_env
source building_env/bin/activate  # Linux/Mac
# OR
building_env\Scripts\activate     # Windows

# Install with specific versions
pip install rasterio==1.3.8 geopandas==0.13.2
pip install google-cloud-storage matplotlib

# Fix GDAL issues (common on Windows)
pip install GDAL --find-links https://www.lfd.uci.edu/~gohlke/pythonlibs/
**Memory Issues with Large Files:**
# Process in chunks for large rasters
import rasterio
from rasterio.windows import Window

def process_large_raster_chunked(filepath, chunk_size=1000):
    with rasterio.open(filepath) as src:
        height, width = src.height, src.width

        for row in range(0, height, chunk_size):
            for col in range(0, width, chunk_size):
                window = Window(col, row, 
                              min(chunk_size, width - col),
                              min(chunk_size, height - row))

                chunk = src.read(window=window)
                # Process chunk here
                yield chunk

πŸ“Š Performance Optimization

⚑ QGIS Performance Tuning

πŸ–₯️ System Settings

  • Memory: Settings β†’ Options β†’ System β†’ Memory: Set to 75% of RAM
  • CPU: Enable multi-threading in Processing settings
  • Graphics: Enable OpenGL rendering in Advanced settings
  • Cache: Increase tile cache size to 100-500MB

πŸ“Š Layer Optimization

  • Indexes: Create spatial indexes for vector layers
  • Pyramids: Build overviews for large rasters
  • Simplification: Use scale-dependent rendering
  • Formats: Use GeoPackage instead of Shapefile
#### πŸ”§ **Performance Commands**
-- Create spatial index
CREATE SPATIAL INDEX ON buildings_table USING GIST (geometry);

-- Simplify complex geometries
ST_Simplify(geometry, 0.0001)  -- Adjust tolerance as needed

-- Scale-dependent rendering expression
CASE 
    WHEN @map_scale > 10000 THEN 'simple_style'
    ELSE 'detailed_style'
END

πŸ—„οΈ Data Management Best Practices

#### πŸ“ **File Organization**
πŸ“‚ building_heights_project/
β”œβ”€β”€ πŸ“Š data/
β”‚   β”œβ”€β”€ πŸ”’ raw/               # Original downloads
β”‚   β”œβ”€β”€ πŸ”„ processed/         # Cleaned data
β”‚   └── 🎯 analysis/          # Analysis results
β”œβ”€β”€ πŸ—ΊοΈ qgis_projects/        # QGIS project files
β”œβ”€β”€ πŸ“ˆ outputs/              # Final maps and exports
β”‚   β”œβ”€β”€ πŸ–ΌοΈ images/           # PNG, JPG exports
β”‚   β”œβ”€β”€ πŸ“„ documents/        # PDF reports
β”‚   └── 🌐 web/              # Web exports
└── πŸ“ documentation/        # Metadata and notes
#### πŸ’Ύ **Storage Optimization**
File Type Best Format Compression Use Case
🏒 Vector Buildings GeoPackage (.gpkg) Built-in Analysis, storage
πŸ“Š Height Rasters GeoTIFF (.tif) LZW or DEFLATE Analysis, visualization
🌐 Web Sharing Shapefile (.shp) ZIP archive Compatibility
πŸ“± Web Maps MBTiles PNG tiles Online viewing

🌍 Temporal Data Inconsistencies

⏰ Handling Multi-Year Variations

#### πŸ“Š **Year Selection Strategy** 1. **🎯 Data Quality Assessment:**
# Analyze data quality across years
years = [2019, 2020, 2021, 2022, 2023]
quality_scores = {}

for year in years:
    # Load data for each year
    valid_buildings = count_valid_heights(year)
    cloud_coverage = get_cloud_coverage(year)

    # Calculate quality score
    quality_scores[year] = valid_buildings * (1 - cloud_coverage)

best_year = max(quality_scores, key=quality_scores.get)
print(f"Best data quality: {best_year}")
2. **πŸ”„ Multi-Year Averaging:**
-- Create averaged heights across multiple years
SELECT 
    building_id,
    AVG(height) as avg_height,
    STDDEV(height) as height_variability,
    COUNT(*) as year_count
FROM building_temporal_data
WHERE height IS NOT NULL AND building_presence > 0.5
GROUP BY building_id
HAVING COUNT(*) >= 3  -- At least 3 years of data

πŸ“ Spatial Misalignment Fixes

#### πŸ”§ **Building Matching Across Years**
# Python script for spatial matching
import geopandas as gpd
from shapely.geometry import Point, Polygon

def match_buildings_across_years(buildings_2019, buildings_2023, tolerance=5):
    """
    🎯 Match buildings across different years using spatial proximity
    """
    matched_pairs = []

    for idx_2023, building_2023 in buildings_2023.iterrows():
        centroid_2023 = building_2023.geometry.centroid

        # Find nearby buildings from 2019
        distances = buildings_2019.geometry.centroid.distance(centroid_2023)
        closest_idx = distances.idxmin()
        closest_distance = distances.min()

        if closest_distance < tolerance:  # Within tolerance meters
            matched_pairs.append({
                'id_2019': closest_idx,
                'id_2023': idx_2023,
                'distance': closest_distance,
                'height_2019': buildings_2019.loc[closest_idx, 'height'],
                'height_2023': building_2023['height']
            })

    return pd.DataFrame(matched_pairs)

πŸŽ“ Expert Tips and Tricks

πŸ’‘ Advanced Workflow Optimizations

⚑ Speed Hacks

  • 🎯 Batch Processing: Process multiple countries simultaneously
  • πŸ”„ Automation: Use QGIS Model Builder for repeated tasks
  • πŸ’Ύ Caching: Save intermediate results to avoid recomputation
  • βš™οΈ Parallel Processing: Use multiprocessing for Python scripts

🎨 Quality Improvements

  • πŸ” Multi-Source Validation: Compare with OpenStreetMap data
  • πŸ“Š Statistical Filtering: Remove outliers using IQR method
  • 🌍 Local Knowledge: Validate against known landmarks
  • πŸ“ˆ Trend Analysis: Use temporal patterns for validation

πŸ› οΈ Tool Integration

  • πŸ—ΊοΈ QGIS + PostGIS: For large-scale database operations
  • 🐍 Python + R: Combine processing with statistical analysis
  • 🌐 Web Integration: Create online dashboards with Leaflet
  • πŸ“± Mobile Sync: Use QField for field validation

πŸ” Debugging Checklist

#### βœ… **Pre-Processing Checklist** - [ ] **πŸ“ CRS Consistency:** All layers use same coordinate system - [ ] **πŸ“Š Data Validity:** No NULL or negative height values - [ ] **πŸ“ Unit Verification:** Heights in meters, not feet - [ ] **🎯 Quality Filter:** Building presence > 0.5 - [ ] **πŸ“ Geometry Validity:** No invalid or self-intersecting polygons #### βœ… **Processing Checklist** - [ ] **πŸ’Ύ Sufficient Memory:** At least 8GB RAM for large areas - [ ] **⏰ Timeout Settings:** Increased for large exports - [ ] **πŸ”§ Scale Appropriateness:** Balance between detail and performance - [ ] **πŸ“Š Output Validation:** Sample outputs match expectations - [ ] **πŸ—„οΈ Backup Strategy:** Save intermediate results #### βœ… **Post-Processing Checklist** - [ ] **🎨 Visualization Quality:** Colors and styles appropriate - [ ] **πŸ“Š Statistical Validation:** Heights within expected ranges - [ ] **πŸ—ΊοΈ Spatial Accuracy:** Buildings align with satellite imagery - [ ] **πŸ“± Export Compatibility:** Files work in target applications - [ ] **πŸ“ Documentation:** Methods and parameters recorded

πŸŽ‰ Troubleshooting Master!

You're now equipped to solve any building height extraction challenge!