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>
import { scaleTime, scaleLinear } from 'd3-scale';
import { extent, max } from 'd3-array';
import { line, curveBasis } from 'd3-shape';
import Axis from './AxisD3.svelte';
import Labels from './Labels.svelte';
import { csv } from 'd3-fetch';
import { onMount } from 'svelte';
import { draw } from 'svelte/transition';
let data, xScale, yScale;
// 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((csv) => (data = csv));
});
// Dimensions, Margins, Scales
let width; // width will be set by the clientWidth
const height = 350;
const margin = { top: 10, right: 0, bottom: 20, left: 35 };
$: if (data && width) {
xScale = scaleTime()
.domain(extent(data, (d) => new Date(d.date)))
.range([margin.left, width - margin.right]);
yScale = scaleLinear()
.domain([0, max(data, (d) => +d.price + 4)])
.range([height - margin.bottom, margin.top]);
}
// Line function from d3 to create the d attribute for a path element
// which will be our line,
$: lineGenerator = line()
.x((d) => xScale(new Date(d.date)))
.y((d) => yScale(+d.price))
.curve(curveBasis);
</script>
<!-- bind width of the container div to the svg width-->
<!-- what this will to is to set the width of the svg responsively, same width like its container div -->
<div class="wrapper" bind:clientWidth={width}>
{#if data && width}
<svg {width} {height}>
<Axis
{width}
{height}
{margin}
tick_number={width > 380 ? 10 : 4}
scale={xScale}
position="bottom" />
<Axis {width} {height} {margin} scale={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: 2000 }}
shape-rendering="crispEdges"
d={lineGenerator(data)}
stroke="#fcd34d"
stroke-width={1.5}
stroke-linecap="round"
fill="none" />
</svg>
{/if}
</div>
We are reusing here the axis and label components we created in the Scatter Chart II example.
What we do above additionally is to create the line generating function first:
$: lineGenerator = line()
.x((d) => xScale(new Date(d.date)))
.y((d) => yScale(+d.price));
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.