I need to change the range for yAxis ticks in my d3 chart. Currently, it has a range of 2M and looks like this:
The majority of data is spread between 0 and 4M. I would like to have a smaller range for ticks up until 4M and then a bigger range. So I would have ticks for 1M, 2M, 3M, 4M and then 8M, 12M, 16M. Here is the code:
const width = 1000;
const height = 700;
const padding = 120; // between title and svg borders
const marginTop = 120;
// Min and max for y axis for Revenue values
const maxRevenue = d3.max(dataset, (d) => d[1]);
const minRevenue = d3.min(dataset, (d) => d[1]);
const yScale = d3
.scaleLinear()
.domain([minRevenue, maxRevenue])
.range([height - padding, marginTop]);
const yAxis = d3.axisLeft(yScale);
svg
.append("g")
.attr("transform", `translate(${padding}, 0)`)
.call(yAxis); // if need to move the chart to the right (for yaxis)
My recommendation is to use a "split" y-axis. Something like this:
<html>
<meta charset="utf-8" />
<style>
/* set the CSS */
.bar {
fill: steelblue;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = { top: 20, right: 20, bottom: 30, left: 100 },
width = 500 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
pbottomsize = 0.66,
ptopsize = 0.25;
// set the ranges
var xd = ['A', 'B', 'C', 'D'];
var x = d3.scaleBand().range([0, width]).padding(0.1).domain(xd);
var y = d3.scaleLinear().range([height * pbottomsize, 0]).domain([0, 20]);
var y1 = d3.scaleLinear().range([height * ptopsize, 0]).domain([1000000, 2000000]);
var svg = d3
.select('body')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);
var g1 = svg
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + (margin.top + height * 0.33) + ')');
var g2 = svg
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var data = d3.range(1, 100).map(function (d, i) {
return {
x: xd[Math.floor(Math.random() * xd.length)],
y: Math.random() < 0.75 ? Math.random() * 20 : (Math.random() + 1) * 1000000,
};
});
var data0 = data.filter(function(d){
return d.y < 1000000;
});
var data1 = data.filter(function(d){
return d.y > 1000000;
})
// append the rectangles for the bar chart
g1
.selectAll('.circle')
.data(data0)
.enter()
.append('circle')
.attr('cx', function (d) {
return x(d.x) + (x.bandwidth() / 2);
})
.attr('r', 10)
.attr('cy', function (d) {
return y(d.y);
})
.style('fill', 'steelblue');
g2
.selectAll('.circle')
.data(data1)
.enter()
.append('circle')
.attr('cx', function (d) {
return x(d.x) + (x.bandwidth() / 2);
})
.attr('r', 10)
.attr('cy', function (d) {
return y1(d.y);
})
.style('fill', 'red');
// add the x Axis
g1
.append('g')
.attr('transform', 'translate(0,' + (height * pbottomsize) + ')')
.call(d3.axisBottom(x));
// add the y Axis
g1.append('g').call(d3.axisLeft(y));
g2.append('g').call(d3.axisLeft(y1).ticks(3));
var g3 = svg.append('g')
.attr('transform', 'translate(' + 70.5 + ',' + 136 + ')')
g3.append('path')
.attr('d', 'M 10 10 Q 20 0, 30 10 T 50 10 M 30 10 L 30 -2')
.attr('stroke', 'black')
.attr('fill', 'none');
g3.append('path')
.attr('d', 'M 10 20 Q 20 10, 30 20 T 50 20 M 30 20 L 30 32')
.attr('stroke', 'black')
.attr('fill', 'none');
</script>
</body>
</html>
Related
I have made two separate graph on separate page of Bar and pie chart respectively and now i wanted to combine this two graph in the single page so that I can have a dashboard. but when i start to combine to two graph in the main page its not happening and they overlap of each other.
Code:
https://github.com/Mustafa2911/d3-design/blob/main/combine.html
Combine file contain: Code of both pie and bar chart.
Bar file contain: Code of bar chart.
Pie chart contain: Code of pie chart.
Tried this with your code.
Scroll to see the bar graph axis.
NOTE: The bar graph data will not be available ∵ it is from the demo1.csv file in your repository.
Hope this helps.
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<style>
#my_dataviz {
display: inline-block;
width: 50%;
}
</style>
</head>
<body>
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var width = 800
height = 450
margin = 40
// The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
var radius = Math.min(width, height) / 2 - margin
// append the svg object to the div called 'my_dataviz'
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Create dummy data
var data = {
Corporation_Tax: 15,
Income_Tax: 15,
Customs: 5,
Union_Excise_Duties: 7,
Good_and_Service_tax: 16,
Non_tax_Revenue: 5,
Non_Dept_Capital_Receipt: 2,
Borrowings_Liabilities: 35
}
// set the color scale
var color = d3.scaleOrdinal()
.domain(["a", "b", "c", "d", "e", "f", "g", "h"])
.range(d3.schemeSet1);
// Compute the position of each group on the pie:
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {
return d.value;
})
var data_ready = pie(d3.entries(data))
// The arc generator
var arc = d3.arc()
.innerRadius(radius * 0.5) // This is the size of the donut hole
.outerRadius(radius * 0.8)
// Another arc that won't be drawn. Just for labels positioning
var outerArc = d3.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9)
// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d) {
return (color(d.data.key))
})
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 1)
// Add the polylines between chart and labels:
svg
.selectAll('allPolylines')
.data(data_ready)
.enter()
.append('polyline')
.attr("stroke", "black")
.style("fill", "none")
.attr("stroke-width", 1)
.attr('points', function(d) {
var posA = arc.centroid(d) // line insertion in the slice
var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that
var posC = outerArc.centroid(d); // Label position = almost the same as posB
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
return [posA, posB, posC]
})
// Add the polylines between chart and labels:
svg
.selectAll('allLabels')
.data(data_ready)
.enter()
.append('text')
.text(function(d) {
console.log(d.data.key);
return d.data.key
})
.attr('transform', function(d) {
var pos = outerArc.centroid(d);
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
pos[0] = radius * 0.99 * (midangle < Math.PI ? 1 : -1);
return 'translate(' + pos + ')';
})
.style('text-anchor', function(d) {
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
return (midangle < Math.PI ? 'start' : 'end')
})
</script>
<style>
#my_dataviz {
display: inline-block;
width: 50%;
}
</style>
<div id="my_dataviz_es"></div>
<script>
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 30,
bottom: 40,
left: 160
},
width = 460,
height = 400;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz_es")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Parse the Data
d3.csv("demo1.csv", function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([0, 550000])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var y = d3.scaleBand()
.range([0, height])
.domain(data.map(function(d) {
return d.Country;
}))
.padding(.1);
svg.append("g")
.call(d3.axisLeft(y))
//Bars
svg.selectAll("myRect")
.data(data)
.enter()
.append("rect")
.attr("x", x(0))
.attr("y", function(d) {
return y(d.Country);
})
.attr("width", function(d) {
return x(d.Value);
})
.attr("height", y.bandwidth())
.attr("fill", "#69b3a2")
// .attr("x", function(d) { return x(d.Country); })
// .attr("y", function(d) { return y(d.Value); })
// .attr("width", x.bandwidth())
// .attr("height", function(d) { return height - y(d.Value); })
// .attr
})
</script>
</body>
</html>
EDIT: See here - https://codepen.io/KZJ/pen/rNpqvdq?editors=1011 - for changes made reg. the below comment
what if I want to have my bar chart at the top and on right side i want to have my pie chart
Changed -
a) Both charts were using the same name 'svg' to d3.select() the divs. This caused the charts to overlap.
b) Modified width, height, transform, and added some border CSS - only for demonstration purposes - It can be removed/edited as required.
FYR this is how it looks now -
I try to do a beeswarm plot with different radius; inspired by this code
The issue I have, is that my point are offset regarding my x axis:
The point on the left should be at 31.7%. I don't understand why, so I would appreciate if you could guide me. This could be improved by changing the domain of x scale, but this can't match the exact value; same issue if I remove the d3.forceCollide()
Thank you,
Data are available here.
Here is my code:
$(document).ready(function () {
function tp(d) {
return d.properties.tp60;
}
function pop_mun(d) {
return d.properties.pop_mun;
}
var margin = {top: 20, right: 20, bottom: 20, left: 40},
width = 1280 - margin.right - margin.left,
height = 300 - margin.top - margin.bottom;
var svg = d3.select("body")
.append("svg")
.attr("viewBox", `0 0 ${width} ${height}`)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var z = d3.scaleThreshold()
.domain([.2, .3, .4, .5, .6, .7])
.range(["#35ff00", "#f1a340", "#fee0b6",
"#ff0000", "#998ec3", "#542788"]);
var loading = svg.append("text")
.attr("x", (width) / 2)
.attr("y", (height) / 2)
// .attr("dy", ".35em")
.style("text-anchor", "middle")
.text("Simulating. One moment please…");
var formatPercent = d3.format(".0%"),
formatNumber = d3.format(".0f");
d3.json('static/data/qp_full.json').then(function (data) {
features = data.features
//1 create scales
var x = d3.scaleLinear()
.domain([0, d3.max(features, tp)/100])
.range([0, width - margin.right])
var y = d3.scaleLinear().domain([0, 0.1]).range([margin.left, width - margin.right])
var r = d3.scaleSqrt().domain([0, d3.max(features, pop_mun)])
.range([0, 25]);
//2 create axis
var xAxis = d3.axisBottom(x).ticks(20)
.tickFormat(formatPercent);
svg.append("g")
.attr("class", "x axis")
.call(xAxis);
var nodes = features.map(function (node, index) {
return {
radius: r(node.properties.pop_mun),
color: '#ff7f0e',
x: x(node.properties.tp60 / 100),
y: height + Math.random(),
pop_mun: node.properties.pop_mun,
tp60: node.properties.tp60
};
});
function tick() {
for (i = 0; i < nodes.length; i++) {
var node = nodes[i];
node.cx = node.x;
node.cy = node.y;
}
}
setTimeout(renderGraph, 10);
function renderGraph() {
// Run the layout a fixed number of times.
// The ideal number of times scales with graph complexity.
// Of course, don't run too long—you'll hang the page!
const NUM_ITERATIONS = 1000;
var force = d3.forceSimulation(nodes)
.force('charge', d3.forceManyBody().strength(-3))
.force('center', d3.forceCenter(width / 2, height/2))
.force('x', d3.forceX(d => d.x))
.force('y', d3.forceY(d => d.y))
.force('collide', d3.forceCollide().radius(d => d.radius))
.on("tick", tick)
.stop();
force.tick(NUM_ITERATIONS);
force.stop();
svg.selectAll("circle")
.data(nodes)
.enter()
.append("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", d => d.radius)
.style("fill", d => z(d.tp60/100))
.on("mouseover", function (d, i) {
d3.select(this).style('fill', "orange")
console.log(i.tp60,i)
svg.append("text")
.attr("id", "t")
.attr("x", function () {
return d.x - 50;
})
.attr("y", function () {
return d.y - 50;
})
.text(function () {
return [x.invert(i.x), i.tp60]; // Value of the text
})
})
.on("mouseout", function (d, i) {
d3.select("#t").remove(); // Remove text location
console.log(i)
d3.select(this).style('fill', z(i.tp60/100));
});
loading.remove();
}
})
})
I am creating an area chart with d3 (maybe v4). In the database, it has some data points doesn't have the key I want. I mean it has missing data, which cause I can't create an area chart with the all data.
I already tried to use following code to remove the data point with missing data, but it doesn't work:
drawAirVisualData(data) {
var divE = document.createElement("div");
var divId = document.createAttribute('id');
divId.value = 'AirVisualDiv';
divE.setAttributeNode(divId);
divE.style.textAlign = "center";
var title = document.createElement("text");
title.style.lineHeight = "40px";
title.style.fontSize = "20px";
title.textContent = "Air Visual";
document.getElementById('chartDiv').appendChild(divE);
document.getElementById('AirVisualDiv').appendChild(title);
// for each chart, the x and xAxis are same, the y and yAxis are always changed.
var width = w - margin.left - margin.right,
height = (h - margin.top) / 9;
var parseTime = d3.time.format.utc("%H:%M").parse,
midnight = parseTime("00:00");
var x = d3.time.scale.utc()
.domain([midnight, d3.time.day.utc.offset(midnight,1)])
.range([0, width]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(25).tickFormat(d3.time.format.utc("%I %p"));
//---------------------------- chart 1-------------------------------
var y = d3.scale.linear()
.range([height, 0])
.domain([0, 100]);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(10);
var areaInHumidity = d3.svg.area()
.defined(function (d) {
return d.y1 != null;
})
.x(function (d) {
var time = new Date(d.created_at);
return x(time);
})
.y0(height)
.y1(function (d, i) {
var humidity = d.data["current"].hm;
return y(humidity);
});
var areaOutHumidity = d3.svg.area()
.defined(function (d) {
return d.y1 != null;
})
.x(function (d) {
var time = new Date(d.created_at);
var dayTime = time.getHours() + time.getMinutes() / 60 + time.getSeconds() / 3600;
return x(dayTime);
})
.y0(height)
.y1(function (d) {
var humidity = d.data.outdoor_weather.hu;
return y(humidity);
});
var chart1 = d3.select("#AirVisualDiv")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr('id', 'HumidityChart')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Add legend
chart1.append('text').text('Outdoor Humidity - Indoor Humidity').attr("x", width / 2).attr("y", 0).attr("text-anchor", "middle");
chart1.append("circle").attr("cx", width * 7 / 10).attr("cy", 10).attr("r", 6)
.style({
'fill': "#0d7dfa",
'opacity': 0.2
});
chart1.append("circle").attr("cx", width * 8 / 10).attr("cy", 10).attr("r", 6)
.style({
'fill': "#0d7dfa",
'opacity': 0.6
});
chart1.append("text").attr("x", (width * 7 / 10) + 14).attr("y", 10).text("Indoor Humidity").style("font-size", "12px").attr("alignment-baseline", "middle");
chart1.append("text").attr("x", (width * 8 / 10) + 14).attr("y", 10).text("Outdoor Humidity").style("font-size", "12px").attr("alignment-baseline", "middle");
chart1.append("g")
.attr("class", "axisLine")
.style("font", "12px centralesanscndlight")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the X Axis
chart1.append("g")
.style("font", "12px centralesanscndlight")
.style('stroke-width', 1)
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
chart1.append("g")
.attr("class", "axisLine")
.style("font", "12px centralesanscndlight")
.call(yAxis);
// Add area for indoor humidity
chart1.append('path')
.attr({
'd': areaInHumidity(data),
'fill': '#0d7dfa',
'opacity': 0.2
});
// Add area for outdoor humidity
chart1.append('path')
.attr({
'd': areaOutHumidity(data),
'fill': '#0d7dfa',
'opacity': 0.6
});
//---------------------------- chart 2-------------------------------
var y2 = d3.scale.linear()
.range([height, 0])
.domain([0, 50]);
var yAxis2 = d3.svg.axis().scale(y2)
.orient("left").ticks(10);
var areaInTemp = d3.svg.area()
.defined(function (d) {
return d.y != null;
})
.x(function (d) {
var time = new Date(d.created_at);
var dayTime = time.getHours() + time.getMinutes() / 60 + time.getSeconds() / 3600;
return x(dayTime);
})
.y0(height)
.y1(function (d) {
var temperature = d.data.current.tp;
return y2(temperature);
});
var areaOutTemp = d3.svg.area()
.defined(function (d) {
return d.y != null;
})
.x(function (d) {
var time = new Date(d.created_at);
var dayTime = time.getHours() + time.getMinutes() / 60 + time.getSeconds() / 3600;
return x(dayTime);
})
.y0(height)
.y1(function (d) {
var temperature = d.data.outdoor_weather.tp;
return y2(temperature);
});
var chart2 = d3.select("#AirVisualDiv")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
chart2.append('text').text('Outdoor Temperature - Indoor Temperature').attr("x", width / 2).attr("y", 0).attr("text-anchor", "middle");
// Add legend
chart2.append("circle").attr("cx", width * 7 / 10).attr("cy", 10).attr("r", 6)
.style({
'fill': "#f26100"
});
chart2.append("circle").attr("cx", width * 8 / 10).attr("cy", 10).attr("r", 6)
.style({
'fill': "#ff9b00"
});
chart2.append("text").attr("x", (width * 7 / 10) + 14).attr("y", 10).text("Indoor Temperature").style("font-size", "12px").attr("alignment-baseline", "middle");
chart2.append("text").attr("x", (width * 8 / 10) + 14).attr("y", 10).text("Outdoor Temperature").style("font-size", "12px").attr("alignment-baseline", "middle");
// Add the X Axis
chart2.append("g")
.attr("class", "axisLine")
.style("font", "12px centralesanscndlight")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
chart2.append("g")
.attr("class", "axisLine")
.style("font", "12px centralesanscndlight")
.call(yAxis2);
// Add area for indoor humidity
chart2.append('path')
.attr({
'd': areaInTemp(data),
'fill': orange,
'opacity': 0.5
});
// Add area for outdoor humidity
chart2.append('path')
.attr({
'd': areaOutTemp(data),
'fill': lightorange,
'opacity': 0.5
});
//---------------------------- chart 3-------------------------------
var y3 = d3.scale.linear()
.range([height, 0])
.domain([0, 1000]);
var yAxis3 = d3.svg.axis().scale(y3)
.orient("left").ticks(10);
var coLine = d3.svg.line()
.defined(function (d) {
return d.y != null;
})
.x(function (d) {
var time = new Date(d.created_at);
var dayTime = time.getHours() + time.getMinutes() / 60 + time.getSeconds() / 3600;
return x(dayTime);
})
.y(function (d) {
var co = d.data.current.co;
return y3(co);
});
var chart3 = d3.select("#AirVisualDiv")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
chart3.append('text').text('CO2 Level').attr("x", width / 2).attr("y", 0).attr("text-anchor", "middle");
// Add the X Axis
chart3.append("g")
.attr("class", "axisLine")
.style("font", "12px centralesanscndlight")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
chart3.append("g")
.attr("class", "axisLine")
.style("font", "12px centralesanscndlight")
.call(yAxis3);
// Add line for co2
chart3.append('path')
.attr({
'd': coLine(data),
'stroke': grey,
'stroke-width': '1.5px',
'fill': 'none'
});
//---------------------------- chart 4-------------------------------
var y4 = d3.scale.linear()
.range([height, 0])
.domain([0, 50]);
var yAxis4 = d3.svg.axis().scale(y4)
.orient("left").ticks(10);
var p2Line = d3.svg.line()
.defined(function (d) {
return d.y != null;
})
.x(function (d) {
var time = new Date(d.created_at);
var dayTime = time.getHours() + time.getMinutes() / 60 + time.getSeconds() / 3600;
return x(dayTime);
})
.y(function (d) {
var p2 = d.data.current.p2;
return y4(p2);
});
var chart4 = d3.select("#AirVisualDiv")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
chart4.append('text').text('PM 2.5 Level').attr("x", width / 2).attr("y", 0).attr("text-anchor", "middle");
// Add the X Axis
chart4.append("g")
.attr("class", "axisLine")
.style("font", "12px centralesanscndlight")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
chart4.append("g")
.attr("class", "axisLine")
.style("font", "12px centralesanscndlight")
.call(yAxis4);
// Add line for co2
chart4.append('path')
.attr({
'd': p2Line(data),
'stroke': grey,
'stroke-width': '1.5px',
'fill': 'none'
});
}
The normal data point looks like:
{clusterAliases: ["dlab"]
created_at: "2019-06-04T05:15:18.794Z"
data:{
current:{
co: 429,
hm: 62,
p01: 17,
p1: 25,
p2: 22,
tp: 22.7834,
ts: "2019-06-04T05:10:10.646Z",
__proto__: Object},
outdoor_station: {
p1: {…},
api_id: 1646,
ts: "2019-06-04T04:00:00.000Z",
p2: {…},
mainus: "p2"},
outdoor_weather: {
wd: 0,
hu: 40,
ic: "01d",
ts: "2019-06-04T05:00:00.000Z",
tp: 33,
__proto__: Object},
identifier: "54:C9:DF:E3:AE:19",
meta: {version: 0},
type: "AQI_STATUS",
updated_at: "2019-06-04T05:15:18.808Z",
__v: 1,
_id: "5cf5fe661d9b1900213c98ec",
__proto__: Object}
The missing data point looks like:
{clusterAliases: ["dlab"]
created_at: "2019-06-04T05:13:50.977Z"
data:{
message: "HTTPSConnectionPool(host='www.airvisual.com', port=443): Read timed out. (read timeout=10)"
status: "ERROR",
__proto__: Object
},
identifier: "54:C9:DF:E3:AE:19",
meta: {version: 0},
type: "ERROR",
updated_at: "2019-06-04T05:13:50.990Z",
__v: 1,
_id: "5cf5fe0e1d9b1900213c98e5",
__proto__: Object}
The big difference between normal data point and missing data point is in missing data point it does't have "current" key under data, and its type shows "ERROR". I already tried to remove this data point before it was used to create area chart, but it can't be removed. so I also tried to use defined() to overcome it, but it doesn't work. Does anyone know how to overcome or remove the missing data point from area chart by d3? Thank you.
"I checked the d3 API and noticed that '''defined()''' required to have at least the key of the value. for example,"
'''
data {
temperature: 65,
humidity: null
}
'''
"this kind of data missing can be solved by" ''' defined()'''
"However, when the key (in our case humidity) is missing, '''defined()''' can not overcome the missing data anymore. to solve this problem, my current solution is to check if it has a key, if not, then define a value for y/x to keep drawing the line or areas"
In my d3 bar chart, I should have Y-axis dynamic ticks and grid lines for integer values (no ticks and grid lines for decimal values). But its not working , Please help me on this
var itemData =[{month: "MARCH", year: 2018, number: 26, date:1519842600000},{month: "MAY", year: 2018, number: 34, date: 1525113000000}];
createChart(itemData )
createChart(itemData) {
const router_temp = this.router;
const element = this.chartContainer.nativeElement;
const factoryId = itemData['id'];
const data = itemData.data;
d3.select(element).selectAll('*').remove();
const div = d3.select('body').append('div')
.attr('class', 'tooltip-bar-chart')
.style('display', 'none');
const svg = d3.select(element),
margin = {top: 10, right: 10, bottom: 20, left: 30},
width = +this.el.nativeElement.offsetWidth - margin.left - margin.right,
height = +svg.attr('height') - margin.top - margin.bottom;
const x = d3.scaleBand().range([10, width - 10]).padding(1),
y = d3.scaleLinear().rangeRound([height, 0]);
// add the X gridlines
svg.append('g')
.attr('class', 'grid')
.attr('transform', 'translate(30,' + height + ')')
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat('')
);
// add the Y gridlines
svg.append('g')
.attr('class', 'grid')
.attr('transform', 'translate(30, 10)')
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat('')
);
const g = svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
x.domain(data.map(function(d) { return d.month; }));
y.domain([0, d3.max(data, function(d) { return d.number; })]);
//
g.selectAll('.bar')
.data(data)
.enter().append('rect')
.attr('class', 'bar')
.attr('x', function(d) { return x(d.month); })
.attr('y', function(d) { return y(d.number); })
.attr('width', 12)
.attr('height', function(d) { return height - y(d.number); })
.on('mouseover', function(d) {
div.style('display', 'block');
div.html(
'<div class=\'main\'>' +
'<div class=\'month\'>' +
d.month +
'</div>' +
'<div class=\'number\'>' +
d.number +
'</div>' +
'<div class=\'bottom\'>' +
'Number of Applications Transformed & Migrated' +
'</div>' +
'</div>'
)
.style('left', (d3.event.pageX + 15) + 'px')
.style('top', (d3.event.pageY - 50) + 'px');
})
.on('mouseout', function(d) {
div.style('display', 'none');
})
const dataLength = data.length;
const xPositions = [];
for (let i = 0; i < dataLength; i += 1) {
xPositions.push(x(data[i].month) + margin.left);
}
const newX = d3.scaleOrdinal().range(xPositions);
const xScale = newX.domain(itemData.xlabels);
svg.append('g')
.attr('class', 'axis axis--x')
.attr('transform', 'translate(0,' + (height + 10) + ')')
.call(d3.axisBottom(xScale));
g.append('g')
.attr('class', 'axis axis--y')
.call(d3.axisLeft(y).ticks(5));
// gridlines in x axis function
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(1);
}
// gridlines in y axis function
function make_y_gridlines() {
return d3.axisLeft(y)
.ticks(5);
}
}
}
Here is sample
I created a fiddle.
that while I had to change a few things to account for no angular, but shows the axis gridlines and labels aligned. I moved everything into one g group is is then translated and the individual components are no longer translated.
I have a scatterplot that has zoom functioning perfectly. I am trying to add a tooltip such that on 'mouseenter' on a <circle> element, the tooltip fires. I have this working, i.e the 'mouseenter' event is called but I cannot zoom while the mouse stays on this <circle>. Is there a way to get them to both occur at the same time?
Here is a minimal version of the code that reproduces the issue.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<button id="resetBtn">Reset</button>
<div id="chart"></div>
<script>
var data = [
{
x: 0.5, y: 0.5
},
{
x: 0.6, y: 0.6
},
{
x: 0.45, y: 0.65
},
{
x: 0.76, y: 0.61
},
{
x: 0.51, y: 0.05
},
{
x: 0.16, y: 6.8
}
];
var plot = volcanoPlot()
.xColumn("x")
.yColumn("y");
d3.select('#chart')
.data([data])
.call(plot);
function volcanoPlot() {
var width = 960,
height = 500,
margin = {top: 20, right: 20, bottom: 40, left: 50},
xColumn,
dotRadius = 10,
yColumn,
xScale = d3.scaleLinear(),
yScale = d3.scaleLog();
function chart(selection){
var innerWidth = width - margin.left - margin.right, // set the size of the chart within its container
innerHeight = height - margin.top - margin.bottom;
selection.each(function(data) {
xScale.range([0, innerWidth])
.domain(d3.extent(data, function(d) { return d[xColumn]; }))
.nice();
yScale.range([0, innerHeight])
.domain(d3.extent(data, function(d) { return d[yColumn]; }))
.nice();
var zoom = d3.zoom()
.scaleExtent([1, 20])
.translateExtent([[0, 0], [width, height]])
.on('zoom', zoomFunction);
var svg = d3.select(this).append('svg')
.attr('height', height)
.attr('width', width)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
d3.select('#resetBtn')
.style('top', margin.top * 1.5 + 'px')
.style('left', margin.left * 1.25 + 'px')
.on('click', reset);
svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('height', innerHeight)
.attr('width', innerWidth);
// add the axes
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
var gX = svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + innerHeight + ')')
.call(xAxis);
gX.append('text')
.attr('class', 'label')
.attr('transform', 'translate(' + width / 2 + ',' + (margin.bottom - 6) + ')')
.attr('text-anchor', 'middle')
.text(xColumn);
var gY = svg.append('g')
.attr('class', 'y axis')
.call(yAxis);
gY.append('text')
.attr('class', 'label')
.attr('transform', 'translate(' + (0 - margin.left / 1.5) + ',' + (height / 2) + ') rotate(-90)')
.style('text-anchor', 'middle')
.text(yColumn);
var zoomBox = svg.append('rect')
.attr('class', 'zoom')
.attr('height', innerHeight)
.attr('width', innerWidth)
.attr('fill', 'none')
.attr('pointer-events', 'all')
.call(zoom);
var circles = svg.append('g')
.attr('class', 'circlesContainer')
.attr('clip-path', 'url(#clip)');
circles.selectAll(".dot")
.data(data)
.enter().append('circle')
.attr('r', dotRadius)
.attr('cx', function(d) { return xScale(d[xColumn]); })
.attr('cy', function(d) { return yScale(d[yColumn]); })
.attr('class', 'dot')
.attr('stroke', 'none')
.on('mouseenter', function(){
console.log("hi");
});
function zoomFunction() {
var transform = d3.zoomTransform(this);
d3.selectAll('.dot')
.attr('transform', transform)
.attr('r', dotRadius / Math.sqrt(transform.k));
gX.call(xAxis.scale(d3.event.transform.rescaleX(xScale)));
gY.call(yAxis.scale(d3.event.transform.rescaleY(yScale)));
}
function reset() {
var ease = d3.easePolyIn.exponent(4.0);
d3.select('.zoom')
.transition().duration(750)
.ease(ease)
.call(zoom.transform, d3.zoomIdentity);
}
});
}
chart.width = function(value) {
if (!arguments.length) return width;
width = value;
return chart;
};
chart.height = function(value) {
if (!arguments.length) return height;
height = value;
return chart;
};
chart.margin = function(value) {
if (!arguments.length) return margin;
margin = value;
return chart;
};
chart.xColumn = function(value) {
if (!arguments.length) return xColumn;
xColumn = value;
return chart;
};
chart.yColumn = function(value) {
if (!arguments.length) return yColumn;
yColumn = value;
return chart;
};
return chart;
}
</script>
</body>
</html>
You're calling your zoom function on the rectangle and, because of that, the zoom will not work when you hover over the circles. It has nothing to do with the mouseenter function: you can remove the mouseenter and the zoom still won't work when you hover over the circles.
A simple solution is calling the zoom on your SVG group, not on the rectangle:
var svg = d3.select(this).append('svg')
.attr('height', height)
.attr('width', width)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.call(zoom);
Here is your code with that change only:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<button id="resetBtn">Reset</button>
<div id="chart"></div>
<script>
var data = [
{
x: 0.5, y: 0.5
},
{
x: 0.6, y: 0.6
},
{
x: 0.45, y: 0.65
},
{
x: 0.76, y: 0.61
},
{
x: 0.51, y: 0.05
},
{
x: 0.16, y: 6.8
}
];
var plot = volcanoPlot()
.xColumn("x")
.yColumn("y");
d3.select('#chart')
.data([data])
.call(plot);
function volcanoPlot() {
var width = 960,
height = 500,
margin = {top: 20, right: 20, bottom: 40, left: 50},
xColumn,
dotRadius = 10,
yColumn,
xScale = d3.scaleLinear(),
yScale = d3.scaleLog();
function chart(selection){
var innerWidth = width - margin.left - margin.right, // set the size of the chart within its container
innerHeight = height - margin.top - margin.bottom;
selection.each(function(data) {
xScale.range([0, innerWidth])
.domain(d3.extent(data, function(d) { return d[xColumn]; }))
.nice();
yScale.range([0, innerHeight])
.domain(d3.extent(data, function(d) { return d[yColumn]; }))
.nice();
var zoom = d3.zoom()
.scaleExtent([1, 20])
.translateExtent([[0, 0], [width, height]])
.on('zoom', zoomFunction);
var svg = d3.select(this).append('svg')
.attr('height', height)
.attr('width', width)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.call(zoom);
d3.select('#resetBtn')
.style('top', margin.top * 1.5 + 'px')
.style('left', margin.left * 1.25 + 'px')
.on('click', reset);
svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('height', innerHeight)
.attr('width', innerWidth);
// add the axes
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
var gX = svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + innerHeight + ')')
.call(xAxis);
gX.append('text')
.attr('class', 'label')
.attr('transform', 'translate(' + width / 2 + ',' + (margin.bottom - 6) + ')')
.attr('text-anchor', 'middle')
.text(xColumn);
var gY = svg.append('g')
.attr('class', 'y axis')
.call(yAxis);
gY.append('text')
.attr('class', 'label')
.attr('transform', 'translate(' + (0 - margin.left / 1.5) + ',' + (height / 2) + ') rotate(-90)')
.style('text-anchor', 'middle')
.text(yColumn);
var zoomBox = svg.append('rect')
.attr('class', 'zoom')
.attr('height', innerHeight)
.attr('width', innerWidth)
.attr('fill', 'none')
.attr('pointer-events', 'all');
var circles = svg.append('g')
.attr('class', 'circlesContainer')
.attr('clip-path', 'url(#clip)');
circles.selectAll(".dot")
.data(data)
.enter().append('circle')
.attr('r', dotRadius)
.attr('cx', function(d) { return xScale(d[xColumn]); })
.attr('cy', function(d) { return yScale(d[yColumn]); })
.attr('class', 'dot')
.attr('stroke', 'none')
.on('mouseenter', function(){
console.log("hi");
});
function zoomFunction() {
var transform = d3.zoomTransform(this);
d3.selectAll('.dot')
.attr('transform', transform)
.attr('r', dotRadius / Math.sqrt(transform.k));
gX.call(xAxis.scale(d3.event.transform.rescaleX(xScale)));
gY.call(yAxis.scale(d3.event.transform.rescaleY(yScale)));
}
function reset() {
var ease = d3.easePolyIn.exponent(4.0);
d3.select('.zoom')
.transition().duration(750)
.ease(ease)
.call(zoom.transform, d3.zoomIdentity);
}
});
}
chart.width = function(value) {
if (!arguments.length) return width;
width = value;
return chart;
};
chart.height = function(value) {
if (!arguments.length) return height;
height = value;
return chart;
};
chart.margin = function(value) {
if (!arguments.length) return margin;
margin = value;
return chart;
};
chart.xColumn = function(value) {
if (!arguments.length) return xColumn;
xColumn = value;
return chart;
};
chart.yColumn = function(value) {
if (!arguments.length) return yColumn;
yColumn = value;
return chart;
};
return chart;
}
</script>
</body>
</html>