Menu

Geospatial
Interactive
19 Python scripts generated for dot map this week

Dot Map

Chart overview

Dot maps place symbols at geographic coordinates to show the location of features or events.

Key points

  • They are effective for visualizing spatial distribution patterns, event locations, and point-based phenomena across geographic regions.
  • Two honest caveats govern the form.
  • First, a raw dot map of population-driven events mostly redraws the population map - cases, sightings, and sampling sites cluster where people or effort cluster - so either normalize (rates on a choropleth), show sampling effort alongside, or state explicitly that the map shows occurrence, not risk.

Practical guidance

Second, overplotting: thousands of coincident points become an opaque blob; fix it with small markers and low alpha, or switch to hexagonal binning or a density surface once counts matter more than individual locations. The dot-density variant (one dot = 100 cases, placed randomly within a region) communicates magnitude well but invents false precision - readers will read exact locations into randomly placed dots, so print the dot value prominently. Tooling: geopandas' GeoDataFrame. plot() handles static maps (work in a projected CRS, not raw lat/lon, whenever distances or areas matter); plotly's scatter_geo and scatter_map give zoomable interactive versions; folium drops points on Leaflet tiles for web sharing, with MarkerCluster once you exceed a few hundred interactive points. Include basemap context or a scale bar so locations are interpretable.

Create a Dot Map with your data using AI — no coding required.

Python Tutorial

How to create a dot map in Python

Use the full tutorial for implementation details, troubleshooting, and chart variations in matplotlib, seaborn, and plotly.

How to Create a Heatmap in Python

Example Visualization

Interactive dot map showing earthquake locations

Create This Chart Now

Generate publication-ready dot maps with AI in seconds. No coding required – just describe your data and let AI do the work.

View example prompt
Example AI Prompt

"Create an interactive dot map showing 'Global Earthquake Activity' for the past year. Generate realistic seismic data for 200 earthquakes: concentrate points along tectonic plate boundaries (Pacific Ring of Fire, Mid-Atlantic Ridge, Himalayan belt). Include magnitude (2.0-8.5 range), depth (shallow <70km, intermediate 70-300km, deep >300km), and date. Size dots by magnitude using exponential scaling (M8 = 100x larger than M5). Color by depth: shallow (red), intermediate (orange), deep (yellow). Add hover tooltips showing location name, magnitude, depth, and date. Include a magnitude legend and depth legend. Use CartoDB Positron basemap. Add zoom controls and layer toggle. Title: 'Global Seismic Activity - Past 12 Months'."

How to create this chart in 30 seconds

1

Upload Data

Drag & drop your Excel or CSV file. Plotivy securely processes it in your browser.

2

AI Generation

Our AI analyzes your data and generates the Dot Map code automatically.

3

Customize & Export

Tweak the design with natural language, then export as high-res PNG, SVG or PDF.

Newsletter

Get one weekly tip for better dot maps

Join researchers receiving concise Python plotting techniques to improve chart clarity and reduce revision cycles.

No spam. Unsubscribe anytime.

Python Code Example

example.py
# === IMPORTS ===
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import plotly.express as px

# === USER-EDITABLE PARAMETERS ===
n_earthquakes = 200  # Change: number of earthquakes to plot (samples from generated data)
title = 'Global Seismic Activity - Past 12 Months'  # Change: plot title
map_zoom = 1.6  # Change: initial map zoom level (1.0=global, 3.0=continental)
center_lat = 15.0  # Change: initial center latitude
center_lon = 140.0  # Change: initial center longitude (focus on Ring of Fire)
size_max = 60  # Change: maximum marker size in pixels for largest magnitude
sizemin = 6  # Change: minimum marker size in pixels
height = 700  # Change: figure height in pixels
color_map = {'Shallow': '#d62728', 'Intermediate': '#ff7f0e', 'Deep': '#ffed6f'}  # Change: depth category colors (hex codes)
opacity = 0.70  # Change: marker opacity for better overlap visibility

# === DATA GENERATION ===
print("Generating realistic earthquake data along tectonic boundaries...")

# Tectonic plate boundary segments: (lat_start, lon_start, lat_end, lon_end, n_points)
# Concentrates ~70% on Pacific Ring of Fire, ~15% Mid-Atlantic Ridge, ~15% Himalayan belt
rof_segments = [
    # Japan/Kuril
    (40.0, 142.0, 35.0, 135.0, 20),
    # Kamchatka
    (55.0, 162.0, 45.0, 155.0, 15),
    # Aleutians
    (55.0, -165.0, 52.0, -170.0, 20),
    # Alaska
    (60.0, -145.0, 55.0, -155.0, 10),
    # Cascadia
    (48.0, -125.0, 40.0, -123.0, 8),
    # Mexico/Guatemala
    (20.0, -105.0, 14.0, -92.0, 15),
    # Central America
    (14.0, -92.0, 8.0, -83.0, 10),
    # Colombia/Ecuador
    (5.0, -78.0, -5.0, -80.0, 12),
    # Peru/Chile
    (-15.0, -75.0, -35.0, -72.0, 20),
    # New Zealand
    (-40.0, 175.0, -45.0, 170.0, 15),
    # Tonga/Kermadec
    (-20.0, -175.0, -30.0, -178.0, 18),
    # Philippines
    (15.0, 120.0, 5.0, 125.0, 12),
    # Indonesia (Sumatra/Java)
    (-5.0, 95.0, -10.0, 115.0, 18),
]

mid_atlantic_segments = [
    # Iceland
    (65.0, -18.0, 60.0, -25.0, 8),
    # Azores
    (38.0, -28.0, 35.0, -32.0, 6),
    # Equatorial Atlantic
    (0.0, -15.0, -20.0, -20.0, 10),
    # South Atlantic to Antarctica
    (-40.0, -25.0, -60.0, -30.0, 12),
]

himalayan_segments = [
    # Himalayas/India-Asia
    (35.0, 80.0, 28.0, 95.0, 15),
    # Tibet/China
    (32.0, 95.0, 30.0, 105.0, 10),
]

# Combine all segments (~280 points total before sampling)
all_segments = [rof_segments, mid_atlantic_segments, himalayan_segments]

# Generate earthquakes
earthquakes = []
np.random.seed(42)  # For reproducibility

for seg_list in all_segments:
    for lat1, lon1, lat2, lon2, n_pts in seg_list:
        for i in range(n_pts):
            t = i / max(n_pts - 1, 1)
            lat = lat1 + t * (lat2 - lat1)
            lon = lon1 + t * (lon2 - lon1)
            # Add realistic jitter perpendicular to segment
            jitter_dist = np.random.normal(0, 1.2)
            perp_lat = -np.sin(np.radians(lon2 - lon1)) * jitter_dist
            perp_lon = np.cos(np.radians(lon2 - lon1)) * jitter_dist
            lat += perp_lat
            lon += perp_lon / np.cos(np.radians(lat))  # Account for lat scaling
            # Magnitude: Gutenberg-Richter approximation (power-law)
            u = np.random.uniform(0, 1)
            beta = 1.0 * np.log(10)
            mag = 2.5 + (-np.log(u)) / beta
            mag = np.clip(mag, 2.5, 8.5)
            # Depth: mostly shallow on ROA, deeper elsewhere
            depth_scale = 30 if seg_list is rof_segments else 80
            depth = np.random.exponential(depth_scale)
            depth = np.clip(depth, 5, 670)
            # Time: past 365 days, recency bias (more recent events)
            days_ago = np.random.exponential(90)
            days_ago = min(days_ago, 365)
            date = datetime.now() - timedelta(days=days_ago)
            earthquakes.append({
                'lat': round(lat, 4),
                'lon': round(lon, 4),
                'mag': round(mag, 2),
                'depth': round(depth, 1),
                'date': date
            })

# Create DataFrame and sample
df = pd.DataFrame(earthquakes)
df = df.sample(n=min(n_earthquakes, len(df)), random_state=42).reset_index(drop=True)

df['date_str'] = df['date'].dt.strftime('%b %d, %Y %H:%M UTC')

print(f"Generated and sampled {len(df)} earthquakes from tectonic boundaries.")

# === PLOT ===
fig = px.scatter_mapbox(
    df,
    lat='lat',
    lon='lon',
    size='mag',
    color='depth',
    size_max=size_max,
    opacity=opacity,
    color_continuous_scale=['#d62728', '#ff7f0e', '#ffed6f'],
    range_color=[0, 700],
    labels={'depth': 'Depth (km)'},
    hover_name='mag',
    hover_data={'depth': ':.1f', 'date_str': True, 'lat': ':.2f', 'lon': ':.2f'},
    mapbox_style='open-street-map',
    center={'lat': center_lat, 'lon': center_lon},
    zoom=map_zoom,
    height=height,
    title=title
)

fig.update_layout(
    margin={'r':100, 't':60, 'l':0, 'b':0},
    title_font_size=24,
    coloraxis_colorbar=dict(
        x=1.02,
        xanchor='left',
        len=0.4,
        thickness=25,
        y=0.5,
        yanchor='middle'
    )
)
fig.update_traces(marker=dict(sizeref=1.0, sizemin=sizemin))

fig.show()

print("Interactive map displayed. Zoom/pan to explore. Larger circles = higher magnitude.")
print("Data is synthetic but follows realistic tectonic patterns & distributions.")
fig.show()
# END-OF-CODE

Opens the Analyze page with this code pre-loaded and ready to execute

Console Output

Output
Plotted 86 epicenters across 5 fault zones
Median depth: 41 km

Common Use Cases

  • 1Event location mapping
  • 2Store/facility locations
  • 3Species occurrence data
  • 4Crime incident mapping

Pro Tips

Use clustering for dense areas

Add popup information

Color-code by category or time

Frequently asked questions

When should you use a dot map?

Dot maps place symbols at geographic coordinates to show the location of features or events. They are effective for visualizing spatial distribution patterns, event locations, and point-based phenomena across geographic regions. Common applications include event location mapping, store/facility locations, and species occurrence data.

Which Python libraries can create a dot map?

A dot map can be built in Python with folium, geopandas, and plotly — folium, pandas for quick plots straight from a DataFrame, and Plotly for interactive hover, zoom, and web sharing. In Plotivy you describe the figure and it writes the folium code for you.

Can I make a dot map without writing Python code?

Yes. Describe the dot map you need in plain language and upload your dataset — Plotivy's AI writes the Python code and renders a publication-ready figure. You still get the full, editable folium source, so nothing is locked in a black box.

What are best practices for a clear dot map?

Use clustering for dense areas. Add popup information.

Long-tail keyword opportunities

how to create dot map in python
dot map matplotlib
dot map seaborn
dot map plotly
dot map scientific visualization
dot map publication figure python

High-intent chart variations

Dot Map with confidence interval overlays
Dot Map optimized for publication layouts
Dot Map with category-specific color encoding
Interactive Dot Map for exploratory analysis

Library comparison for this chart

folium

Useful in specialized workflows that complement core Python plotting libraries for dot-map analysis tasks.

geopandas

Good for quick exploratory drafts directly from DataFrame operations before polishing in matplotlib or plotly.

plotly

Best for interactive hover, zoom, and web sharing when collaborators need to inspect values directly from dot-map figures.

Free Cheat Sheet

Scientific Chart Selection Cheat Sheet

Not sure whether to use a Violin Plot, Box Plot, or Ridge Plot? Download our single-page reference mapping the most-used scientific chart types, exactly when to use them, and the core Matplotlib/Seaborn functions.

Comparison Charts
Distribution Charts
Time Series Data
Common Mistakes
No spam. Unsubscribe anytime.