framework icon indicating copy to clipboard operation
framework copied to clipboard

Datawrapper loader example

Open palewire opened this issue 1 year ago • 13 comments

This proposal adds an example that generates and then embeds a chart created by Datawrapper.

In addition to the Python dependencies, it requires a Datawrapper API key available in the Python environment as DATAWRAPPER_ACCESS_TOKEN. Screen Shot 2024-08-17 at 6 50 30 AM

Screen Shot 2024-08-17 at 6 50 41 AM

palewire avatar Aug 17 '24 10:08 palewire

To help reviewing I have deployed the project to https://observablehq.observablehq.cloud/framework-example-loader-datawrapper/

Fil avatar Aug 19 '24 12:08 Fil

I believe I addressed all of your requests. I'm open to whatever approach you want to take regarding the Python environment.

palewire avatar Aug 19 '24 14:08 palewire

I'm sorry I edited my main comment just after I sent it, but you might have read it by email? https://github.com/observablehq/framework/pull/1585#pullrequestreview-2245372013

Also you have removed the "fixed" data/chart.html that I added. We need it so people can see what to expect without actually having to connect to the API (and so we can also rebuild all the examples when necessary).

Fil avatar Aug 19 '24 14:08 Fil

I did miss that, sorry.

I'm open to another example. I was thinking, "Let's keep it super simple" and give the user a bare-bones starting point.

I'm happy to change the chart to something else. What appeals to you? A dressed-up stacked bar, a range plot, a dozen donuts?

palewire avatar Aug 19 '24 14:08 palewire

If you ask me, I like "Germany is the third-oldest country in the world". But it's only an opinion :)

Fil avatar Aug 19 '24 17:08 Fil

Should we make a note that the datawrapper iframe does not appear to support dark mode? Capture d’écran 2024-08-19 à 21 28 38

Fil avatar Aug 19 '24 19:08 Fil

Alrighty. I've updated it with the dot range plot. Screenshot from 2024-08-19 16-30-59

palewire avatar Aug 19 '24 20:08 palewire

Ready for your review again, @Fil

palewire avatar Aug 19 '24 20:08 palewire

I'm a bit reluctant to publish it as is, because there are a few things that ought to be better:

dark mode

I've found a way to enable dark="auto" in the chart's preferences (editing the published chart), but I don't know how to pass this "render" option in the API call that creates the chart. Maybe it's not available in the python API?

responsive

Datawrapper has this concept of responsive charts, where the height depends on the (reactive) width and some javascript updates the iframe height. This example instead uses a fixed height, which ends up hiding some information (in our example, the footer) in a mobile view.

EDIT: I've created a helper function to solve both problems, though. See below.

tons of new charts

It's kind of a bummer that it creates a new chart each time it runs. This makes it quite damaging for the environment your account, and the Datawrapper admins might not like that; more importantly maybe, it makes a lousy user experience as it prevents you from making the chart better by editing it (post-creation) with the DataWrapper UI.

Ideally what I'd like to do is have a unique code in the script; if a chart with that code already exists, we reuse it, otherwise we populate it. If the chart depends on the data, then the code can be computed as a hash of the data state.

I have not implemented that (yet), it's more on the python side.

Capture d’écran 2024-08-21 à 15 59 16

Fil avatar Aug 21 '24 14:08 Fil

I've redeployed to https://observablehq.observablehq.cloud/framework-example-loader-datawrapper/

Note that this helper function should be able to accommodate several charts on the page — maybe that's something we could add to the example too.

Fil avatar Aug 21 '24 15:08 Fil

what I'd like to do is have a unique code in the script; if a chart with that code already exists, we reuse it, otherwise we populate it

We could search for a chart that has that id set in a given hidden field, but I don't see if it's a possibility with the current API.

Fil avatar Aug 21 '24 16:08 Fil

Thanks for this detailed feedback. I'm going to try to address your concerns piecemeal. The most recent commit is my first effort. I believe I have configured the Python chart configuration to activate Datawrapper's dark mode, which is off by default.

I'll loop back on your other items soon.

palewire avatar Aug 21 '24 16:08 palewire

@Fil, here's a thought on the responsive iframe issue. Would we be better off switching to the web component, as described here: https://blog.datawrapper.de/web-component-embedding/

palewire avatar Aug 21 '24 18:08 palewire

I think you're right!

Also, I have tried pipenv, and it's great. Maybe this is an opportunity to write down how it works in this case.

For me it was:

# https://docs.pipenv.org/#install-pipenv-today
brew install pipenv 
# https://docs.pipenv.org/basics/#importing-from-requirements-txt
pipenv install -r ./requirements.txt
# https://app.datawrapper.de/account/api-tokens
echo 'DATAWRAPPER_ACCESS_TOKEN="****"' > ./.env
# https://docs.pipenv.org/basics/
pipenv run yarn dev

Fil avatar Aug 22 '24 08:08 Fil

Do you have an established pattern for templating a script tag to be injected into the page? I tried passing the chart ID out of the data loader and then printing that into the page with a ${x} style template literal, but that's not working.

I was thinking something like this, but I'm not sure how that kind of thing fits into your framework.

```js
const chartId = await FileAttachment("data/chart.txt").text()
```

<div>
   <script type="text/javascript" defer 
        src="https://datawrapper.dwcdn.net/${chartId}/embed.js?v=14">
   </script>
   <noscript>
      <img src="https://datawrapper.dwcdn.net/${chartId}/full.png" alt="[aria-description]" />
   </noscript>
</div>

palewire avatar Aug 22 '24 14:08 palewire

I think I got it working and solved the responsive bug with:

```js echo
const chartId = await FileAttachment("data/chart.txt").text()
const tag = display(document.createElement('script'));
tag.setAttribute('src', `https://datawrapper.dwcdn.net/${chartId}/embed.js?v=14`);
```

Let me know what you think. If we have this one, I will move onto the final issue: Endless chart creation.

palewire avatar Aug 23 '24 10:08 palewire

Yes it looks much simpler.

One issue that I had solved with my system but has a regression now, is when the page sets a color mode that is not the same as the browser's preference.

If you set this in the front-matter

---
theme: dark
---

and visit with a browser with light mode preferences, the chart is generated in light mode, and some text becomes unreadable. Same issue if you reverse the situation (theme: light, and a dark mode browser).

I think this is an upstream bug with datawrapper, though? We correctly set :root {color-scheme: dark;} and it should respect that, if set, over the browser preference. Or maybe I'm missing something?

Fil avatar Aug 23 '24 11:08 Fil

I'm not a dark mode expert, so I'll defer to you on this. I can contact the datawrapper support team after we finish this ticket, if you think that's the right path.

On Fri, Aug 23, 2024, at 7:06 AM, Philippe Rivière wrote:

Yes it looks much simpler.

One issue that I had solved with my system but has a regression now, is when the page sets a color mode that is not the same as the browser's preference.

If you set this in the front-matter

`--- theme: dark

`

and visit with a browser with light mode preferences, the chart is generated in light mode, and some text becomes unreadable. Same issue if you reverse the situation (theme: light, and a dark mode browser).

I think this is an upstream bug with datawrapper, though? We correctly set :root {color-scheme: dark;} and it should respect that, if set, over the browser preference. Or maybe I'm missing something?

— Reply to this email directly, view it on GitHub https://github.com/observablehq/framework/pull/1585#issuecomment-2306855981, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAACOCPLQSJUMKUS2HLHL2DZS4JRRAVCNFSM6AAAAABMVKF276VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMBWHA2TKOJYGE. You are receiving this because you authored the thread.Message ID: @.***>

palewire avatar Aug 23 '24 11:08 palewire

Inspecting the script, I see it only reads window.matchMedia("(prefers-color-scheme: dark)").matches. Probably something to report upstream.

Fil avatar Aug 23 '24 12:08 Fil

Good catch. I'll send an email to the Datawrapper support team reporting the bug.

Separately, I've patched the loader to "get or create" the chart, rather than create a new one each time.

Are you good with that edit? If so, anything else you'd like to see before merging?

palewire avatar Aug 23 '24 13:08 palewire

I think we only need to add the built chart.txt (so that in the future we can rebuild the project without datawrapper credentials).

What do you think of calling this "datawrapper-api" rather than "loader-datawrapper"? (It's not really "loading data", even though it uses the data loader architecture.)

Also, shouldn't we present the simpler version at the beggining of the page, explaining how a user can create a chart in datawrapper, then embed it in a framework page with a simple <script>. And then start the more powerful approach by saying "but here's how you can also create the chart from your framework code…". (Most people will probably only ever need the first approach, and for the others it can be used as a gentle introduction.)

Fil avatar Aug 23 '24 13:08 Fil

I've added the cached chart.txt file and renamed the example as "Datawrapper API."

I'm not sure I know what you mean by "the simpler version," but I took a thwack at what I think you mean. A web component that does not rely on the data loader is at the top. It is then followed by the Python code, which is then embedded with a variation on the snippet at the top. Is that what you mean?

palewire avatar Aug 23 '24 13:08 palewire

Yes, exactly!

Fil avatar Aug 23 '24 14:08 Fil

Reading https://blog.datawrapper.de/web-component-embedding/ I found out how to solve the dark mode issue, by adding data-dark="true" or "false". I'll fix in a moment (also doing some light copy-editing).

Fil avatar Aug 23 '24 14:08 Fil

hmmm, I was trying to embed another chart and I'm getting errors on nki3d and K2J9t (from https://blog.datawrapper.de/pigeon-internet-speed/), looks like in these instances the script tries to get the data from my own server…?

Fil avatar Aug 23 '24 14:08 Fil

Huh. Now you're past my knowledge. The chart isn't so old that it predates web components. Maybe we found another bug?

On Fri, Aug 23, 2024, at 10:37 AM, Philippe Rivière wrote:

hmmm, I was trying to embed another chart and I'm getting errors on nki3d and K2J9t (from https://blog.datawrapper.de/pigeon-internet-speed/), looks like in these instances the script tries to get the data from my own server…?

— Reply to this email directly, view it on GitHub https://github.com/observablehq/framework/pull/1585#issuecomment-2307228960, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAACOCJSULNKQQP65NVECYTZS5CMJAVCNFSM6AAAAABMVKF276VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMBXGIZDQOJWGA. You are receiving this because you authored the thread.Message ID: @.***>

palewire avatar Aug 23 '24 14:08 palewire

I don't know what I was doing wrong, but K2J9t and nki3d now work as expected. I've added a different chart at the top for some diversity, polished the prose a bit, and added a helper function that handles dark mode in sync with Framework (bypassing the bug we've noticed). I think it's close to done!

Fil avatar Aug 23 '24 15:08 Fil

Redeployed at https://observablehq.observablehq.cloud/framework-example-datawrapper-api/

Fil avatar Aug 23 '24 15:08 Fil

Looks good. I'm ready to ship it when you are. Where is that dark variable being set?

palewire avatar Aug 23 '24 15:08 palewire

It's a reactive variable available in all pages. See https://observablehq.com/framework/lib/generators#dark (I linked to this page in the "tip")

Fil avatar Aug 23 '24 15:08 Fil