Illustration by Alysheia Shaw-Dansby

Using Datawrapper to Make Custom Data Visualization More Efficient

Urban Institute
7 min readMay 9, 2024


The Urban Institute data visualization team creates a wide array of visual products, including static charts for reports and briefs, interactive standalone graphs for the Urban Wire blog, and larger exploratory tools, all to make research findings more accessible for policymakers, researchers, community leaders, and other stakeholders.

But each of these products requires a different tool set. Static graphs are typically created in Excel or R, and larger interactive products use developer tools like the JavaScript framework Svelte alongside visualization libraries like D3.js and Mapbox. Over the past year, we’ve incorporated Datawrapper — a drag-and-drop, browser-based data visualization tool — into our workflow to create interactive, responsive graphs on Urban Wire.

Generally, Datawrapper wasn’t made to create complex interactive visualizations that control multiple charts on the same page, like a custom data tool built in JavaScript (or an off-the-shelf tool like Tableau or PowerBI) would. But through our recent work, we’ve combined the built-in capabilities of Datawrapper with the data-handling capabilities of a custom JavaScript framework for creating web applications like Svelte. Below, we walk through an example data tool that marries a complex, multifaceted research output with a slick, intuitive interface using Datawrapper and Svelte and show how others can extend this method to visualizations and research dissemination products.

Gathering technical requirements

For this project, we were asked to build a county-level map of North Carolina that would enable users to explore demographic information, access to health care, and other data points relevant to the state’s immigrant community. The tool would include a custom table layout that could dynamically display county-based information — including text, numbers, and margins of error — based on a map click or dropdown selection.

At the beginning of the project, the data visualization and research teams met to discuss goals, target audiences, and possible visualization types. The data visualization team then created a wireframe of the tool, which the research team reacted to align on a tool structure.

Together, we settled on three project requirements. First, we would include an interactive map with tooltip or hover/click capabilities when the user selected a county. Second, information boxes and tables would change to dynamically display the selected information. And third, a dropdown menu should enable the user to select an active county.

This kind of interactive data visualization project is fairly standard at Urban, but previously, we would create each project from scratch, rewriting similar core code over and over. This time, we sought a better solution that would marry the more bespoke possibilities that code bases like JavaScript and Svelte offer with the off-the-shelf capabilities from a tool like Datawrapper.

Datawrapper is especially useful for teams and organizations with smaller design staffs; it was initially developed to support smaller newsrooms. But Datawrapper graphs aren’t designed to be the main figure within a complex data tool or dashboard. So to meet the goals of this project, we needed more than a simple Datawrapper chart.

Datawrapper charts are embedded on web pages using the <iframe> tag, meaning the chart is hosted on Datawrapper’s servers and loaded as a small inline element on the user’s project page. With Datawrapper’s Chart Interaction Events script, when a user interacts with a Datawrapper chart, such as by clicking on a particular geography of a map, the data behind that object are exposed to the parent page and ready to pass to other functions. We created the underlying data for the Datawrapper map so the datapoints would be dispatched directly to the JavaScript application.

The image below shows the data structure we used in building the map of North Carolina in Datawrapper. The fips_full field is the Federal Information Processing System (FIPS) code, which uniquely identifies each county in the state. The population field is the population for each county, indicators is a categorical marker for each element the user would select in the drop-down, and the name field is the name of each county.

With the base map created in Datawrapper, we turned to Svelte, our team’s preferred JavaScript framework. Svelte takes the dispatched data from the chart interaction (click/hover) and uses the data to set a writable “currently selected county” variable with one of Svelte’s reactive stores. A second read-only store is derived from the county-specific information in the underlying source data (which also contain all county FIPS codes). From there, the information box and table components would subscribe to that derived store to update the content.

With these handoffs enabled, a simplified application structure looks something like the diagram below.

Transforming the data into our application

With an engineering strategy in place, we started connecting the pieces. After cleaning and transforming the Excel data provided by the research team in R, the resulting tabular JSON file for all counties (main-data.json) looked like the table below with more than 30 measures. State data were separated into their own file (main-state-data.json).

We set up two reactive stores using the cleaned and converted data: a writable store for setting the active county and a read-only derived store for all county data. In Svelte, the setup for reactive stores is straightforward — import the functions/data and set the exported stores to be used throughout the application. The derived store is filtered by the FIPS code if a county has been set, otherwise state data are used.

Then, we initialized the first component to display the data. In the simplified Population.svelte file below, we import the derived reactive store and a number formatting function to display information about the selected geography’s population. With that, we write out the HTML and CSS we want to generate.

The HTML written in this .svelte file is very close to what ends up in the browser. That’s because Svelte uses a declarative programming framework where the user specifies what code they want to see generated, as opposed to an imperative programming framework in vanilla JavaScript, where the user specifies how they want the code to be generated. This is one of the many wonderful traits of Svelte!

Outside of data display components, the main component of our application is the Datawrapper map iframe. Iframes embed other webpages in a parent webpage and is the main tool for embedding Datawrapper figures. Although it’s not required to create a dedicated Svelte component for this iframe, it lends itself to code cleanliness and reuse across projects.

Because we want to capture interaction events from this child iframe component and assign the writable store with event data, we used the event dispatch functionality from Svelte to expose events to the parent component. To track what county a user has hovered or clicked on, we need to import Datawrapper’s chart interaction events script (copy-pasted into the project codebase). Then, we import Svelte’s event dispatch API.

Datawrapper’s chart interaction events documentation gives more information on all available events, but in the code below, we attach a listener to two Datawrapper interaction events — and region.mouseenter — which pass their associated data (like county ID) in the variable e. Under the hood, this script uses the browser’s window.postMessage()API. Svelte’s dispatch() function passes this event information to the parent component.

Finally, we bring everything together. The App.svelte file contains our writable store and our two components: the Datawrapper iframe and Population data display. The event listeners for regionclick and regionmouseenter in DatawrapperIframe are the result of the dispatched events and are used to assign the FIPS code to the writable store.


Bringing together the capabilities of Svelte and Datawrapper to build an interactive map with dynamic information tables has proved valuable for our team, as we’ve been able to avoid other complex, custom visualization tools while still making impressive, interactive dashboards. Moving forward, we hope to incorporate Datawrapper’s web components to improve load time compared with iframes, which could decrease the processing burden for projects where a user needs to switch quickly between charts. The full code for the project can be found here.

If you’re looking to get started with Svelte, you can visit the official Svelte Tutorial, which assumes you have some JavaScript, CSS, and HTML knowledge. Additionally, you can use Datawrapper for free and follow the Datawrapper Academy to get started.

— Ben Kates

Want to learn more? Sign up for the Data@Urban newsletter.



Urban Institute

Data@Urban is a place to explore the code, data, products, and processes that bring Urban Institute research to life.