Add choropleth map implementation - #500
Conversation
|
Great start! Here's one thing. If you look in the tests/samples folder you will see that we've packaged some JSON configuration files and data uploads drawn from the real-world charts that Datawrapper includes in its documentation site. Those are then integrated into tests that verify the code is working. One sample is pulled out and featured in our documentation site with a Pythonic implementation as an example. Do you think you'd be able to try add those pieces yet? |
There was a problem hiding this comment.
Pull Request Overview
This PR adds support for choropleth maps to the datawrapper library, enabling users to create geographic data visualizations where regions are colored based on data values.
Key changes:
- New
ChoroplethMapclass with comprehensive configuration options for data mapping, basemaps, colors, and tooltips - Three new enum classes (
ColorScale,ColorMode,BasemapProjection) for type-safe configuration - Integration with existing library architecture through proper imports and exports
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| datawrapper/charts/enums/color_scale.py | Defines ColorScale enum with scale types (linear, log, sqrt, quantile, jenks) |
| datawrapper/charts/enums/color_mode.py | Defines ColorMode enum for gradient vs buckets coloring |
| datawrapper/charts/enums/basemap_projection.py | Defines BasemapProjection enum with map projection types |
| datawrapper/charts/enums/init.py | Exports new enum classes for external use |
| datawrapper/charts/choropleth_map.py | Main implementation with ChoroplethMap class and Tooltip configuration |
| datawrapper/charts/base.py | Adds "d3-maps-choropleth" to supported chart types |
| datawrapper/charts/init.py | Exports ChoroplethMap and related classes |
| datawrapper/init.py | Re-exports ChoroplethMap and enums at package level |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| map_key_attr: str = Field( | ||
| default="", | ||
| alias="map-key-attr", | ||
| description="The attribute in the basemap to match against your keys column (e.g., 'iso-a3', 'fips', 'ags)", |
There was a problem hiding this comment.
Missing closing single quote in the description string. The string should end with 'ags')" instead of 'ags)".
| description="The attribute in the basemap to match against your keys column (e.g., 'iso-a3', 'fips', 'ags)", | |
| description="The attribute in the basemap to match against your keys column (e.g., 'iso-a3', 'fips', 'ags')", |
| if self.color_scale == "quantile": | ||
| interpolation = "equidistant" | ||
| elif self.color_scale == "jenks": |
There was a problem hiding this comment.
Line 295 initializes interpolation to 'equidistant', then line 297 redundantly sets it to the same value when color_scale == 'quantile'. The if-condition on line 296-297 has no effect and should be removed.
| if self.color_scale == "quantile": | |
| interpolation = "equidistant" | |
| elif self.color_scale == "jenks": | |
| if self.color_scale == "jenks": |
|
Thank you!
Sure, that's a great idea!
Basically I create a map and downlod the json structure of the datawrapper object, correct?
Best
Claus
Norddeutscher Rundfunk
PB Programm- und Portfoliomanagement
PG Digitale Angebote / NDR DATA
Rothenbaumchaussee 132
20149 Hamburg
phone: +49.170.2039123
e-mail: ***@***.***
…________________________________
Von: Ben Welsh ***@***.***>
Gesendet: Friday, October 31, 2025 2:34:26 PM
An: chekos/Datawrapper ***@***.***>
Cc: Hesseling, Claus ***@***.***>; Author ***@***.***>
Betreff: Re: [chekos/Datawrapper] Add choropleth map implementation (PR #500)
[https://avatars.githubusercontent.com/u/9993?s=20&v=4]palewire left a comment (chekos/Datawrapper#500)<#500 (comment)>
Great start!
Here's one thing. If you look in the tests/samples folder you will see that we've packaged some JSON configuration files and data uploads drawn from the real-world charts that Datawrapper includes in its documentation site.
Those are then integrated into tests that verify the code is working. One sample is pulled out and featured in our documentation site with a Pythonic implementation as an example.
Do you think you'd be able to try add those pieces yet?
—
Reply to this email directly, view it on GitHub<#500 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AOZ2EIOVZKGGVKS2T4HDDXT32NQOFAVCNFSM6AAAAACKYXPCO6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTINZTGEYTSNZVGI>.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
|
Yes, that's right. We use this tool to snatch the JSON from the official examples. https://palewi.re/docs/datawrapper-json-bookmarklet/ |
palewire
left a comment
There was a problem hiding this comment.
Thanks for adding choropleth support — this is a worthwhile chart type to bring into the typed API, and the core shape is headed in the right direction. I reviewed the PR metadata, comments, full diff, implementation, exports, comparable chart classes/tests/docs, the bundled JSON/CSV sample, current CI/merge state, and ran focused local checks in a fresh worktree. My recommendation is request changes for now: the package imports and the existing test suite still passes, but the new chart type is not integrated deeply enough to be merge-ready, and realistic Academy-style parsing/serialization exposes several gaps.
Blocking findings
-
The PR is currently not mergeable.
GitHub reportsCONFLICTING/DIRTYagainstmain. The only visible status check is the Read the Docs build; I do not see the repository’s usual Ruff, mypy, pytest matrix, and build checks for this PR. It needs a rebase/update and full CI before merge. -
get_chart()cannot return aChoroplethMap.
The new class is exported at the top level, butdatawrapper/chart_factory.pywas not updated. A live/API choropleth returned byget_chart(chart_id=...)would still raiseValueError: Unsupported chart type: d3-maps-choroplethbecausechart_type_maplacks"d3-maps-choropleth": ChoroplethMap. This is inconsistent with the existing typed chart workflow and with comparable chart additions. -
There are no runnable choropleth tests.
The PR addsdatawrapper/charts/choropleth_map.pyand a fixture, but notests/integration/test_choropleth_map.pyor unit tests exercise construction, imports, aliases, serialization, deserialization, colorscale handling, tooltips, custom basemap settings, annotations, or factory support. In the local run,datawrapper/charts/choropleth_map.pyshowed only 15.68% coverage because only imports/class definitions were touched by the existing suite. -
The bundled sample fixture is under the wrong path and is not wired into the localized testing approach.
The files were added as:tests/samples/choropleth_map/tests/samples/choropleth_map/internet_usagecountry.csv tests/samples/choropleth_map/tests/samples/choropleth_map/internet_usagecountry.jsonExisting fixtures live directly under
tests/samples/<chart_type>/..., andtests/integration/test_sample_charts.pyonly covers the bar sample. Because of the nestedtests/samples/...path and the missing test file, this real choropleth fixture is never exercised. -
Realistic Academy-config round-tripping drops important map configuration.
I parsed the bundled non-secret JSON fixture (Share of people using the internet, chart id6Ue5p) withChoroplethMap.deserialize_model()and serialized it back. The basics worked — title, type, axes, basemap, key attr, tooltip text, and simple color fields survived — but major visualization settings were missing or changed:colorscale.stopschanged fromprettytoequidistant.colorscale.stopCountchanged from5to7(color-steps), andcustomStops,rangeMin,rangeMax,palette,map,categoryOrder, andcategoryLabelswere dropped.tooltip.enabled,tooltip.sticky, andtooltip.migratedwere dropped.legends,map-type-set,mapView,zoom-button-pos,map-label-format,max-map-height,highlighted-series,highlighted-values,miniMap,patterns, andlabelswere all dropped.
Some lossiness is acceptable if the public API intentionally starts small, but these are real Datawrapper choropleth fields from the fixture this PR adds. The tests should make the intended support boundary explicit and avoid silently changing settings that affect rendered output.
-
Tooltipis too narrow for real Datawrapper tooltip objects.
The sample tooltip includesenabled,sticky, andmigrated, but the model only preservesbody,title, andfields. Because Pydantic’s defaultextra="ignore"behavior is in effect onTooltip, those extra fields are silently discarded during validation/deserialization. At minimum, tests should confirm whether this is intentional; ideally the model should preserve supported Datawrapper tooltip options that affect behavior. -
The public exports are inconsistent.
datawrapper.__init__exportsColorModeandColorScale, butdatawrapper.charts.__init__imports onlyBasemapProjection; it does not import or includeColorModeandColorScalein__all__. That meansfrom datawrapper import ColorModeworks, whilefrom datawrapper.charts import ColorModefails. Comparable enums are generally available through both import paths. -
There is no user-facing documentation page or docs navigation entry.
The PR adds the class docstring and schema examples, but nodocs/user-guide/charts/choropleth-maps.mdand nodocs/index.mdtoctree entry. Comparable chart types have a chart guide with a runnable example, and PR #500’s earlier discussion specifically asked for real examples/tests based on Academy chart JSON.
Test and validation notes
I ran:
uv sync --frozen --extra test --extra mypy
uv run python - <<'PY'
import datawrapper
from datawrapper import ChoroplethMap
print(ChoroplethMap().chart_type)
PY
uv run pytest tests/unit/test_enum_imports.py tests/unit/test_enum_backwards_compatibility.py tests/integration/test_sample_charts.py -q
uv run pytest -q
uv run python - <<'PY'
# loaded tests/samples/choropleth_map/tests/samples/choropleth_map/internet_usagecountry.json,
# ran ChoroplethMap.deserialize_model(...), instantiated the model, serialized it,
# and compared key metadata.visualize fields against the source fixture
PY
uv run mypy ./ --ignore-missing-importsResults:
- Importing
datawrapperandChoroplethMapworks. - Focused existing tests passed:
71 passed. - Full test suite passed locally on Python 3.13:
1049 passed, 3 skipped. - The realistic choropleth fixture parse/serialize check confirmed the lossy fields listed above.
uv run mypy ./ --ignore-missing-importsstill fails with 15 errors intests/conftest.py; those appear pre-existing rather than caused by this PR, but CI should be reviewed after rebase because the workflow runs mypy.- Ruff was not available in the local uv environment because it is not declared in the project’s dev/test extras, so I could not run the exact local Ruff command without adding undeclared tooling.
Consistency with repository examples and documentation
The proposed class follows several repo conventions well: it subclasses BaseChart, uses aliases for Datawrapper hyphenated keys, adds the chart type to BaseChart.chart_type, and uses enums for a few higher-level choices. The missing parts are the same integration points other chart types rely on: factory mapping, chart-specific tests, fixture placement under tests/samples/<chart_type>/, docs page/toctree entry, and explicit assertions against real example JSON.
For the Academy/localized testing approach, I would expect at least one test module that loads the real choropleth JSON/CSV fixture, validates deserialization into ChoroplethMap, checks representative fields (axes, basemap, key attr, colorscale, tooltip, legend/display settings), serializes back, and documents which fields are intentionally unsupported. Additional constructor/API tests should cover a small Pythonic example using a DataFrame and enum values.
Suggestions / non-blocking API design notes
- Consider introducing structured models for
colorscale, legends, minimap, labels, and patterns rather than flattening only part of the choropleth API into top-level fields. If the first release intentionally supports only a smaller subset, document that clearly. key_column_typewrites intometadata.data.column-format, but there is no direct test proving it preserves existing column-format settings or only sets the intended column.color_paletteis accepted and serialized ascolor-palette, but the real sample’s palette-ish fields live insidecolorscale; tests should clarify which Datawrapper color path is actually used for choropleths.- The sample added in this PR (
6Ue5p) does not appear to be from the current public “Examples of Datawrapper choropleth maps” Academy article I checked; if it is from another Academy page or generated example, please note that in the fixture/test name or docs so future maintainers know its provenance.
Positive findings
- The basic class import and construction path works.
- The model correctly recognizes the
d3-maps-choroplethchart type and serializes Datawrapper-stylemetadata.axesfor keys/values. - Basemap, map key attribute, simple color fields, tooltip body/title, and annotations integration are a sensible starting slice.
- Including a real JSON/CSV fixture is exactly the right direction; it just needs to be placed and tested consistently with the rest of the repository.
I’d be happy to re-review after the branch is rebased, factory support is added, the fixture path is fixed, real choropleth tests/docs are added, the chart exports are made consistent, and the lossy handling of real choropleth visualize fields is either fixed or clearly scoped and tested.
Added implementation for Datawrapper's choropleth map API