D3 assign colors to specific series - javascript

I want to assign two colors to two series in my data so that when I sort ascending or descending, the colors remain the same for each group.
The data is pulled programmatically from web map features. I thought I could get away with using an alternating function to assign colors but this doesn't work if I use sorting. I am trying to find a proper way to assign colors specifically to the series.
The data I am using has OL and NOL as two groups. You can see below how it is structured.
jsfiddle
relevant code:
var values = feature.properties;
var data = [
{name:"N11OL",value:values["N11OL"]},
{name:"N11NOL",value:values["N11NOL"]},
{name:"N21OL",value:values["N21OL"]},
{name:"N21NOL",value:values["N21NOL"]},
{name:"N22OL",value:values["N22OL"]},
{name:"N22NOL",value:values["N22NOL"]},
{name:"N23OL",value:values["N23OL"]},
{name:"N23NOL",value:values["N23NOL"]},
{name:"N31_33OL",value:values["N31_33OL"]},
{name:"N31_33NOL",value:values["N31_33NOL"]},
{name:"N41OL",value:values["N41OL"]},
{name:"N41NOL",value:values["N41NOL"]}
];
var Colors = ["#a6cee3", "#1f78b4"]
var margin = {top: 40, right: 2, bottom: 30, left: 180},
width = 400 - margin.left - margin.right,
height = 575 - margin.top - margin.bottom,
barHeight = height / data.length;
// Scale for X axis
var x = d3.scale.linear()
.domain([0, d3.max(data, function(d){return d.value;})])
.range([0, width]);
var y = d3.scale.ordinal()
.domain(["NAICS11", "NAICS21", "NAICS22", "NAICS23", "NAICS31-33", "NAICS41"])
.rangeRoundBands([0, height]);
//y axis
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.outerTickSize(0);
var svg = d3.select(div).select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.classed("chart", true);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var bar = svg.selectAll("g.bar")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
bar.append("rect")
.attr("width", function(d){return x(d.value);})
.attr("fill", function(d, i) {return Colors[i % 2]; }) //Alternate colors
.attr("height", barHeight - 1);
bar.append("text")
.attr("class", "text")
.attr("x", function(d) { return x(d.value) - 3; })
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) { return d.value; })
.attr("fill", "white")
.attr("font-family", "sans-serif")
.attr("font-size", "14px")
.attr("text-anchor", "end");
svg.append("text")
.attr("class", "title")
.attr("x", width/7)
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.text("Employment by industry " + "(Total OL: " + feature.properties.IndOLTot + ")");

Starting at Line 241 in your jsFiddle
bar.append("rect")
.attr("width", function(d){return x(d.value);})
.attr("fill", function(d, i) {
if(d.name.indexOf("NOL") > -1) {
//return Colors[0];
return "red";
} else {
//return Colors[1];
return "black";
}
}) //Alternate colors
.attr("height", barHeight - 1);
This checks the name property for the substring "NOL". If the name contains "NOL" it uses the first color, if "NOL" is not found it uses the second color for a fill.
(I'm under the assumption that the series is determined by the name)

Related

How I can scale x-axis of graph with time format containing milliseconds using d3.js?

I want to generate heat-map using d3.js by using csv data. For heat-map plotting I'm trying to set x-axis,y-axis and z-axis. But I'm facing issues while setting x-axis of the graph.
sample csv data :
var csv_data = "date,bucket,count\n07:31:01 001,10000,12\n07:31:01 119,50000,13\n07:31:01 128,60000,53\n07:31:01 200,90000,24\n07:31:01 555,75000,56";
program code-
<script>
var margin = {top: 20, right: 90, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse,
formatDate = d3.time.format("%b %d");
//
var x = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
z = d3.scale.linear().range(["white", "steelblue"]);
// The size of the buckets in the CSV data file.
// This could be inferred from the data if it weren't sparse.
var xStep = 864e5,
yStep = 100;
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 csv_data = "date,bucket,count\n07:31:01 001,10000,12 005\n07:31:01 119,50000,13\n07:31:01 128,60000,53";
var buckets = d3.csv.parse(csv_data);
buckets.forEach(function(d) {
d.date = d.date;
d.bucket = +d.bucket;
d.count = +d.count;
});
x.domain(d3.extent(buckets, function(d) { return d.date; }));
y.domain(d3.extent(buckets, function(d) { return d.bucket; }));
z.domain([0, d3.max(buckets, function(d) { return d.count; })]);
// Extend the x- and y-domain to fit the last bucket.
// For example, the y-bucket 3200 corresponds to values [3200, 3300].
x.domain([x.domain()[0], +x.domain()[1] + xStep]);
y.domain([y.domain()[0], y.domain()[1] + yStep]);
// Display the tiles for each non-zero bucket.
svg.selectAll(".tile")
.data(buckets)
.enter().append("rect")
.attr("class", "tile")
.attr("x", function(d) { return x(d.date); })
.attr("y", function(d) { return y(d.bucket + yStep); })
.attr("width", x(xStep) - x(0))
.attr("height", y(0) - y(yStep))
.style("fill", function(d) { return z(d.count); });
// Add a legend for the color values.
var legend = svg.selectAll(".legend")
.data(z.ticks(6).slice(1).reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(" + (width + 20) + "," + (20 + i * 20) + ")"; });
legend.append("rect")
.attr("width", 20)
.attr("height", 20)
.style("fill", z);
legend.append("text")
.attr("x", 26)
.attr("y", 10)
.attr("dy", ".35em")
.text(String);
svg.append("text")
.attr("class", "label")
.attr("x", width + 20)
.attr("y", 10)
.attr("dy", ".35em")
.text("Count");
// Add an x-axis with label.
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.svg.axis().scale(x).orient("bottom"))
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.attr("text-anchor", "end")
.text("Time");
// Add a y-axis with label.
svg.append("g")
.attr("class", "y axis")
.call(d3.svg.axis().scale(y).orient("left"))
.append("text")
.attr("class", "label")
.attr("y", 6)
.attr("dy", ".71em")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
.text("Latency");
</script>
Currently Graph is showing like this :
How I can set x-axis of graph with data whatever into the string? what I'm missing here?
The x axis represents a time scale. You need to pass in valid date objects instead of strings. In your particular example, this would become:
buckets.forEach(function(d) {
d.date = timeFormat.parse(d.date);
d.bucket = +d.bucket;
d.count = +d.count;
});
where timeFormat is a d3.time.format formatter:
var timeFormat = d3.time.format('%H:%M:%S %L');
To parse milliseconds you can use the following directive:
%L - milliseconds as a decimal number [000, 999].
In your CSV data, the dates should follow the specified format. for ex:
07:31:01 001,10000,12005
13:34:01 119,50000,13
17:39:01 128,60000,53
Here is a working jsfiddle:

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);

D3 bar chart with autosize

Good afternoon.
I need to automatic update the size of the chart.
My code is above.
My data is something like this, when the data is small i do not have problem but when it is big the values in xAxis and the bars are overlapping.
var data = [
{key:1, value:5},
{key:2, value:10},
{key:3, value:15},
{key:4, value:26},
{key:5, value:33}
];
var margin = {
top: 30,
right: 10,
bottom: 30,
left: 30
},
width = 900 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(data.map(function(d) {
return d.key;
}))
.rangeRoundBands([margin.left, width], 0.05);
var y = d3.scale.linear()
.domain([0, d3.max(data, function(d) {
return d.value;
})])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var key = function(d) {
return d.key;
};
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right + 10)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.text("Your tooltip info")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Log(number sts) vs Nodes - Gen" + " " + startGen + " "+"to" + " "+ endGen)
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(-30," + height + ")")
.call(xAxis)
.append("text")
.attr("x", width)
.attr("dy", 30)
.attr("text-anchor", "end")
.text("Number of nodes");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -30)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Log(Number Sts)");
var bars = svg.selectAll("rect")
.data(data, key)
.enter().append("rect")
.attr("x", function(d) {
return x(d.key) + x.rangeBand() / 2 - 40;
})
.attr("y", function(d) {
return y(d.value);
})
.attr("width", 20)
.attr("height", function(d) {
return height - y(d.value);
})
.style("fill", "blue");
If you want to size the chart according to how much data you have then you can simply replace your "width" variable with a calculation: something like:
width = Math.min(900, 20 * data.length);
But perhaps what you mean is to size the bars based on how much room there is? You are already using x.rangeBand that gives you the available range width - try using that for the bar width
...
.attr("width", x.rangeBand())
If you want to get fancy you can have finer control over the bar width and gap. Something like:
var barWidth = Math.max(1, 0.9 * x.rangeBand());
var halfGap = Math.max(0, x.rangeBand() - barWidth) / 2;
var bars = svg.selectAll("rect")
.data(data, key)
.enter().append("rect")
.attr("x", function(d) {
return x(d.key) + halfGap - 30 ;
})
.attr("width", barWidth)
...
You can try the fiddle here

Categories

Resources