Plotting normal density function with d3 js - javascript

I'm trying to plot this continuous function with D3 js version 4 but i'm having many problems with arrays. this is my javascript code:
var x = d3.range(-4., 4.1, 0.1)
var fnorm = x => (1. / Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow(x, 2))
var y = new Array()
for (var i = 0 ; i < x.length ; i++) {
y[i] = fnorm(x[i])
}
var dataset = []
for (var j = 0; j < x.length; j++) {
dataset[j] = []
dataset[j][0] = x[j]
dataset[j][1] = y[j]
}
console.log(dataset[0])
console.log(dataset[1])
var w = 500
var h = 500
var padding = 50
var xScale = d3.scaleLinear()
.domain([d3.min(x, function(d) { return d }), d3.max(x, function(d) { return d })])
.range([padding, w - padding * 2])
var yScale = d3.scaleLinear()
.domain([0, 0.4])
.range([h - padding, padding])
function mycanvas() {
var svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h)
svg.append('rect')
.attr('width', '100%')
.attr('height', '100%')
.attr('fill', 'blue')
// Define the axis
var xAxis = d3.axisBottom().scale(xScale).ticks(9)
var yAxis = d3.axisLeft().scale(yScale).ticks(9)
// Create the axis
svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(0,' + (h - padding) + ')')
.call(xAxis)
svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(' + padding + ',0)')
.call(yAxis)
svg.selectAll('line')
.data(dataset)
.enter()
.append('line')
.attr('x1', function(d) {
return xScale(d[0])
})
.attr('y1', function(d) {
return yScale(d[1])
})
.attr('x2', function(d) {
return xScale(d[1])
})
.attr('y2', function(d) {
return yScale(d[0])
})
.attr('stroke', 'white')
}
function main() {
mycanvas()
}
window.onload = main
<script src="https://d3js.org/d3.v4.min.js"></script>
The main problem is when i try to plot with svg line i don't know how to fix the right way to call and apply dataset array with x1,y1,x2,y2

You could use d3.line to produce a path from dataset:
var line = d3.line()
.x(function(d) { return xScale(d[0]);})
.y(function(d) { return yScale(d[1]);});
svg.append("path")
.attr("d", line(dataset))
.attr("stroke", "white")
.attr("fill", "none");
Demo: https://jsfiddle.net/LukaszWiktor/kkxe5sbc/

Related

D3.js rect no display on chart

I started the D3.js challenge on FreeCodeCamp, the problem is that I solved it with the chart but it only gives me a display on the rectum, only one with the width and height that it I put, I'll show the code below.
The entire code on
<script>
//set d3
var w = 1000, h = 500;
var padding = 50;
var svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h)
//title
svg.append('text')
.attr('x', w / 2)
.attr('y', 50)
.text('United States GDP')
fetch('https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json')
.then((result)=>result.json())
.then((data)=>{
var the_data = data['data']
//get vals
var get_max = d3.max(data['data'])
var get_mix = d3.min(data['data'])
//for x
var max_x = Number(get_max[0].split('-')[0])
var min_x = Number(get_mix[0].split('-')[0])
//for y
var max_y = get_max[1]
var min_y = get_mix[1]
var xScale = d3.scaleLinear()
.domain([min_x, max_x])
.range([padding, w-padding])
var yScale = d3.scaleLinear()
.domain([min_y, max_y])
.range([h-padding, padding])
//the_chars
for(var i in the_data){
var get_year = Number(the_data[i][0].split('-')[0])
the_data[i][0] = get_year
}
svg.selectAll('rect')
.data(the_data)
.enter()
.append('rect')
.attr("x", (d) => { xScale(d[0]) })
.attr('y', (d)=>{ yScale(d[1]) })
.attr("width", 200)
.attr("height", 20)
//axis
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
//display axis
svg.append("g")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
svg.append('g')
.attr('transform', 'translate(' + padding + ', 0)')
.call(yAxis)
})
Now, what I need to do to display the charts!
I mention that the script tags are embedded in the body
Problem: Arrow functions without a return value. Solution: Instead use an explicit or an implicit return.
.attr("x", (d) => { xScale(d[0]) }) // returns undefined
.attr("x", (d) => xScale(d[0])) // implicit return
.attr("x", (d) => { return xScale(d[0]) }) // explicit return
Problem: Fixed height value. Solution Evaluate the height of each based on the GDP value (d[1]) instead.
.attr('height', 20) // fixed height
.attr('height', d => yScale(min_y) - yScale(d[1]))
// subtract from min range to account for padding and inverted y coordinates in SVG
Full solution in this codepen

D3 line chart and adding data points real time

I am beginner to d3 and trying to create real time chart which adds in new values on the go. I want the chart to shift the old points to the left as new points are added. Below is my code but for some reason, the browser freezes with the code (I have commented out the .on() line in the end that causes the freeze).
What am I doing wrong?
<!DOCTYPE html>
<head></head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js">
</script>
<script>
<!DOCTYPE html>
<head></head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js">
</script>
<script>
var t = -1;
var n = 40;
var duration = 750;
var data = [];
console.log('hello');
function next() {
return {
time: ++t,
value: Math.random() * 10
}
}
var margin = {
top: 6,
right: 0,
bottom: 20,
left: 40
},
width = 560 - margin.right,
height = 120 - margin.top - margin.bottom;
var xScale = d3.scaleTime()
.domain([t - n + 1, t])
.range([0, width]);
var yScale = d3.scaleLinear()
.domain([0, 10])
.range([height, 0]);
var line = d3.line()
.x((d) => xScale(d.time))
.y((d) => yScale(d.value));
var svg = d3.select('body').append('p').append('svg');
var chartArea = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
chartArea.append('defs').append('clipPath')
.attr('id', 'clip2')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
chartArea.append('rect')
.attr('class', 'bg')
.attr('x', 0)
.attr('y', 0)
.attr('width', this.chartWidth)
.attr('height', this.chartHeight);
var xAxis = d3.axisBottom(xScale);
var xAxisG = chartArea.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0, ${height})`);
xAxisG.call(xAxis);
d3.selectAll('x-axis path').style('stroke', 'red')
.style('stroke-width', 2);
var yAxis = d3.axisLeft(yScale);
var yAxisG = chartArea.append('g').attr('class', 'y-axis');
yAxisG.call(yAxis);
var grids = chartArea.append('g')
.attr('class', 'grid')
.call(d3.axisLeft(yScale).tickSize(-(width)).tickFormat((domain, number) => {
return ""
}));
var pathsG = chartArea.append('g')
.attr('id', 'paths')
.attr('class', 'paths')
.attr('clip-path', 'url(#clip2)');
tick();
function tick() {
console.log('working');
var newValue = {
time: ++t,
value: Math.random() * 10
};
data.push(newValue);
xScale.domain([newValue.time - n + 2, newValue.time]);
xAxisG.transition().duration(500).ease(d3.easeLinear).call(xAxis);
console.log('is it?');
var minerG = pathsG.selectAll('.minerLine').data([data]);
var minerGEnter = minerG.enter()
.append('g')
.attr('class', 'minerLine')
.merge(minerG);
var minerSVG = minerGEnter.selectAll('path').data((d) => [d]);
var minerSVGEnter = minerSVG.enter()
.append('path')
.attr('class', 'line')
.merge(minerSVG)
.transition()
.duration(500)
.ease(d3.easeLinear, 2)
.attr('d', line(data))
.on('end', () => {
requestAnimationFrame(tick)
})
}
</script>
</body>
</html>
The problem is caused by the fact that tick is called immediately and synchronously at the end of the transition. The CPU process executing the JavaScript remains busy updating data and chart, and is not available to do anything else on this tab.
One way to fix this is to use Window.requestAnimationFrame().
.on('end', () => {
requestAnimationFrame(tick)
})
The updated snippet below shows this solution in action.
It does not fix other issues not mentioned in the question, like the fact that no data is shown in the chart.
<!DOCTYPE html>
<head></head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js">
</script>
<script>
var t = -1;
var n = 40;
var duration = 750;
var data = [];
console.log('hello');
function next() {
return {
time: ++t,
value: Math.random() * 10
}
}
var margin = {
top: 6,
right: 0,
bottom: 20,
left: 40
},
width = 560 - margin.right,
height = 120 - margin.top - margin.bottom;
var xScale = d3.scaleTime()
.domain([t - n + 1, t])
.range([0, width]);
var yScale = d3.scaleLinear()
.domain([0, 10])
.range([height, 0]);
var line = d3.line()
.x((d) => xScale(d.time))
.y((d) => yScale(d.value));
var svg = d3.select('body').append('p').append('svg');
var chartArea = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
chartArea.append('defs').append('clipPath')
.attr('id', 'clip2')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
chartArea.append('rect')
.attr('class', 'bg')
.attr('x', 0)
.attr('y', 0)
.attr('width', this.chartWidth)
.attr('height', this.chartHeight);
var xAxis = d3.axisBottom(xScale);
var xAxisG = chartArea.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0, ${height})`);
xAxisG.call(xAxis);
d3.selectAll('x-axis path').style('stroke', 'red')
.style('stroke-width', 2);
var yAxis = d3.axisLeft(yScale);
var yAxisG = chartArea.append('g').attr('class', 'y-axis');
yAxisG.call(yAxis);
var grids = chartArea.append('g')
.attr('class', 'grid')
.call(d3.axisLeft(yScale).tickSize(-(width)).tickFormat((domain, number) => {
return ""
}));
var pathsG = chartArea.append('g')
.attr('id', 'paths')
.attr('class', 'paths')
.attr('clip-path', 'url(#clip2)');
tick();
function tick() {
console.log('working');
var newValue = {
time: ++t,
value: Math.random() * 10
};
data.push(newValue);
xScale.domain([newValue.time - n + 2]);
xAxisG.transition().duration(500).ease().call(xAxis);
console.log('is it?');
var minerG = pathsG.selectAll('.minerLine').data([data]);
var minerGEnter = minerG.enter()
.append('g')
.attr('class', 'minerLine')
.merge(minerG);
var minerSVG = minerGEnter.selectAll('path').data((d) => [d]);
var minerSVGEnter = minerSVG.enter()
.append('path')
.attr('class', 'line')
.merge(minerSVG)
.transition()
.duration(500)
.ease(d3.easeLinear, 2)
.attr('d', line(data))
.on('end', () => {
requestAnimationFrame(tick)
})
}
</script>
</body>
</html>

d3.js brushable choropleth

I'm following this tutorial to build a brushable scatterplot and choropleth map.
I also want to show the states name by adding tooltips on choropleth.
The problem might be how to get the states name in the json file.
I tried features.properties.name but got the error : Uncaught TypeError: Cannot read property 'name' of undefined.
Could anyone please help?
Thanks!
<!DOCTYPE html>
<meta charset="utf-8">
<style>
div { float: left; }
</style>
<body>
<!-- <svg width="760" height="400"></svg> -->
<div id="choropleth"></div>
<div id="scatterplot"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<script>
d3.queue()
.defer(d3.csv, 'https://raw.githubusercontent.com/irrie/myprojects/master/usage0.csv', function (d) {
return {
name: d.State,
penetration: +d.Facebook_Penetration,
young_proportion: +d.YoungProportion
}
})
.defer(d3.json, 'https://raw.githubusercontent.com/python-visualization/folium/master/tests/us-states.json')
.awaitAll(initialize)
var color = d3.scaleThreshold()
.domain([0.3, 0.44, 0.6])
.range(['#fbb4b9', '#f768a1', '#c51b8a', '#7a0177'])
function initialize(error, results) {
if (error) { throw error }
var data = results[0]
var features = results[1].features
var components = [
choropleth(features),
scatterplot(onBrush)
]
function update() {
components.forEach(function (component) { component(data) })
}
function onBrush(x0, x1, y0, y1) {
var clear = x0 === x1 || y0 === y1
data.forEach(function (d) {
d.filtered = clear ? false
: d.young_proportion < x0 || d.young_proportion > x1 || d.penetration < y0 || d.penetration > y1
})
update()
}
update()
}
function scatterplot(onBrush) {
var margin = { top: 10, right: 15, bottom: 40, left: 75 }
var width = 360 - margin.left - margin.right
var height = 300 - margin.top - margin.bottom
var x = d3.scaleLinear()
.range([0, width])
var y = d3.scaleLinear()
.range([height, 0])
var xAxis = d3.axisBottom()
.scale(x)
// .tickFormat(d3.format('.2s'))
var yAxis = d3.axisLeft()
.scale(y)
.tickFormat(d3.format('.0%'))
var brush = d3.brush()
.extent([[0, 0], [width, height]])
.on('start brush', function () {
var selection = d3.event.selection
var x0 = x.invert(selection[0][0])
var x1 = x.invert(selection[1][0])
var y0 = y.invert(selection[1][1])
var y1 = y.invert(selection[0][1])
onBrush(x0, x1, y0, y1)
})
var svg = d3.select('#scatterplot')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
//.attr("transform", "translate(-370,390)")
.append('g')
.attr("transform", "translate(50,10)")
// .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
var bg = svg.append('g')
var gx = svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
var gy = svg.append('g')
.attr('class', 'y axis')
gx.append('text')
.attr('x', width)
.attr('y', 35)
.style('text-anchor', 'end')
.style('fill', '#000')
.style('font-weight', 'bold')
.text('Young Proportion')
gy.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', 0)
.attr('y', -40)
.style('text-anchor', 'end')
.style('fill', '#000')
.style('font-weight', 'bold')
.text('Facebook Penetration')
svg.append('g')
.attr('class', 'brush')
.call(brush)
return function update(data) {
x.domain(d3.extent(data, function (d) { return d.young_proportion })).nice()
y.domain(d3.extent(data, function (d) { return d.penetration })).nice()
gx.call(xAxis)
gy.call(yAxis)
var bgRect = bg.selectAll('rect')
.data(d3.pairs(d3.merge([[y.domain()[0]], color.domain(), [y.domain()[1]]])))
bgRect.exit().remove()
bgRect.enter().append('rect')
.attr('x', 0)
.attr('width', width)
.merge(bgRect)
.attr('y', function (d) { return y(d[1]) })
.attr('height', function (d) { return y(d[0]) - y(d[1]) })
.style('fill', function (d) { return color(d[0]) })
var circle = svg.selectAll('circle')
.data(data, function (d) { return d.name })
circle.exit().remove()
circle.enter().append('circle')
.attr('r', 4)
.style('stroke', '#fff')
.merge(circle)
.attr('cx', function (d) { return x(d.young_proportion) })
.attr('cy', function (d) { return y(d.penetration) })
.style('fill', function (d) { return color(d.penetration) })
.style('opacity', function (d) { return d.filtered ? 0.5 : 1 })
.style('stroke-width', function (d) { return d.filtered ? 1 : 2 })
}
}
function choropleth(features) {
var width = 450
var height = 320
var projection = d3.geoAlbersUsa()
.scale([width * 1.25])
.translate([width / 2, height / 2])
var path = d3.geoPath().projection(projection)
var svg = d3.select('#choropleth')
.append('svg')
.attr('width', width)
.attr('height', height)
svg.selectAll('path')
.data(features)
.enter()
.append('path')
.attr('d', path)
.style('stroke', '#fff')
.style('stroke-width', 1)
.on("mouseenter", function(d) {
d3.select(this)
.style("stroke-width", 1.5)
.style("stroke-dasharray", 0)
d3.select("#choropleth")
.transition()
.style("opacity", 1)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px")
.text(features.properties.name)}) //here
.on("mouseleave", function(d) {
d3.select(this)
.style("stroke-width", .25)
.style("stroke-dasharray", 1)
d3.select("#Text")
.transition()
.style("opacity", 0.9);
})
return function update(data) {
svg.selectAll('path')
.data(data, function (d) { return d.name || d.properties.name })
.style('fill', function (d) { return d.filtered ? '#ddd' : color(d.penetration) })
}
}
</script>
</body>
(see also this fiddle: http://jsfiddle.net/swo8r7zk/)
You can use d.name in that scope. d also has penetration and young_proportion properties for each state. These are defined at the beginning of the file where you load the CSV data.

Draw vertical line after n data points in d3

I have a graph drawn with d3 with the x and y scales defined as follows:
x = d3.scaleLinear().domain([30, 150]).range([0, width])
y = d3.scaleLinear().domain([0, 100]).range([height, 0])
I need to draw a vertical line after 25% of data points. So I have my code like this:
svg.append('line')
.attr('x1', lowerLimit)
.attr('y1', 0)
.attr('x2', lowerLimit)
.attr('y2', height)
.style('stroke', 'red')
My problem is I am not sure how to set the lowerLimit x value to be 25% of all the x-values in the scale. Can someone help please? Thanks in advance!
Well, your question is not clear. When you say:
I need to draw a vertical line after 25% of data points
You're talking about the first quartile, which is impossible to calculate without the data, and not only that, but which changes for every different data set.
If you are indeed talking about the first quartile, this is what you have to do:
Given an data array called data, you can use d3.quantile:
var firstQuartile = d3.quantile(data, 0.25);
In the following demo, I'm plotting 100 dots, and calculating the 25 percentile (first quartile) regarding the property x:
var lowerLimit = d3.quantile(data, 0.25, function(d) {
return d.x
});
The console shows the value. Check the demo:
var data = d3.range(100).map(() => ({
x: Math.random() * 120 + 30,
y: Math.random() * 100
}));
var w = 500,
h = 160;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
x = d3.scaleLinear().domain([30, 150]).range([20, w - 20]);
y = d3.scaleLinear().domain([0, 100]).range([h - 20, 20]);
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var circles = svg.selectAll("circles")
.data(data)
.enter()
.append("circle")
.attr("r", 2)
.attr("fill", "teal")
.attr("cx", d => x(d.x))
.attr("cy", d => y(d.y));
var data = data.sort((a, b) => d3.ascending(a.x, b.x))
var lowerLimit = d3.quantile(data, 0.25, function(d) {
return d.x
});
console.log(lowerLimit);
svg.append('line')
.attr('x1', x(lowerLimit))
.attr('y1', 20)
.attr('x2', x(lowerLimit))
.attr('y2', h - 20)
.style('stroke', 'red')
svg.append("g")
.attr("transform", "translate(0," + (h - 20) + ")")
.call(xAxis);
svg.append("g")
.attr("transform", "translate(20,0)")
.call(yAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
However, if you're talking about "getting the value that is 25% of the domain", the answer is easy. You can, for instance, create a function:
function findLimit(percentage) {
return x(x.domain()[0] + (x.domain()[1] - x.domain()[0]) * percentage / 100);
};
And pass the value of that function to lowerLimit:
var lowerLimit = findLimit(25);
Check this demo, drawing a line at 25% of the x axis:
var data = d3.range(100).map(() => ({
x: Math.random() * 120 + 30,
y: Math.random() * 100
}));
var w = 500,
h = 200;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
x = d3.scaleLinear().domain([30, 150]).range([20, w - 20]);
y = d3.scaleLinear().domain([0, 100]).range([h - 20, 20]);
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var circles = svg.selectAll("circles")
.data(data)
.enter()
.append("circle")
.attr("r", 2)
.attr("fill", "teal")
.attr("cx", d => x(d.x))
.attr("cy", d => y(d.y));
var data = data.sort((a, b) => d3.ascending(a.x, b.x))
var lowerLimit = d3.quantile(data, 0.25, function(d) {
return d.x
});
console.log(lowerLimit);
svg.append('line')
.attr('x1', x(lowerLimit))
.attr('y1', 20)
.attr('x2', x(lowerLimit))
.attr('y2', h - 20)
.style('stroke', 'red')
svg.append("g")
.attr("transform", "translate(0," + (h - 20) + ")")
.call(xAxis);
svg.append("g")
.attr("transform", "translate(20,0)")
.call(yAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>

How to add a line on x-axis on a horizontal bar chart in d3

I would like to add a line on my horizontal bar chart something like the image, the line should represent 270 on x-axis in this case, but I get the error invalid path attribute. Here is the plunker code:
var info = [
{name: "Walnuts", value:206},
{name: "Almonds", value:332}
];
/* Set chart dimensions */
var width = 960,
height = 500,
margin = {top:10, right:10, bottom:20, left:60};
//subtract margins
width = width - margin.left - margin.right;
height = height - margin.top - margin.bottom;
//sort data from highest to lowest
info = info.sort(function(a, b){ return b.value - a.value; });
//Sets the y scale from 0 to the maximum data element
var max_n = 0;
var category = []
for (var d in info) {
max_n = Math.max(info[d].value, max_n);
category.push(info[d].name)
}
var dx = width / max_n;
var dy = height / info.length;
var y = d3.scale.ordinal()
.domain(category)
.rangeRoundBands([0, height], .1);
var x = d3.scale.linear()
.range([0, width]);
var yAxis = d3.svg.axis()
.scale(y)
.orient('left')
var svg = d3.select("#chart")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.attr('preserveAspectRatio', 'xMidYMin')
.attr("viewBox", '0 0 ' + parseInt(width + margin.left + margin.right) + ' ' + parseInt(height + margin.top + margin.bottom))
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.selectAll(".bar")
.data(info)
.enter()
.append("rect")
.attr("class", function(d, i) {return "bar" + d.name;})
.attr("x", function(d, i) {return 0;})
.attr("y", function(d, i) {return dy*i;})
.attr("width", function(d, i) {return dx*d.value})
.attr("height", dy)
.attr("fill", function(d, i){
if(d.name == 'Walnuts') {return 'red'} else {return 'green'}
});
var y_xis = svg.append('g')
.attr('id','yaxis')
.call(yAxis);
var lineEnd = 270;
var line = d3.svg.line()
line
.x(function(d, i) {
return x(d.value) + i; })
.y(function(d, i) { return lineEnd; });
svg.append("path")
.datum(info)
.attr("class", "line")
.attr("d", line);
You don't need d3.svg.line() here. Just create a simple line:
var lineEnd = 270;
var line = svg.append("line")
.attr("x1", lineEnd)
.attr("x2", lineEnd)
.attr("y1", 0)
.attr("y2", height)
.attr("stroke-width", 8)
.attr("stroke", "black")
.attr("stroke-dasharray", "8,8");
This is the plunker: http://plnkr.co/edit/dOhZjRvBHzFqWFByerKH?p=preview
PS: This is not 270 on x-axis, this is simply 270px on the SVG. Right now you cannot use x as a scale because there is no domain. Set a domain for x and use it to set the width of your bars.
First, get rid of this:
var max_n = 0;
var category = []
for (var d in info) {
max_n = Math.max(info[d].value, max_n);
category.push(info[d].name)
}
var dx = width / max_n;
var dy = height / info.length;
Now, set the scales:
var y = d3.scale.ordinal()
.domain(info.map(function(d){ return d.name}))
.rangeRoundBands([0, height], .1);
var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(info, function(d){return d.value})])
And then use these scales for your bars:
.attr("x", 0)
.attr("y", function(d){ return y(d.name)})
.attr("width", function(d) {return x(d.value)})
.attr("height", y.rangeBand())
With all these corrected, now we can use 270 in the scale:
var line = svg.append("line")
.attr("x1", function(){ return x(lineEnd)})
.attr("x2", function(){ return x(lineEnd)})
.attr("y1", 0)
.attr("y2", height)
.attr("stroke-width", 6)
.attr("stroke", "black")
.attr("stroke-dasharray", "8,8")
Here is the updated plunker: http://plnkr.co/edit/gtPA12qSf9mBoAY6MeDd?p=preview

Categories

Resources