I'm new to d3.js, and I'm getting a ReferenceError: x is not defined.
I'm just trying to draw a line of points.
var points = svg.selectAll('.dots')
.data(data)
.enter()
.append("g")
.attr("class", "dots");
points.selectAll('.dot')
.data(function (d, index)
{
var a = [];
d.values.forEach(function (values, i)
{
a.push({'x': values.x, 'y': values.y});
});
return a;
})
.enter()
.append('circle')
.attr('class', 'dot')
.attr("r", 2.5)
.attr('fill', function (d, i)
{
return colors[i];
})
.attr("transform", function (d)
{
/* Line 268: Uncaught ReferenceError: x is not defined */
return "translate(" + x(d.x) + "," + y(d.y) + ")";
}
);
In a lot of internet samples, I see x() and y() being used in translate/transform when drawing stuff. What am I doing wrong? I even have other code samples using this x() and y() and they're not throwing errors. I can't figure out the difference or what I'm missing.
d.x is actually a date, and d.y is a number.
If I change Line 268 to:
/* Removing x() and y() fixes the error: */
/* d.index increments from 0 up; assume this exists */
return "translate(" + d.index + "," + d.y + ")";
I get a perfectly working collection of points drawn (not a line actually, so not exactly what I need, but at least thousands of points show up and the data is being read correctly).
Got it, silly me, you have to define x and y:
var x = d3.time.scale()
.domain([
d3.min(activeData, function(d) { return d.x; }),
d3.max(activeData, function(d) { return d.x; })
])
.range([0, width]);
var y = d3.scale.linear()
.domain([
(d3.min(activeData, function(d) { return d.y; })),
d3.max(activeData, function(d) { return d.y; })
])
.range([height, 0]);
Related
I've been trying to get a pie chart to update and it works in CodePen but when I try to make it larger scale it completely fails.
This is the code I'm having trouble with:
var d2_data, d2_path, d2_pie, d2_text, d2_arc;
function D2_Update()
{
d2_data = [d2_employed,d2_student,d2_unemployed,d2_retired];
d2_path.data(d2_pie(d2_data))
.transition().duration(1000)
.attrTween("d", arcTween(null, d2_arc)); // Redraw the arcs
d2_text.data(d2_pie(d2_data))
.transition().duration(1000)
.attr("transform", function (d) {
return "translate(" + d2_arc.centroid(d) + ")";
})
.text(function(d){return d.data;});
}
function arcTween(a, arc) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
When this update function is called the text on the chart correctly updates--once--and then it fails to actually change the arcs like in the CodePen I linked above. All I get in return is a console error reading TypeError: r is not a function coming from my D3js JavaScript file.I am completely confused here because I'm not really sure what I should be doing differently.
Any help is appreciated in understanding my issue. I will also display my code for this graph pie chart:
// D2 pie
d2_data = [d2_employed,d2_student,d2_unemployed,d2_retired];
var d2_dataKey = ["Employed","Student","Unemployed","Retired"];
var d2_width = 400,
d2_height = 400,
d2_radius = Math.min(d2_width, d2_height) / 2;
d2_arc = d3.svg.arc()
.outerRadius(d2_radius - 10)
.innerRadius(d2_radius - 85);
d2_pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d;
});
var d2_svg = d3.select("#general_d2-graph").append("svg")
.attr("width", d2_width)
.attr("height", d2_height)
.append("g")
.attr("id", "pieChart")
.attr("transform", "translate(" + d2_width / 2 + "," + d2_height / 2 + ")");
d2_path = d2_svg.selectAll("path")
.data(d2_pie(d2_data))
.enter()
.append("path");
d2_text = d2_svg.selectAll("text")
.data(d2_pie(d2_data))
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("transform", function (d) {
return "translate(" + d2_arc.centroid(d) + ")";
})
.text(function(d){return d.data;});
d2_path.transition()
.duration(1000)
.attr("fill", function(d, i) {
return color(d.data);
})
.attr("d", d2_arc)
.each(function(d) {
this._current = d;
}); // Store the initial angles
Thank you.
I'm trying to plot a time scale using D3. However, the scatter points don't line up with the x-axis. They are offset slightly to the right. Any suggestions?
https://jsfiddle.net/kevinjhc/maaek6tb/1/
var data = [
{
date: "2016-05-22T09:33:57-04:00",
value: 80
}
]
var x = d3.time.scale()
.domain(d3.extent(data, function(d) { return new Date(d.date); }))
.range([ 0, width ]);
g.selectAll("scatter-dots")
.data(data)
.enter().append("svg:circle")
.attr("cx", function (d) { return x( new Date(d.date) ); } )
.attr("cy", function (d) { return y(d.value); } )
.attr("r", 8);
did some origin correction. The circles get drawn from the left-top co-ordiates... so u have to translate them to draw them from center:
g.selectAll("scatter-dots")
.data(data)
.enter().append("svg:circle")
.attr("cx", function (d) { return x( new Date(d.date) ); } )
.attr("cy", function (d) { return y(d.value); } )
.attr('transform', 'translate('+ -rad/2 + ',' + -rad/2 + ')')
.attr("r", rad);
check: https://jsfiddle.net/maaek6tb/3/
also corrected the focus lines... as they need to be translated accordingly too.
I have a set of circles defined as
nodes = [{
x: xRange(xvalue),
y: yRange(getY(xvalue)),
...
}]
vis.selectAll(".nodes")
.data(nodes)
.enter().append("circle")
.attr("class", "nodes")
.attr("cx", function (d) {
return d.x;
(coordinate display)
})
.attr("cy", function (d) {
return d.y;
})
.attr("r", "7px")
.attr("fill", "black")
.attr("transform", function (p) {
return "translate(" + p.x + "," + p.y + ")";
})
The problem that I am having with these circles is that the coordinates taken from nodes are undefined when the circles are being defined, despite being defined everywhere else. Here is a test case to represent this problem, where the coordinates of one of the dots should be displayed, but isn't, since it seems to be undefined. To prove that the axes work, I have placed a dot in the first quadrant of the graph. Is there any reason for why this is happening?
You're returning before you run the logic :
.attr("cx", function (d) {
return d.x;
(coordinate display)
})
change to :
.attr("cx", function (d) {
(coordinate display)
return d.x;
})
I am following two tutorials to make a map in TOPOJson :
Display countries, borders and cities (dot & labels). Tutorial here.
Move and zoom the map. Tutorial here.
I am able to display the pan, to pan, to zoom, but the names of the cities are not redrawn.
var path = d3.geo.path()
.projection(projection)
.pointRadius(2);
/* What's hapenning here ? */
var svg = d3.select("#vis").append("svg:svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().on("zoom", redraw));
/* Format projected 2D geometry appropriately for SVG or Canvas. */
d3.json("uk.json", function(error, uk) {
svg.selectAll(".subunit")
.data(topojson.feature(uk, uk.objects.subunits).features)
.enter().append("path")
.attr("class", function(d) { return "subunit " + d.id; })
.attr("d", path);
svg.append("path")
.datum(topojson.mesh(uk, uk.objects.subunits, function(a, b) { return a !== b && a.id !== "IRL"; }))
.attr("d", path)
.attr("class", "subunit-boundary");
svg.append("path")
.datum(topojson.mesh(uk, uk.objects.subunits, function(a, b) { return a === b && a.id === "IRL"; }))
.attr("d", path)
.attr("class", "subunit-boundary IRL");
svg.append("path")
.datum(topojson.feature(uk, uk.objects.places))
.attr("d", path)
.attr("class", "place");
svg.selectAll(".place-label")
.data(topojson.feature(uk, uk.objects.places).features)
.enter().append("text")
.attr("class", "place-label")
.attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
.attr("x", function(d) { return d.geometry.coordinates[0] > -1 ? 6 : -6; })
.attr("dy", ".35em")
.style("text-anchor", function(d) { return d.geometry.coordinates[0] > -1 ? "start" : "end"; })
.text(function(d) { return d.properties.name; });
svg.selectAll(".subunit-label")
.data(topojson.feature(uk, uk.objects.subunits).features)
.enter().append("text")
.attr("class", function(d) { return "subunit-label " + d.id; })
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.properties.name; });
});
function redraw() {
// d3.event.translate (an array) stores the current translation from the parent SVG element
// t (an array) stores the projection's default translation
// we add the x and y vales in each array to determine the projection's new translation
var tx = t[0] * d3.event.scale + d3.event.translate[0];
var ty = t[1] * d3.event.scale + d3.event.translate[1];
projection.translate([tx, ty]);
// now we determine the projection's new scale, but there's a problem:
// the map doesn't 'zoom onto the mouse point'
projection.scale(s * d3.event.scale);
// redraw the map
svg.selectAll("path").attr("d", path);
// redraw the labels
svg.selectAll(".place-label");
// redraw the x axis
xAxis.attr("x1", tx).attr("x2", tx);
// redraw the y axis
yAxis.attr("y1", ty).attr("y2", ty);
}
I have tried to add this line :
svg.selectAll(".place-label").attr("d", path);
in the redraw function but it did not worked.
Could you tell me which line should I add to refresh their positions ?
Here is my live code : Plunker live example & code
To make the labels move along with the map you need to do this:
On redraw function
svg.selectAll(".place-label")[0].forEach( function(d){
var data = d3.select(d).data()[0];//this will give you the text location data
d3.select(d).attr("transform", "translate("+projection(data.geometry.coordinates)+")" )//pass the location data here to get the new translated value.
});
For subunits do:
svg.selectAll(".subunit-label")
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
Working example here
Hope this works!
I have a scatter plot with a line of best fit. I want to draw vertical lines (residual error lines) from each data point to the regression line. How can I do this?
If possible, I would like to use a transition to rotate the line of best fit and have the error lines expand or contract as the line of best rotates. Any help would be greatly appreciated!
Edit:
As pointed out, I incorrectly said the data for my line was contained within "data"; however, the line is being drawn using an array called lin_reg_results that is structured as follows:
var lin_reg_results = [{'x':3.4,'y':4.6},{'x':3.6,'y',2.4}...]
lin_reg_results data points were created by performing a linear regression server side and then passing the results back with ajax.
var x = d3.scale.linear()
.domain(d3.extent(data, function(d) { return d[x_val]; }))
.range([0, width]);
var y = d3.scale.linear()
.domain(d3.extent(data, function(d) { return d[y_val]; }))
// PLOT THE DATA POINTS
svg.selectAll(".dot")
.data(data)
.enter()
.append("circle")
.attr("class", "dot")
.attr("transform", "translate("+50+"," + 10 + ")")
.attr("r", 2.5)
.attr("cx", function(d) { return x(d[x_val]); })
.attr("cy", function(d) { return y(d[y_val]); })
.style("fill", function(d) { return color(d[z_val]); });
// DRAW THE PATH
var x = d3.scale.linear()
.domain(d3.extent(data, function(d) { return d['x']; }))
.range([0, width]);
var y = d3.scale.linear()
.domain(d3.extent(data, function(d) { return d['y']; }))
var line = d3.svg.line()
.x(function(d) { return x(d['x']); })
.y(function(d) { return y(d['y']); })
.interpolate("linear");
svg.append("path")
.datum(lin_reg_results)
.attr("transform", "translate("+50+"," + 10 + ")")
.attr("id","regression_line")
.attr("class", "line")
.attr("d", line);
You need to append a line for each data point from the coordinates of that point to where it meets the line. The code would look something like the following (with some code adapted from this question):
d3.selectAll("line")
.data(data)
.enter()
.append("line")
.attr("x1", function(d) { return x(d[x_val]); })
.attr("x2", function(d) { return x(d[x_val]); })
.attr("y1", function(d) { return y(d[y_val]); })
.attr("y2", function(d) {
var line = d3.select("#regression_line").node(),
x = x(d[x_val]);
function getXY(len) {
return line.getPointAtLength(len);
}
var curlen = 0;
while (getXY(curlen).x < x) { curlen += 0.01; }
return getXY(curlen).y;
});