I am drawing line chart but unable to figure out the scale for x-axies I am using ordinal scale because i am showing categories on x-axis here is the code for scaling. please let me know what i am doing wrong here.
var xScale = d3.scale.ordinal()
.domain(xExtents)
.range([padding, w - padding * 2]);
here is the sample code sorry for putting all javascript and HTML at one place.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script>
<style type="text/css">
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.y1 {
fill: white;
stroke: orange;
stroke-width: 1.5px;
}
.y2 {
fill: white;
stroke: red;
stroke-width: 1.5px;
}
.y3 {
fill: white;
stroke: steelblue;
stroke-width: 1.5px;
}
.line {
fill: none;
stroke-width: 1.5px;
}
div.tooltip {
position: absolute;
text-align: center;
width: 50px;
height: 10px;
padding: 5px;
font: 10px sans-serif;
background: whiteSmoke;
border: solid 1px #aaa;
pointer-events: none;
box-shadow: 2px 2px 1px #888;
}
.legend {
padding: 5px;
font: 10px sans-serif;
background: yellow;
box-shadow: 2px 2px 1px #888;
}
.title {
font: 13px sans-serif;
}
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 300;
var padding = 50;
var dataset = [
[
{x: "USA", y: 0},
{x: "UK", y: 0},
{x: "BRAZIL", y: 2},
{x: "KORIA", y: 0},
{x: "JAPAN", y: 0},
{x: "CHINA", y: 0}
],
[
{x: "USA", y: 3},
{x: "UK", y: 4},
{x: "BRAZIL", y: 1},
{x: "KORIA", y: 3},
{x: "JAPAN", y: 1},
{x: "CHINA", y: 2}
],
[
{x: "USA", y: 2},
{x: "UK", y: 0},
{x: "BRAZIL", y: 2},
{x: "KORIA", y: 3},
{x: "JAPAN", y: 4},
{x: "CHINA", y: 1}
]
];
var color_hash = { 0 : ["apple", "green"],
1 : ["mango", "orange"],
2 : ["cherry", "red"]
}
// Define axis ranges & scales
var yExtents = d3.extent(d3.merge(dataset), function (d) { return d.y; });
var xExtents = d3.extent(d3.merge(dataset), function (d) { return d.x; });
var xScale = d3.scale.ordinal()
.domain(xExtents)
.range([padding, w - padding * 2]);
var yScale = d3.scale.linear()
.domain([0, yExtents[1]])
.range([h - padding, padding]);
// Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// Define lines
var line = d3.svg.line()
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y1, d.y2, d.y3); });
var pathContainers = svg.selectAll('g.line')
.data(dataset);
pathContainers.enter().append('g')
.attr('class', 'line')
.attr("style", function(d) {
return "stroke: " + color_hash[dataset.indexOf(d)][1];
});
pathContainers.selectAll('path')
.data(function (d) { return [d]; }) // continues the data from the pathContainer
.enter().append('path')
.attr('d', d3.svg.line()
.x(function (d) { return xScale(d.x); })
.y(function (d) { return yScale(d.y); })
);
// add circles
pathContainers.selectAll('circle')
.data(function (d) { return d; })
.enter().append('circle')
.attr('cx', function (d) { return xScale(d.x); })
.attr('cy', function (d) { return yScale(d.y); })
.attr('r', 3);
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5);
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
//Add X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Add Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
// Add title
svg.append("svg:text")
.attr("class", "title")
.attr("x", 20)
.attr("y", 20)
.text("Fruit Sold Per Hour");
// add legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("x", w - 65)
.attr("y", 25)
.attr("height", 100)
.attr("width", 100);
legend.selectAll('g').data(dataset)
.enter()
.append('g')
.each(function(d, i) {
var g = d3.select(this);
g.append("rect")
.attr("x", w - 65)
.attr("y", i*25)
.attr("width", 10)
.attr("height", 10)
.style("fill", color_hash[String(i)][1]);
g.append("text")
.attr("x", w - 50)
.attr("y", i * 25 + 8)
.attr("height",30)
.attr("width",100)
.style("fill", color_hash[String(i)][1])
.text(color_hash[String(i)][0]);
});
</script>
</body>
</html>
If you want to show different categories on x axis (in your case, there are five countries with corresponding data), the x scale setting should be using rangeBands or rangeRoundBands for ordinal data. (see ordinal.rangeBands and ordinal.rangeRoundBands in official api documents).
var xScale = d3.scale.ordinal()
.domain(xExtents)
.rangeRoundBands([padding, w - padding * 2], 0.1);
range is often used with linear type of data. Hope this helps.
First Problem:
Use this https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js
Instead of this http://mbostock.github.com/d3/d3.js
Second Problem:
d3.extent(d3.merge(dataset), function (d) { return d.x; }
will return ["BRAZIL", "USA"]
You need all the unique countries.
var countries = d3.merge(dataset).map(function(d){return d.x});
countries = d3.set(countries).values();//unique countries
var xScale = d3.scale.ordinal()
.domain(countries)
.rangeBands([padding, w - padding * 2], 1);
this will return ["USA", "UK", "BRAZIL", "KORIA", "JAPAN", "CHINA"]
Last Problem:
var xScale = d3.scale.ordinal()
.domain(countries)
.rangeBands([padding, w - padding * 2], 1);//with ordinals we give range bands
Working code here
Hope this helps!
Related
I found a vertical stack bar graph sample on google - http://bl.ocks.org/juan-cb/43f10523858abf6053ae
I want to convert it in horizontal stacked bar graph. I have done the changes but something is wrong. Graph is not correct.I think all the bars are overlapped.
Please help me to resolve this. Code is copied.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
text{
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
.legend {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 60%;
}
text {
font: 10px sans-serif;
}
.axis text {
font: 10px sans-serif;
}
.axis path{
fill: none;
stroke: #000;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
</style>
<body>
<div class="barGraph" id='stacked-bar'></div>
<script src="http://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.7.0/d3-legend.min.js"></script>
<script>
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
init();
function init(){
var dataset = [{
"goodRating": 27,
"avgRating": 21,
"badRating": 16,
"rooms": "0.01"
},
{
"goodRating": 26,
"avgRating": 22,
"badRating": 31,
"rooms": "0.02"
},
{
"goodRating": 100,
"avgRating": 0,
"badRating": 0,
"rooms": "1"
}];
var groupSpacing = 6;
var margin = {top: 10, right: 10, bottom: 60, left: 100},
width = 1000 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var y = d3.scaleBand()
.range([height, 0]);
var x = d3.scaleLinear()
.range([0, width], .1,.3);
// var colorRange = d3.scale.category20();
var color = d3.scaleOrdinal(d3.schemeCategory20);
var xAxis = d3.axisBottom(x).tickFormat(dataset.rooms),
yAxis = d3.axisLeft(y);
var svg = d3.select("#stacked-bar").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 divTooltip = d3.select("body").append("div").attr("class", "toolTip");
color.domain(d3.keys(dataset[0]).filter(function(key) { return key !== "rooms"; }));
dataset.forEach(function(d) {
var y0 = 0;
var y1 = 0;
d.values = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.values[d.values.length - 1].y1;
});
y.domain(dataset.map(function(d) { return d.rooms; }));
x.domain([0, d3.max(dataset, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".5em")
.attr("transform", "rotate(-65)");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 9)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Satisfaction %");
var bar = svg.selectAll(".rooms")
.data(dataset)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + y(d.rooms) + ",0)"; });
svg.selectAll(".x.axis .tick text")
.call(wrap, y.bandwidth());
var bar_enter = bar.selectAll("rect")
.data(function(d) { return d.values; })
.enter();
bar_enter.append("rect")
.attr("height", y.bandwidth())
.attr("x", function(d) { return x(d.y1); })
.attr("width", function(d) { return x(d.y1) - x(d.y0) })
.style("fill", function(d) { return color(d.name); });
bar_enter.append("text")
.text(function(d) { return d3.format(".2s")(d.y1-d.y0)+"%"; })
.attr("x", function(d) { return x(d.y1)+(x(d.y0) - x(d.y1))/2; })
.attr("y", y.bandwidth()/3)
.style("fill", '#ffffff');
bar.on("mousemove", function(d){
divTooltip.style("left", d3.event.pageX+10+"px");
divTooltip.style("top", d3.event.pageY-25+"px");
divTooltip.style("display", "inline-block");
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l-1
element = elements[l].__data__
value = element.y1 - element.y0
divTooltip.html("Room No : "+(d.rooms)+"<br>"+element.name+" : "+value+"%");
});
bar.on("mouseout", function(d){
divTooltip.style("display", "none");
});
}
</script>
</body>
Regards,
Pinki Sharma
A few minor things were missing/incorrect:
The group (<g>) containing the bars was being transformed incorrectly (I'm guessing you missed this while changing from vertical stacked to horizontal) i.e. the following line
.attr("transform", function(d) { return "translate(" + y(d.rooms) + ",0)"; });
translates the bar groups from the left and the y position would be 0 and hence the overlap. I've changed that to this:
.attr("transform", function(d) { return "translate(0, " + y(d.rooms) + ")"; });
The rects' x value is changed from x(d.y1) to x(d.y0) (might be a typo)
bar_enter.append("rect")
.attr("height", y.bandwidth())
.attr("x", function(d) { return x(d.y0); })
Axis padding was missing for the scaleBand(). I've added that (check docs for more info)
var y = d3.scaleBand()
.rangeRound([height, 0]).padding(0.1);
Reset the margins to adapt to the SVG dimensions:
var margin = {top: 10, right: 60, bottom: 60, left: 50},
Combining all of the above, here's a fork of your codepen:
HORIZONTAL STACKED BAR CHART DEMO
Hope this helps.
I know it's little weird, I do have a requirement to have bar chart with fixed width instead of dynamic width handling. This is implemented with below code by handling x and width, now the spacing between the bars more when there is only few bars. So is there any possibility in d3 to render x axis values and chart in center of the axis line with fixed bar width and fixed spacing between bars?
bars.append('rect')
.attr('class', function(d,i) {
return 'bar';
})
.attr('id', function(d, i) {
return name+'-bar-'+i;
})
.attr('x', function(d) {
return xScale(d.month) + (xScale.rangeBand() - 15)/2;
})
.attr('width', function(){
return Math.min(xScale.rangeBand()-2, 15);
})
.attr('y', function(d) { return yScale(d.set.count); })
.attr('height', function(d) { return height - yScale(d.set.count); })
.on('click', function(d, i) {
//
});
fiddle
An easy way to do that is setting your xScale range dynamically:
var xScaleRange = data.length * 30;
var xScale = d3.scale.ordinal()
.rangeRoundBands([width / 2 - xScaleRange, width / 2 + xScaleRange], 0.2);
The magic number 30 here is simply twice the bar width.
Here is your code with that change:
// container size
var margin = {
top: 10,
right: 10,
bottom: 30,
left: 30
},
width = 600,
height = 300;
var data = [{
"month": "DEC",
"set": {
"count": 26,
"id": 1,
"label": "Set",
"year": "2016"
}
}, {
"month": "JAN",
"set": {
"count": 30,
"id": 1,
"label": "Set",
"year": "2017"
}
}, {
"month": "FEB",
"set": {
"count": 30,
"id": 1,
"label": "Set",
"year": "2017"
}
}];
var name = 'dashboard';
var xScaleRange = data.length * 30;
// x scale
var xScale = d3.scale.ordinal()
.rangeRoundBands([width / 2 - xScaleRange, width / 2 + xScaleRange], 0.2);
// set x and y scales
xScale.domain(data.map(function(d) {
return d.month;
}));
// x axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.outerTickSize(0);
var yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) {
return d.set.count;
})])
.range([height, 0]);
var ticks = yScale.ticks(),
lastTick = ticks[ticks.length - 1];
var newLastTick = lastTick + (ticks[1] - ticks[0]);
if (lastTick < yScale.domain()[1]) {
ticks.push(lastTick + (ticks[1] - ticks[0]));
}
// adjust domain for further value
yScale.domain([yScale.domain()[0], newLastTick]);
// y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.tickSize(-width, 0, 0)
.tickFormat(d3.format('d'))
.tickValues(ticks);
// create svg container
var svg = d3.select('#chart')
.append('svg')
.attr('class', 'd3-setup-barchart')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Horizontal grid (y axis gridline)
svg.append('g')
.attr('class', 'grid horizontal')
.attr("transform", "translate(" + (width / 2 - xScaleRange) + ",0)")
.call(d3.svg.axis()
.scale(yScale)
.orient('left')
.tickSize(-xScaleRange * 2, 0, 0)
.tickFormat('')
.tickValues(ticks)
);
// create bars
var bars = svg.selectAll('.bar')
.data(data)
.enter()
.append('g');
bars.append('rect')
.attr('class', function(d, i) {
return 'bar';
})
.attr('id', function(d, i) {
return name + '-bar-' + i;
})
.attr('x', function(d) {
return xScale(d.month) + (xScale.rangeBand() - 15) / 2;
})
.attr('width', function() {
return Math.min(xScale.rangeBand() - 2, 15);
})
.attr('y', function(d) {
return yScale(d.set.count);
})
.attr('height', function(d) {
return height - yScale(d.set.count);
})
.on('click', function(d, i) {
//
});
// draw x axis
svg.append('g')
.attr('id', name + '-x-axis')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
// draw y axis
svg.append('g')
.attr('class', 'y axis')
.attr("transform", "translate(" + (width / 2 - xScaleRange) + ",0)")
.call(yAxis)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end');
// remove 0 in y axis
svg.select('.y')
.selectAll('.tick')
.filter(function(d) {
return d === 0 || d % 1 !== 0;
}).remove();
svg
.select('.horizontal')
.selectAll('.tick')
.filter(function(d) {
return d === 0 || d % 1 !== 0;
}).remove();
.d3-setup-barchart {
background-color: #666666;
}
.d3-setup-barchart .axis path {
fill: none;
stroke: #000;
}
.d3-setup-barchart .bar {
fill: #ccc;
}
.d3-setup-barchart .bar:hover {
fill: orange;
cursor: pointer;
}
.d3-setup-barchart .bar.selected {
fill: orange;
stroke: #fff;
stroke-width: 2;
}
.d3-setup-barchart .label-text {
text-anchor: middle;
font-size: 12px;
font-weight: bold;
fill: orange;
opacity: 0;
}
.d3-setup-barchart .label-text.selected {
opacity: 1;
}
.d3-setup-barchart .axis text {
fill: rgba(255, 255, 255, 0.6);
font-size: 9px;
}
.d3-setup-barchart .axis-text.selected {
fill: orange;
}
.d3-setup-barchart .y.axis path {
display: none;
}
.d3-setup-barchart .y.axis text {
font-size: 6px;
}
.d3-setup-barchart .x.axis path {
fill: none;
stroke: #353C41;
}
.d3-setup-barchart .grid .tick {
stroke: #fff;
opacity: .18 !important;
stroke-width: 0;
}
.d3-setup-barchart .grid .tick line {
stroke-width: .5 !important;
}
.d3-setup-barchart .grid path {
stroke-width: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chart"></div>
How do I highlight an elliptical arc drawn, on mouseover and display tooltip on the same using d3.js?
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<style>
body { font: 10px sans-serif; }
.d3-tip {
background: rgba(0, 0, 0, 0.8);
border-radius: 2px;
color: #fff;
font-weight: bold;
line-height: 1;
padding: 12px;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var w = window.innerWidth,
h = window.innerHeight,
margin = { top: 40, right: 20, bottom: 20, left: 40 };
var svg = d3.select("body").append("svg").attr({
width: w,
height: h
});
var dataset = [
{ toolTip: "one", d: "M 50 200 a 100 50 0 1 1 250 50" },
{ toolTip: "two", d: "M 400 100 a 100 50 30 1 1 250 50" },
{ toolTip: "three", d: "M 400 300 a 100 50 45 1 1 250 50" },
{ toolTip: "four", d: "M 750 200 a 100 50 135 1 1 250 50" }
];
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Elipse:</strong> <span style='color:red'>" + d.toolTip + "</span>";
});
svg.selectAll("g")
.data(dataset)
.enter()
.append("g")
.attr("stroke-width", 3)
.attr("stroke", "black")
.attr("fill", "none")
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.append("path")
.attr("d", function(d) { return d.d })
.on('mouseover', highLight)
.on('mouseout', unHighLight);
svg.call(tip);
function highLight(){
var foo = d3.select(this);
foo.attr("stroke","red");
}
function unHighLight(){
var foo = d3.select(this);
foo.attr("stroke","black");
}
</script>
</body>
</html>
view block here
Using d3-tip to add tooltips to a d3 bar chart
Index.html:
Using d3-tip to add tooltips to a d3 bar chart.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: orange;
}
.bar:hover {
fill: orangered ;
}
.x.axis path {
display: none;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var margin = {top: 40, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(formatPercent);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:red'>" + d.frequency + "</span>";
})
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.call(tip);
d3.tsv("data.tsv", type, function(error, data) {
x.domain(data.map(function(d) { return d.letter; }));
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
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("Frequency");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
function type(d) {
d.frequency = +d.frequency;
return d;
}
</script>
Data.tsv
letter frequency
A .08167
B .01492
C .02780
D .04253
E .12702
F .02288
G .02022
H .06094
I .06973
J .00153
K .00747
L .04025
M .02517
N .06749
O .07507
P .01929
Q .00098
R .05987
S .06333
T .09056
U .02758
V .01037
W .02465
X .00150
Y .01971
Z .00074
Reference:
i have created a line chart using d3.js and added x and y grid in the chart. Only y-axis grid lines are coming and not x-axis grid lines.
I want to create grid like shown in the image below and a line at the top of y-axis, so it will look like perfect rectangle.
var data = [{
x: '1-May-12',
y: 5
}, {
x: '30-Apr-12',
y: 28
}, {
x: '27-Apr-12',
y: 58
}, {
x: '26-Apr-12',
y: 88
}, {
x: '25-Apr-12',
y: 8
}, {
x: '24-Apr-12',
y: 48
}, {
x: '23-Apr-12',
y: 28
}, {
x: '20-Apr-12',
y: 68
}, {
x: '19-Apr-12',
y: 8
}, {
x: '18-Apr-12',
y: 58
}, {
x: '17-Apr-12',
y: 5
}, {
x: '16-Apr-12',
y: 80
}, {
x: '13-Apr-12',
y: 38
}];
var margin = {
top: 30,
right: 20,
bottom: 35,
left: 50
},
width = 1200 - (margin.left + margin.right);
height = 360 - 2 * (margin.top + margin.bottom);
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
var xScale = d3.time.scale().range([0, width]);
var yScale = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(xScale)
.orient("bottom").ticks(0).tickSize(0)
.tickFormat("").outerTickSize(0);
var yAxis = d3.svg.axis().scale(yScale)
.orient("left").tickSize(0).ticks(0)
.tickFormat("");
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("class", "bg-color")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
function make_x_axis() {
return d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5)
}
// function for the y grid lines
function make_y_axis() {
return d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
}
svg.append("g")
.attr("class", "grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
);
// Draw the y Grid lines
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
);
xScale.domain(d3.extent(data, function(d) {
return parseDate(d.x);
}));
yScale.domain([0, d3.max(data, function(d) {
return d.y;
})]);
data.sort(function(a, b) {
return parseDate(a.x) - parseDate(b.x);
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Define the line
var lineGen = d3.svg.line()
.interpolate("monotone")
.x(function(d) {
return xScale(parseDate(d.x));
})
.y(function(d) {
return yScale(d.y);
});
svg.append('path')
.attr("class", "line")
.style("stroke", "red")
.attr('d', lineGen(data));
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 2;
shape-rendering: crispEdges;
}
.grid .tick {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
See another example on jsfiddle. https://jsfiddle.net/ermineia/cmqzh33x/
var data = [{
x: '1-May-12',
y: 5
}, {
x: '30-Apr-12',
y: 28
}, {
x: '27-Apr-12',
y: 58
}, {
x: '26-Apr-12',
y: 88
}, {
x: '25-Apr-12',
y: 8
}, {
x: '24-Apr-12',
y: 48
}, {
x: '23-Apr-12',
y: 28
}, {
x: '20-Apr-12',
y: 68
}, {
x: '19-Apr-12',
y: 8
}, {
x: '18-Apr-12',
y: 58
}, {
x: '17-Apr-12',
y: 5
}, {
x: '16-Apr-12',
y: 80
}, {
x: '13-Apr-12',
y: 38
}];
var margin = {
top: 30,
right: 20,
bottom: 35,
left: 50
},
width = 1200 - (margin.left + margin.right);
height = 360 - 2 * (margin.top + margin.bottom);
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y");
var xScale = d3.time.scale().range([0, width]);
var yScale = d3.scale.linear().range([height, 0]);
xScale.domain(d3.extent(data, function(d) {
return parseDate.parse(d.x);
}));
yScale.domain([0, d3.max(data, function(d) {
return d.y;
})]);
var xAxis = d3.svg.axis().scale(xScale)
.orient("bottom").ticks(0).tickSize(0)
.tickFormat("").outerTickSize(0);
var yAxis = d3.svg.axis().scale(yScale)
.orient("left").tickSize(0).ticks(0)
.tickFormat("");
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("class", "bg-color")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
function make_x_axis() {
return d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(25)
}
// function for the y grid lines
function make_y_axis() {
return d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(25);
}
svg.append("g")
.attr("class", "grid")
.call(make_x_axis()
.tickSize(height, 0, 0)
.tickFormat("")
);
// Draw the y Grid lines
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
);
data.sort(function(a, b) {
return parseDate.parse(a.x) - parseDate.parse(b.x);
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Define the line
var lineGen = d3.svg.line()
.interpolate("monotone")
.x(function(d) {
return xScale(parseDate.parse(d.x));
})
.y(function(d) {
return yScale(d.y);
});
svg.append('path')
.attr("class", "line")
.style("stroke", "red")
.attr('d', lineGen(data));
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 2;
shape-rendering: crispEdges;
}
.grid .tick {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I want to draw an xy multiseries linechart with d3.js. Thats ok.
But afterwards I want to scale the x-axes ordinal.
so thats the code of my xy linechart:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 12px Arial;
}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
padding: 5px;
font: 14px sans-serif;
background: black;
color: white;
border: 0px;
border-radius: 8px;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1px;
}
</style>
<body>
<script src="d3.js"></script>
<script src="jquery-2.1.4.js" charset="utf-8"></script>
<script>
var margin = {
top: 20,
right: 20,
bottom: 20,
left: 50
},
width = 1180 - margin.left - margin.right,
height = 580 - margin.top - margin.bottom;
var x = d3.scale.linear().rangeRound([0, width]);
var y = d3.scale.linear().rangeRound([height, 0]);
var linearScale = d3.scale.linear();
var xAxis = d3.svg.axis()
.scale(x)
.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 + ")");
/* var line = d3.svg.line()
.x(function(d) { console.log('x'+x(d.arbeitsgang));return x(d.arbeitsgang); })
.y(function(d) { console.log('y'+y(d.koordinaten));return y(d.koordinaten); });
*/
var line = d3.svg.line()
.x(function (d) {
return x(d.x);
})
.y(function (d) {
return y(d.y);
});
// Define 'div' for tooltips
var div = d3.select("body")
.append("div") // declare the tooltip div
.attr("class", "tooltip") // apply the 'tooltip' class
.style("opacity", 0); // set the opacity to nil
//d3.json("Arbeitsgang.json", function(error, data) {
var data = [
{
"key": "Paket 1",
"values": [
{
"x": 0,
"y": 40,
"arbeitsgang": "A1"
},
{
"x": 6,
"y": 30,
"arbeitsgang": "A2"
},
{
"x": 17,
"y": 20,
"arbeitsgang": "A3"
}
]
},
{
"key": "Paket 3",
"values": [
{
"x": 0,
"y": 85,
"arbeitsgang": "A1"
},
{
"x": 8,
"y": 50,
"arbeitsgang": "A2"
},
{
"x": 17,
"y": 89,
"arbeitsgang": "A3"
}
]
},
{
"key": "Paket 2",
"values": [
{
"x": 0,
"y": 45,
"arbeitsgang": "A1"
},
{
"x": 6,
"y": 145,
"arbeitsgang": "A1"
},
{
"x": 17,
"y": 53,
"arbeitsgang": "A1"
}
]
}
];
linearScale.domain(d3.keys(data[0]).filter(function (key) {
return key;
}));
x.domain([
d3.min(data, function (c) {
return d3.min(c.values, function (v) {
return v.x;
});
}),
d3.max(data, function (c) {
return d3.max(c.values, function (v) {
return v.x;
});
})
]);
y.domain([
d3.min(data, function (c) {
return d3.min(c.values, function (v) {
return v.y;
});
}),
d3.max(data, function (c) {
return d3.max(c.values, function (v) {
return v.y;
});
})
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var graphen = svg.selectAll(".graphen")
.data(data)
.enter().append("g")
.attr("class", "graphen");
var graph = graphen.append("path")
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
});
graph.on("mouseover", function (d) {
d3.select(this).style("stroke-width", 7);
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.key)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
div.style("visibility", "visible");
var selectthegraphs = $('.line').not(this); //select all the rest of the lines, except the one you are hovering on and drop their opacity
d3.selectAll(selectthegraphs)
.style("opacity", 0.2);
var selectcircles = $('.circle');
d3.selectAll(selectcircles)
.style("opacity", 0.2);
})
.on("mouseout", function () {
d3.select(this).style("stroke-width", 1);
div.transition()
.duration(500)
.style("opacity", 0.01);
div.style("visibility", "hidden");
var selectthegraphs = $('.line'); //select all the rest of the lines, except the one you are hovering on and drop their opacity
d3.selectAll(selectthegraphs)
.style("opacity",1);
var selectcircles = $('.circle');
d3.selectAll(selectcircles)
.style("opacity", 1);
});
graphen.each(function (p, j) {
d3.select(this).selectAll("circle")
.data(p.values)
.enter().append("circle")
.style("stroke", "black")
.style("fill", "white")
.attr("class","circle")
.attr("r", 5)
.attr("cx", function (d) {
return x(d.x);
})
.attr("cy", function (d) {
return y(d.y);
})
.on("mouseover", function (d) {
d3.select(this).transition().duration(500)
.attr("r", 10);
div.transition()
.duration(500)
.style("opacity", 0.9);
div.style("visibility", "visible");
div.html("X: " + d.x + "<br/>" + "Y: " + d.y + "<br/>" + "Arbeitsgang: " + d.arbeitsgang)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function (d) {
d3.select(this).transition().duration(500)
.attr("r", 5);
div.transition()
.duration(500)
.style("opacity", 0);
div.style("visibility", "hidden");
})
});
ok. but now I want the same graph with an ordinal scale.
The ticks shall be "data.values.arbeitsgang"
"arbeitsgang": "A1" for example.
please help me
Ordinal scales are not so tough.
var x = d3.scale.ordinal()
.domain(["A1","A2","A3"])
.rangeRoundPoints([0, width]);
The scale should now divide the range going from 0 to your width into 3 equally large parts. I choose for rangeRoundPoints because the values of the ticks are rounded to integers then and I like integers.
I believe you can customize the text of the x axis (of course using your ordinal scale to scale the axis), showing "Arbeitsgang:A1" for example, but I wouldn't know how to do that right on the top of my head.
For more information about ordinal scales, check out this link. Unless I totally misunderstood the question, I think this is the only thing you need.
I realize that I have hardcoded the values of the domain, but an array containing the values will do as well.