D3.js <div> not working - javascript

Maybe not a perfect title, but I don't know how to actually describe it since I'm fairly new to web design and programming, as well as to d3. I have the following code:
function draw(data) {
"use strict";
var container_dimensions = {width: 900, height: 400},
margins = {top:10, right:20, bottom:30, left:60},
chart_dimensions = {
width: container_dimensions.width - margins.left - margins.right,
height: container_dimensions.height - margins.top - margins.bottom
};
var chart = d3.select("#timeseries")
.append("svg")
.attr("width", container_dimensions.width)
.attr("height", container_dimensions.height)
.append("g")
.attr("transform", "translate (" + margins.left + "," + margins.top + ")")
.attr("id", "chart");
var time_scale = d3.scaleTime()
.range([0, chart_dimensions.width])
.domain([new Date(2008, 0, 1), new Date(2011, 3, 1)]);
var percent_scale = d3.scaleLinear()
.range([chart_dimensions.height, 0])
.domain([65, 90]);
var time_axis = d3.axisBottom(time_scale);
var count_axis = d3.axisLeft(percent_scale);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + chart_dimensions.height + ")")
.call(time_axis);
chart.append("g")
.attr("class", "y axis")
.call(count_axis);
d3.select(".y.axis")
.append("text")
.attr("text-anchor", "middle")
.text("percent on time")
.attr("transform", "translate(-35, 135)rotate (-270)")
.attr("x", container.height/2)
.attr("y", 50);
//comment
var key_items = d3.select("#key")
.selectAll("div")
.data(data)
.enter()
.append("div")
.attr("class", "key_line")
.attr("id", function(d) {return d.line_id;})
key_items.append("div")
.attr("id", function(d){return "key_square_" + d.line_id})
.attr("class", "key_square")
key_items.append("div")
.attr("class", "key_label")
.text(function(d){return d.line_name})
}
I added two div's in the body, but only one seems to be working at the time. With the above code, only the first (timeseries) works. If I delete everything in the function before the "comment" comment, the second div (key) works just fine.
<div id="timeseries"></div>
<div id="key"></div>
<script>
d3.json("data/subway_wait_mean.json", draw);
</script>
What needs to be changed so this could work properly?

You need to learn how to use your browser's developer tools.
When I ran your code in Chrome, Chrome's dev tools showed me the error Uncaught ReferenceError: container is not defined, pointing to this line:
.attr("x", container.height/2)
See the problem?
I think you want
.attr("x", container_dimensions.height/2)
instead.

Related

D3 graph is missing as much text elements as there are ticks in axis

I experience the weirdest problem:
If I draw my axis before my graph, the graph misses as much text elements as there are ticks in the axis. When I increase or decrease the number of ticks, the number of missing text elements increases or decreases alike.
If I draw my axis after my graph, everything is alright.
I want to draw the axis first, as I want the grid lines to appear below the graph. And first of all, I want to understand what is going on here.
Here the code snippet in question:
var generateVisualization = function() {
var margin = {top: 30, right: 10, bottom: 30, left: 10};
var width = 1000 - margin.left - margin.right;
var height = (dataset.length * 11) + 5;
var xScale = d3.scale.linear()
.domain([1850, 2020])
.range([0, width])
var xAxisBottom = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickSize(-height)
.tickFormat(d3.format("d")); // removes the comma as thousands separator
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 + ")")
// Axis drawn first
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxisBottom);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(d.BeginDate);
})
.attr("y", function(d, i) {
return i * 11 + 3;
})
.attr("width", function(d, i) {
return xScale(d.EndDate) - xScale(d.BeginDate);
})
.attr("height", 4)
.attr("class", "line");
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d.DisplayName;
})
.attr("x", function(d, i) {
return xScale(d.BeginDate) + (xScale(d.EndDate) - xScale(d.BeginDate)) + 4;
})
.attr("y", function(d, i) {
return i * 11 + 8;
})
.attr("font-family", "sans-serif")
.attr("font-size", 8);
// Alternative: Axis drawn last
/*
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxisBottom);
*/
};
My hunch:
Instead of this:
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d.DisplayName;
})
do this:
svg.selectAll(".myLabel")//selection via class
.data(dataset)
.enter()
.append("text")
.attr("class", "myLabel")//adding a class to the label
.text(function(d) {
return d.DisplayName;
})
Reason: when you do
svg.selectAll("text")
It will select the text on ticks, and bind the data to it. This is the reason for the anomaly... you increase the ticks the labels displayed decreases.
The above solution will add the class myLabel to only the labels but not the tick text, so the problem should resolve.

D3.js -- How do I update dataset via Javascript?

I have a dataset with 11 different variables (csv file with 12 columns). I want to be able to select a certain column for my scatterplot, but I'm having some difficulties. Please bear with me, as JavaScript is not my strong suit (obviously). Here's what I attempted:
<div class="variables" id="fixedacidity" onclick="drawPlot('fixedacidity');">
<h1>fixed acidity</h1>
</div>
<div class="variables" id="volatileacidity" onclick="drawPlot('volatileacidity');">
<h1>volatile acidity</h1>
</div>
<div class="variables" id="citricacid" onclick="drawPlot('citricacid');">
<h1>citric acid</h1>
</div>
<div class="variables" id="residualsugar" onclick="drawPlot('residualsugar');">
<h1>residual sugar</h1>
</div>
etc ...
I made a simple menu that calls on the drawPlot function, but I'm having trouble trying to get the variable to pass on correctly.
Relevant d3/javascript:
function drawPlot(selectedVar){
$(".visarea").html("");
var wineVar = selectedVar;
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 860 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0])
.domain([0,10]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left").ticks(10);
var chart1 = d3.select(".visarea").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("red.csv", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.wineVar = +d.wineVar;
d.quality = +d.quality;
});
x.domain(d3.extent(data, function(d) { return d.wineVar; })).nice();
y.domain([0,10]).nice();
chart1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text(wineVar);
chart1.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Rated Quality")
chart1.selectAll(".red.dot")
.data(data)
.enter().append("circle")
.attr("class", "red dot")
.attr("r", 3)
.attr("cx", function(d) { return x(d.wineVar); })
.attr("cy", function(d) { return y(d.quality); })
.style("fill", "red");
});
}
Although the variable gets passed on to the function, d.wineVar, as expected, does not return the desired value, and thus the chart does not draw the correct values. Can anyone recommend a workaround for this? It seems so simple, yet I've spent hours failing trying to figure this out.
Sample of red.csv:
fixedacidity,volatileacidity,citricacid,residualsugar,chlorides,freesulfurdioxide,totalsulfurdioxide,density,pH,sulphates,alcohol,quality
7.4,0.7,0,1.9,0.076,11,34,0.9978,3.51,0.56,9.4,5
7.8,0.88,0,2.6,0.098,25,67,0.9968,3.2,0.68,9.8,5
7.8,0.76,0.04,2.3,0.092,15,54,0.997,3.26,0.65,9.8,5
Image of what I'm trying to accomplish. The first dataset, fixedacidity, gets drawn up fine. I'm having difficulties trying to get the menu to correctly show its respective dataset. "Rated Quality" will always be the data for the Y-axis.
You has wrong variable reference, here:
data.forEach(function(d) {
d.wineVar = +d.wineVar; // <---------Here
d.quality = +d.quality;
});
change by:
data.forEach(function(d) {
d.wineVar = +d[wineVar]; // <----------Here
d.quality = +d.quality;
});
There is the obvious issue pointed out by klaujesi about data extraction. But there are more issues with your code.
I would say you need to adapt your approach to the way d3.js works. Currently you will add a new svg on each call to the function, caused by this line in your code: d3.select(".visarea").append("svg")
I usually have some init code wrapped in one function, which creates the svg and sets ups everything static. Then there is an update function which will handle input changes to show different data, use different scales etc.
The nice thing about d3.js is that you can control very easily what's to happen with newly introduced data via .enter() and removed data via .exit().

D3.js grouped bar chart plotting data multiple times

I am trying to create a grouped bar chart using D3.js. I have followed the examples provided in the D3 wiki at GitHub and have a semi working graph. However, it seems like all datapoints for a certain value get plotted at the same spot.
my data looks is a JSON array, which looks like this
[{"experiment":30385,"c":1,"ratio":0.022,"stdev":0.363,"median":0.032,"zscore":6.359},
{"experiment":30385,"c":2,"ratio":-0.02,"stdev":0.351,"median":-0.005,"zscore":-4.786},
{"experiment":30385,"c":3,"ratio":0.074,"stdev":0.339,"median":0.089,"zscore":29.036},
{"experiment":30385,"c":4,"ratio":-0.077,"stdev":0.361,"median":-0.065,"zscore":-25.704},
{"experiment":30385,"c":5,"ratio":-0.354,"stdev":0.569,"median":-0.223,"zscore":-145.625},
{"experiment":30385,"c":6,"ratio":-0.02,"stdev":0.352,"median":-0.007,"zscore":-2.545},
{"experiment":30385,"c":7,"ratio":0.018,"stdev":0.346,"median":0.036,"zscore":7.412},
{"experiment":30385,"c":8,"ratio":-0.11,"stdev":0.348,"median":-0.096,"zscore":-37.69},
{"experiment":30385,"c":9,"ratio":-0.012,"stdev":0.357,"median":0.008,"zscore":-4.394},
{"experiment":30385,"c":10,"ratio":-0.054,"stdev":0.366,"median":-0.036,"zscore":-14.158},
{"experiment":30385,"c":11,"ratio":-0.071,"stdev":0.344,"median":-0.044,"zscore":-21.4},
{"experiment":30385,"c":12,"ratio":-0.01,"stdev":0.352,"median":0.002,"zscore":-1.467},
{"experiment":30385,"c":13,"ratio":-0.03,"stdev":0.366,"median":-0.014,"zscore":-2.375},
{"experiment":30385,"c":14,"ratio":-0.039,"stdev":0.339,"median":-0.025,"zscore":-8.816},
{"experiment":30385,"c":15,"ratio":-0.02,"stdev":0.357,"median":0.0065,"zscore":-4.2},
{"experiment":30385,"c":16,"ratio":0.449,"stdev":0.439,"median":0.4215,"zscore":69.859},
{"experiment":30385,"c":17,"ratio":-0.028,"stdev":0.367,"median":-0.007,"zscore":-4.9},
{"experiment":30385,"c":18,"ratio":-0.071,"stdev":0.357,"median":-0.061,"zscore":-17.268},
{"experiment":30385,"c":19,"ratio":0.143,"stdev":0.356,"median":0.1415,"zscore":13.961},
{"experiment":30385,"c":20,"ratio":0.022,"stdev":0.349,"median":0.0405,"zscore":3.462},
{"experiment":30385,"c":21,"ratio":-0.076,"stdev":0.335,"median":-0.086,"zscore":-11.368},
{"experiment":30385,"c":22,"ratio":0.038,"stdev":0.355,"median":0.07,"zscore":3.152},
{"experiment":30385,"c":23,"ratio":0,"stdev":0,"median":0,"zscore":3.152},
{"experiment":30385,"c":24,"ratio":0,"stdev":0,"median":0,"zscore":3.152},
{"experiment":30384,"c":1,"ratio":-0.058,"stdev":0.403,"median":-0.042,"zscore":-14.154},
{"experiment":30384,"c":2,"ratio":-1.017,"stdev":0.418,"median":-0.982,"zscore":-360.857},
{"experiment":30384,"c":3,"ratio":-0.094,"stdev":0.417,"median":-0.074,"zscore":-30.964},
{"experiment":30384,"c":4,"ratio":-0.155,"stdev":0.397,"median":-0.157,"zscore":-54.593},
{"experiment":30384,"c":5,"ratio":-0.024,"stdev":0.381,"median":-0.001,"zscore":-8.125},
{"experiment":30384,"c":6,"ratio":0.013,"stdev":0.37,"median":0.0245,"zscore":7.455},
{"experiment":30384,"c":7,"ratio":-0.2,"stdev":0.434,"median":-0.171,"zscore":-56.706},
{"experiment":30384,"c":8,"ratio":-0.017,"stdev":0.367,"median":0.003,"zscore":-5.621},
{"experiment":30384,"c":9,"ratio":0.025,"stdev":0.365,"median":0.044,"zscore":6.818},
{"experiment":30384,"c":10,"ratio":-0.168,"stdev":0.422,"median":-0.121,"zscore":-44.158},
{"experiment":30384,"c":11,"ratio":-0.073,"stdev":0.382,"median":-0.056,"zscore":-22.067},
{"experiment":30384,"c":12,"ratio":0.002,"stdev":0.379,"median":0.019,"zscore":2.533},
{"experiment":30384,"c":13,"ratio":-0.054,"stdev":0.39,"median":-0.0295,"zscore":-8.375},
{"experiment":30384,"c":14,"ratio":0.019,"stdev":0.376,"median":0.025,"zscore":6.447},
{"experiment":30384,"c":15,"ratio":-0.054,"stdev":0.421,"median":-0.0265,"zscore":-11},
{"experiment":30384,"c":16,"ratio":0.055,"stdev":0.375,"median":0.0695,"zscore":8.297},
{"experiment":30384,"c":17,"ratio":0.024,"stdev":0.394,"median":0.054,"zscore":3.767},
{"experiment":30384,"c":18,"ratio":-0.049,"stdev":0.36,"median":-0.018,"zscore":-11.902},
{"experiment":30384,"c":19,"ratio":0.095,"stdev":0.37,"median":0.1135,"zscore":10.24},
{"experiment":30384,"c":20,"ratio":0.157,"stdev":0.343,"median":0.174,"zscore":29.423},
{"experiment":30384,"c":21,"ratio":-0.091,"stdev":0.407,"median":-0.067,"zscore":-14},
{"experiment":30384,"c":22,"ratio":0.071,"stdev":0.381,"median":0.104,"zscore":7.329},
{"experiment":30384,"c":23,"ratio":0,"stdev":0,"median":0,"zscore":7.329},
{"experiment":30384,"c":24,"ratio":0,"stdev":0,"median":0,"zscore":7.329}]
The data contains an experiment id, chromosome number, ratio and some satistics. The array can contain data from various experiments, which all have a different id.
my js code currently looks like this:
<script>
function unique(list) {
var result = [];
$.each(list, function(i, e) {
if ($.inArray(e, result) == -1) result.push(e);
});
return result;
}
var margin = {top: 50, right: 50, bottom: 50, left: 50};
var width = 1000 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var threshold={upper:0.1,lower:-0.1};
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("#svg").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.json("{{settings.Base_url}}/templates/addons/data.json", function(error, data) {
if (error) throw error;
var expNames =unique(data.map(function(d) { return d.experiment; }));
x0.domain(data.map(function(d) { return d.c; }));
x1.domain(expNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([-1.5,1.5]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -50)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Average Ratio/Chromosome");
var chr = svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(" + x0(d.c) + ",0)"; });
chr.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("x", function(d) {return x1(d.experiment);})
.attr("y", function(d) { return y(Math.max(0, d.ratio)); })
.attr("height", function(d) { return Math.abs(y(d.ratio)-y(0)); })
.attr("width", x1.rangeBand())
.style("fill", function(d) { return color(d.experiment); })
.style({"opacity":0.6,"stroke-width":"2"})
.text("test");
var legend = svg.selectAll(".legend")
.data(expNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
</script>
which results in a graph like this:
any ideas? I have a general idea where the error is, but cant seem to find a solution.
Note sure if I understand the question properly, but here's what I get:
You bind the data to the groups which you transform in x direction.
Afterwards you want to display two bars (for each experiment) in each group (c value)
If that's the case, you don't need to bind the data again for the bars, so it's just:
var chr = svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function (d) {
return "translate(" + x0(d.c) + ",0)";
});
chr.append("rect")
.attr("x", function (d) {
return x1(d.experiment);
})
...etc
See fiddle
Does that help?

How can I make a triple bar chart using D3?

The code below is working perfectly fine but I want to use another dataset. A dataset where the attributes are arrays themselves. They are structured likes this: [year, population, man, woman]. The year will be the X-axis and the other three will be displayed as bars next to each other. How can I make an triple bar chart? Where to start?
<script type="text/javascript">
//Width and height
var w = 500;
var h = 250;
var barPadding = 5;
//Dataset
var dataset = [10027, 10200, 10328, 10436, 10551, 10680, 10822, 10957, 11096, 11278,
11417, 11556, 11721, 11890 ];
//The other dataset
//[year, population, man, woman]
//var dataset = [[1950, 10027, 4998, 5029], [1950, 10027, 4998, 5029], [1950, 10027, 4998, 5029], etc];
//Scale
var x = d3.scale.ordinal().range([0, w])
var y = d3.scale.linear().range([h, 0]);
// Axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - (d / 50);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d / 50;
})
.attr("fill", function(d) {
return "rgb(102, 0, 51)";
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis)
.style("text-anchor", "end")
.text("Years");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.5em")
.style("text-anchor", "end")
.text("Population in millions");
</script>
(little question: why doesn't my x-axis appear?)
Thanks in advance
Towards your little question: your x- and y-axis get rendered, but outside of the svg visible space. The common way for dealing with this is to add a margin inside the svg and render the chart with the width and height inside of the margin. This is described by the author of D3 as conventional margin
I have created a snippet with what you call a tripple bar chart.
This code is the grouped barchart of Bostock applied to your dataset.
I changed the dataset a little bit, so that each year is an object with the properties population, men, women and year. With this setup it is easer to process the values.
The idea behind the code for the grouped bar chart is to add a group element for each object in your dataset and render the bars inside this group.
Therefore you bind the dataset to the year groups.
Inside the years selection, each element is bound to the corresponding object from your dataset array.
If this all doesn't make that much sense to you, maybe you should read the Let's make a Bar Chart tutorials by Bostock. They give a great overview on the basic steps ;)
var dataset = [{year:1950, population:10000, men:4500, women:5500}, {year:1951, population:10200, men:5000, women:6200}, {year:1952, population:11000, men:6000, women:5000}, {year:1953, population:12000, men:5900, women:6100}];
// setup conventional margin, see http://bl.ocks.org/mbostock/3019563
var margin = {top: 20, right: 30, bottom: 30, left: 60},
width = 700 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// accessor functions for the 4 values
var year = function(d) { return d.year; };
var population = function(d) { return d.population; };
var men = function(d) { return d.men; };
var women = function(d) { return d.women; };
var valueObject = function(d) { return [{name:"population", value:population(d)},{name:"men", value: men(d)}, {name: "women", value: women(d)}]; };
var color = d3.scale.ordinal()
.domain(["population","men","women"])
.range(["#31a354","#3182bd","#e6550d"]);
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .2)
.domain(dataset.map(year)); // use the year for the xAxis
var x1 = d3.scale.ordinal()
.domain(["population","men","women"])
.rangeRoundBands([0, x0.rangeBand()]);
var y = d3.scale.linear()
.range([height, 0])
.domain([0, d3.max(dataset.map(population))]); // use the population for calculating the maximum value
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
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.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
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("Population");
var years = svg.selectAll(".year")
.data(dataset)
.enter()
.append("g")
.attr("class", "year")
.attr("transform", function(d) { return "translate(" + x0(year(d)) + ",0)"; });
years.selectAll("rect")
.data(valueObject)
.enter()
.append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(["population","men","women"])
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Can d3.js / JavaScript update a text value like in a chart?

I've been searching around for a while now for a possible solution to this problem. I've created a bar chart for a company dashboard based on this graph.
http://bl.ocks.org/mbostock/3887051
This is working great, however what I would like to do now is display some of the external data that I have in text underneath the graph so for example. "Total Sales Today = ......" instead of just a monthly graph.
So I guess I'm asking is there a way to do this in d3.js using a text element or anything similar? if not pointing me to something that can would be great. Ill also add that the data is coming from a csv.
This is the code:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
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.csv("data.csv", function(error, data) {
var Names = d3.keys(data[0]).filter(function(key) { return key !== "Month"; });
data.forEach(function(d) {
d.Total = Names.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Month; }));
x1.domain(Names).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.Total, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
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("Sales Value £");
var text = svg.selectAll("text")
.data(data)
.enter()
.append("text");
var Month = svg.selectAll(".Month")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.Month) + ",0)"; });
Month.selectAll("rect")
.data(function(d) { return d.Total; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(Names.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
If you need any more info just say
Cheers!
In your HTML file, create a div for your chart and a div below that for your label
<div id="chart"></div>
<div id="label"></div>
In your d3 code, instead of appending an svg element to the body, select the "chart" div and append an svg element to it.
var svg = d3.select("#chart").append("svg"). ...
Use that svg element to draw your chart like in your above code.
At some point in your code calculate the total sales for the day and create a variable called totalSales. You could do this by summing up the sales value when you draw the chart, but it doesn't really matter as long as totalSales is calculated.
Create another svg element on the "label" div
var svgLabel = d3.select("#label").append("svg") ...
Use this svgLabel to write a text element with totalSales as the text attribute.
svg.append("text")
...
.text(totalSales);

Categories

Resources