Y-axis transition results in changing side - javascript

I'm having a bizarre d3 issue wherein my y-axis transition results in the axis switching sides. Besides that, I am happy with how the transition looks. A gif that demonstrates the issue is available at https://i.imgflip.com/g4kdc.gif. I have followed a few examples including http://bl.ocks.org/mbostock/4323929, but can't seem to figure out the issue.
var dataset = [{
"year_decided": 1982,
"Total": 0
}, //some more data
{
"year_decided": "2000",
"Total": "310"
}]; // default dataset that we can access and override
var margin = {
top: 30,
right: 20,
bottom: 20,
left: 35
};
var w = $("#section").width() - margin.left - margin.right;
var h = $("#section").height() - margin.top - margin.bottom;
///create the default scales
var xScale = d3.scale.linear()
.domain([0,dataset.length])
.range([0,w]);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset,function(d){ return +d.Total }) ])
.range([h,0]);
// create the axes
var xAxis = d3.svg.axis()
.scale(xScale)
.tickSize(6, 0)
.orient("bottom")
.tickFormat(function(d,i){
return d + 1982;
});
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("right")
.tickSize(w);
//define the svg and add it to the document
var svg = d3.select("#section").append("svg")
.attr("width",w + margin.left + margin.right)
.attr("height",h + margin.top + margin.bottom)
.attr("id", "main-chart");
svg.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
//add an axis group and add the y axis
var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.call(customAxis)
var gx = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + margin.left + "," + h + ")")
.call(xAxis);
//create the line
var line = d3.svg.line()
.x(function(d, i){ return xScale(i) })
.y(function(d){ return yScale(+d.Total) })
.interpolate("linear");
svg.append('path')
.classed('data-line', true)
.attr('d', line(dataset))
.attr("transform", "translate(" + margin.left + ",0)");
//create the tooltip
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5)
.attr("transform", "translate(" + margin.left + ",0)")
;
var tool_tip_year = focus.append("text")
.attr("x", 9)
.attr("dy", ".35em")
.attr("transform", "translate(" + margin.left + ",0)")
;
var tool_tip_total = focus.append("text")
.attr("x", 9)
.attr("dy", "1.8em")
.attr("transform", "translate(" + margin.left + ",0)")
;
svg.append("rect")
.attr("class", "overlay")
.attr("width", w)
.attr("height", h)
.attr("transform", "translate(" + margin.left + ",0)")
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
var bisectIndex = d3.bisector(function(d, i) { return i; }).left;
function mousemove() {
var x0 = xScale.invert(d3.mouse(this)[0]),
i = Math.round(x0),
d = dataset[i];
focus.attr("transform", "translate(" + xScale(i) + "," + yScale(+d.Total) + ")");
tool_tip_year.text(1982 + i);
tool_tip_total.text(d3.format(",")(+d.Total));
}
function customAxis(g){
g.selectAll("text")
.attr("x",4)
.attr("dy",-4);
}
//update the graph following http://bl.ocks.org/d3noob/7030f35b72de721622b8
$("#submission").submit(function(){
//define url to request
var submission = "php/data.php?word=" + $("#submission-text").val();
//request json and save as dataset
d3.json(submission, function(error, json) {
if (error) return console.warn(error);
dataset = json;
//rescale the graphs
xScale = d3.scale.linear()
.domain([0,dataset.length])
.range([0,w]);
yScale = d3.scale.linear()
.domain([0, d3.max(dataset,function(d){ return +d.Total }) ])
.range([h,0]);
gy.transition()
.duration(2500)
.call(yAxis);
gy.call(customAxis);
svg.select(".data-line")
.transition()
.duration(2000)
.attr("d",line(dataset));
})
});

Related

Inserting two separate charts on one page D3.js v4

In Bellow code I am trying to use separate charts (i.e. Bar and line chart) and getting Error: attribute d: Expected number, "MNaN,116LNaN,117L…"
Tried with using different SVG elements for both charts. Give some suggestions if I am missing something.
If I commenting Bar chart code then Line chart works properly and same works with the Bar chart but both at a same time doesn't work.
<div>
<div>Simple Bar Chart</div>
<div class="simpleBar">
<svg width="960" height="500"></svg>
</div>
</div>
<div>
<div>Line Chart</div>
<div id="lineGraph"></div>
</div>
<script>
// --------------- Bar chart code starts -----------------------
var svg = d3.select(".simpleBar > svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var tooltip = d3.select("body").append("div").attr("class", "toolTip");
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
var colours = d3.scaleOrdinal()
.range(["#6F257F", "#CA0D59"]);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("dataSample.json", function(error, data) {
if (error) throw error;
x.domain(data.map(function(d) { return d.Timestamp; }));
y.domain([0, d3.max(data, function(d) { return d.DayTotal; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(5).tickFormat(function(d) { return parseInt(d) + "Rs"; }).tickSizeInner([-width]))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 1)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.attr("fill", "#5D6971")
.text("Average Expence(Rs)");
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("x", function(d) { return x(d.Timestamp); })
.attr("y", function(d) { return y(d.DayTotal); })
.attr("width", x.bandwidth())
.attr("height", function(d) { return height - y(d.DayTotal); })
.attr("fill", function(d) { return colours(d.Timestamp); })
.on("mousemove", function(d){
tooltip
.style("left", d3.event.pageX - 50 + "px")
.style("top", d3.event.pageY - 70 + "px")
.style("display", "inline-block")
.html((d.Timestamp) + "<br>" + "Rs" + (d.DayTotal));
})
.on("mouseout", function(d){ tooltip.style("display", "none");});
});
// --------------- Line chart code starts -----------------------
// parse the Timestamp / time
var parseTime = d3.timeParse("%d-%b-%y");
// set the ranges
var xLine = d3.scaleTime().range([0, width]);
var yLine = d3.scaleLinear().range([height, 0]);
// define the line
var valueline = d3.line()
.x(function(d) { return x(d.Timestamp); })
.y(function(d) { return y(d.DayTotal); });
var svgLine = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svgLine = d3.select("#lineGraph").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.json("dataSample.json", function(error, data) {
if (error) throw error;
// format the data
data.forEach(function(d) {
d.Timestamp = parseTime(d.Timestamp);
d.DayTotal = +d.DayTotal;
});
// Scale the range of the data
xLine.domain(d3.extent(data, function(d) { return d.Timestamp; }));
yLine.domain([0, d3.max(data, function(d) { return d.DayTotal; })]);
// Add the valueline path.
svgLine.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline);
// Add the X Axis
svgLine.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xLine).ticks(5));
// Add the Y Axis
svgLine.append("g")
.call(d3.axisLeft(yLine));
});
</script>
and bellow is the Json data format:
[
{
"DayTotal": "418",
"Timestamp": "15-Mar-18"
},{...}
]
You are supposed to use xLine, yLine in your d3 line function whereas you used the ones(x, y) that you meant for bar charts.
var valueline = d3.line()
.x(function(d) { return xLine(d.Timestamp); })
.y(function(d) { return yLine(d.DayTotal); });
Solved JSFiddle

D3 with Meteor Error :: Returns y=0 and heights are same

I am using this http://bl.ocks.org/mbostock/3885304 reference for drawing Bar Char using Meteor and D3
This code returns y Axis is 0 and height always same.....
CODE PART
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var yScale = d3.scale.linear()
.range([height, 0]);
var xAxis =d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
var svg = d3.select('#Rectangle')
.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 drawCircles = function(error,update) {
if (error) throw error;
var data = Extra.find().fetch();
xScale.domain(data.map(function(d) { return d.inst; }));
yScale.domain([0, d3.max(data, function(d) { return d.percent; })]);
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("Percentaz");
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr("x", function(d) { return xScale(d.inst); })
.attr("y", function(d) { return yScale(d.percent); })
.attr("width", xScale.rangeBand())
.attr("height", function(d) { return height-yScale(d.percent); });
};
Extra.find().observe({
added: function () {
x =[];
var f = Extra.find().fetch() ;
for(var i=0;i<f.length;i++){
x.push(parseInt(f[i].percent))
}
drawCircles(false);
},
changed: _.partial(drawCircles, true)
});
};
Please provide me solution regarding this so i can implement it

D3 Bar chart. Values not aligned with Y axis

I am facing an issue while plotting values. The bars go beyond Y-Axis.
<div id = "Bar1">
<script>
var margin1 = {top: 40, right: 20, bottom: 30, left: 40},
width1 = 460 //- margin.left - margin.right,
height1 = 200 //- margin.top - margin.bottom;
var formatPercent1 = d3.format("");
var x1 = d3.scale.ordinal()
.rangeRoundBands([0, width1], 0);
//.rangeRoundBands([width1, 0);
var y1 = d3.scale.linear()
.range([height1, 0]);
var xAxis1 = d3.svg.axis()
.scale(x1)
.orient("bottom");
var yAxis1 = d3.svg.axis()
.scale(y1)
.orient("left")
.tickFormat(formatPercent1);
var tip1 = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:red'>" + d.frequency + "</span>";
})
var svg1 = d3.select("#Bar1").append("svg")
.attr("width", width1 + margin1.left + margin1.right)
.attr("height", height1 + margin1.top + margin1.bottom)
.append("g")
.attr("transform", "translate(" + margin1.left + "," + margin1.top + ")");
svg1.call(tip1);
d3.tsv(data, type, function(error, data1) {
x1.domain(data1.map(function(d) { return d.letter; }));
y1.domain([0, d3.max(data1, function(d) { return d.frequency; })]);
svg1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height1 + ")")
.call(xAxis1);
svg1.append("g")
.attr("class", "y axis")
.call(yAxis1)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
svg1.selectAll(".bar")
.data(data1)
.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 height1 - y(d.frequency); })
.on('mouseover', tip1.show)
.on('mouseout', tip1.hide)
});
function type(d) {
d.frequency = +d.frequency;
return d;
}
</script>
</div>
The CSV:
letter frequency
django 12
dictionary 33
C 55
D 100
E 90
F 300
G 80
H 10
I 0
J 0
Can Anyone please help me out with this code. I am not understanding why this is an issue.
The X and Y axis are scaled too. Is there something that i have missed out?
Thanks,
Sriram
You must have a mistake elsewhere than in the code you sent. I just put it to JSFiddle and it works correctly:
var tsv = "letter frequency\n" +
"django 12\n" +
"dictionary 33\n" +
"C 55\n" +
"D 100\n" +
"E 90\n" +
"F 300\n" +
"G 80\n" +
"H 10\n" +
"I 0\n" +
"J 0";
var margin1 = {top: 40, right: 20, bottom: 30, left: 40},
width1 = 460 //- margin.left - margin.right,
height1 = 200 //- margin.top - margin.bottom;
var formatPercent1 = d3.format("");
var x1 = d3.scale.ordinal()
.rangeRoundBands([0, width1], 0);
//.rangeRoundBands([width1, 0);
var y1 = d3.scale.linear()
.range([height1, 0]);
var xAxis1 = d3.svg.axis()
.scale(x1)
.orient("bottom");
var yAxis1 = d3.svg.axis()
.scale(y1)
.orient("left")
.tickFormat(formatPercent1);
var svg1 = d3.select("#Bar1").append("svg")
.attr("width", width1 + margin1.left + margin1.right)
.attr("height", height1 + margin1.top + margin1.bottom)
.append("g")
.attr("transform", "translate(" + margin1.left + "," + margin1.top + ")");
var data1 = d3.tsv.parse(tsv, type)
x1.domain(data1.map(function(d) { return d.letter; }));
y1.domain([0, d3.max(data1, function(d) { return d.frequency; })]);
svg1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height1 + ")")
.call(xAxis1);
svg1.append("g")
.attr("class", "y axis")
.call(yAxis1)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
svg1.selectAll(".bar")
.data(data1)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x1(d.letter); })
.attr("width", x1.rangeBand())
.attr("y", function(d) { return y1(d.frequency); })
.attr("height", function(d) { return height1 - y1(d.frequency); })
function type(d) {
d.frequency = +d.frequency;
return d;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id='Bar1'></div>
In your snippet, you are referring to x scale as x variable, while you actually save it in x1. The same goes for y and y1 variables. That's corrected in my snippet.
Other than that, I changed the TSV loading from d3.tsv to d3.tsv.parse, but that's just skipping the AJAX fetch of the resource. I also removed the d3.tip tooltip, but again, that shouldn't change the barchart itself.
From the looks of your image, I'd guess you're not converting the frequency to Number but leave it as a String. But that's just a guess, you might want to show the actual code that's giving you trouble.

How to apply the the enter() and data() methods for ds3 in-memory data

I have loaded data from a WebSocket connection into an array variable "data". I can see the 50 elements in the array and they do have the correct map elements.
The following snippet works properly: at the end the "data" elements have all rows transformed:
data.forEach(function (d) {
d[date] = parseDate(d[date]);
d[close] = +d[close];
});
Now, how to apply this data array to the internal d3 "values" so that the subsequent d3 dom manipulations use that data? In the next snippet I have made the attempt based on the examples / blogs I had seen:
var svg = d3.select("body").selectAll("svg")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
/* The following is NOT the correct place/way to do it.. need help here! */
.data(data)
.enter()
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
UPDATE Well I just tried moving those two data(data) and .enter() lines around - now placing them right after the selectAll().
var svg = d3.select("body").selectAll("svg")
.data(data)
.enter()
.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 + ")")
The results? Well we do have data now ! Maybe too much of a good thing?
EDIT Here is the entire function
function updateD3(data) {
var WIDTH = 1800, HEIGHT = 800;
var margin = {top: 120, right: 20, bottom: 120, left: 100},
width = WIDTH - margin.left - margin.right,
height = HEIGHT - margin.top - margin.bottom;
var parseDate = d3.time.format("%m-%d-%Y %H").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom").ticks(31);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.x(function (d) {
return x(d[date]);
})
.y(function (d) {
return y(d[close]);
});
var myNode = document.body;
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
}
var len = data.length;
console.log("data size=" + len + " date: " + data[0][date] + " close: " + data[0][close]
+ " last value: date: " + data[len-1][date] + " close: " + data[len-1][close]);
var date = "CALL_HOUR";
var close = "DROPPED_CALL";
data.forEach(function (d) {
d[date] = parseDate(d[date]);
d[close] = +d[close];
});
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 + ")");
x.domain(d3.extent(data, function (d) {
return d[date];
}));
y.domain(d3.extent(data, function (d) {
return d[close];
}));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-1.1em")
.attr("dy", ".15em")
.attr("transform", function (d) {
return "rotate(-65)"
});
svg.append("text") // text label for the x axis
.attr("x", width / 2)
.attr("y", height + margin.bottom)
.style("text-anchor", "middle")
.style("font-size", "14px")
.text("Call Date");
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("Dropped Calls");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "20px")
.style("text-decoration", "underline")
.text("No. of Dropped Calls vs Date Line Chart");
}
By biding your data to svg elements, you are creating as many svg elements as you have data items. I suspect that is not what you want. I created this FIDDLE exemplifying what you are doing but also showing how to bind the data to a single g.
Part of fiddle with data under a single g:
var data = [10,20,30];
var svg = d3.select("body")
.append("svg")
.attr("class","oneSvg")
.attr("width", 100)
.attr("height",100)
.append("g")
.attr("transform", "translate(0,0)");
circles = svg.selectAll("circle")
.data(data);
circles
.enter()
.append("circle")
.attr("cx",function (d) {return d;})
.attr("cy",20)
.attr("r",5)
.style("fill","blue");

D3js Strange Drawing Focus + Context via Brushing

I have implemented the Drawing Focus + Context via Brushing diagram to display the chi-square results, but the drawing of the results in d3 are strange (check image below at 7 AM).
Also below the image I have included the code which draws the diagram.
ChiSquare Image
var chiSquare = function(config,data,d3){
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 20, left: 40},
width = 1127 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%b %Y").parse;
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.timestamp_unix); })
.y0(height)
.y1(function(d) { return y(d.chiSquare); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d.timestamp_unix); })
.y0(height2)
.y1(function(d) {return y2(d.chiSquare); });
var svg = d3.select(config.selector).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
x.domain(d3.extent(data,(function(d) { return d.timestamp_unix; })));
y.domain([0, d3.max(data, (function(d) { return d.chiSquare; }))]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.timestamp_unix = parseDate(d.timestamp_unix);
d.chiSquare = +d.chiSquare;
return d;
}
//end class
}
I can't see anything wrong in the code, so I assume that the problem is from D3js but I don't know where to look, any ideas?

Categories