I'm trying to create a scatter plot and while my axes are rendered, I can't see any circles. I can't figure out what's wrong.
I realized that my data values are in string so I used '+' operator. Still doesn't work. There is no error message. I can see the elements in debug window being created but they are not displayed.
Here is my code:
function visualize(data) {
var margin = { top: 20, bottom: 80, right:50, left: 70 };
var width = 720 - margin.left + margin.right, height = 500 - margin.top - margin.bottom;
var svg = d3.select("body")
.append("svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.right + margin.left);
g=svg.append("g")
.attr("transform","translate("+margin.left+","+margin.top+")");
var xScale = d3.scaleLinear().domain(d3.extent(data,function(d) {
return +d.FTAG;
})).range([0, width]);
var yScale = d3.scaleLinear().domain([0,d3.max(data,function(d) { return +d["AF"]; })]).range([height, 0]);
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
g.append("g").attr("class", "x-axis").attr("transform", "translate(0," + height + ")").call(xAxis);
g.append("g").attr("class", "y-axis").attr("transform", "translate(0,0)").call(yAxis);
d3.selectAll("dot").data(data)
.enter()
.append("g")
.append("circle")
.attr("r", 20)
.attr("cx",
function(d) {
return xScale(+d.FTAG);
})
.attr("cy",
function(d) {
return yScale(+d.AF);
})
.style("fill",
function(d) {
if (+d.AF >= 20) {
return "red";
} else
return "steelblue";
})
.style("stroke","black")
.style("stroke-width",1.5);
}
In your code...
d3.selectAll("dot")
.data(data)
.enter()
.append("g")
... doesn't append groups anywhere.
It has to be:
svg.selectAll("dot")
.data(data)
.enter()
.append("g")
Since svg is the selection that appends an SVG to the <body>.
Related
I am trying to implement the following problem while learning d3.js for visualization.
Using the following titanic dataset:
Plot in scatterplot :
a)the male passengers using an SVG square (width 5, x and y - 2.5 )
b)the female passengers using a circle of radius 2.8
c) Have the survived column used as opacity such that the dead have opacity 0.25 and alive have opacity: 1;
fill-opacity:.1;
stroke: black;
Make the scatterplot axes, make the y axis to log scale, and add the passengers name on their mark (using the SVG title element).
I am implementing the following code to achieve my goals but, I have am not successful in displaying my graph.
Can anyone please help me.
The titanic dataset - here
And my code here:
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - 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://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(rawData) {
const data = rawData.map(function(d) {
return {
age: Number(d.age),
fare: Number(d.fare),
sex: d.sex,
survived: d.survived === "1",
name: d.name
};
});
// Add X axis
var x = d3.scaleLinear()
.domain([0, 80])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")");
// Add Y axis
var y = d3.scaleLog()
.domain([1e+0, 1e+3])
.range([height, 0]);
svg.append("g");
// Add dots
svg.append('g')
.selectAll("dot").select("female")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return x(d.age);
})
.attr("cy", function(d) {
return y(d.fare);
})
//.attr("r", 2.8)
.style("opacity", function(d) {
return d.survived ? "1" : "0.25";
})
.style("stroke", "black")
.style("fill-opacity", 0.1)
svg.append('g')
.selectAll("dot").select("male")
.data(data)
.enter()
.append("rect")
.attr("cx", function(d) {
return x(d.age);
})
.attr("cy", function(d) {
return y(d.fare);
})
//.attr("width", 5)
.style("opacity", function(d) {
return d.survived ? "1" : "0.25";
})
.style("stroke", "black")
.style("fill-opacity", 0.1)
.append("svg:title")
.text(function(d) {
return d.name
});
})
<script src="https://d3js.org/d3.v4.js"></script>
<div id="my_dataviz"></div>
can anyone please highlight where i am making mistake and help me please
You really, really need to read the manual, especially the SVG one. rect nodes don't have cx and cy, they have x and y, width, and height. And circle needs a radius r in order to be visible.
And you gave all the properties you read a lowercase starting letter. They need capitals. Look up a manual on debugging.
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - 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://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(rawData) {
const data = rawData.map(function(d) {
return {
age: Number(d.Age),
fare: Number(d.Fare),
sex: d.Sex,
survived: d.Survived === "1",
name: d.Name
};
});
// Add X axis
var x = d3.scaleLinear()
.domain([0, 80])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")");
// Add Y axis
var y = d3.scaleLog()
.domain([1e+0, 1e+3])
.range([height, 0]);
svg.append("g");
// Add dots
svg.append('g')
.selectAll("dot").select("female")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return x(d.age);
})
.attr("cy", function(d) {
return y(d.fare);
})
.attr("r", 2.8)
.style("opacity", function(d) {
return d.survived ? "1" : "0.25";
})
.style("stroke", "black")
.style("fill-opacity", 0.1)
svg.append('g')
.selectAll("dot").select("male")
.data(data)
.enter()
.append("rect")
.attr("x", function(d) {
return x(d.age);
})
.attr("y", function(d) {
return y(d.fare);
})
.attr("width", 5)
.attr("height", 5)
.style("opacity", function(d) {
return d.survived ? "1" : "0.25";
})
.style("stroke", "black")
.style("fill-opacity", 0.1)
.append("svg:title")
.text(function(d) {
return d.name
});
})
<script src="https://d3js.org/d3.v4.js"></script>
<div id="my_dataviz"></div>
I have an issue with D3 scatterplot where the data are not correctly plot
(plotted to 1 horizontal line rather than a scattered plot, the actual data is also scattered)
and the x-axis not able to show up.
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// parse the date / time
var parseTime = d3.timeParse("%Y-%m-%dT%H:%M:%S.%L%Z");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// append the svg obgect to the body of the page
// appends 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 + ")");
// Get the data
data = data.rows;
// format the data
data.forEach(function(d) {
var momentTemp = moment(d[0]).format("YYYY-MM-DDTHH:mm:ss.SSSZ");
var parseTemp = parseTime(momentTemp);
d.date = parseTemp;
d.close += d[1];
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.close;
})]);
var xValue = function(d) {
return d.date;
}
var yValue = function(d) {
return d.close;
}
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 1.5)
.attr("cx", function(d) {
return x(d.date);
})
.attr("cy", function(d) {
return y(d.close);
});
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis
svg.append("g")
.attr("transform", "translate(" + margin.left + " ,0)")
.call(d3.axisLeft(y));
That happens when your data is invalid. Are you sure the field close is correct? Your data calls the column ratio. I made some sample data and everything works:
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// parse the date / time
var parseTime = d3.timeParse("%Y-%m-%dT%H:%M:%S.%L%Z");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// append the svg obgect to the body of the page
// appends 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 = new Array(100)
.fill(undefined)
.map(function(d, i) {
return {
date: new Date(Number(new Date("01/01/2000")) + i * 24 * 60 * 60 * 1000),
close: Math.random(),
};
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.close;
})]);
var xValue = function(d) {
return d.date;
}
var yValue = function(d) {
return d.close;
}
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 1.5)
.attr("cx", function(d) {
return x(d.date);
})
.attr("cy", function(d) {
return y(d.close);
});
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis
svg.append("g")
.attr("transform", "translate(" + margin.left + " ,0)")
.call(d3.axisLeft(y));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
I am trying to plot some extremely small values with d3.js. Is there a direct way to visualise the tick labels in scientific (exponential) notation?
<!DOCTYPE html>
<meta charset="utf-8">
<style>
</style>
<body>
<!-- load the d3.js library -->
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// parse the date / time
var data = [[0.3, 5e-300],[0.1, 3e-300],[0.7, 4e-300],[0.2, 7e-300],[0.6, 2.5e-300],[0.9, 4.2e-300]]
// set the ranges
var x = d3.scaleLinear().range([0, width]).domain([0, d3.max(data, function(d) { return d[0]; })]);
var y = d3.scaleLinear().range([height, 0]).domain([0, d3.max(data, function(d) { return d[1]; })]);
// append the svg obgect to the body of the page
// appends 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 + ")");
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("cx", function (d,i) { return x(d[0]); } )
.attr("cy", function (d) { return y(d[1]); } )
.attr("r", 8);
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis
svg.append("g")
.call(d3.axisLeft(y)
.tickFormat(d3.formatPrefix(".1s", 1e-300)));;
</script>
</body>
Here's an example created with in matplotlib. I would like to achieve the same thing with regard to y-axis notation
A solution with d3.format:
svg.append("g")
.call(d3.axisLeft(y)
.tickFormat(d3.format(".1e")));
Here is a demo:
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// parse the date / time
var data = [[0.3, 5e-300],[0.1, 3e-300],[0.7, 4e-300],[0.2, 7e-300],[0.6, 2.5e-300],[0.9, 4.2e-300]]
// set the ranges
var x = d3.scaleLinear().range([0, width]).domain([0, d3.max(data, function(d) { return d[0]; })]);
var y = d3.scaleLinear().range([height, 0]).domain([0, d3.max(data, function(d) { return d[1]; })]);
// append the svg obgect to the body of the page
// appends 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 + ")");
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("cx", function (d,i) { return x(d[0]); } )
.attr("cy", function (d) { return y(d[1]); } )
.attr("r", 8);
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis
svg.append("g")
.call(d3.axisLeft(y)
.tickFormat(d3.format(".1e")));
<script src="https://d3js.org/d3.v4.min.js"></script>
I am trying to populate a data set into D3's Bar chart data. I am using this example from the d3:
https://bl.ocks.org/mbostock/1134768
var causes = ["wounds", "other", "disease"];
var parseDate = d3.time.format("%m/%Y").parse;
var margin = {top: 20, right: 50, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
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 + ")");
d3.tsv("data.csv", function(error, crimea) {
if (error) throw error;
var layers = d3.layout.stack()(causes.map(function(c) {
return crimea.map(function(d) {
return {x: parseDate(d.date), y: +d[c]};
});
}));
var x = d3.scale.ordinal()
.domain([0,1])
.rangeRoundBands([0, width], 0.1, 0);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var z = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%b"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
console.log(layers);
x.domain(layers[0].map(function(d) { return d.x; }));
y.domain([0, d3.max(layers[layers.length - 1], function(d) { return d.y0 + d.y; })]).nice();
var ticks = x.domain().filter(function(d,i){ return !(i%20); } );
xAxis.tickValues( ticks );
var layer = svg.selectAll(".layer")
.data(layers)
.enter().append("g")
.attr("class", "layer")
.style("fill", function(d, i) { return z(i); });
layer.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y + d.y0); })
.attr("height", function(d) { return y(d.y0) - y(d.y + d.y0); })
.attr("width", x.rangeBand() - 1);
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(" + 0 + ",0)")
.call(yAxis);
});
This issue I am getting is that I have some white space which looks ugly. This space come before the 1st bar and also after the last bar of the chart. I have tried tweaking the x value of the bar, But I think that is not a good way to do.
This space does not come when the data set is small. But when dataset is large then this space comes up. How can I remove this space from the start and from end.
JSFiddle For the Above code is
https://jsfiddle.net/7qnngbdc/
See here --> https://github.com/mbostock/d3/wiki/Ordinal-Scales#ordinal_rangeRoundBands
"Note that rounding necessarily introduces additional outer padding which is, on average, proportional to the length of the domain. For example, for a domain of size 50, an additional 25px of outer padding on either side may be required. Modifying the range extent to be closer to a multiple of the domain length may reduce the additional padding."
After you've set the domain, try this -->
var mult = Math.max (1, Math.floor (width / x.domain().length));
x.rangeRoundBands ([0, (x.domain().length * mult)], 0.1, 0);
Changed in https://jsfiddle.net/7qnngbdc/1/
Is it possible to put D3 code into a function and then call the function?
For example, I am interested in using this histogram code
http://bl.ocks.org/3048450
If I put code in a function and call like
function hist(bin, data) {
//the D3 histogram plotting code
// Generate an Irwin–Hall distribution of 10 random variables.
var values = d3.range(1000).map(d3.random.irwinHall(10));
// A formatter for counts.
var formatCount = d3.format(",.0f");
var margin = {top: 10, right: 30, bottom: 30, left: 30},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([0, 1])
.range([0, width]);
// Generate a histogram using twenty uniformly-spaced bins.
var data = d3.layout.histogram()
.bins(x.ticks(20))
(values);
var y = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.y; })])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
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 bar = svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; });
bar.append("rect")
.attr("x", 1)
.attr("width", x(data[0].dx) - 1)
.attr("height", function(d) { return height - y(d.y); });
bar.append("text")
.attr("dy", ".75em")
.attr("y", 6)
.attr("x", x(data[0].dx) / 2)
.attr("text-anchor", "middle")
.text(function(d) { return formatCount(d.y); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
}
hist(...); //call the function
it doesn't plot. Why is that?
I found the cause of the bug. I misspell "function" as "function"
Where are you including and running that code? If you're including and runningit in the <head> element, then when the script executes the browser will not be aware of the <body> element. d3.select("body") will return an empty selection, and therefore there will be nothing to which to append and svg element.
Try putting the script within the <body> or use a library like jQuery (i.e., $(document).ready()) to ensure that the document has been loaded before executing your script.