Home > Enterprise >  D3/React - Skip blanks in scatterplot not working
D3/React - Skip blanks in scatterplot not working

Time:10-25

I have a dataset with blank cells that I would like not to be drawn in my linechart with scatter dots. For the line I did manage to skip blanks, but for the line I can't get it to work.

My data looks like this:

DATE,VALUE
5/31/2022,12
6/1/2022,23
6/2/2022,24
6/3/2022,26
6/4/2022,32
6/5/2022,32
6/6/2022,35
6/6/2022,32
6/7/2022,31
6/8/2022,30
6/8/2022,21
6/10/2022,23
6/11/2022,13
6/12/2022,13
6/13/2022,14
6/14/2022,
6/15/2022,
6/16/2022,
6/17/2022,
6/18/2022,
6/19/2022,
6/20/2022,
6/21/2022,
6/22/2022,
6/23/2022,
6/24/2022,
6/25/2022,
6/26/2022,
6/27/2022,

I skip the blanks in the line like this:

const linevalue = d3.line()
  .defined(function(d) { return d.value; })
  .x(function(d) { return x(d.date) })
  .y(function(d) { return y(d.value) })

And try to do it in the scatter / dot part like this:

g.append("svg")
.selectAll("dotDemand")
.data(data)
.enter()
.append("circle")
.defined(function(d) { return d.value; })  // <<<< Here I try to do it in the same way
.attr("cy", function(d) { return y(d.value) } )
.attr("cx", function(d) { return x(d.date) } )
.attr("r", 5)
.attr("fill", "#7EE0FA")

But it doesn't work, this gives an error:

Uncaught TypeError: g.append(...).selectAll(...).data(...).enter(...).append(...).defined is not a function

I'm brand new to both React as D3 and I think I might also mess up dome things in the g.append("svg") parts but I can't figure it out how it should work.

I will upload the full code for the chart in a moment, stackoverflow is having issues at the moment with adding a lot multiple lines with code (saying to dent then indent, the code even if I try to add it as a javascript snippet)

import * as d3 from 'd3';
import {useEffect,useState} from 'react';
import csvFile from'../../data/TestData.csv';

const BasicLinechart=(props)=>{

const [data,setData]=useState([]);
console.log(csvFile)

const {width,height} =props;

useEffect(()=>{
if(data.length>0){
drawChart();
}else{
getCSVData();
}
},[data]);

const getCSVData=async()=>{
const tempData=[];

awaitd3.csv(
csvFile,
function(d){
tempData.push({
date:d3.timeParse("%m/%d/%Y")(d.DATE),
month:d3.timeParse("%m/%d/%Y")(d.DATE),
value:Number(d.VALUE),
});
}
);
setData(tempData);
console.log("1");

console.log(data.date)
};

const drawChart=()=>{

const parseDate=d3.timeParse("%m/%d/%Y"),
formatDay=d3.timeFormat("%d"),
formatMonth=d3.timeFormat("%b");

var div=d3.select("body").append("div")
.attr("class","tooltip")
.style("opacity",0);

//createthechartarea
const svg=d3.select('.svg-canvas')
svg.selectAll("*").remove();
var margin={top:20,left:30};

//AddXaxis-->itisadateformat
var x=d3.scaleTime()
.domain(d3.extent(data,function(d){returnd.date;}))
.range([0,width])

var x2=d3.scaleTime()
.domain(d3.extent(data,function(d){returnd.date;}))
.range([0,width]);

var g=svg.append('g')
.attr('transform','translate(' margin.left ',' margin.top ')')
.attr("class","legendOrdinal");

var xAxisDay=d3.axisBottom()
.scale(x)
.ticks(d3.timeDay.every(1))
.tickFormat(formatDay);

g.append("g")
.attr("transform","translate(0," height ")")
.attr("stroke","#595959")
.attr("font-family","cursive")
.call(xAxisDay)
.selectAll("text")
.style("font-size","12px")

g.selectAll("path")
.style("stroke","#595959")

g.append("g")
.select(".domain")
.attr("stroke","#595959")
.attr("stroke-width","6")
.attr("opacity",".6");

var xAxisMonth=d3.axisBottom()
.scale(x2)
.ticks(d3.timeMonth.every(1))
.tickFormat(formatMonth);


g.append("g")
.attr("transform","translate(0," (height 40) ")")
.call(xAxisMonth)
.selectAll("text")
.style("font-size","12px")
.attr("stroke","#595959");

//AddYaxis
var y=d3.scaleLinear()
.domain([0,d3.max(data,function(d){return Math.max(d.value);})])
.range([height,10]);

g.append("g")
.call(d3.axisLeft(y))
.attr("stroke","#595959")
.selectAll("text")
.style("font-size","12px")
.attr("stroke","#595959");


//set lines coordinates
const linevalue=d3.line()
.defined(function(d){returnd.value;})
.x(function(d){returnx(d.date)})
.y(function(d){returny(d.value)})

//Addtheline&pointsforvalue
g.append("path")

.datum(data)
.attr("fill","none")
.attr("stroke","#7EE0FA")
.attr("stroke-width",2)
.attr("d",linevalue)

g.append("svg")
.selectAll("dotDemand")
.data(data)
.enter()
.append("circle")
//.defined("cy",function(d){returny(d.value);})
.attr("cy",function(d){returny(d.value)})

.attr("cx",function(d){returnx(d.date)})
.attr("r",5)
.attr("fill","#7EE0FA")
.on('mouseover',function(d,i){
d3.select(this).transition()
.duration('100')
.attr("r",10);
div.transition()
.duration('50')
.style("opacity",0);
div.html("$" d3.format(".2f")(d.date))
.style("left",x(d.value) 10 "px")
.style("top",y(d.date) "px");
})
.on('mouseout',function(d,i){
d3.select(this).transition()
.duration('200')
.attr("r",5);
//makesdivdisappear
div.transition()
.duration('200')
.style("opacity",0);
});
}

return(
<div>
<svgclassName="svg-canvas"width="800px"height="600px"/>
</div>
)
}

export default BasicLinechart;

CodePudding user response:

Indeed the defined() function only exists on a d3 line generator, you cannot do that on a selection. Instead you can filter the data that you bind to the selection like this:

g.append("svg")
.selectAll("dotDemand")
.data(data.filter(d => d.value))
.enter()
.append("circle")
.attr("cy",function(d){return y(d.value)})
.attr("cx",function(d){return x(d.date)})
.attr("r",5)
.attr("fill","#7EE0FA")
  • Related