I got this piece of code in which the timeline updates his value by sliding(manually). Problem is That I got an error saying that projection is not a code. Can someone help me please.
Setting the size of the slider.
var margin = {
top: 50,
right: 90,
bottom: 50,
left: 50
},
width = 1000 - margin.left - margin.right,
height = 300 - margin.bottom - margin.top;
// scale function
var timeScale = d3.time.scale()
.domain([new Date('2016-01-01'), new Date('2016-12-31')])
.range([0, width])
.clamp(true);
// initial value
var startValue = timeScale(new Date('2012-03-20'));
startingValue = new Date('2016-08-12');
//////////
defines brush
var brush = d3.svg.brush()
.x(timeScale)
.extent([startingValue, startingValue])
.on("brush", brushed);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
// classic transform to position g
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
// put in middle of screen
.attr("transform", "translate(0," + height / 2 + ")")
// inroduce axis
.call(d3.svg.axis()
.scale(timeScale)
.orient("bottom")
.tickFormat(function(d) {
return formatDate(d);
})
.tickSize(0)
.tickPadding(12)
.tickValues([timeScale.domain()[0], timeScale.domain()[1]]))
.select(".domain")
.select(function() {
console.log(this);
return this.parentNode.appendChild(this.cloneNode(true));
})
.attr("class", "halo");
var slider = svg.append("g")
.attr("class", "slider")
.call(brush);
slider.selectAll(".extent,.resize")
.remove();
slider.select(".background")
.attr("height", height);
var handle = slider.append("g")
.attr("class", "handle")
handle.append("path")
.attr("transform", "translate(0," + height / 2 + ")")
.attr("d", "M 0 -20 V 20")
handle.append('text')
.text(startingValue)
.attr("transform", "translate(" + (-18) + " ," + (height / 2 - 25) + ")");
slider
.call(brush.event)
Sets the canvas with the projection.
var width = 1280;
var height = 900;
var projection = d3.geo.mercator()
.scale(200000)
.center([4.9, 52.36])
.translate([width / 2, height / 2]);
var canvas = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().on("zoom", function () {
canvas.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
}))
.append("g")
Logs the events of the day and the coordinates to the console.
function brushed() {
var value = brush.extent()[0];
console.log()
if (d3.event.sourceEvent) { // not a programmatic event
value = timeScale.invert(d3.mouse(this)[0]);
brush.extent([value, value]);
}
handle.attr("transform", "translate(" + timeScale(value) + ",0)");
handle.select('text').text(formatDate(value));
slidedate = (formatDate(value));
console.log(slidedate)
console.log("dit is datum" + slidedate)
dataCsv.forEach(function(d) {
//console.log("datum is" + slidedate)
if (slidedate == d.Datepattern_startdate) {
console.log(slidedate)
console.log(d.Title)
coords = projection([+d["Longitude"],+d["Latitude"]]);
console.log(coords);
var circle = canvas.append("circle")
.attr("cx", coords[0] )
.attr("cy", coords[1] )
.attr("r", "6px")
.attr("fill", "orange")
.style("opacity", .6)
.append("title")
.text(function(dataCsv) {return d.Title})
} else {
//console.log(" Werkt niet")
}
});
Error = mapm.html:272 Uncaught TypeError: projection is not a function.
Related
I am creating a visualisation using d3.js and svg images in PowerBi (this uses version 3 of d3).
I have got my visual working, however my legend is not rendering. I tested this in a browser, and the legend items appear in the elements of the page, but just aren't showing up.
My code for the legend items are
var pbi = {
width:1108,
height:636,
colors:[
"#A70240",
"#4A2366",
"#009A44",
"#A0D081",
"#01B5BB",
"#137B88",
"#5D6771",
"#CDC8C1"
]
var margin = {top: 20, right: 30, bottom: 30, left: 140},
width = pbi.width - margin.left - margin.right,
height = pbi.height - margin.top - margin.bottom,
legendleft = pbi.width - margin.right;
var ly = d3.scale.ordinal() // For legend
.rangeRoundBands([0, height], barPad, barOuterPad);
var svg = d3.select("#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
----
ly.domain(rData.map(function(d) { return d.milestone; })); // Legend
var milestoneMap = {}; // Maps years to colours
var legendArray = []; // For legend
rData.forEach(function (d) {
var entry = d.year;
var rowEntry = {
entry: entry, // Axis label
milestone: d.milestone, // For colour lookup
date: d.date, // For X position of points
y: y(entry)
}
if (!(d.milestone in milestoneMap)) {
// First occurrence of each year saved to legend
legendArray.push({milestone: d.milestone});
rowArray.push(rowEntry);
var legend = svg.append("g").attr("id", "legend")
.attr("transform", "translate(" + legendleft + "," + margin.top + ")").selectAll(null)
.data(legendArray)
.enter();
// Legend agency labels
legend.append("text")
.attr("class", "milestoneLabel")
.attr("x", 25)
.attr("y", function(d) { return ly(d.milestone)+5; })
.style("stroke", "black")
.style("stroke-width", .3)
.text(function(d) { return d.milestone; });
legend.append("circle")
.attr("class", "legend")
.attr("cx", 12)
.attr("cy", function(d) { return ly(d.milestone); })
.attr("r", 8)
.style("stroke", "black")
.style("stroke-width", 1)
.style("fill", function(d, i) { return milestoneMap[d.milestone]; });
This is omitting code that calculates all other elements.
Why is it that the legend circle and label is appearing as an element on the page but isn't rendering anything?
Thanks
Turns out, I just needed to add my legend left to my svg.
From
var svg = d3.select("#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
to
var svg = d3.select("#chart")
.attr("width", width + margin.left + margin.right + legendleft)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
I am using scaleBand() for both x and y axes for a bar chart. For some reason, the height of the bars are in between the ticks of the y axis. I would appreciate any help. Here is my code:
var margin_ = { top: 20, right: 20, bottom: 30, left: 40 },
width_ = 960 - margin_.left - margin_.right,
height_ = 500 - margin_.top - margin_.bottom;
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 x = d3.scaleBand()
.range([0, width_])
.padding(0.2)
var y = d3.scaleBand()
.range([height_, 0]);
x.domain(satisfactScaleKeyValues);
y.domain(graphYvalues);
svg_.selectAll(".bar")
.data(datas)
.enter().append("rect")
.attr("class", "bar__")
.attr("x", function (d) { return x(d.variable); })
.attr("width", x.bandwidth())
.attr("y", function (d) { return y(d.satisLevel); })
.attr("height", function (d) { return height_ - y(d.satisLevel); });
// add the x Axis
svg_.append("g")
.attr("transform", "translate(0," + height_ + ")")
.call(d3.axisBottom(x));
// add the y Axis
svg_.append("g")
.call(d3.axisLeft(y))
You should use d3.scalePoint, which would provide a better translation from an ordinal domain to linear points on a range:
let datas = [{variable: 1, satisLevel: "Neutral"}]
var margin_ = { top: 20, right: 50, bottom: 30, left: 75 },
width_ = 960 - margin_.left - margin_.right,
height_ = 500 - margin_.top - margin_.bottom;
var svg_ = d3.select("body").append("svg")
.attr("width", width_ + margin_.left + margin_.right)
.attr("height", height_ + margin_.top + margin_.bottom)
var g = svg_.append("g")
.attr("transform",
"translate(" + margin_.left + "," + margin_.top + ")");
var x = d3.scaleBand()
.range([0, width_])
.padding(0.2)
var y = d3.scalePoint()
.range([height_, 0])
.padding(0.2)
x.domain([1]);
y.domain(["Not satisfied", "Neutral", "Satisfied"]);
g.selectAll(".bar")
.data(datas)
.enter().append("rect")
.attr("class", "bar__")
.attr("x", function (d) { return x(d.variable); })
.attr("width", x.bandwidth())
.attr("y", function (d) { return y(d.satisLevel); })
.attr("height", function (d) { return height_ - y(d.satisLevel); });
// add the x Axis
g.append("g")
.attr("transform", "translate(0," + height_ + ")")
.call(d3.axisBottom(x));
// add the y Axis
g.append("g")
.call(d3.axisLeft(y))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
If you want the height of the lowest Satisfaction Level to be more than zero, you can add padding to the scalePoint, like in the example.
I want to add a legend to my D3js donut chart, like this post, its supposed to be kind of simple but I can't get it and I don't know what I'm doing wrong, also the console is not throwing any errors, anyone can see the error?
my data comes from a csv and looks like this:
data = [{
value: 30,
key: "Alta"
}, {
value: 37,
key: "Media"
}, {
value: 15,
key: "Moderada"
}, {
value: 8,
key: "Baja"
},
{
value: 13,
key: "Muy baja"
},
]
and this is the part that adds the data to the chart:
var margin = {top: 20, right: 20, bottom: 20, left: 20},
width = 500 - margin.right - margin.left,
height = 500 - margin.top - margin.bottom,
radius = width/2;
var color = d3.scaleOrdinal()
.range(["#B4DC70", "#FEFE2B", "#FE8E2B", "#FE2B2B", "#2B5EFE"]);
// arc generator
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 70);
// generate pie chart and donut chart
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.value; });
// define the svg for pie chart
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("alertas.csv", function(error, data) {
if (error) throw error;
var amenazasCount = d3.nest()
.key(function(d) { return d.TEXTO_AMENAZA; })
.rollup(function(v) { return v.length; })
.entries(data);
amenazasCount.forEach(function(d) {
d.value = +d.value;
});
var g = svg.selectAll(".arc")
.data(pie(amenazasCount))
.enter().append("g")
.attr("class", "arc");
// append path
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.key); });
var legendG = svg.selectAll(".legend")
.data(pie(amenazasCount))
.enter().append("g")
.attr("transform", function(d,i){
return "translate(" + (width - 110) + "," + (i * 15 + 20) + ")";
})
.attr("class", "legend");
legendG.append("rect")
.attr("width", 10)
.attr("height", 10)
.attr("fill", function(d) { return color(d.data.key); });
legendG.append("text")
.text(function(d){
return d.value + " " + d.data.key;
})
.style("font-size", 12)
.attr("y", 10)
.attr("x", 11);
});
The SVG and G elements are not sized correctly or consistently with the margins you had defined, so that legend was positioned too far to the right, and outside of the SVG view.
If you set up your SVG and g elements like this then it will work:
// set a width and height inclusive of the margins
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
// create a parent g element for everything to be included within
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// position the pie half of the width and height
var pieG = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")")
.attr("class", "arc");
And then append the legendG to the "g" element:
var legendG = g.selectAll(".legend")
.data(legendData)
.enter()
.append("g")
.attr("transform", function(d,i){
return "translate(" + (width - 60) + "," + (i * 15 + 20) + ")";
})
.attr("class", "legend");
I'm drawing a simple bar chart with d3, and I have an x axis setup and have the brush setup so that I can brush to "select" a group of the bars. I would like to then drill down and scale the chart to contain only these bars. The following code works and the colors of the bars inside and touched by the brush turn the right color, but I can't make the thing zoom.
I have looked at this: http://bl.ocks.org/mbostock/1667367 and a bunch of other stuff and just cannot figure it out.
Here is a fiddle, can someone show me how to simply zoom the darn thing?
var brush;
function go3()
{
var dataset = [];
var m = 40;
var count = 500;
dataset.push(m);
for (var i = 0; i < 150; i++) { //Loop 25 times
var newNumber = Math.random() * m; //New random number (0-30)
dataset.push(newNumber); //Add new number to array
}
margin = {top: 10, right: 10, bottom: 30, left: 10},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom
w = width;
h = height;
yScale = d3.scale.linear().domain([0, d3.max(dataset)]).range([0, h * .95]);
xScale = d3.scale.linear()
.range([0, w])
.domain([0, w]);
var xAxis = d3.svg.axis().scale(xScale).orient("bottom");
console.log("Max: " + d3.max(dataset));
svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
;
svg.append("rect")
.attr("stroke", "grey")
.attr("stroke-width", 1)
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.attr("fill", "#FFFFFF")
.classed("main-container", true);
svg.append("rect")
.attr("width", w)
.attr("height", h)
.attr("stroke", "grey")
.attr("stroke-width", 0)
.attr("fill", "#EEFFEE")
.attr("x", margin.left)
.attr("y", margin.top)
.classed("brushable-container", true)
;
xAxisGroup = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + (h + margin.top) + ")")
.call(xAxis)
padding=2;
rects = svg.append("g").selectAll(".brushable")
.data(dataset)
.enter()
.append("rect")
.classed("brushable", true);
brush = d3.svg.brush()
.x(xScale)
.on("brush", brushmove)
.on("brushend", brushend);
context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "brush")
.call(brush)
.selectAll('rect')
.attr('height', h);
barWidth = w / dataset.length;
console.log("Width: " + barWidth);
rects
.attr("width", 4)
.attr("height", function(d, i){ return yScale(d)})
.attr("stroke", "yellow")
.attr("stroke-width", .3)
.attr("x", function(d, i){ return (i * barWidth + margin.left) })
.attr("y", function(d, i){ return h - yScale(d) + margin.top} )
;
}
function brushend(){
var extent = brush.extent();
var min = extent[0] >= extent[1] ? extent[1] : extent[0];
var max = extent[0] >= extent[1] ? extent[0] : extent[1];
var lolobb = d3.selectAll("rect.brushable");
var lob = lolobb[0];
console.log(min + " - " + max);
var i = 0;
while( i < lob.length ){
var bbb = lob[i];
try {
var p = parseFloat(bbb.attributes.x.value);
if(min <= p && max >= p) {
d3.select(bbb).attr("fill", "#00FF00");
} else {
d3.select(bbb).attr("fill", "#000000");
}
i++;
} catch(r) {
console.log("BBB");
console.log(bbb);
console.log("Error with " + i);
console.log(typeof(bbb));
console.log(r);
}
}
console.log(min + " - " + max);
console.log(lolobb);
}
function brushmove() {
var extent = brush.extent();
}
You can do this by adding calling a zoom function on "body", you can do so by doing:
svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
;
The zooming part is:
.append("g")
.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
Then add the zoom() function:
function zoom() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
Here is a Fiddle Example. Use the scroll wheel to zoom.
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));
})
});