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")