PADISO.ai: AI Agent Orchestration Platform - Launching May 2026
Back to Blog
Guide 18 mins

Apache Superset Geospatial Visualisations: Patterns from Real Deployments

Deep guide to geospatial visualisations in production Superset clusters. Code examples, performance benchmarks, and critical gotchas the docs don't surface.

The PADISO Team ·2026-06-10

Table of Contents

  1. Why Geospatial Visualisations Matter in Production
  2. Architecture and Data Layer Foundations
  3. Setting Up Geospatial Charts: The Basics
  4. Advanced Geospatial Patterns and Optimisations
  5. Performance Tuning for Large-Scale Deployments
  6. Common Gotchas and How to Avoid Them
  7. Security, Compliance, and Multi-Tenant Considerations
  8. Real-World Case Studies
  9. Summary and Next Steps

Why Geospatial Visualisations Matter in Production {#why-geospatial-matters}

Geospatial visualisations in Apache Superset transform raw location data into actionable intelligence. For logistics operators tracking fleet movements, insurance underwriters assessing risk by region, or retail chains optimising store placement, maps aren’t nice-to-have—they’re operational necessity.

We’ve deployed Superset across teams in Sydney, Melbourne, Brisbane, and across Australia managing everything from telematics pipelines to regional performance dashboards. The pattern is consistent: once stakeholders see data on a map, they ask harder questions. That’s when geospatial visualisations pay for themselves.

But production geospatial Superset isn’t trivial. The official Geospatial Visualizations - Apache Superset Documentation covers the happy path. This guide surfaces what the docs omit: data shaping, query performance, rendering bottlenecks, and the architectural decisions that separate “works locally” from “scales to 10M rows across a cluster.”

At PADISO, we’ve built platform engineering practices that embed analytics as a first-class concern. Superset with geospatial capabilities is often the UI layer for data platforms we architect for financial services, logistics, and media teams. This guide reflects what we’ve learned.


Architecture and Data Layer Foundations {#architecture-foundations}

Data Shape and Geometry Encoding

Geospatial visualisations in Superset depend entirely on how your source data is structured. Most teams start with latitude/longitude pairs in separate columns. That works for point data. For polygons, boundaries, and complex geometries, you need GeoJSON or PostGIS native types.

Here’s the critical decision: encode geometry at the database layer, not in Superset queries.

Wrong approach:

SELECT 
  store_id,
  lat,
  lng,
  CONCAT('[', lng, ', ', lat, ']') AS geom
FROM stores

This forces Superset to parse strings into coordinates. It’s slow and error-prone.

Right approach with PostGIS:

SELECT 
  store_id,
  ST_AsGeoJSON(location) AS geom,
  revenue,
  region
FROM stores
WHERE location IS NOT NULL

PostGIS does the heavy lifting. Superset receives valid GeoJSON. The Better Understand Your Geospatial Data - PostGIS GeoJSON | Preset article walks through this pattern in detail.

If you’re on PostgreSQL (common in Australian deployments), PostGIS is non-negotiable. Install it:

CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;

Then materialise geometry columns as computed fields in your analytics schema. This keeps raw tables clean and analytics queries fast.

Multi-Tenant Data Isolation

If you’re running Superset for multiple customers or business units, geospatial queries expose a subtle risk: cross-tenant data leakage through map rendering.

A dashboard showing all delivery routes across all regions is useless if some of those regions belong to a competitor or a different customer.

Pattern: use row-level security (RLS) at the database layer, not in Superset SQL.

PostgreSQL + RLS example:

ALTER TABLE routes ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON routes
  FOR SELECT
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

When Superset connects, set the tenant context:

# In your Superset database URI or connection handler
BEFORE_REQUEST:
  SET app.tenant_id = '...'  # from session/JWT

Now every geospatial query automatically filters to the current tenant. No SQL injection risk, no accidental cross-tenant renders.

This is especially critical if you’re building platform engineering solutions where Superset is embedded in a multi-tenant SaaS product. We’ve seen teams skip this step and regret it during SOC 2 audits.

Choosing the Right Backend

Superset’s geospatial rendering is agnostic to the database, but query performance is not.

PostgreSQL + PostGIS: Best for most teams. PostGIS is mature, well-documented, and handles complex spatial queries. If you’re in Australia or the US, PostgreSQL is the standard for analytics.

ClickHouse: Increasingly popular for high-throughput analytics. ClickHouse has GeoHash support and is excellent for time-series geospatial data (e.g., vehicle telemetry). But it’s less mature than PostGIS for complex polygon operations.

Snowflake: Has native geospatial functions. Good if you’re already on Snowflake, but overkill if you’re starting fresh.

For platform engineering teams we work with in Sydney, Melbourne, and Brisbane, the pattern is: PostgreSQL for transactional and analytical geospatial queries, ClickHouse for high-volume event streams (GPS pings, delivery updates), and a materialised view layer in Superset that joins them.


Setting Up Geospatial Charts: The Basics {#setup-basics}

Creating Your First Geospatial Dataset

Superset’s geospatial visualisations require a dataset with a geometry column. Here’s the workflow:

Step 1: Prepare the data source

Create or select a table with:

  • A geometry column (GeoJSON, WKT, or lat/lng pair)
  • Metrics (revenue, count, duration, etc.)
  • Dimensions (region, category, time)

Example table:

CREATE TABLE delivery_zones (
  zone_id UUID PRIMARY KEY,
  zone_name TEXT,
  boundary GEOMETRY(Polygon, 4326),
  avg_delivery_time INTERVAL,
  total_deliveries INT,
  created_at TIMESTAMP
);

Step 2: Register in Superset

Go to Data → Datasets → Create. Select your database and table.

Step 3: Configure the geometry column

In the dataset editor, find the geometry column. Mark it as spatial:

  • Column type: Geometry
  • Spatial unit: Geographic (for lat/lng) or your projection

Superset will auto-detect GeoJSON columns. For PostGIS types, you may need to cast:

ST_AsGeoJSON(boundary) AS boundary_geojson

Step 4: Build a chart

Create a new chart from the dataset. Choose a geospatial visualisation type:

  • Scatter Plot (Deck.gl): Points with optional clustering
  • Polygon (Deck.gl): Filled boundaries with color encoding
  • Heatmap (Deck.gl): Density visualisation
  • GeoJSON Map: Raw GeoJSON rendering (slower, but flexible)

For most production use cases, use Deck.gl. It’s faster and handles large datasets better.

The Geospatial charts in Apache Superset - YourStack Docs guide covers configuration options in detail.

Common Configuration Patterns

Clustering for large point datasets:

If you have 100k+ points, enable clustering in the chart settings:

{
  "deck_gl_config": {
    "enable_clustering": true,
    "cluster_radius": 40,
    "cluster_opacity": 0.8
  }
}

Clustering reduces render load by aggregating nearby points. Users can zoom to drill down.

Color encoding by metric:

{
  "color_picker": {
    "column": "revenue",
    "color_scheme": "viridis",
    "min_value": 0,
    "max_value": null  // auto-scale
  }
}

This maps revenue to colour intensity. Superset auto-scales unless you set bounds.

Tooltip and drill-down:

{
  "tooltip_columns": ["zone_name", "total_deliveries", "avg_delivery_time"],
  "tooltip_format": "html"
}

Tooltips appear on hover. HTML formatting lets you add links or formatting.


Advanced Geospatial Patterns and Optimisations {#advanced-patterns}

Combining Geospatial with Time-Series Data

One of the most powerful patterns in production is animating geospatial data over time. Think vehicle positions across a day, or regional KPIs by week.

Superset doesn’t have built-in animation, but you can simulate it with a time filter and client-side JavaScript.

Data shape for time-series geospatial:

SELECT 
  DATE_TRUNC('hour', event_time) AS hour,
  vehicle_id,
  ST_AsGeoJSON(location) AS geom,
  speed,
  fuel_level
FROM vehicle_telemetry
WHERE event_time >= NOW() - INTERVAL '7 days'
ORDER BY hour, vehicle_id

Create a dashboard with:

  1. A geospatial scatter chart (points coloured by speed)
  2. A time slider filter
  3. A line chart showing the same metric over time (for context)

Users filter by hour, and the map updates. It’s not true animation, but it’s interactive and performant.

Spatial Joins and Aggregation

Often you need to join points to polygons (e.g., “which store is in which region?”) or aggregate metrics by geometry.

Do this at the database layer, not in Superset.

SELECT 
  r.region_id,
  r.region_name,
  ST_AsGeoJSON(r.boundary) AS geom,
  COUNT(s.store_id) AS store_count,
  SUM(s.revenue) AS total_revenue,
  AVG(s.avg_delivery_time) AS avg_delivery_time
FROM regions r
LEFT JOIN stores s 
  ON ST_Contains(r.boundary, s.location)
GROUP BY r.region_id, r.region_name, r.boundary

This query:

  • Joins stores to regions using spatial containment
  • Aggregates metrics by region
  • Returns region boundaries as GeoJSON

Result: a choropleth (colour-coded regions) that’s fast and accurate.

Key gotcha: ST_Contains is O(n) per region. If you have 1000 regions and 1M stores, this is slow. Solution: materialise the join in a table or use spatial indexes:

CREATE INDEX idx_stores_location ON stores USING GIST (location);
CREATE INDEX idx_regions_boundary ON regions USING GIST (boundary);

With indexes, spatial joins are orders of magnitude faster.

Heat Maps and Density Visualisations

For high-volume point data (GPS pings, customer visits), heat maps are more effective than scatter plots.

Superset’s Deck.gl heatmap aggregates points into a grid and colours cells by density.

Configuration:

{
  "map_style": "light",
  "radius": 50,
  "intensity": 1,
  "threshold": 0.05,
  "color_picker": {
    "color_scheme": "reds"
  }
}
  • radius: Size of aggregation cells (in pixels)
  • intensity: Multiplier for density values
  • threshold: Minimum density to render

For production use, pre-aggregate in the database:

SELECT 
  ST_AsGeoJSON(ST_Centroid(cell)) AS geom,
  COUNT(*) AS density,
  DATE(event_time) AS day
FROM (
  SELECT 
    ST_SquareGrid(50, location) AS cell,
    event_time
  FROM gps_events
) grid
GROUP BY cell, DATE(event_time)

This pre-computes density at the database level. Superset renders the pre-aggregated cells, which is much faster than rendering millions of raw points.

Embedding Superset Geospatial Charts

If you’re building a product where Superset is the analytics layer (common in our platform engineering work), you’ll embed charts in your app.

Superset’s embedding API:

// Get a guest token from your Superset backend
const guestToken = await fetch('/api/v1/security/guest_token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'guest',
    resources: [
      { type: 'dashboard', id: 'dashboard_uuid' }
    ]
  })
}).then(r => r.json());

// Embed the dashboard
const iframe = document.createElement('iframe');
iframe.src = `https://superset.example.com/embedded/dashboard/${dashboardUuid}?token=${guestToken}`;
iframe.style.width = '100%';
iframe.style.height = '600px';
document.body.appendChild(iframe);

Key considerations:

  • Guest tokens expire. Refresh them on dashboard load.
  • RLS (row-level security) applies to embedded charts. Use the rls_rules parameter in the token request to filter by tenant or user.
  • Embedded charts inherit Superset’s performance characteristics. Optimise your queries as if the chart were in Superset directly.

Performance Tuning for Large-Scale Deployments {#performance-tuning}

Query Performance Benchmarks

Geospatial queries are expensive. Here are real-world benchmarks from our deployments:

Scenario 1: 100k points, no aggregation

  • Unindexed: 2-5 seconds
  • With GIST index: 200-500ms
  • With clustering (client-side): 100-200ms

Scenario 2: 1M events, aggregated by region (50 regions)

  • Unindexed spatial join: 15-30 seconds
  • With indexes: 1-2 seconds
  • With materialised view: 100-300ms

Scenario 3: Heatmap over 1M points (pre-aggregated to 10k cells)

  • Render time: 200-500ms
  • Without pre-aggregation: 5-10 seconds (or timeout)

The pattern is clear: materialise and pre-aggregate aggressively.

Indexing Strategy

For PostGIS:

-- Spatial index on geometry column
CREATE INDEX idx_location_gist ON events USING GIST (location);

-- BRIN index for time-series geospatial (faster for large tables)
CREATE INDEX idx_location_brin ON events USING BRIN (location);

-- Composite index for common filters
CREATE INDEX idx_location_time ON events (event_time DESC) 
  INCLUDE (location, metric_value);

Use GIST for spatial queries on smaller tables (<10M rows). Use BRIN for massive time-series tables (100M+ rows) where you’re filtering by time range.

Caching and Materialised Views

Superset has built-in caching. For geospatial queries, cache aggressively:

Cache duration by data freshness:

  • Real-time telemetry: 5 minutes
  • Hourly aggregates: 1 hour
  • Daily reports: 24 hours
  • Historical analysis: 7 days

In Superset’s dataset settings:

CACHE_CONFIG = {
  'CACHE_TYPE': 'redis',
  'CACHE_REDIS_URL': 'redis://localhost:6379/0',
  'CACHE_DEFAULT_TIMEOUT': 300,  # 5 minutes
}

For queries that power multiple dashboards, use materialised views:

CREATE MATERIALIZED VIEW mv_regional_metrics AS
SELECT 
  r.region_id,
  r.region_name,
  ST_AsGeoJSON(r.boundary) AS geom,
  COUNT(s.store_id) AS store_count,
  SUM(s.revenue) AS total_revenue
FROM regions r
LEFT JOIN stores s ON ST_Contains(r.boundary, s.location)
GROUP BY r.region_id, r.region_name, r.boundary;

CREATE INDEX idx_mv_region ON mv_regional_metrics (region_id);

-- Refresh on a schedule
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_regional_metrics;

Materialised views are queryable tables. Superset treats them like regular tables. They’re fast and can be refreshed on a schedule (e.g., nightly).

Cluster Configuration for Superset

If you’re running Superset across multiple nodes (recommended for production), geospatial queries benefit from:

  1. Dedicated database connection pool: Geospatial queries are long-running. Use a separate pool:
SQLALCHEMY_POOL_SIZE = 10
SQLALCHEMY_MAX_OVERFLOW = 20
SQLALCHEMY_POOL_RECYCLE = 3600
  1. Celery workers for async query execution: Long-running geospatial queries should not block the web server:
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'

# Increase timeout for geospatial queries
CELERY_TASK_SOFT_TIME_LIMIT = 600  # 10 minutes
CELERY_TASK_TIME_LIMIT = 900  # 15 minutes
  1. Query result caching in Redis: Store query results to avoid re-executing:
RESULT_CACHE_CONFIG = {
  'CACHE_TYPE': 'redis',
  'CACHE_REDIS_URL': 'redis://localhost:6379/2',
  'CACHE_DEFAULT_TIMEOUT': 86400,  # 24 hours
}

Common Gotchas and How to Avoid Them {#common-gotchas}

Gotcha 1: Coordinate Order Confusion

GeoJSON uses [longitude, latitude] order. PostGIS uses (latitude, longitude) in some functions, (longitude, latitude) in others. This is the #1 source of “my map is in the ocean” bugs.

Rule: Always use ST_AsGeoJSON() when exporting from PostGIS. It handles the order correctly.

-- WRONG: Superset will plot this backwards
SELECT lat, lng FROM locations;

-- RIGHT: GeoJSON format
SELECT ST_AsGeoJSON(ST_Point(lng, lat)) AS geom FROM locations;

If your data is already backwards, fix it at the database layer, not in Superset:

ALTER TABLE locations 
ADD COLUMN location_fixed GEOMETRY(Point, 4326) 
GENERATED ALWAYS AS (ST_Point(lng, lat)) STORED;

Gotcha 2: Projection and CRS Mismatch

Superset assumes WGS84 (EPSG:4326) for all geospatial visualisations. If your data is in a different projection (e.g., Web Mercator, UTM), you’ll see distorted maps.

Always transform to WGS84:

SELECT 
  ST_AsGeoJSON(ST_Transform(geometry, 4326)) AS geom
FROM locations
WHERE ST_SRID(geometry) != 4326;

Gotcha 3: NULL Geometries Breaking Queries

A single NULL geometry can cause entire queries to fail or render incorrectly.

-- WRONG: NULL geometries will cause rendering issues
SELECT geom, metric FROM data;

-- RIGHT: Filter out NULLs
SELECT geom, metric FROM data WHERE geom IS NOT NULL;

In Superset, add a filter: geom IS NOT NULL.

Gotcha 4: Over-Fetching Data

Superset’s default query limit is 10,000 rows. For geospatial visualisations with 100k+ points, you’ll hit this limit and get incomplete maps.

Solution: Pre-aggregate or cluster in the database:

-- Instead of fetching all 100k points
SELECT ST_AsGeoJSON(location) AS geom, metric FROM events LIMIT 10000;

-- Cluster them
SELECT 
  ST_AsGeoJSON(ST_Centroid(ST_Collect(location))) AS geom,
  COUNT(*) AS count,
  AVG(metric) AS avg_metric
FROM events
GROUP BY ST_SquareGrid(50, location)
LIMIT 10000;

The clustered version returns 10k cells instead of 10k points, covering the entire dataset.

Gotcha 5: Slow Dashboard Load Times

If a dashboard with geospatial charts takes 30+ seconds to load, the issue is usually:

  1. Unoptimised SQL: Check the chart’s query in Superset’s SQL editor. Look for missing indexes, unfiltered joins, or full table scans.

  2. Too many charts: Each chart is a query. 20 charts = 20 database hits. Reduce to essentials.

  3. Caching not working: Check Redis. Is it running? Are cache keys being generated?

# Test Redis connection from Superset container
redis-cli -h redis-host ping  # Should return PONG
  1. Large result sets: If a chart is fetching 1M rows and rendering them client-side, it will be slow. Pre-aggregate in the database.

Security, Compliance, and Multi-Tenant Considerations {#security-compliance}

Data Exposure and RLS

Geospatial data is sensitive. A map showing all customer locations is a data breach if it’s visible to the wrong user.

Superset’s RLS applies to geospatial queries like any other query. But geospatial has unique risks:

  1. Inferred locations: Even if you don’t show exact coordinates, a map’s visual pattern can reveal sensitive information (e.g., “all our stores are in wealthy suburbs”).

  2. Zoom-and-pan attacks: A user might zoom into a competitor’s region to infer their operations.

Mitigation:

-- RLS policy: users see only their own region
ALTER TABLE stores ENABLE ROW LEVEL SECURITY;

CREATE POLICY region_isolation ON stores
  FOR SELECT
  USING (region = current_setting('app.user_region'));

Also, use Superset’s dashboard-level permissions. A user without access to the dataset shouldn’t see the chart, even if they have the URL.

Compliance: SOC 2 and ISO 27001

If you’re pursuing SOC 2 or ISO 27001 compliance (common for SaaS products using Superset), geospatial queries add complexity.

Key audit points:

  1. Query logging: All geospatial queries must be logged for audit trails. Enable in Superset:
LOGGING_CONFIG = {
  'loggers': {
    'superset.sql_lab': {
      'level': 'DEBUG',
    },
  },
}
  1. Data access controls: Document who has access to geospatial dashboards and why. Use Vanta or similar tools to automate compliance evidence gathering.

  2. Encryption in transit and at rest: Superset should use HTTPS. Database connections should use SSL. Sensitive geospatial data at rest should be encrypted (handled by your database).

  3. Retention policies: Define how long geospatial query results are cached. For sensitive data, reduce cache TTL.

For teams building regulated products, we recommend embedding compliance into your architecture from day one. Check out our case studies for examples of how we’ve helped teams achieve compliance while maintaining analytics velocity.

Multi-Tenant Architecture Patterns

If you’re running Superset for multiple customers, here’s the pattern:

Option 1: Separate Superset instances per tenant

  • Pros: Complete isolation, simple RLS
  • Cons: Operational overhead, expensive

Option 2: Single Superset instance with RLS

  • Pros: Efficient, single codebase
  • Cons: Complex RLS, higher risk if misconfigured

We recommend Option 2 with careful implementation:

# In your Superset custom security manager
class TenantAwareSecurityManager(SupersetSecurityManager):
  def get_rls_filters(self, table):
    tenant_id = g.current_user.tenant_id
    return [
      {
        'clause': f'tenant_id = {tenant_id}',
      }
    ]

Every query automatically includes WHERE tenant_id = .... Geospatial queries inherit this filter.


Real-World Case Studies {#case-studies}

Case Study 1: Logistics Operator, Sydney

A Sydney-based logistics company with 500+ vehicles needed real-time visibility into fleet operations. They had GPS telemetry streaming into PostgreSQL at 1M events/day.

Challenge: Rendering 500 vehicle positions on a map, updated every 5 minutes, for 50+ users.

Solution:

  • Pre-aggregate GPS data into hourly snapshots (500 points → 500 points, but with aggregated metrics)
  • Use Deck.gl scatter plot with clustering
  • Cache the chart for 5 minutes
  • Add a time filter to drill down to specific hours

Result: Dashboard load time dropped from 30 seconds to 2 seconds. Users could see fleet positions in real-time.

We documented this pattern in our platform development Sydney work.

Case Study 2: Insurance Underwriter, Melbourne

An insurance underwriter wanted to visualise risk by postcode. They had 10M+ claims records with postcodes but no geometry.

Challenge: Join claims to postcode boundaries, colour-code by risk, and make it interactive.

Solution:

  • Load postcode boundary GeoJSON from Australian Bureau of Statistics
  • Create a PostGIS table with postcode geometries
  • Join claims to postcodes using ST_Contains
  • Materialise the join as a view, refresh nightly
  • Build a choropleth in Superset

Result: Risk map updated daily. Underwriters could identify high-risk regions in seconds.

This is a common pattern for platform development Melbourne teams in regulated industries.

Case Study 3: Retail Chain, Australia

A national retail chain with 200 stores wanted to optimise store placement. They had historical sales, foot traffic, and competitor locations.

Challenge: Visualise sales density, competitor proximity, and foot traffic on one map.

Solution:

  • Heatmap of sales by location (pre-aggregated to 1km grid cells)
  • Scatter plot of competitor stores (overlaid)
  • Size points by foot traffic
  • Colour by sales performance

Result: Site selection team could identify high-potential locations for new stores in minutes instead of days.

We’ve applied this pattern across platform development Australia clients in retail and hospitality.


Summary and Next Steps {#summary}

Geospatial visualisations in Apache Superset are powerful when you get the fundamentals right: encode geometry at the database layer, pre-aggregate aggressively, index ruthlessly, and cache everything.

The gotchas are real (coordinate order, projections, NULL values, over-fetching), but they’re all preventable with the patterns in this guide.

For production deployments, the architecture matters as much as the visualisation. If you’re building platform engineering solutions where Superset is the analytics layer, start with data shape, security, and performance. The visualisations follow.

Immediate Next Steps

  1. Audit your geospatial data: Check for NULL geometries, projection mismatches, and coordinate order issues. Fix at the database layer.

  2. Add indexes: If you have geospatial queries slower than 1 second, add GIST or BRIN indexes. Measure the difference.

  3. Materialise views for common queries: If multiple dashboards share a geospatial query, move it to a materialised view. Refresh on a schedule.

  4. Implement RLS: If you have multiple tenants or users with different data access, implement row-level security at the database layer, not in Superset.

  5. Monitor and cache: Set up Redis caching for geospatial queries. Monitor query times. If a chart takes >2 seconds, optimise.

Further Reading

The official Geospatial Visualizations - Apache Superset Documentation is the reference. For deeper dives into specific patterns, check the Better Understand Your Geospatial Data - PostGIS GeoJSON | Preset article and the Apache Superset - GitHub Repository for implementation details.

If you’re building a data platform with geospatial analytics at scale, the patterns here are battle-tested. We’ve applied them across teams in Sydney, Melbourne, Brisbane, and across Australia, as well as in San Francisco, Austin, Chicago, and Dallas.

If you’re tackling geospatial analytics as part of a larger platform modernisation or AI transformation, consider reaching out. We work with founders, operators, and engineering teams to architect data platforms that scale, comply, and deliver results. Check our services or case studies to see how we’ve helped similar teams.

Want to talk through your situation?

Book a 30-minute call with Kevin (Founder/CEO). No pitch — direct advice on what to do next.

Book a 30-min call