I have this scatterplot which is not working with d3 v3. I don't get any error in the console but it's not showing the axis as it should.
Here is the js file:
var data = [
{
"xaxis": 0.2,
"yaxis": 0.8,
"color": 0
},
{
"xaxis": 0.3,
"yaxis": 0.7,
"color": 1
},
]
// 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
function draw(data) {
// Add X axis
var x = d3.scale.linear()
.domain([0, 1])
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.svg.axis(y));
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
// Add Y axis
var y = d3.scale.linear()
.domain([0, 1])
.range([ height, 0]);
svg.append("g")
.call(d3.svg.axis(y));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Value");
// Color scale: give me a specie name, I return a color
var color = d3.scale.ordinal()
.domain(["0", "1", "2" ])
.range([ "#440154ff", "#21908dff", "#fde725ff"])
// Add dots
svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d.xaxis); } )
.attr("cy", function (d) { return y(d.yaxis); } )
.attr("r", 5)
.style("fill", function (d) { return color(d.color) } )
}
draw(data);
and the html:
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v3.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
I have adapted this scatterplot from v4 to work for v3 but seems like something is missing and I can't manage to find it. Any help would be appreciated.
This is one of the few times I've seen a question asking about downgrading a version. Why you're doing this is unclear. Nevertheless, the issue is clear, in D3 v3 you don't pass the scale to the axis generator like you did:
d3.svg.axis(y)
It has to be:
d3.svg.axis()
.scale(y)//pass the scale here
.orient("left")//or "right", depending on what position you want
Related
Have a line graph shown as here: https://imgur.com/1kadiJF
Would love the x-axis to display a & sign after each tick, 10%, 20%, etc. How does one accomplish this?
I've read up on a format method one can use, as well as saw people using Math and actually doing a conversion, but figure there must be a quick way to add a string % after each tick, surely!
Using V4 of D3 here
<script>
// set the dimensions and margins of the graph
const formatPercent = d3.format(".0%")
const margin = {top: 20, right: 30, bottom: 60, left: 250},
width = 1000 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// append the svg object to the body of the page
const svg = d3.select(".line")
.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.json("./data/linedata.json", function(data) {
// Add X axis
const x = d3.scaleLinear()
.domain([0, 100])
.range([ 0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text").attr('class', 'xaxis')
.attr("transform", "translate(0,0 )")
.style("text-anchor", "end");
// Y axis
const y = d3.scaleBand()
.range([ 0, height ])
.domain(data.map(function(d) { return d.desc; }))
.padding(.1)
svg.append("g").attr('class', 'xaxis')
.call(d3.axisLeft(y))
//Bars
svg.selectAll("myRect")
.data(data)
.enter()
.append("rect")
.attr("x", x(0) )
.attr("y", function(d) { return y(d.desc); })
.attr("width", function(d) { return x(d.total); })
.attr("height", y.bandwidth() )
.attr("fill", "#008080")
})
</script>
Have you tried using the tickFormat function?
Something like this should work:
.tickFormat(d => d + "%")
I am trying to modify below code from this example
https://enappd.com/blog/adding-charts-in-ionic-4-apps-and-pwa-part-2/54/
to a line plot or connected scatter plot (preferred). How?
Nearly all simple D3 examples I find a bar charts or have different syntax since they read data from a cvs and not locally in the example above.
D3 is a bit cryptic for me so far.
this.g.selectAll('.bar')
.data(this.barData)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('fill', 'rgb(34, 167, 240)')
.attr('x', (d) => this.x(d.season))
.attr('y', (d) => this.y(d.viewers))
.attr('width', this.x.bandwidth())
.attr('height', (d) => this.height - this.y(d.viewers));
I believe this is a line plot, not sure if it meets your requirements, let me know:
// 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 + ")");
//d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/2_TwoNum.csv", function(data) {
//console.log(data);
//});
var data = [
{ x: 1, y: 2500000 },
{ x: 2, y: 3800000 },
{ x: 3, y: 5000000 },
{ x: 4, y: 6900000 },
{ x: 5, y: 6900000 },
{ x: 6, y: 7500000 },
{ x: 7, y: 10000000 },
{ x: 8, y: 17000000 }
];
// Add X axis
var x = d3.scaleLinear()
.domain([0, 10])
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 20000000])
.range([ height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Add dots - scatter plot
//svg.append('g')
// .selectAll("dot")
// .data(data)
// .enter()
// .append("circle")
// .attr("cx", function (d) { return x(d.x); } )
// .attr("cy", function (d) { return y(d.y); } )
// .attr("r", 1.5)
// .style("fill", "#69b3a2")
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.x) })
.y(function(d) { return y(d.y) })
)
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("season");
// Add the y Axis
svg.append("g")
.call(d3.axisLeft(y));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("viewers");
</script>
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
Important as for reading from CSV, it's relatively simple to grasp how to get rid of it in the examples. Here's how you could load data from csv:
d3.csv("https://.../master/Example_dataset/2_TwoNum.csv", function(data) {
//do something with data here
});
So, basically you do the drawing within the callback (once you've got the data, right?). If you know data when writing the script (like in your example), you simply assign the data and use it in d3 transformations. Here's a great example of scatter plot drawing in d3. All I've done is simply got rid of the callback and assign your data + re-scale the x and y axes.
I am trying to make simple chart right now importing data from a CSV. Everything on the chart is working great except for the labels. In element inspect I can see that they are being appended and that their x and y coordinates are even correct, but for some reason they are all trapped in the top left corner in the SVG itself.
I have tried changing the x placement function at first because I thought it just wasn't giving the labels a x position, but upon further inspection the labels have the correct metadata.
//Graph Dimensions
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//Set Ranges
var x_scale = d3.scaleBand()
.range([0, width])
.padding(0.1);
var y_scale = d3.scaleLinear()
.range([height, 0]);
//Create SVG object
var svg = d3.select('#chart')
.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 + ")");
//Retrieve data
d3.csv('sales.csv').then(function(data){
//Set domains based on data
x_scale.domain(data.map(function(d) { return d.month; }));
y_scale.domain([0, d3.max(data, function(d) { return d.sales; })]);
//Create bars
svg.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x_scale(d.month); })
.attr("width", x_scale.bandwidth())
.attr("y", function(d) { return y_scale(d.sales); })
.attr("height", function(d) { return height - y_scale(d.sales); });
//Create labels
svg.selectAll('text')
.data(data)
.enter().append('text')
.attr('class', 'label')
.attr("x", function(d) { return x_scale(d.month); })
.attr("y", function(d) { return y_scale(d.sales); })
.attr( 'font-size', 14 )
.attr( 'fill', '#555555' )
.attr( 'text-anchor', 'middle' );
//Add Axes
svg.append("g") //X Axis
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x_scale));
svg.append("g") //Y Axis
.call(d3.axisLeft(y_scale));
})
The only thing im looking for is the labels actually appearing. I can change their location later if needed.
I'm attempting to create a bar chart in D3 that replicates this design. The idea is that values can range from -100 to 100 and are displayed alongside each other. The scale must stay as 0-100, with colours being used to indicate whether the number is above or below 0.
I've managed to create a simple bar chart that displays positive numbers but as soon as a negative number is added, the chart breaks. The following code is used to create the x and y axis. Negative values are displayed if the x domain is changed to [-100, 100], but doing so renders the chart in a way that is too different from the original design.
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
var x = d3.scaleLinear()
.range([0, width]);
x.domain([0, 100])
y.domain(data.map(function(d) { return d.sentiment; }));
Can anyone provide some tips/guidance on producing a graph that looks similar to the provided design, if it's even possible? Link to my current graph can be found in the JSFiddle below:
JSFiddle
Many thanks.
Just use Math.abs():
.attr("width", function(d){
return x(Math.abs(d.value));
})
Here is the demo:
var data = [{"sentiment":"Result","value":28},{"sentiment":"Result2","value":-56}]
var margin = {top: 20, right: 20, bottom: 50, left: 70},
width = 850 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
var x = d3.scaleLinear()
.range([0, width]);
var svg = d3.select("#graph").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 + ")");
data.forEach(function(d) {
d.value = +d.value;
});
x.domain([0, 100])
y.domain(data.map(function(d) { return d.sentiment; }));
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("width", function(d) {return x(Math.abs(d.value)); } )
.attr("y", function(d) { return y(d.sentiment) + 15; })
.attr("height", y.bandwidth())
.attr("fill", function(d) {
if (d.value <= 0) {
return "#FC4E5C";
} else {
return "#34A232";
}
});
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
svg.append("g")
.call(d3.axisLeft(y));
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "end")
.attr("x", width - 300)
.attr("y", height + 40)
.text("Sentiment (%)");
.bar {
margin-top: 50px;
height: 30px;
}
text {
fill: black;
font-size: 14px;
}
path {
stroke: black;
}
line {
stroke: black;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<div id="graph">
</div>
I'm trying to adapt this code:
http://bl.ocks.org/anupsavvy/9513382
To plot a stacked-bar chart using custom data. I don't need any transitions, just a simple plot.
I end up with this code:
data = jsonArr;
var margin = {
top: 40,
right: 40,
bottom: 40,
left: 40
},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var color = d3.scale.ordinal()
.range(colorrange);
var stack = d3.layout.stack();
stack(data);
var xScale = d3.time.scale()
.domain([new Date(0, 0, 0, data[0][0].label, 0, 0, 0), new Date(0, 0, 0, data[0][data[0].length - 1].label, 0, 0, 0)])
.rangeRound([0, width - margin.left - margin.right]);
var yScale = d3.scale.linear()
.domain([0,
d3.max(data, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.value;
});
})
])
.range([height - margin.bottom - margin.top, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.ticks(d3.time.hour, 1)
.tickFormat(d3.time.format("%H"));
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10);
var svg = d3.select("#info")
.append("svg")
.attr("width", width)
.attr("height", height);
var groups = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("class", "rgroups")
.attr("transform", "translate(" + margin.left + "," + (height - margin.bottom) + ")")
.style("fill", function(d, i) {
return colorrange[i];
});
var rects = groups.selectAll("rect")
.data(function(d) {
return d;
})
.enter()
.append("rect")
.attr("width", 6)
.attr("height", function(d) {
return -yScale(d.value) + (height - margin.top - margin.bottom);
})
.attr("x", function(d) {
return xScale(new Date(0, 0, 0, d.label, 0, 0, 0));;
})
.attr("y", function(d) {
return -(-yScale(d.y0) - yScale(d.value) + (height - margin.top - margin.bottom) * 2);
});
console.log(rects);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(40," + (height - margin.bottom) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(yAxis);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - 5)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.text("Number of complaints");
svg.append("text")
.attr("class", "xtext")
.attr("x", width / 2 - margin.left)
.attr("y", height - 5)
.attr("text-anchor", "middle")
.text("Hour of day");
More specifically:
yScale(d.y0) is returning NaN.
If I comment this piece of code, I can see the axes:
After a while, I managed to see the and some data (among errors):
I guess I'm not understanding the properly way to plot the data itself.
Any help would be appreciated.
My json label attribute is related to the y coordinate, while value is related to the x coordinate.
EDIT:
It seems that the problem begins when I call stack. The first array has y0 values as 0, but the second and third ones have y0 = NaN. I don't know how to fix this.
This is the relative jsfiddle:
https://jsfiddle.net/rhzkz9gb/13/
You need to provide the accessor functions for the data (because it is not keyed with 'x' and 'y').
var stack = d3.layout.stack().x(function(d,i){return i;}).y(function(d){return d.value;});
https://jsfiddle.net/ermineia/rhzkz9gb/14/