d3js graph plotting at incorrect coordinates - javascript

i was trying to draw simple d3js graph.I got through drawing the axis and even plotted the data but the data isn't appearing where it is expected to be.
As per my json data below
var d1 = [{
value1: "30",
value2: "10"
}];
i'm trying to plot a circle at coordinates x axis 30 and y axis 10but the circle on the graph appears some where else.
Here is the jsfiddle demo
Here is my code
var d1 = [{
value1: "30",
value2: "10"
}];
function Update(){
var circles = vis.selectAll("circle").data(d1)
circles
.enter()
.insert("svg:circle")
.attr("cx", function (d) { return d.value1; })
.attr("cy", function (d) { return d.value2; })
.style("fill", "red")
circles
.transition().duration(1000)
.attr("cx", function (d) { return d.value1; })
.attr("cy", function (d) { return d.value2; })
.attr("r", function (d) { return 5; })
circles.exit ()
.transition().duration(1000)
.attr("r", 0)
.remove ();
}
/*************************************************/
/*******************Real Stuff starts here*******************/
var vis = d3.select("#visualisation"),
WIDTH = 600,
HEIGHT = 400,
MARGINS = {
top: 20,
right: 20,
bottom: 20,
left: 50
},
xRange = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([0,100]),
yRange = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([0,300]),
xAxis = d3.svg.axis() // generate an axis
.scale(xRange) // set the range of the axis
.tickSize(5) // height of the ticks
.tickSubdivide(true), // display ticks between text labels
yAxis = d3.svg.axis() // generate an axis
.scale(yRange) // set the range of the axis
.tickSize(5) // width of the ticks
.orient("left") // have the text labels on the left hand side
.tickSubdivide(true); // display ticks between text labels
function init() {
vis.append("svg:g") // add a container for the axis
.attr("class", "x axis") // add some classes so we can style it
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")") // move it into position
.call(xAxis); // finally, add the axis to the visualisation
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
}
init();
$('#btn').click(function(){
Update();
});

It works if you
define the numbers as numbers and not as strings (i.e. value1: 30 instead of value1: "30") and
use the scales you define (i.e. return xRange(d.value1) instead of return d.value1).
Working jsfiddle here.

Your circle is appearing at pixel (30,10), but that doesn't correspond to the place 30,10 as labeled by your axes. Use your scales to set the point's location.
.attr("cx", function (d) { return xRange(d.value1); })
.attr("cy", function (d) { return yRange(d.value2); })

You will need to apply xScale and yScale to your coordinates to transform them into the plotting space.
See this jsFiddle
.attr("cx", function (d) { return xRange(d.value1); })
.attr("cy", function (d) { return yRange(d.value2); })

Actually it is working fine. It is just that top left corner is (0,0) and not bottom left (as I suspect, you must be assuming).
Set both x,y to 0. Circle will appear at top left corner.

Related

How do I draw gridlines in d3.js with zoom and pan

I have been able to make a scatter plot with zoom and pan functionality where the axes scale properly and everything works well. Now I am trying to figure out how to add gridlines, but running into some issues. I have started with only adding x-axis gridlines to figure things out. I have attached a fiddle with a working example to build from.
I commented out the initial gridlines when the graph is generated, because they would remain after zooming causing clutter, and I will add them back later when I get things working. When zooming the gridlines appear to be drawn correctly, but they do not match up with the x-axis labels, and the x-axis labels disappear after zooming or panning.
If you comment out line 163 and uncomment line 164 you can see the basic graph without any gridlines. Clicking the plot button will always generate a new graph. I have left behind some commented out code of different things that I have tried from searching through stackoverflow.
Example is using d3.js - 5.9.2
JSFiddle: https://jsfiddle.net/eysLvqkh/11/
HTML:
<div id="reg_plot"></div>
<button id="b" class="myButton">plot</button>
Javascript:
var theButton = document.getElementById("b");
theButton.onclick = createSvg;
function createSvg() {
// clear old chart when 'plot' is clicked
document.getElementById('reg_plot').innerHTML = ""
// dimensions
var margin = {top: 20, right: 20, bottom: 30, left: 55},
svg_dx = 1200,
svg_dy =600,
chart_dx = svg_dx - margin.right - margin.left,
chart_dy = svg_dy - margin.top - margin.bottom;
// data
var y = d3.randomNormal(400, 100);
var x_jitter = d3.randomUniform(-100, 1400);
var d = d3.range(1000)
.map(function() {
return [x_jitter(), y()];
});
// fill
var colorScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[1]; }))
.range([0, 1]);
// y position
var yScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[1]; }))
.range([chart_dy, margin.top]);
// x position
var xScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[0]; }))
.range([margin.right, chart_dx]);
// y-axis
var yAxis = d3.axisLeft(yScale);
// x-axis
var xAxis = d3.axisBottom(xScale);
// append svg to div element 'reg_plot' and set zoom to our function named 'zoom'
var svg = d3.select("#reg_plot")
.append("svg")
.attr("width", svg_dx)
.attr("height", svg_dy);
svg.call(d3.zoom().on("zoom", zoom));
// clip path - sets boundaries so points will not show outside of the axes when zooming/panning
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr('width', chart_dx)
.attr('height', chart_dy);
// plot data
var circles = svg.append("g")
.attr("id", "circles")
.attr("transform", "translate(75, 0)")
.attr("clip-path", "url(#clip)")
.selectAll("circle")
.data(d)
.enter()
.append("circle")
.attr("r", 4)
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.style("fill", function(d) {
var norm_color = colorScale(d[1]);
return d3.interpolateInferno(norm_color)
});
// add y-axis
var y_axis = svg.append("g")
.attr("id", "y_axis")
.attr("transform", "translate(75,0)")
.call(yAxis).style("font-size", "10px")
// add x-axis
var x_axis = svg.append("g")
.attr("id", "x_axis")
.attr("transform", `translate(${margin.left}, ${svg_dy - margin.bottom - margin.top})`)
.call(xAxis).style("font-size", "10px")
// add x and y grid lines
x_axis.call(xAxis.scale(xScale).ticks(20).tickSize(-chart_dy));
y_axis.call(yAxis.scale(yScale).ticks(20).tickSize(-chart_dx));
function zoom(e) {
// re-scale y axis during zoom
y_axis.transition()
.duration(50)
.call(yAxis.scale(d3.event.transform.rescaleY(yScale)));
// re-scale x axis during zoom
x_axis.transition()
.duration(50)
.call(xAxis.scale(d3.event.transform.rescaleX(xScale)));
// re-draw circles using new scales
var new_xScale = d3.event.transform.rescaleX(xScale);
var new_yScale = d3.event.transform.rescaleY(yScale);
// re-scale axes and gridlines
x_axis.call(xAxis.scale(new_xScale).ticks(20).tickSize(-chart_dy));
y_axis.call(yAxis.scale(new_yScale).ticks(20).tickSize(-chart_dx));
circles.data(d)
.attr('cx', function(d) {return new_xScale(d[0])})
.attr('cy', function(d) {return new_yScale(d[1])});
}
}
For anyone looking, I have solved this problem. I have updated the javascript in the original post, and updated the jsfiddle. If you are copying this code to your local machine where you are using d3.js 7.4.4 or higher then you need to change the lines that say d3.event.transform.... to just e.transform.

Creating a zoom function in D3

I have a function where that when a button is pressed (Several buttons the represent several animal types), that animal types SVG is updated with its corresponding data. I'm trying to replicate this zoom function but am having issues implementing it with my code. There are several SVGs that are used globally like this (one for each animal type):
let x = d3.scaleLinear()
.domain([0, 1000])
.range([ 0, width ]);
var xAxis = d3.axisBottom(x);
svgReptile.append("g")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
const yAxis = d3.scaleLinear()
.domain([0, 220])
.range([ height, 0])
svgReptile.append("g")
.call(d3.axisLeft(yAxis))
The function below is called when one of the animal buttons is pressed.
function update(animal, whatSVG, xAxis, yAxis, color) {
const points = whatSVG
.selectAll("circle")
.data(data);
points.enter()
.append("circle")
.attr("cx", function(d) {
return xAxis(d.state);
})
.attr("cy", function(d) {
return yAxis(d.percentage);
})
.merge(points)
.attr("r", 3)
.attr("cx", function(d) {
return xAxis(d.decade)
})
.attr("cy", function(d) {
return yAxis(d.count)
})
.style("fill", function (d) { return colour(d.animal) } );
points.exit()
.attr('r', 0)
.remove();
}
Question:
How can I implement a zoom feature that expands the x-axis when zoomed (or anything similar) like the one linked above?
I think you're looking for a 'brush zoom' from the last line of your question.
The following source code if from an example in a d3 graph gallery
The cross hair allows you to select an area to expand. If you follow the link there is a graph above it that is entitled "Zoom with axis" but it doesn't zoom in the way you've described, it just moves the axis, but doesn't enlarge the graph contents with it. Perhaps both will be useful!
Hope this helps
// set the dimensions and margins of the graph
var margin = {top: 10, right: 20, bottom: 20, left: 20},
width = 500 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var Svg = d3.select("#brushZoom")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv", function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([4, 8])
.range([ 0, width ]);
var xAxis = Svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 9])
.range([ height, 0]);
Svg.append("g")
.call(d3.axisLeft(y));
// Add a clipPath: everything out of this area won't be drawn.
var clip = Svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("width", width )
.attr("height", height )
.attr("x", 0)
.attr("y", 0);
// Color scale: give me a specie name, I return a color
var color = d3.scaleOrdinal()
.domain(["setosa", "versicolor", "virginica" ])
.range([ "#440154ff", "#21908dff", "#fde725ff"])
// Add brushing
var brush = d3.brushX() // Add the brush feature using the d3.brush function
.extent( [ [0,0], [width,height] ] ) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
.on("end", updateChart) // Each time the brush selection changes, trigger the 'updateChart' function
// Create the scatter variable: where both the circles and the brush take place
var scatter = Svg.append('g')
.attr("clip-path", "url(#clip)")
// Add circles
scatter
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d.Sepal_Length); } )
.attr("cy", function (d) { return y(d.Petal_Length); } )
.attr("r", 8)
.style("fill", function (d) { return color(d.Species) } )
.style("opacity", 0.5)
// Add the brushing
scatter
.append("g")
.attr("class", "brush")
.call(brush);
// A function that set idleTimeOut to null
var idleTimeout
function idled() { idleTimeout = null; }
// A function that update the chart for given boundaries
function updateChart() {
extent = d3.event.selection
// If no selection, back to initial coordinate. Otherwise, update X axis domain
if(!extent){
if (!idleTimeout) return idleTimeout = setTimeout(idled, 350); // This allows to wait a little bit
x.domain([ 4,8])
}else{
x.domain([ x.invert(extent[0]), x.invert(extent[1]) ])
scatter.select(".brush").call(brush.move, null) // This remove the grey brush area as soon as the selection has been done
}
// Update axis and circle position
xAxis.transition().duration(1000).call(d3.axisBottom(x))
scatter
.selectAll("circle")
.transition().duration(1000)
.attr("cx", function (d) { return x(d.Sepal_Length); } )
.attr("cy", function (d) { return y(d.Petal_Length); } )
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id="brushZoom"></div>

d3.js Multi-series line chart interactive (tsv into literal data)

I have a question. How should I redo this example (http://bl.ocks.org/DStruths/9c042e3a6b66048b5bd4) which uses a .tsv file to instead utilize a script with literal data?
So far I have done the following: http://codepen.io/Balzzac/pen/MJorXw?editors=0010 , but nothing works.
My code:
var dataset = [here is 15000 raws of original data converted into JSON, using http://codebeautify.org/tsv-to-json-converter]
var margin = {top: 20, right: 200, bottom: 100, left: 50},
margin2 = { top: 430, right: 10, bottom: 20, left: 40 },
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var bisectDate = d3.bisector(function(d) { return d.date; }).left;
var xScale = d3.time.scale()
.range([0, width]),
xScale2 = d3.time.scale()
.range([0, width]); // Duplicate xScale for brushing ref later
var yScale = d3.scale.linear()
.range([height, 0]);
// 40 Custom DDV colors
var color = d3.scale.ordinal().range(["#48A36D", "#56AE7C", "#64B98C", "#72C39B", "#80CEAA", "#80CCB3", "#7FC9BD", "#7FC7C6", "#7EC4CF", "#7FBBCF", "#7FB1CF", "#80A8CE", "#809ECE", "#8897CE", "#8F90CD", "#9788CD", "#9E81CC", "#AA81C5", "#B681BE", "#C280B7", "#CE80B0", "#D3779F", "#D76D8F", "#DC647E", "#E05A6D", "#E16167", "#E26962", "#E2705C", "#E37756", "#E38457", "#E39158", "#E29D58", "#E2AA59", "#E0B15B", "#DFB95C", "#DDC05E", "#DBC75F", "#E3CF6D", "#EAD67C", "#F2DE8A"]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom"),
xAxis2 = d3.svg.axis() // xAxis for brush slider
.scale(xScale2)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return xScale(d.date); })
.y(function(d) { return yScale(d.rating); })
.defined(function(d) { return d.rating; }); // Hiding line value defaults of 0 for missing data
var maxY; // Defined later to update yAxis
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom) //height + margin.top + margin.bottom
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Create invisible rect for mouse tracking
svg.append("rect")
.attr("width", width)
.attr("height", height)
.attr("x", 0)
.attr("y", 0)
.attr("id", "mouse-tracker")
.style("fill", "white");
//for slider part-----------------------------------------------------------------------------------
var context = svg.append("g") // Brushing context box container
.attr("transform", "translate(" + 0 + "," + 410 + ")")
.attr("class", "context");
//append clip path for lines plotted, hiding those part out of bounds
svg.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
//end slider part-----------------------------------------------------------------------------------
// d3.tsv("data.tsv", function(error, data)
function render(data){
color.domain(d3.keys(data[0]).filter(function(key) { // Set the domain of the color ordinal scale to be all the csv headers except "date", matching a color to an issue
return key !== "date";
}));
data.forEach(function(d) { // Make every date in the csv data a javascript date object format
d.date = parseDate(d.date);
});
var categories = color.domain().map(function(name) { // Nest the data into an array of objects with new keys
return {
name: name, // "name": the csv headers except date
values: data.map(function(d) { // "values": which has an array of the dates and ratings
return {
date: d.date,
rating: +(d[name]),
};
}),
visible: (name === "Unemployment" ? true : false) // "visible": all false except for economy which is true.
};
});
xScale.domain(d3.extent(data, function(d) { return d.date; })); // extent = highest and lowest points, domain is data, range is bouding box
yScale.domain([0, 100
//d3.max(categories, function(c) { return d3.max(c.values, function(v) { return v.rating; }); })
]);
xScale2.domain(xScale.domain()); // Setting a duplicate xdomain for brushing reference later
//for slider part-----------------------------------------------------------------------------------
var brush = d3.svg.brush()//for slider bar at the bottom
.x(xScale2)
.on("brush", brushed);
context.append("g") // Create brushing xAxis
.attr("class", "x axis1")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
var contextArea = d3.svg.area() // Set attributes for area chart in brushing context graph
.interpolate("monotone")
.x(function(d) { return xScale2(d.date); }) // x is scaled to xScale2
.y0(height2) // Bottom line begins at height2 (area chart not inverted)
.y1(0); // Top line of area, 0 (area chart not inverted)
//plot the rect as the bar at the bottom
context.append("path") // Path is created using svg.area details
.attr("class", "area")
.attr("d", contextArea(categories[0].values)) // pass first categories data .values to area path generator
.attr("fill", "#F1F1F2");
//append the brush for the selection of subsection
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("height", height2) // Make brush rects same height
.attr("fill", "#E6E7E8");
//end slider part-----------------------------------------------------------------------------------
// draw line graph
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("x", -10)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Issues Rating");
var issue = svg.selectAll(".issue")
.data(categories) // Select nested data and append to new svg group elements
.enter().append("g")
.attr("class", "issue");
issue.append("path")
.attr("class", "line")
.style("pointer-events", "none") // Stop line interferring with cursor
.attr("id", function(d) {
return "line-" + d.name.replace(" ", "").replace("/", ""); // Give line id of line-(insert issue name, with any spaces replaced with no spaces)
})
.attr("d", function(d) {
return d.visible ? line(d.values) : null; // If array key "visible" = true then draw line, if not then don't
})
.attr("clip-path", "url(#clip)")//use clip path to make irrelevant part invisible
.style("stroke", function(d) { return color(d.name); });
// draw legend
var legendSpace = 450 / categories.length; // 450/number of issues (ex. 40)
issue.append("rect")
.attr("width", 10)
.attr("height", 10)
.attr("x", width + (margin.right/3) - 15)
.attr("y", function (d, i) { return (legendSpace)+i*(legendSpace) - 8; }) // spacing
.attr("fill",function(d) {
return d.visible ? color(d.name) : "#F1F1F2"; // If array key "visible" = true then color rect, if not then make it grey
})
.attr("class", "legend-box")
.on("click", function(d){ // On click make d.visible
d.visible = !d.visible; // If array key for this data selection is "visible" = true then make it false, if false then make it true
maxY = findMaxY(categories); // Find max Y rating value categories data with "visible"; true
yScale.domain([0,maxY]); // Redefine yAxis domain based on highest y value of categories data with "visible"; true
svg.select(".y.axis")
.transition()
.call(yAxis);
issue.select("path")
.transition()
.attr("d", function(d){
return d.visible ? line(d.values) : null; // If d.visible is true then draw line for this d selection
})
issue.select("rect")
.transition()
.attr("fill", function(d) {
return d.visible ? color(d.name) : "#F1F1F2";
});
})
.on("mouseover", function(d){
d3.select(this)
.transition()
.attr("fill", function(d) { return color(d.name); });
d3.select("#line-" + d.name.replace(" ", "").replace("/", ""))
.transition()
.style("stroke-width", 2.5);
})
.on("mouseout", function(d){
d3.select(this)
.transition()
.attr("fill", function(d) {
return d.visible ? color(d.name) : "#F1F1F2";});
d3.select("#line-" + d.name.replace(" ", "").replace("/", ""))
.transition()
.style("stroke-width", 1.5);
})
issue.append("text")
.attr("x", width + (margin.right/3))
.attr("y", function (d, i) { return (legendSpace)+i*(legendSpace); }) // (return (11.25/2 =) 5.625) + i * (5.625)
.text(function(d) { return d.name; });
// Hover line
var hoverLineGroup = svg.append("g")
.attr("class", "hover-line");
var hoverLine = hoverLineGroup // Create line with basic attributes
.append("line")
.attr("id", "hover-line")
.attr("x1", 10).attr("x2", 10)
.attr("y1", 0).attr("y2", height + 10)
.style("pointer-events", "none") // Stop line interferring with cursor
.style("opacity", 1e-6); // Set opacity to zero
var hoverDate = hoverLineGroup
.append('text')
.attr("class", "hover-text")
.attr("y", height - (height-40)) // hover date text position
.attr("x", width - 150) // hover date text position
.style("fill", "#E6E7E8");
var columnNames = d3.keys(data[0]) //grab the key values from your first data row
//these are the same as your column names
.slice(1); //remove the first column name (`date`);
var focus = issue.select("g") // create group elements to house tooltip text
.data(columnNames) // bind each column name date to each g element
.enter().append("g") //create one <g> for each columnName
.attr("class", "focus");
focus.append("text") // http://stackoverflow.com/questions/22064083/d3-js-multi-series-chart-with-y-value-tracking
.attr("class", "tooltip")
.attr("x", width + 20) // position tooltips
.attr("y", function (d, i) { return (legendSpace)+i*(legendSpace); }); // (return (11.25/2 =) 5.625) + i * (5.625) // position tooltips
// Add mouseover events for hover line.
d3.select("#mouse-tracker") // select chart plot background rect #mouse-tracker
.on("mousemove", mousemove) // on mousemove activate mousemove function defined below
.on("mouseout", function() {
hoverDate
.text(null) // on mouseout remove text for hover date
d3.select("#hover-line")
.style("opacity", 1e-6); // On mouse out making line invisible
});
function mousemove() {
var mouse_x = d3.mouse(this)[0]; // Finding mouse x position on rect
var graph_x = xScale.invert(mouse_x); //
//var mouse_y = d3.mouse(this)[1]; // Finding mouse y position on rect
//var graph_y = yScale.invert(mouse_y);
//console.log(graph_x);
var format = d3.time.format('%b %Y'); // Format hover date text to show three letter month and full year
hoverDate.text(format(graph_x)); // scale mouse position to xScale date and format it to show month and year
d3.select("#hover-line") // select hover-line and changing attributes to mouse position
.attr("x1", mouse_x)
.attr("x2", mouse_x)
.style("opacity", 1); // Making line visible
// Legend tooltips // http://www.d3noob.org/2014/07/my-favourite-tooltip-method-for-line.html
var x0 = xScale.invert(d3.mouse(this)[0]), /* d3.mouse(this)[0] returns the x position on the screen of the mouse. xScale.invert function is reversing the process that we use to map the domain (date) to range (position on screen). So it takes the position on the screen and converts it into an equivalent date! */
i = bisectDate(data, x0, 1), // use our bisectDate function that we declared earlier to find the index of our data array that is close to the mouse cursor
/*It takes our data array and the date corresponding to the position of or mouse cursor and returns the index number of the data array which has a date that is higher than the cursor position.*/
d0 = data[i - 1],
d1 = data[i],
/*d0 is the combination of date and rating that is in the data array at the index to the left of the cursor and d1 is the combination of date and close that is in the data array at the index to the right of the cursor. In other words we now have two variables that know the value and date above and below the date that corresponds to the position of the cursor.*/
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
/*The final line in this segment declares a new array d that is represents the date and close combination that is closest to the cursor. It is using the magic JavaScript short hand for an if statement that is essentially saying if the distance between the mouse cursor and the date and close combination on the left is greater than the distance between the mouse cursor and the date and close combination on the right then d is an array of the date and close on the right of the cursor (d1). Otherwise d is an array of the date and close on the left of the cursor (d0).*/
//d is now the data row for the date closest to the mouse position
focus.select("text").text(function(columnName){
//because you didn't explictly set any data on the <text>
//elements, each one inherits the data from the focus <g>
return (d[columnName]);
});
};
//for brusher of the slider bar at the bottom
function brushed() {
xScale.domain(brush.empty() ? xScale2.domain() : brush.extent()); // If brush is empty then reset the Xscale domain to default, if not then make it the brush extent
svg.select(".x.axis") // replot xAxis with transition when brush used
.transition()
.call(xAxis);
maxY = findMaxY(categories); // Find max Y rating value categories data with "visible"; true
yScale.domain([0,maxY]); // Redefine yAxis domain based on highest y value of categories data with "visible"; true
svg.select(".y.axis") // Redraw yAxis
.transition()
.call(yAxis);
issue.select("path") // Redraw lines based on brush xAxis scale and domain
.transition()
.attr("d", function(d){
return d.visible ? line(d.values) : null; // If d.visible is true then draw line for this d selection
});
};
}; // End Data callback function
function findMaxY(data){ // Define function "findMaxY"
var maxYValues = data.map(function(d) {
if (d.visible){
return d3.max(d.values, function(value) { // Return max rating value
return value.rating; })
}
});
return d3.max(maxYValues);
}
render(dataset);
date should be a string. Thanks to:
https://github.com/d3/d3/issues/2543

Ordinal scale's rangeRoundBands()

I'm building a bar chart that will have a varied number of data points. All the examples I've seen use an ordinal scale for the x axis, then call rangeRoundBands() to get the width for the bars.
I'm getting the error "Uncaught TypeError: Cannot read property '1' of undefined" when I try to called .rangeRoundBands() and as far as I can tell I'm setting the scale up properly.
http://jsfiddle.net/rLzbbec0/1/
var globOb = {
bar: {
height: 390,
width: 675,
innerHeight: 300,
innerWidth: 615,
margin: {
bottom: 70,
left: 40,
right: 20,
top: 20
}
},
barData: [
{ task: "meetingsTask", val: 2.5 },
{ task: "reportsTask", val: 3 },
{ task: "emailsTask", val: 2 },
{ task: "planningTask", val: 1.5 },
{ task: "clientsTask", val: 4 },
{ task: "dataAnalysisTask", val: 3 }
]};
//Set X Scale
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, globOb.bar.innerWidth], .05, .1);
xScale.domain(globOb.barData.map(function(d) {
return d.task
}));
//Set Y Scale
var yScale = d3.scale.linear()
.domain([0, d3.max(globOb.barData, function(d) {
return d.val + 1
})])
.range([globOb.bar.innerHeight, 0]);
//Grab SVG and set dimensions
var svg = d3.select("#viewport").append("svg")
.attr("width", globOb.bar.width)
.attr("height", globOb.bar.height);
//Set the drawing area of the SVG
var inner = svg.append("g")
.attr("transform", "translate(" + globOb.bar.margin.left + "," +
globOb.bar.margin.top + ")")
.attr("width", globOb.bar.innerWidth)
.attr("height", globOb.bar.innerHeight);
//Setup Axes
var xAxis = d3.svg.axis()
.scale(xScale)
.innerTickSize(0)
.outerTickSize(-globOb.bar.innerHeight)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.innerTickSize(-globOb.bar.innerWidth)
.outerTickSize(-globOb.bar.innerWidth)
.orient("left");
//Add X Axis
inner.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (globOb.bar.innerHeight) + ")")
.call(xAxis);
//Add Y axis
inner.append("g")
.attr("class", "axis")
.attr("transform", "translate(0,0)")
.call(yAxis);
//draw data
inner.selectAll("bar")
.data(globOb.barData)
.enter()
.append("rect")
.attr("class", function(d) {
return d.task.substring(0, d.task.length - 4) + "-bar"
})
.attr("x", function(d) {
return xScale(d.task)
})
.attr("width", 50) //xScale.rangeRoundBands())
.attr("y", function(d) {
return yScale(d.val)
})
.attr("height", function(d) {
return globOb.bar.innerHeight - yScale(d.val)
});
console.log(xScale.rangeRoundBands());
In the fiddle I have changed the call of rangeRoundBands() to a set number to show the chart otherwise draws fine. At the end I'm using console.log() to show the error with .rangeRoundBands().
ordinal.rangeRoundBands is a configuration setter, and you cannot call it without arguments, so it generates an error while trying to access the second item x[1] (indexed from zero) in the first argument x. You can take a look at the source.
You probably want to use ordinal.rangeBand() instead, which:
Returns the band width. When the scale’s range is configured with rangeBands or rangeRoundBands, the scale returns the lower value for the given input. The upper value can then be computed by offsetting by the band width. If the scale’s range is set using range or rangePoints, the band width is zero.

d3js graph retaining old axis data on refreshing with new data

Here is a picture of my problem
Every time try to refresh my d3js graph with new data, its x axis and y axis gets messed up with both old and new axis.In the picture on the y axis 3,2.5,2,1.5 .... was my old axis and 800,700,600.....was my new axis.Similarly with the x axis
Can any one tell me wat i'm doing wrong.I only want the new axis to show up.
Here is my d3js code.
function ShowGraph(data) {
var vis = d3.select("#visualisation"),
WIDTH = 500,
HEIGHT = 500,
MARGINS = {
top: 20,
right: 20,
bottom: 20,
left: 30
},
xRange = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(data, function (d) {
return d.year;
}),
d3.max(data, function (d) {
return d.year;
})]),
yRange = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(data, function (d) {
return d.count;
}),
d3.max(data, function (d) {
return d.count;
})]),
xAxis = d3.svg.axis() // generate an axis
.scale(xRange) // set the range of the axis
.tickSize(5) // height of the ticks
.tickSubdivide(true), // display ticks between text labels
yAxis = d3.svg.axis() // generate an axis
.scale(yRange) // set the range of the axis
.tickSize(5) // width of the ticks
.orient("left") // have the text labels on the left hand side
.tickSubdivide(true); // display ticks between text labels
var transition = vis.transition().duration(1000).ease("exp-in-out");
transition.select(".x.axis").call(xAxis);
transition.select(".y.axis").call(yAxis);
vis.append("svg:g") // add a container for the axis
.attr("class", "x axis") // add some classes so we can style it
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")") // move it into position
.call(xAxis); // finally, add the axis to the visualisation
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
var circles = vis.selectAll("circle").data(data)
circles.enter()
.append("svg:circle")
.attr("cx", function (d) {
return xRange(d.year);
})
.attr("cy", function (d) {
return yRange(d.count);
})
.style("fill", "red")
circles.transition().duration(1000)
.attr("cx", function (d) {
return xRange(d.year);
})
.attr("cy", function (d) {
return yRange(d.count);
})
.attr("r", 10)
circles.exit()
.transition().duration(1000)
.attr("r", 10)
.remove();
}
Here is it have a look. link Try with word "the,and,i,and,the" one at a time
Try to empty the axis before build the graph
function ShowGraph(data) {
d3.selectAll('.axis').remove();
var vis = d3.select("#visualisation"),
//...
EDIT
OK maybe I found the solution
The problem is the axis that appends every time to call the function.
So, if you add a check like so:
var hasAxis = vis.select('.axis')[0][0];
if(!hasAxis) {
vis.append("svg:g") // add a container for the axis
.attr("class", "x axis") // add some classes so we can style it
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")") // move it into position
.call(xAxis); // finally, add the axis to the visualisation
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
}
it should works

Categories

Resources