Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions plugins/plotly-express/docs/choropleth-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Choropleth Map

A choropleth map plot is a geographic visualization that shades regions of a tile-based map according to a data value. It uses MapLibre map tiles, providing rich geographic context with zoom and pan, making it ideal for thematic maps that need detailed underlying imagery.

Choropleth map plots are appropriate when the dataset contains values associated with regions defined by GeoJSON. For a simpler tile-free projection, use [`choropleth`](./choropleth.md). For point-based map visualizations, see [`scatter_map`](./scatter-map.md).

## What are choropleth map plots useful for?

- **Regional comparisons with map context**: They are excellent for comparing a single quantitative value across geographic regions while keeping detailed map imagery underneath.
- **Interactive exploration**: Users can zoom and pan to inspect specific regions in detail.
- **Live, region-level data**: Because the figure updates as the underlying Deephaven table ticks, choropleth map plots can reflect changing aggregate values per region in real time.

## Examples

### A basic choropleth map with custom GeoJSON

`choropleth_map` requires GeoJSON to define the regions. Use `featureidkey` to point at the property in the GeoJSON that matches the values in the `locations` column.

```python order=choropleth_map_plot,election_table
import deephaven.plot.express as dx
from plotly import express as px

# Load the election dataset (ticking by default)
election_table = dx.data.election()

# plotly ships matching geojson for the election dataset
geojson = px.data.election_geojson()

# Color districts by votes for one candidate; updates live as the table ticks
choropleth_map_plot = dx.choropleth_map(
election_table,
locations="District",
geojson=geojson,
featureidkey="properties.district",
color="Joly",
zoom=9,
center={"lat": 45.55, "lon": -73.7},
)
```

### Customize the color scale

Change the color scale using the `color_continuous_scale` argument and constrain it with `range_color`.

```python order=choropleth_map_plot,election_table
import deephaven.plot.express as dx
from plotly import express as px

election_table = dx.data.election()
geojson = px.data.election_geojson()

choropleth_map_plot = dx.choropleth_map(
election_table,
locations="District",
geojson=geojson,
featureidkey="properties.district",
color="Joly",
color_continuous_scale=["yellow", "orange", "red"],
zoom=9,
center={"lat": 45.55, "lon": -73.7},
)
```

### Adjust opacity to show map detail

Lower the `opacity` so the underlying map tiles remain visible through the colored regions.

```python order=choropleth_map_plot,election_table
import deephaven.plot.express as dx
from plotly import express as px

election_table = dx.data.election()
geojson = px.data.election_geojson()

choropleth_map_plot = dx.choropleth_map(
election_table,
locations="District",
geojson=geojson,
featureidkey="properties.district",
color="Joly",
opacity=0.5,
zoom=9,
center={"lat": 45.55, "lon": -73.7},
)
```

### Change map style

Use different base map styles with the `map_style` argument. The default style depends on the theme.

```python order=choropleth_map_plot,election_table
import deephaven.plot.express as dx
from plotly import express as px

election_table = dx.data.election()
geojson = px.data.election_geojson()

choropleth_map_plot = dx.choropleth_map(
election_table,
locations="District",
geojson=geojson,
featureidkey="properties.district",
color="Joly",
map_style="open-street-map",
zoom=9,
center={"lat": 45.55, "lon": -73.7},
)
```

## API Reference

```{eval-rst}
.. dhautofunction:: deephaven.plot.express.choropleth_map
```
102 changes: 102 additions & 0 deletions plugins/plotly-express/docs/choropleth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Choropleth

A choropleth plot is a geographic visualization that shades regions of a map according to a data value. It uses a basic geographic projection without map tiles, making it ideal for thematic maps where the focus is on regional values rather than detailed geographic context.

Choropleth plots are appropriate when the dataset contains values associated with named geographic regions (countries, states, custom polygons defined by GeoJSON). For tile-based maps with zoom and pan over detailed map imagery, use [`choropleth_map`](./choropleth-map.md). For point-based geographic visualizations, see [`scatter_geo`](./scatter-geo.md).

## What are choropleth plots useful for?

- **Regional comparisons**: They are excellent for comparing a single quantitative value across many geographic regions at a glance.
- **Thematic mapping**: Choropleth plots provide a clear visual encoding for variables like population, election results, or any per-region statistic.
- **Live, region-level data**: Because the figure updates as the underlying Deephaven table ticks, choropleth plots can reflect changing aggregate values per region in real time.

## Examples

### A basic choropleth using built-in country names

When the `locations` column contains values that match a built-in `locationmode` (`'ISO-3'`, `'USA-states'`, or `'country names'`), no GeoJSON is needed.

```python order=choropleth_plot,gapminder_table
import deephaven.plot.express as dx

# Load the gapminder dataset (ticking by default)
gapminder_table = dx.data.gapminder()

# Color each country by life expectancy using the built-in country geometry
choropleth_plot = dx.choropleth(
gapminder_table,
locations="Country",
locationmode="country names",
color="LifeExp",
projection="natural earth",
)
```

### Choropleth with custom GeoJSON

Pass GeoJSON directly to render arbitrary regions. Use `featureidkey` to point at the property in the GeoJSON that matches the values in the `locations` column.

```python order=choropleth_plot,election_table
import deephaven.plot.express as dx
from plotly import express as px

# Load the election dataset (ticking by default)
election_table = dx.data.election()

# plotly ships matching geojson for the election dataset
geojson = px.data.election_geojson()

# Color districts by votes for one candidate; updates live as the table ticks
choropleth_plot = dx.choropleth(
election_table,
locations="District",
geojson=geojson,
featureidkey="properties.district",
color="Joly",
fitbounds="locations",
)
```

### Customize the color scale

Change the color scale using the `color_continuous_scale` argument and constrain it with `range_color`.

```python order=choropleth_plot,gapminder_table
import deephaven.plot.express as dx

gapminder_table = dx.data.gapminder()

choropleth_plot = dx.choropleth(
gapminder_table,
locations="Country",
locationmode="country names",
color="LifeExp",
color_continuous_scale=["yellow", "orange", "red"],
range_color=[40, 85],
)
```

### Change projection and scope

Use the `projection` argument to switch the map projection (for example `"orthographic"` for a globe view), and `scope` to focus on a region such as `"europe"` or `"north america"`.

```python order=choropleth_plot,gapminder_table
import deephaven.plot.express as dx

gapminder_table = dx.data.gapminder()

choropleth_plot = dx.choropleth(
gapminder_table,
locations="Country",
locationmode="country names",
color="LifeExp",
projection="orthographic",
scope="world",
)
```

## API Reference

```{eval-rst}
.. dhautofunction:: deephaven.plot.express.choropleth
```
8 changes: 8 additions & 0 deletions plugins/plotly-express/docs/sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@
"label": "Candlestick",
"path": "candlestick.md"
},
{
"label": "Choropleth",
"path": "choropleth.md"
},
{
"label": "Choropleth Map",
"path": "choropleth-map.md"
},
{
"label": "Density Heatmap",
"path": "density_heatmap.md"
Expand Down
3 changes: 3 additions & 0 deletions plugins/plotly-express/src/deephaven/plot/express/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
scatter_map,
density_map,
line_map,
choropleth,
choropleth_map,
choropleth_mapbox,
)

from .data import data_generators
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,26 @@ def generate_figure(
data_cols, custom_call_args, table, start_index
)

# Some trace types (choropleth, choropleth_map, choropleth_mapbox) store
# color values in the trace's `z` field rather than `marker.color`. The
# default `color` -> `marker/color` override produces a path the JS client
# cannot walk (TypeError: Cannot set properties of undefined). Rewrite the
# mapping keys for those trace types here so the figure stays in sync as
# the underlying live table updates.
_CHOROPLETH_TRACE_TYPES = {"choropleth", "choroplethmap", "choroplethmapbox"}
for offset, trace in enumerate(px_fig.data):
if getattr(trace, "type", None) not in _CHOROPLETH_TRACE_TYPES:
continue
idx = offset
if idx < len(data_mapping._data_mapping): # noqa: SLF001
var_col = data_mapping._data_mapping[idx] # noqa: SLF001
if "marker/color" in var_col:
var_col["z"] = var_col.pop("marker/color")
if idx < len(hover_mapping):
hov = hover_mapping[idx]
if "marker/color" in hov:
hov["z"] = hov.pop("marker/color")

types = get_hovertext_types(data_cols)

hover_text, legend_title = create_hover_and_axis_titles(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
scatter_map,
density_map,
line_map,
choropleth,
choropleth_map,
choropleth_mapbox,
)
from .heatmap import density_heatmap
from .indicator import indicator
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,22 @@ def process_args(
# Set a default center to prevent px from auto-centering based on data
# which breaks the initial view for map plots since the data may be null initially
# Auto centering on the server side is also a bad idea since the data can change,
# so that should be done on the client side if desired
center = {
"lat": 0,
"lon": 0,
}
render_args["args"]["center"] = center
# so that should be done on the client side if desired.
# Skip for geo-based plots (e.g. `choropleth`) since the geo subplot uses
# `scope`/`projection` and a forced {lat:0, lon:0} center conflicts with
# projections like `albers usa`, which crashes the JS renderer.
is_geo_plot = (
"scope" in render_args["args"]
or "projection" in render_args["args"]
or "locationmode" in render_args["args"]
)
if not is_geo_plot:
center = {
"lat": 0,
"lon": 0,
}
if center is not None:
render_args["args"]["center"] = center

orig_process_args = args_copy(render_args)
orig_process_func = lambda **local_args: create_deephaven_figure(**local_args)[0]
Expand Down
Loading
Loading