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.