Plotting data points
In this tutorial we will use d3 line()
function to draw the line chart below from a given set of points.
line function will generate the data d
attribute needed to draw a line using an svg path
element.
Linechart
<!-- LineChart.svelte -->
<script>
// D3 imports
import { scaleTime, scaleLinear } from 'd3-scale';
import { extent, max } from 'd3-array';
import { line, curveBasis } from 'd3-shape';
import { draw } from 'svelte/transition';
import { onMount } from 'svelte';
// Component imports
import AxisLeft from './AxisLeftV5.svelte';
import AxisBottom from './AxisBottomV5.svelte';
import Labels from './Labels.svelte';
import { csv } from 'd3-fetch';
// Get data
// let's use csv function from d3-fetch to download our data.
// download data on: https://datavisualizationwithsvelte.com/data/natural_gas.csv
onMount(() => {
csv('/data/natural_gas.csv').then((csvData) => {
data = csvData;
});
});
// State variables
let data = $state(null);
let width = $state(0); // width will be set by the clientWidth
const height = 350;
const margin = { top: 10, right: 0, bottom: 20, left: 35 };
// Computed values
let xScale = $derived(
data && width
? scaleTime()
.domain(extent(data, (d) => new Date(d.date)))
.range([margin.left, width - margin.right])
: null
);
let yScale = $derived(
data && width
? scaleLinear()
.domain([0, max(data, (d) => +d.price + 4)])
.range([height - margin.bottom, margin.top])
: null
);
// Line function from D3 to create the d attribute for a path element
// which will be our line.
let lineGenerator = $derived(
xScale && yScale
? line()
.x((d) => xScale(new Date(d.date)))
.y((d) => yScale(+d.price))
.curve(curveBasis)
: null
);
</script>
<!-- bind width of the container div to the svg width-->
<div class="wrapper" bind:clientWidth={width}>
{#if data && width && xScale && yScale && lineGenerator}
<svg {width} {height}>
<AxisBottom
{width}
{height}
{margin}
tick_number={width > 380 ? 10 : 4}
{xScale}
format={(d) => d.getFullYear()} />
<AxisLeft {width} {height} {margin} {yScale} position="left" />
<Labels
labelfory={true}
{width}
{height}
{margin}
tick_number={10}
yoffset={-50}
xoffset={270}
label={'$ price per million British thermal units ↑'} />
<path
in:draw={{ duration: 8000 }}
d={lineGenerator(data)}
stroke="#fcd34d"
stroke-width={1.5}
fill="none" />
</svg>
{/if}
</div>
What we do above additionally is to create the line generating function first:
let lineGenerator = $derived(
xScale && yScale
? line()
.x((d) => xScale(new Date(d.date)))
.y((d) => yScale(+d.price))
.curve(curveBasis)
: null
);
and then in the markup we used the line() function like so to set the d attribute of our path element:
<path
in:draw={{ duration: 2000 }}
shape-rendering="crispEdges"
d={lineGenerator(data)}
stroke="#fcd34d"
stroke-width={1.5}
stroke-linecap="round"
fill="none" />
We achieved the drawing animation using the draw
from svelte and applying it to our path element.
Join our Discord to share your charts, ask questions, or collaborate with fellow developers!