I am trying to create D3 charts based on elasticsearch nested aggregation. While I can plot a chart based on the first aggregation, I am not sure why I cant plot a similar chart on the nested a subsequent aggregation. Can anyone suggest what I should do?
My code:
esClient.search({
index: 'vehicle',
body: {
query:{
match:{
_all:searchTerms
}
},
aggs: {
touchdowns: {
terms: {
field: "country",
size:5
},
aggs: {
corp: {
terms: {
field: "companyName",
size:5
}
}
},
}
},
sort: [sortObject],
from: resultsPage * 10,
}
}).then(function(es_return){
deferred.resolve(es_return);
//// Pie Chart first aggregation
var touchdowns = es_return.aggregations.touchdowns.buckets;
// d3 donut chart
var width = 600,
height = 300,
radius = Math.min(width, height) / 2;
var color = ['#ff7f0e', '#d62728', '#2ca02c', '#1f77b4'];
var arc = d3.svg.arc()
.outerRadius(radius - 60)
.innerRadius(120);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) { return d.doc_count; });
var svg = d3.select("#donut-chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width/1.4 + "," + height/2 + ")");
var g = svg.selectAll(".arc")
.data(pie(touchdowns))
.enter()
.append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d, i) { return color[i]; });
g.append("text")
.attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.style("fill", "white")
.text(function (d) { return d.data.key; });
//// Pie Chart
var touchdowns = es_return.aggregations.touchdowns.buckets.corp.buckets;
// d3 donut chart
var width = 600,
height = 300,
radius = Math.min(width, height) / 2;
var color = ['#ff7f0e', '#d62728', '#2ca02c', '#1f77b4'];
var arc = d3.svg.arc()
.outerRadius(radius - 60)
.innerRadius(120);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) { return d.doc_count; });
var svg = d3.select("#donut-chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width/1.4 + "," + height/2 + ")");
var g = svg.selectAll(".arc")
.data(pie(touchdowns))
.enter()
.append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d, i) { return color[i]; });
g.append("text")
.attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.style("fill", "white")
.text(function (d) { return d.assignee.key; });
}, function(error){
deferred.reject(error);
});
return deferred.promise;};
Related
I want to make the axis lines either less opaque, or make them light grey. I tried to just do .style(opacity, 0.5), but it only makes the TICKS opaque, not the actual line itself. I want to make the ACTUAL LINE less opaque/light grey. I also tried adding the call(d3.axisLeft...).style(less opaque) approach but I still get nothing. How do I go about doing that?
import React, {Component, useRef, useEffect} from 'react';
import ExperienceScoresData from './experience_scores';
import * as d3 from "d3";
import { select, csv} from 'd3';
import { extent, max, min } from "d3-array";
ExperienceScoresData.map(function(val){
val.customerExperienceScore *= 100;
return 0;
})
class Linechart extends Component {
constructor(props){
super(props)
this.createBarChart = this.createBarChart.bind(this)
}
componentDidMount() {
this.createBarChart()
}
componentDidUpdate() {
this.createBarChart()
}
createBarChart() {
var margin = {top: 85, right: 60, bottom: 60, left: 80},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var node = this.node
var divObj = select(node)
var svgObj = divObj
.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 + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/QamarFarooq/data-for-testing/main/5_OneCatSevNumOrdered.csv", function(data) {
// group the data: I want to draw one line per group
var sumstat = d3.nest() // nest function allows to group the calculation per level of a factor
.key(function(d) { return d.name;})
.entries(data);
//console.log(sumstat)
// Define the div for the tooltip
var tooltip = divObj
.append("div")
.attr("class","tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "1px")
.style("border-radius", "5px")
.style("padding", "10px")
.text("I AM A TOOLTIP pakistan zindabad");
// Add title for linechart
svgObj.append("text")
.attr("text-anchor", "end")
.attr("font-size", 25)
.attr("x", 110)
.attr("y", -50)
.text("Online Ratings");
// Add X axis --> it is a date format
var x = d3.scaleLinear()
.domain(d3.extent(data, function(d) { return d.year; }))
.range([ 0, width ]);
svgObj.append("g")
.attr("transform", "translate(0," + height + ")")
.attr("stroke-width","0.3")
.style("opacity","0.5")
.call(d3.axisBottom(x).tickSize(-height).tickFormat('').ticks(5));
// ticks
svgObj.append("g")
.style("opacity","0.85")
.style("font", "14px times")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(5));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) { return +d.n; })])
.range([ height, 0 ]);
svgObj.append("g")
.attr("stroke-width","0.3")
.style("opacity","0.5")
.call(d3.axisLeft(y).tickSize(-width).tickFormat('').ticks(5));
// ticks
svgObj.append("g")
.style("opacity","0.85")
.style("font", "14px times")
.call(d3.axisLeft(y).ticks(5));
// Add X axis label:
svgObj.append("text")
.attr("text-anchor", "end")
.attr("font-size", 20)
.attr("x", width/2 + margin.left)
.attr("y", height + 50)
.style("fill", d3.color("grey"))
.text("Year Of Birth");
// Add Y axis label:
svgObj.append("text")
.attr("text-anchor", "end")
.attr("font-size", 20)
.attr("transform", "rotate(-90)")
.attr("x", -height/2 + 40)
.attr("y", -margin.left + 25)
.style("fill", d3.color("grey"))
.text("N-Value")
// color palette
var key = sumstat.map(function(d){ return d.key }) // list of group names
var color = d3.scaleOrdinal()
.domain(key)
.range(['#e41a1c','#377eb8','#4daf4a'])
// Add one DOT in the legend for each name.
svgObj.selectAll(".dots")
.data(key)
.enter()
.append("circle")
.attr("cx", function(d,i){ return 250 + i*120})
.attr("cy", -30)
.attr("r", 7)
.style("fill", function(d){ return color(d)})
// Add LABEL for legends of each dot.
svgObj.selectAll(".labels")
.data(key)
.enter()
.append("text")
.style("fill", d3.color("grey"))
.attr("x", function(d,i){ return 270 + i*120})
.attr("y", -28)
.text(function(d){ return d})
.attr("text-anchor", "left")
.style("alignment-baseline", "middle")
// Draw the line
svgObj.selectAll(".line")
.data(sumstat)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", function(d){ return color(d.key) })
.attr("stroke-width", 4.5)
.attr("d", function(d){
return d3.line()
.curve(d3.curveMonotoneX)
.x(function(d) { return x(d.year); })
.y(function(d) { return y(+d.n); })
(d.values)
})
.on("mouseover", function(){return tooltip.style("visibility", "visible");})
.on("mousemove", function(){return tooltip.style("top", (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");})
var dataUnpacked = sumstat.map( function(d){return d.values})
console.log(data)
// Draw dots on points
svgObj.selectAll(".lineChartDots")
.data(data)
.enter()
.append("circle")
.attr("class","lineChartDots")
.style("fill","white")
.style("stroke-width", "3px")
.style("stroke", function (d) { return color(d.name) })
.attr("cx", function(d) {return x(d.year); })
.attr("cy", function(d) {return y(d.n); })
.attr("r", 5.5)
})
}
render() {
return <div ref={node => this.node = node} className="example_div"> </div>
}
}
export default Linechart;
The following could change the axis line's opacity.
svg.append("g")
.style("opacity", 0.5)
.call(d3.axisLeft(y))
.call(g => { // manipulate the elements' attrs here
g.select("path")
.attr("opacity", 0.5)
});
I run your code and found that the above code actually worked but since there are two svg lines in the axis, both the axis path and the first background grid line, so you might feel the opacity wasn't changed. See jsfiddle here.
a simple demo:
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered_comma.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) { return +d.value; })])
.range([ height, 0 ]);
svg.append("g")
.style("opacity", 0.5)
.call(d3.axisLeft(y))
.call(g => {
g.select("path")
.attr("opacity", 0.5)
});
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
})
</script>
I am creating grouped bar chart using D3 V5 in react.I am able to display y axis but not ticks and text.but in case of x-axis it's completely invisible. i have added d3.min.js to index.html file, but nothing works. any help is appreciated
here I am attaching my code
DrawChart = (data) => {
var w = 450, h = 300, p = 100;
var x0 = d3.scaleBand().range([0, w]).padding(0.4);
var x1 = d3.scaleBand();
var y = d3.scaleLinear().range([h, 0]);
var color = d3.scaleOrdinal().range(["#a85db3", "#95f578"]);
const svg = d3.select("div#predicative")
.append("svg").attr("width", w).attr("height", h)
.attr("padding", p).style("margin-left", 30)
.style("margin-top", 20).style("margin-bottom", 10);
var ageNames = d3.keys(data[0]).filter(function (key) { return key !== "dept"; });
data.forEach(function (d) {
d.ages = ageNames.map(function (name) { return { name: name, value: +d[name] }; });
});
x0.domain(data.map(function (d) { return d.dept; }));
x1.domain(ageNames).rangeRound([0, x0.bandwidth()]);
y.domain([0, (d3.max(data, function (d) { return d3.max(d.ages, function (d) { return d.value; }); })) + 10]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(d3.axisBottom(x0)
.tickSize(-w, 0, 0)
.tickFormat(''));
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Time");
svg:not(:root){
overflow: visible;
}
Here is my code snippet for implementing the ellipsis on x axis labels in d3 v3.
Can someone help me figure out the changes needed to my code in v4??
//function for adding '...' if length is more than 50 px
var wrap = function () {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while (textLength > (50) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
};
//calling the function
svg.select('.x.axis')
.call(xAxis)
.selectAll('text')
.style('text-anchor', 'end')
.attr('fill', '#8a9299')
.attr('transform', 'rotate(-60)')
.each(wrap);
You just need to save the group element containing x-axis into a variable and use as shown below.
var wrap = function() {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while (textLength > (50) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
};
//calling the function
xAxis.selectAll('text')
.style('text-anchor', 'end')
.attr('fill', '#8a9299')
.attr('transform', 'rotate(-60)')
.each(wrap);
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = 250 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleBand()
.range([0, width])
.padding(0.1);
var y = d3.scaleLinear()
.range([height, 0]);
// append the svg object to the body of the page
// append a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("body").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 + ")");
var data = [{
"salesperson": "Bob Patrickson",
"sales": 33
},
{
"salesperson": "Robin Dearden",
"sales": 12
},
{
"salesperson": "Anne Hathaway",
"sales": 41
},
{
"salesperson": "Mark Wahlberg",
"sales": 16
}
];
// format the data
data.forEach(function(d) {
d.sales = +d.sales;
});
// Scale the range of the data in the domains
x.domain(data.map(function(d) {
return d.salesperson;
}));
y.domain([0, d3.max(data, function(d) {
return d.sales;
})]);
// append the rectangles for the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.salesperson);
})
.attr("width", x.bandwidth())
.attr("y", function(d) {
return y(d.sales);
})
.attr("height", function(d) {
return height - y(d.sales);
});
// add the x Axis
var xAxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// add the y Axis
svg.append("g")
.call(d3.axisLeft(y));
var wrap = function() {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while (textLength > (50) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
};
//calling the function
xAxis.selectAll('text')
.style('text-anchor', 'end')
.attr('fill', '#8a9299')
.attr('transform', 'rotate(-60)')
.each(wrap);
.bar {
fill: steelblue;
}
<script src="//d3js.org/d3.v4.min.js"></script>
I have an error in d3 bar chart, when load on the web page
the error :
Error: Invalid value for <rect> attribute y="NaN" , Error: Invalid value for <rect> attribute height="NaN"
I tried to solve it by edit this code
nothing worked
var countriesData = data.countries;
var datac=[];
for (var key in countriesData) {
datac.push({key: key, value: countriesData[key]});
};
console.log(datac);
var width = 250;
var height = 250;
//console.log(data4);
//x and y Scales
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var yScale = d3.scale.linear()
.range([height, 0]);
xScale.domain(datac.map(function(d) { return d.x; }));
yScale.domain([0, d3.max(datac, function(d) { return d.y; })]);
//x and y Axes
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
//.ticks();
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//.ticks(function(d) { return d.x; });
//create svg container
var svg = d3.select("#barchart").select("svg").remove();
svg = d3.select("#barchart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
//.transition().duration(2000)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//create bars
svg.selectAll(".bar")
.data(datac)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.x); })
.attr("width", xScale.rangeBand())
.attr("y", function(d) { return yScale(d.y); })
.attr("height", function(d) { return height - yScale(d.y); });
//drawing the x axis on svg
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
//drawing the y axis on svg
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Reviews Number");
Please help!
Hard to say, but I'm guessing its the definition of the xScale:
xScale.domain(datac.map(function(d) { return d.x; }));
probably should be something like:
xScale.domain(d3.extent(datac, fucntion (d) {return d.x}))
I am developing bar graph using d3.js integrating with Angularjs. The angular directive code I am using is given below . My problem is ,in my real application , the bar graph is not redrawing but its axis changes when data associated with the bar graph changes
mainApp.directive('ngDatenobargraph', function() {
return {
restrict: 'AE',
scope: {
data: '='
},
link: function (scope, element) {
var margin = {top: 10, right: 10, bottom: 40, left: 60},
width = 410 - margin.left - margin.right,
height = 230 - margin.top - margin.bottom;
var chart = d3.select(element[0])
.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 + ")");
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<span style='font-size: 13px'>Date: </span><span style='color:red;font-size: 13px'>" + d.xValue+ "</span><br>"+
"<span style='font-size: 13px'>Net Value: </span><span style='color:red;font-size: 13px'>" + d.yValue+ "</span><br>"+
"<span style='font-size: 13px'>Buy Value: </span><span style='color:red;font-size: 13px'>" + d.buyValue+ "</span><br>"+
"<span style='font-size: 13px'>Sell Value: </span><span style='color:red;font-size: 13px'>" + d.sellValue+ "</span>";
});
chart.call(tip);
//Render graph based on 'data'
scope.render = function(data) {
if(data) {
var y = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(data, function(d) { return d.yValue; }))
.nice();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(7);
x.domain(data.map(function(d) { return d.xValue; }));
//Redraw the axes
chart.selectAll('g.axis').remove();
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {
return "rotate(-20)";
});
chart.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0-margin.left)
.attr("x",0-(height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Net Value");
chart.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", function(d) { return d.yValue < 0 ? "bar negative" : "bar positive"; })
.attr("x", function(d) { return x(d.xValue); })
.attr("y", height)
.attr("height", 0)
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.transition().duration(2000)
.attr("y", function(d) {return y(Math.max(0, d.yValue)); })
.attr("height", function(d) {return Math.abs(y(d.yValue) - y(0)); })
// .attr("width", x.rangeBand());
.attr("width", Math.min.apply(null, [x.rangeBand()-2, 100]));
}
};
scope.$watch('data', function() {
scope.render(scope.data);
}, true);
}
};
});
I am new to d3.js . If any have solution please help me .The code in application is given http://jsfiddle.net/HB7LU/9000/