d3 line generator and missing data

I am trying to understand why d3.line behaves differently for null when combined with scale.
To elaborate, my sample dataset is following a notebook

	| x   | y                  |
	|-----|--------------------|
	| 50  | 97.04013083865155  |
	| 100 | null               |
	| 150 | 98.62594214598816  |
	| 200 | 76.49419950954189  |
	| 250 | 29.30639006661442  |
	| 300 | 29.366842697148176 |
	| 350 | 51.587600132998325 |
	| 400 | null               |
	| 450 | null               |
	| 500 | 26.90860254816283  |
	| 550 | null               |
	| 600 | 99.1622268038577   |

If I try to generate a line from here without using any scale by

const noScale = d3.line()
    .x(d => d.x)
    .y(d => d.y)
    (data)

it generates this,

However, if I use scale in the generator it fails

const withScale = d3.line()
    .x(d => scaleX(d.x))
    .y(d => scaleY(d.y))
    (data)

However, using defined in the generator makes it indifferent whether scale was used or not.

const noScaleWithDefinedFilter = d3.line()
    .x(d => d.x)
    .y(d => d.y)
    .defined(d => d.y)
    (data.filter((a) => a.y !== null))

works as good as

const withScaleWithDefinedFilter = d3.line()
    .x(d => scaleX(d.x))
    .y(d => scaleY(d.y))
    .defined(d => d.y)
    (data.filter((a) => a.y !== null))

SO as the following two

const noScaleWithDefined = d3.line()
    .x(d => d.x)
    .y(d => d.y)
    .defined(d => d.y)
    (data)

works as good as

const withScaleWithDefined = d3.line()
    .x(d => scaleX(d.x))
    .y(d => scaleY(d.y))
    .defined(d => d.y)
    (data)

How can I generate the same line that const noScale but with the effect of scaling.

Thank you in advance.

in noScale the null value is considered as 0. If this is what you want, you can do

d3.line()
    .x(d => scaleX(d.x))
    .y(d => scaleY(d.y || 0))
    (data)

If you want missing data to create a “gap” in the line, then the blue line is OK. You could add the dots on top of it to make it easier to understand that there are individual data points that are not connected because their neighbors have undefined values.

1 Like

@Fil I wanted to know how withScale can produce what noScale does.

Solved here

I tested out

withScale = d3.line()
    .x(d => scaleX(d.x))
    .y(d => scaleY.unknown(0)(d.y))
    (data)

bound.append('path')
    .attr('class', 'Orange-withScale')
    .attr('d', withScale)
    .attr('fill', 'none')
    .attr('stroke', 'orange')
    .attr('stroke-width', '2')

1 Like