This blog post introduces and briefly describes the Raku package “JavaScript::D3” that can be used for generation of JavaScript D3.js code for making plots and charts.
The package is intended to be used in Jupyter notebooks with the Raku kernel implemented by Brian Duggan, [BD1].
For illustrative examples see the Jupyter notebook “Tests-for-JavaScript-D3”.
The (original versions of the) JavaScript snippets used in this package are taken from “The D3.js Graph Gallery”.
Here is a corresponding video demo (≈7 min): “The Raku-ju hijack hack of D3.js” :

Mission statement
Make first class — beautiful, tunable, and useful — plots and charts with Raku using concise specifications.
Design and philosophy
Here is a list of guiding design principles:
- Concise plot and charts specifications.
- Using Mathematica’s plot functions for commands signatures inspiration. (Instead of, say, R’s “ggplot2”.)
- For example, see
ListPlot,BubbleChart.
- For example, see
- The primary target data structure to visualize is an array of hashes, with all array elements having the one of these sets of keys
<x y><x y group><x y z><x y z group>
- Multiple-dataset plots are produced via dataset records that have the key “group”.
- Whenever possible deduce the keys from arrays of scalars.
- The data reshaping functions in “Data::Reshapers”, [AAp1], should fit nicely into workflows with this package.
- The package functions are tested separately:
- As Raku functions that produce output for given signatures
- As JavaScript plots that correspond to the corresponding intents
How does it work?
Here is a diagram that summarizes the evaluation path from a Raku plot spec to a browser diagram:

Here is the corresponding narration:
- Enter Raku plot command in cell that starts with the magic spec
%% js.- Like
js-d3-list-plot((^12)>>.rand).
- Like
- Jupyter via the Raku kernel evaluates the Raku plot command.
- The Raku plot command produces JavaScript code.
- The Jupyter “lets” the web browser to evaluate the obtained JavaScript code.
- Instead of web browser, say, Visual Studio Code can be used.
The evaluation loop spelled out above is possible because of the magics implementation in the Raku package Jupyter::Kernel, [BD1].
Usage examples
Setup
Here we load the package “JavaScript::D3” and some other packages that are used to generate, summarize, and modify datasets:
use JavaScript::D3;
use Data::Generators;
use Data::Reshapers;
use Data::Summarizers;
Here we use a JavaScript cell that allows the visualization of with D3.js in Jupyter notebooks:
%% javascript
require.config({
paths: {
d3: 'https://d3js.org/d3.v7.min'
}});
require(['d3'], function(d3) {
console.log(d3);
});
Histogram
Here is an example of a histogram:
%% >js
say js-d3-histogram(
random-variate(NormalDistribution.new(120,10), 500),
height=>500,
background=>'white',
title=>'Normal distribution example',
x-axis-label=>'random value',
y-axis-label=>'counts', margins => {top=>120});

List line plot
Here we make random data:
my @dsXYG = random-tabular-dataset(400, <x y group>,
generators => { x => { random-real(100, $_) },
y => { random-real(10, $_) },
group => <astro barista crom dark> });
@dsXYG = @dsXYG.map( -> $r { given $r<group> {
when .starts-with('a') { $r<y> = 0.8*$r<x> + 0.04*(10-$r<x>)*$r<y> }
when .starts-with('b') {$r<y> = 3*sqrt($r<x>) + $r<y>}
when .starts-with('c') { $r<y> = $r<y> - $r<x>/3 + 50 }
};
$r
});
say dimensions(@dsXYG);
say deduce-type(@dsXYG);
(400 3)
Vector(Struct([group, x, y], [Str, Num, Num]), 400)
Here is an example of multi-line list plot:
%%js
js-d3-list-line-plot(@dsXYG.sort({ $_<x> }), background=>'')

Bubble chart
Here we make some random data:
my @ds3DGroups = random-tabular-dataset(100, <x y z group>,
generators => { x => { random-real(20, $_) },
y => { random-variate(NormalDistribution.new(200,50), $_) },
z => { random-variate(NormalDistribution.new(20,12), $_) },
group => <aspirin biscuit cookie>
} );
say deduce-type(@ds3DGroups);
Vector(Struct([group, x, y, z], [Str, Num, Num, Num]), 100)
Here is an example of bubble chart (with tooltips):
%%js
js-d3-bubble-chart(@ds3DGroups,
x-axis-label=>'x coordinates',
y-axis-label=>'Normal distribution',
plot-label=>'Bubble chart over groups',
opacity=>0.5):tooltip:legends

Alternatives
Raku packages
The Raku packages “Text::Plot”, [AAp2], and “SVG::Plot”, [MLp1], provide similar functionalities and both can be used in Jupyter notebooks. (Well, “Text::Plot” can be used anywhere.)
Different backend
Instead of using D3.js as a “backend” it is possible — and instructive — to implement Raku plotting functions that generate JavaScript code for the library Chart.js.
D3.js is lower level than Chart.js, hence in principle Chart.js is closer to the mission of this Raku package. I.e. at first I considered having Raku plotting implementations with Chart.js (in a package called “JavaScript::Chart”.) But I had hard time making Chart.js plots work consistently within Jupyter.
Command Line Interface (CLI)
The package provides a CLI script that can be used to generate HTML files with plots or charts.
js-d3-graphics --help
# Usage:
# js-d3-graphics <cmd> [<points> ...] [-p|--point-char=<Str>] [-w|--width[=UInt]] [-h|--height[=UInt]] [-t|--title=<Str>] [--x-label=<Str>] [--y-label=<Str>] [--background=<Str>] [--color=<Str>] [--format=<Str>] -- Makes textual (terminal) plots.
# js-d3-graphics <cmd> <words> [-w|--width[=UInt]] [-h|--height[=UInt]] [-t|--title=<Str>] [--x-label=<Str>] [--y-label=<Str>] [--background=<Str>] [--color=<Str>] [--format=<Str>] -- Makes textual (terminal) plots by splitting a string of data points.
# js-d3-graphics <cmd> [-w|--width[=UInt]] [-h|--height[=UInt]] [-t|--title=<Str>] [--x-label=<Str>] [--y-label=<Str>] [--background=<Str>] [--color=<Str>] [--format=<Str>] -- Makes textual (terminal) plots from pipeline input
#
# <cmd> Graphics command.
# [<points> ...] Data points.
# -p|--point-char=<Str> Plot points character. [default: '*']
# -w|--width[=UInt] Width of the plot. (-1 for Whatever.) [default: 800]
# -h|--height[=UInt] Height of the plot. (-1 for Whatever.) [default: 600]
# -t|--title=<Str> Title of the plot. [default: '']
# --x-label=<Str> Label of the X-axis. If Whatever, then no label is placed. [default: '']
# --y-label=<Str> Label of the Y-axis. If Whatever, then no label is placed. [default: '']
# --background=<Str> Image background color [default: 'white']
# --color=<Str> Color. [default: 'steelblue']
# --format=<Str> Output format, one of 'jupyter' or 'html'. [default: 'html']
# <words> String with data points.
Here is an usage example that produces a list line plot:
js-d3-graphics list-line-plot 1 2 2 12 33 41 15 5 -t="Nice plot" --x-label="My X" --y-label="My Y" > out.html && open out.html
Here is an example that produces bubble chart:
js-d3-graphics bubble-chart "1,1,10 2,2,12 33,41,15 5,3,30" -t="Nice plot" --x-label="My X" --y-label="My Y" > out.html && open out.htm
Implementation details
Splicing of JavaScript snippets
The package works by splicing of parametrized JavaScript code snippets and replacing the parameters with concrete values.
In a sense, JavaScript macros are used to construct the final code through text manipulation. (Probably, unsound software-engineering-wise, but it works.)
History
Initially the commands of this package were executed in Jupyter notebook with Raku kernel properly hacked to redirect Raku code to JavaScript backend
Brian Duggan fairly quickly implemented the suggested Jupyter kernel magics, so, now no hacking is needed.
References
Articles
[OV1] Olivia Vane, “D3 JavaScript visualisation in a Python Jupyter notebook”, (2020), livingwithmachines.ac.uk.
[SF1] Stefaan Lippens, Custom D3.js Visualization in a Jupyter Notebook, (2018), stefaanlippens.net.
Packages
[AAp1] Anton Antonov, Data::Reshapers Raku package, (2021-2022), GitHub/antononcube.
[AAp2] Anton Antonov, Text::Plot Raku package, (2022), GitHub/antononcube.
[BD1] Brian Duggan, Jupyter::Kernel Raku package, (2017-2022), GitHub/bduggan.
[MLp1] Moritz Lenz, SVG::Plot Raku package (2009-2018), GitHub/moritz.
3 thoughts on “JavaScript::D3 ”