D3 axis and bar transition not working - javascript

Lost on this especially since I've done it successfully before. The code below is within a function called on a click. This first example works just fine:
y.domain([1, get_max(data)]);
svg.select('.y.axis')
.call(yAxis);
svg.selectAll('.bars')
.attr('y', function (d) { return y(d); })
.attr('height', function (d) { return height - y(d); });
This second example doesn't do anything:
y.domain([1, get_max(data)]);
svg.select('.y.axis')
.transition()
.duration(80)
.call(yAxis);
svg.selectAll('.bars')
.transition()
.duration(80)
.attr('y', function (d) { return y(d); })
.attr('height', function (d) { return height - y(d); });
No javascript errors are produced. It simply doesn't do anything.
Any help would be greatly appreciated. Thank you!
Note: get_max(data) is a special function to get the max of some very oddly formatted data. When I replace it with a hard coded value of 10,000 the problem persists. Again it works fine until I add the transition.
EDIT:
function render(parent, data, brands){
var time_format = parent.attr('data-chart-size') > 3 ? '%b %e' : '%e',
margin = { top: 30, right: 20, bottom: 21, left: 45 },
width = parent.width() - margin.left - margin.right - 110; // -110 for the legends on the right side
height = 205 - margin.top - margin.bottom;
var x = d3.time.scale().domain([ML._dates.start(), ML._dates.end()]).range([0, width]);
y = d3.scale.log().clamp(true).range([height, 1]);
var xAxis = d3.svg.axis().scale(x).orient('bottom')
.tickFormat(d3.time.format(time_format)).tickSize(0).tickPadding(8);
yAxis = d3.svg.axis().scale(y).orient('left').ticks(5, 's').tickSize(0);
svg = d3.select(parent.get(0)).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 brands_length = brands.length,
values_length = data.posts[brands[0]].values.length,
bar_width_adjustment = 60 / values_length,
bar_width = ((width / values_length) / brands_length) - bar_width_adjustment;
range_band = width / values_length;
y.domain([1, get_max(data)]);
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(' + (bar_width * 2) + ',' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(0, 0)')
.call(yAxis);
// BUILD THE BARS AND TOOLTIP HIGHLIGHT AREA
for(var brands_loop = 0; brands_loop < brands_length; ++brands_loop){
svg.selectAll('.chart-hover')
.data(data.posts[brands[brands_loop]].values)
.enter().append('rect')
.attr('width', width / values_length)
.attr('x', function (d, i) { return i * range_band - ((range_band - bar_width * 3) / 2); })
.attr('y', 1)
.attr('height', height - y(y.domain()[1]))
.attr('transform', 'translate(' + ((bar_width * (brands_loop + 1) - (bar_width / 2)) + ', 0)'))
.attr('data-index', function (d, i) { return i; })
.attr('class', 'chart-hover')
.style('opacity', 0.01);
svg.selectAll('.bar-' + brands_loop)
.data(data.posts[brands[brands_loop]].values)
.enter().append('rect')
.attr('data-legend-listener-brand', brands[brands_loop])
.attr('data-legend-listener-metric', 'posts')
.attr('data-hover-dispatcher-index', function (d, i) { return i; })
.attr('width', bar_width)
.attr('x', function (d, i) { return i * range_band; })
.attr('y', function (d) { return y(d); })
.attr('height', function (d) { return height - y(d); })
.attr('transform', 'translate(' + ((bar_width * (brands_loop + 1) - (bar_width / 2)) + ', 0)'))
.attr('class', 'posts bars bar-' + brands_loop);
// POPULATE LEGEND TEXTS FOR POSTS, EXPOSURE AND ENGAGEMENT
$('.brand-' + (brands_loop + 1))
.text(data.posts[brands[brands_loop]].label)
.attr('data-legend-brand', brands[brands_loop])
.attr('data-legend-listener-brand', brands[brands_loop])
.prev('i')
.attr('data-legend-brand', brands[brands_loop])
.attr('data-legend-listener-brand', brands[brands_loop]);
}
etc. etc.

Related

D3 js tooltip violin plot

I have made a violin plot in D3.js with the following code:
<script src="https://d3js.org/d3.v4.js"></script>`
<div id="power"></div>
<script>
var margin = {top: 120, right: 100, bottom: 80, left: 100},
width = 2600 - margin.left - margin.right,
height = 620 - margin.top - margin.bottom;
var svg = d3.select("#power")
.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 and compute summary statistics for each
d3.csv("static/csv/violinsummary.csv", function (data) {
// Show the X scale
var x = d3.scaleBand()
.range([0, width])
.domain(["2017-09", "2017-10", "2018-02", "2018-03"])
.paddingInner(0)
.paddingOuter(.5);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Show the Y scale
var y = d3.scaleLinear()
.domain([80, 105])
.range([height, 0]);
svg.append("g").call(d3.axisLeft(y));
// Features of density estimate
var kde = kernelDensityEstimator(kernelEpanechnikov(.2), y.ticks(50));
// Compute the binning for each group of the dataset
var sumstat = d3.nest()
.key(function (d) {
return d.DATE;
})
.rollup(function (d) { // For each key..
input = d.map(function (g) {
return g.Power;
});
density = kde(input); // And compute the binning on it.
return (density);
})
.entries(data);
var maxNum = 0;
for (i in sumstat) {
allBins = sumstat[i].value;
kdeValues = allBins.map(function (a) {
return a[1]
});
biggest = d3.max(kdeValues);
if (biggest > maxNum) {
maxNum = biggest
}
}
// The maximum width of a violin must be x.bandwidth = the width dedicated to a group
var xNum = d3.scaleLinear()
.range([0, x.bandwidth()])
.domain([-maxNum, maxNum]);
svg
.selectAll("myViolin")
.data(sumstat)
.enter() // So now we are working group per group
.append("g")
.attr("transform", function (d) {
return ("translate(" + x(d.key) + " ,0)")
}) // Translation on the right to be at the group position
.append("path")
.datum(function (d) {
return (d.value)
}) // So now we are working density per density
.style("opacity", .7)
.style("fill", "#317fc8")
.attr("d", d3.area()
.x0(function (d) {
return (xNum(-d[1]))
})
.x1(function (d) {
return (xNum(d[1]))
})
.y(function (d) {
return (y(d[0]))
})
.curve(d3.curveCatmullRom));
});
function kernelDensityEstimator(kernel, X) {
return function (V) {
return X.map(function (x) {
return [x, d3.mean(V, function (v) {
return kernel(x - v);
})];
});
}
}
function kernelEpanechnikov(k) {
return function (v) {
return Math.abs(v /= k) <= 1 ? 0.75 * (1 - v * v) / k : 0;
};
}
</script>
Data (violinsummary.csv):
Power,DATE
89.29,2017-09
89.9,2017-09
91.69,2017-09
89.23,2017-09
91.54,2017-09
88.49,2017-09
89.15,2017-09
90.85,2017-09
89.59,2017-09
93.38,2017-10
92.41,2017-10
90.65,2017-10
91.07,2017-10
90.13,2017-10
91.73,2017-10
91.09,2017-10
93.21,2017-10
91.62,2017-10
89.58,2017-10
90.59,2017-10
92.57,2017-10
89.99,2017-10
90.59,2017-10
88.12,2017-10
91.3,2017-10
89.59,2018-02
91.9,2018-02
87.83,2018-02
90.36,2018-02
91.38,2018-02
91.56,2018-02
91.89,2018-02
90.95,2018-02
90.15,2018-02
90.24,2018-02
94.04,2018-02
85.4,2018-02
88.47,2018-02
92.3,2018-02
92.46,2018-02
92.26,2018-02
88.78,2018-02
90.13,2018-03
89.95,2018-03
92.98,2018-03
91.94,2018-03
90.29,2018-03
91.2,2018-03
94.22,2018-03
90.71,2018-03
93.03,2018-03
91.89,2018-03
I am trying to make a tooltip for each violin that shows the median and mean upon hover. I cannot figure out how to make the tooltip show up.
I know I need to do something like this with mouseover and mouseout but I'm not sure...
var tooltip = d3.select('#power')
.append('div')
.attr('class', 'tooltip')
.style("opacity", 0);
Any tips/guidance would be very appreciated.
You can implement the tooltip functionality by following two steps.
Step 1:
Initialize the tooltip container which already you did I guess.
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
Step 2:
Change the visibility property of the tooltip in the mouseover, mouseout event of the element. In your case, it's myViolin
.on("mouseover", function() {
tooltip.style("display", null);
})
.on("mouseout", function() {
tooltip.style("display", "none");
})
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 25;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
Here is the implementation of tooltip jsFiddle
Hope it helps :)

D3js library from csv to json input

I am a beginner in JS and D3. Doing reseach for my project I found this library which gives the type of plot needed for our project written in d3js. The input is cvs, but the setup requires using json. To migrate the code I have used d3.json, but the app only loads one data element. Any ideas what's going wrong?
input json (snippet)
[
{"date":"2017-09-03 19:49:51","volume":"3070.33","price":"0.0314009","average":"0.0314009"},
{"date":"2017-09-03 19:59:47","volume":"3061.02","price":"0.0313057","average":"0.0313057"},
{"date":"2017-09-03 20:09:46","volume":"3062.63","price":"0.0313221","average":"0.0313221"},
{"date":"2017-09-03 20:19:54","volume":"3049.41","price":"0.0311875","average":"0.0311875"}
]
Code
/* global d3, _ */
(function() {
var margin = {top: 30, right: 20, bottom: 100, left: 50},
margin2 = {top: 210, right: 20, bottom: 20, left: 50},
width = 764 - margin.left - margin.right,
height = 283 - margin.top - margin.bottom,
height2 = 283 - margin2.top - margin2.bottom;
var parseDate = d3.time.format('%d/%m/%Y %H:%M').parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
legendFormat = d3.time.format('%b %d, %Y %H:%M');
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y1 = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]),
y3 = d3.scale.linear().range([60, 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 priceLine = d3.svg.line()
.interpolate('monotone')
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); });
var avgLine = d3.svg.line()
.interpolate('monotone')
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.average); });
var area2 = d3.svg.area()
.interpolate('monotone')
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.price); });
var svg = d3.select('body').append('svg')
.attr('class', 'chart')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom + 60);
svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', width)
.attr('height', height);
var make_y_axis = function () {
return d3.svg.axis()
.scale(y)
.orient('left')
.ticks(3);
};
var focus = svg.append('g')
.attr('class', 'focus')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var barsGroup = svg.append('g')
.attr('class', 'volume')
.attr('clip-path', 'url(#clip)')
.attr('transform', 'translate(' + margin.left + ',' + (margin.top + 60 + 20) + ')');
var context = svg.append('g')
.attr('class', 'context')
.attr('transform', 'translate(' + margin2.left + ',' + (margin2.top + 60) + ')');
var legend = svg.append('g')
.attr('class', 'chart__legend')
.attr('width', width)
.attr('height', 30)
.attr('transform', 'translate(' + margin2.left + ', 10)');
legend.append('text')
.attr('class', 'chart__symbol')
.text('Renos : RNS')
var rangeSelection = legend
.append('g')
.attr('class', 'chart__range-selection')
.attr('transform', 'translate(110, 0)');
d3.json('http://rns.ud.vg/datastockstyle.php', function(err, data) {
data.forEach( function(d) {
date = parseDate(d.date);
price = +d.price;
average = +d.average;
volume = +d.volume;
});
var brush = d3.svg.brush()
.x(x2)
.on('brush', brushed);
var xRange = d3.extent(data.map(function(d) { return d.date; }));
x.domain(xRange);
y.domain(d3.extent(data.map(function(d) { return d.price; })));
y3.domain(d3.extent(data.map(function(d) { return d.price; })));
x2.domain(x.domain());
y2.domain(y.domain());
var min = d3.min(data.map(function(d) { return d.price; }));
var max = d3.max(data.map(function(d) { return d.price; }));
var range = legend.append('text')
.text(legendFormat(new Date(xRange[0])) + ' - ' + legendFormat(new Date(xRange[1])))
.style('text-anchor', 'end')
.attr('transform', 'translate(' + width + ', 0)');
focus.append('g')
.attr('class', 'y chart__grid')
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(''));
var averageChart = focus.append('path')
.datum(data)
.attr('class', 'chart__line chart__average--focus line')
.attr('d', avgLine);
var priceChart = focus.append('path')
.datum(data)
.attr('class', 'chart__line chart__price--focus line')
.attr('d', priceLine);
focus.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0 ,' + height + ')')
.call(xAxis);
focus.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(12, 0)')
.call(yAxis);
var focusGraph = barsGroup.selectAll('rect')
.data(data)
.enter().append('rect')
.attr('class', 'chart__bars')
.attr('x', function(d, i) { return x(d.date); })
.attr('y', function(d) { return 155 - y3(d.price); })
.attr('width', 1)
.attr('height', function(d) { return y3(d.price); });
var helper = focus.append('g')
.attr('class', 'chart__helper')
.style('text-anchor', 'end')
.attr('transform', 'translate(' + width + ', 0)');
var helperText = helper.append('text')
var priceTooltip = focus.append('g')
.attr('class', 'chart__tooltip--price')
.append('circle')
.style('display', 'none')
.attr('r', 2.5);
var averageTooltip = focus.append('g')
.attr('class', 'chart__tooltip--average')
.append('circle')
.style('display', 'none')
.attr('r', 2.5);
var mouseArea = svg.append('g')
.attr('class', 'chart__mouse')
.append('rect')
.attr('class', 'chart__overlay')
.attr('width', width)
.attr('height', height)
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.on('mouseover', function() {
helper.style('display', null);
priceTooltip.style('display', null);
averageTooltip.style('display', null);
})
.on('mouseout', function() {
helper.style('display', 'none');
priceTooltip.style('display', 'none');
averageTooltip.style('display', 'none');
})
.on('mousemove', mousemove);
context.append('path')
.datum(data)
.attr('class', 'chart__area area')
.attr('d', area2);
context.append('g')
.attr('class', 'x axis chart__axis--context')
.attr('y', 0)
.attr('transform', 'translate(0,' + (height2 - 22) + ')')
.call(xAxis2);
context.append('g')
.attr('class', 'x brush')
.call(brush)
.selectAll('rect')
.attr('y', -6)
.attr('height', height2 + 7);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]);
var i = bisectDate(data, x0, 1);
var d0 = data[i - 1];
var d1 = data[i];
var d = x0 - d0.date > d1.date - x0 ? d1 : d0;
helperText.text(legendFormat(new Date(d.date)) + ' - Price: ' + d.price + ' Avg: ' + d.average);
priceTooltip.attr('transform', 'translate(' + x(d.date) + ',' + y(d.price) + ')');
averageTooltip.attr('transform', 'translate(' + x(d.date) + ',' + y(d.average) + ')');
}
function brushed() {
var ext = brush.extent();
if (!brush.empty()) {
x.domain(brush.empty() ? x2.domain() : brush.extent());
y.domain([
d3.min(data.map(function(d) { return (d.date >= ext[0] && d.date <= ext[1]) ? d.price : max; })),
d3.max(data.map(function(d) { return (d.date >= ext[0] && d.date <= ext[1]) ? d.price : min; }))
]);
range.text(legendFormat(new Date(ext[0])) + ' - ' + legendFormat(new Date(ext[1])))
focusGraph.attr('x', function(d, i) { return x(d.date); });
var days = Math.ceil((ext[1] - ext[0]) / (24 * 3600 * 1000))
focusGraph.attr('width', (40 > days) ? (40 - days) * 5 / 6 : 5)
}
priceChart.attr('d', priceLine);
averageChart.attr('d', avgLine);
focus.select('.x.axis').call(xAxis);
focus.select('.y.axis').call(yAxis);
}
var dateRange = ['1h', '1d', '1w', '1m', '3m', '6m', '1y']
for (var i = 0, l = dateRange.length; i < l; i ++) {
var v = dateRange[i];
rangeSelection
.append('text')
.attr('class', 'chart__range-selection')
.text(v)
.attr('transform', 'translate(' + (18 * i) + ', 0)')
.on('click', function(d) { focusOnRange(this.textContent); });
}
function focusOnRange(range) {
var today = new Date(data[data.length - 1].date)
var ext = new Date(data[data.length - 1].date)
if (range === '1m')
ext.setMonth(ext.getMonth() - 1)
if (range === '1w')
ext.setDate(ext.getDate() - 7)
if (range === '1d')
ext.setDate(ext.getDate() - 1)
if (range === '1h')
ext.setTime(ext.getTime() - 60*60*1000)
if (range === '3m')
ext.setMonth(ext.getMonth() - 3)
if (range === '6m')
ext.setMonth(ext.getMonth() - 6)
if (range === '1y')
ext.setFullYear(ext.getFullYear() - 1)
brush.extent([ext, today])
brushed()
document.getElementById("demo").innerHTML =ext;
context.select('g.x.brush').call(brush.extent([ext, today]))
}
})// end Data
}());
The data contains hyphens not forward slashes.
Your date parsing should not be
var parseDate = d3.time.format('%d/%m/%Y %H:%M').parse,
it should be,
var parseDate = d3.time.format('%d-%m-%Y %H:%M').parse,
Also, what is y0? I don't see y0 in your scales.
.y0(height2)
I don't know what's wrong with your code, but others will be able to help easier with this,
jsFiddle

How to print content of tooltip on different lines in D3

Below is the code for horizontal stacked Bar Chart. When I hover on any bar, it shows me content of the element all in single line. I want to add line break to separate each parameter of the data. I tried looking for this type of question and found something with 'tspan' but that is not working in my code. Please have a look.
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# taglib prefix="lit" uri="/WEB-INF/......" %>
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<link rel="stylesheet" media="all" type="text/css" href="<c:url value="/styl........."/>" />
</head>
<body>
<script src="//d3js.org/d3.v3.js"></script>
<script>
var i = 0;
var margins = {
top: 12,
left: 48,
right: 24,
bottom: 24
},
legendPanel = {
width: 180
},
width = 1500 - margins.left - margins.right - legendPanel.width,
height = 900 - margins.top - margins.bottom,
dataset = ${JSONData},
series = dataset.map(function (d) {
return d.name;
}),
dataset = dataset.map(function (d) {
return d.data.map(function (o) {
return {
name: d.name,
y: +o.count,
x: o.time
};
});
}),
stack = d3.layout.stack();
stack(dataset);
var dataset = dataset.map(function (group) {
return group.map(function (d) {
return {
name: d.name,
x: d.y,
y: d.x,
x0: d.y0
};
});
}),
svg = d3.select('body')
.append('svg')
.attr('width', width + margins.left + margins.right + legendPanel.width)
.attr('height', height + margins.top + margins.bottom)
.append('g')
.attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'),
xMax = d3.max(dataset, function (group) {
return d3.max(group, function (d) {
return d.x + d.x0;
});
}),
xScale = d3.scale.linear()
.domain([0, xMax])
.range([0, width]),
months = dataset[0].map(function (d) {
return d.y;
}),
_ = console.log(months),
yScale = d3.scale.ordinal()
.domain(months)
.rangeRoundBands([0, height], .1),
xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom'),
yAxis = d3.svg.axis()
.scale(yScale)
.orient('left'),
colours = d3.scale.category10(),
groups = svg.selectAll('g')
.data(dataset)
.enter()
.append('g')
.style('fill', function (d, i) {
return colours(i);
}),
rects = groups.selectAll('rect')
.data(function (d) {
return d;
})
.enter()
.append('rect')
.attr('x', function (d) {
return xScale(d.x0);
})
.attr('y', function (d, i) {
return yScale(d.y);
})
.attr('height', function (d) {
return yScale.rangeBand();
})
.attr('width', function (d) {
return xScale(d.x);
})
.on('mouseover', function (d) {
var xPos = parseFloat(d3.select(this).attr('x')) / 2 + width/2;
var yPos = parseFloat(d3.select(this).attr('y')) + yScale.rangeBand() / 2;
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.select('#value')
.text("Count: " + d.x + "Time: " + d.y + "String1"+
"\nString2");
//.text(d.x+","+d.y+","+d.name);
d3.select('#tooltip').classed('hidden', false);
})
.on('mouseout', function () {
d3.select('#tooltip').classed('hidden', true);
})
svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'axis')
.call(yAxis);
svg.append('rect')
.attr('fill', 'yellow')
.attr('width', 160)
.attr('height', 30 * dataset.length)
.attr('x', width + margins.left)
.attr('y', 0);
series.forEach(function (s, i) {
svg.append('text')
.attr('fill', 'black')
.attr('x', width + margins.left + 8)
.attr('y', i * 24 + 24)
.text(s);
svg.append('rect')
.attr('fill', colours(i))
.attr('width', 60)
.attr('height', 20)
.attr('x', width + margins.left + 90)
.attr('y', i * 24 + 6);
});
</script>
<div id="tooltip" class="hidden">
<p><span id="value">100</span>
</p>
</div>
</body>
</html>
Your "tooltip" is just an HTML span; so all you need to do is use .html and a <br> for the line break:
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.select('#value')
.html("Count: " + d.x + "Time: " + d.y + " String1" + "<br>String2");
If you had been creating an svg text element, then you'd need to append multiple tspan elements to it.
Full code:
<html>
<head>
</head>
<body>
<script src="//d3js.org/d3.v3.js"></script>
<script>
var i = 0;
var margins = {
top: 12,
left: 48,
right: 24,
bottom: 24
},
legendPanel = {
width: 180
},
width = 1500 - margins.left - margins.right - legendPanel.width,
height = 900 - margins.top - margins.bottom,
dataset = [{data:[{
count: Math.random(),
time: "One"
},{
count: Math.random(),
time: "Two"
},{
count: Math.random(),
time: "Three"
}]}];
series = dataset.map(function(d) {
return d.name;
}),
dataset = dataset.map(function(d) {
return d.data.map(function(o) {
return {
name: d.name,
y: +o.count,
x: o.time
};
});
}),
stack = d3.layout.stack();
stack(dataset);
var dataset = dataset.map(function(group) {
return group.map(function(d) {
return {
name: d.name,
x: d.y,
y: d.x,
x0: d.y0
};
});
}),
svg = d3.select('body')
.append('svg')
.attr('width', width + margins.left + margins.right + legendPanel.width)
.attr('height', height + margins.top + margins.bottom)
.append('g')
.attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'),
xMax = d3.max(dataset, function(group) {
return d3.max(group, function(d) {
return d.x + d.x0;
});
}),
xScale = d3.scale.linear()
.domain([0, xMax])
.range([0, width]),
months = dataset[0].map(function(d) {
return d.y;
}),
_ = console.log(months),
yScale = d3.scale.ordinal()
.domain(months)
.rangeRoundBands([0, height], .1),
xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom'),
yAxis = d3.svg.axis()
.scale(yScale)
.orient('left'),
colours = d3.scale.category10(),
groups = svg.selectAll('g')
.data(dataset)
.enter()
.append('g')
.style('fill', function(d, i) {
return colours(i);
}),
rects = groups.selectAll('rect')
.data(function(d) {
return d;
})
.enter()
.append('rect')
.attr('x', function(d) {
return xScale(d.x0);
})
.attr('y', function(d, i) {
return yScale(d.y);
})
.attr('height', function(d) {
return yScale.rangeBand();
})
.attr('width', function(d) {
return xScale(d.x);
})
.on('mouseover', function(d) {
var xPos = parseFloat(d3.select(this).attr('x')) / 2 + width / 2;
var yPos = parseFloat(d3.select(this).attr('y')) + yScale.rangeBand() / 2;
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.select('#value')
.html("Count: " + d.x + "Time: " + d.y + " String1" + "<br>String2");
d3.select('#tooltip').classed('hidden', false);
})
.on('mouseout', function() {
d3.select('#tooltip').classed('hidden', true);
})
svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'axis')
.call(yAxis);
svg.append('rect')
.attr('fill', 'yellow')
.attr('width', 160)
.attr('height', 30 * dataset.length)
.attr('x', width + margins.left)
.attr('y', 0);
series.forEach(function(s, i) {
svg.append('text')
.attr('fill', 'black')
.attr('x', width + margins.left + 8)
.attr('y', i * 24 + 24)
.text(s);
svg.append('rect')
.attr('fill', colours(i))
.attr('width', 60)
.attr('height', 20)
.attr('x', width + margins.left + 90)
.attr('y', i * 24 + 6);
});
</script>
<div id="tooltip" class="hidden">
<p>
<span id="value">100</span>
</p>
</div>
</body>
</html>

D3js zoom/drag not working any more in my code (+code sample)

Code
In this file http://tc51.net/w/at/stackoverflow.com/20150604.1/20150604.1.zip
You will find all .htm, .js, .css, .csv files of:
The example I started with
My current work in progess.
The problem
Since I did some refactoring required for further developments, the chart drag/zoom feature is not working anymore. No apparent JavaScript error in debugger, and it seems to have to do with 3Djs inner zoom functions so I have no clue what I did wrong. Can you help me find out? Thank you.
(I tried to create two JSFiddles as well but they don't work at all, I have no idea why: Start example:
https://jsfiddle.net/TTTT/erndok36/2 Current work in progress: https://jsfiddle.net/TTTT/mfudwy0q
)
And here is some code:
//Start example: http://mbostock.github.io/d3/talk/20111018/area-gradient.html
function parseDate(unix_timestamp){return new Date(unix_timestamp*1000);}
var svg, m, w, h, x, y, xAxis, yAxis, area, line, gradient, margin, varData,
//parseDate = d3.time.format('%Y-%m-%d').parse,
format = d3.time.format('%Y')
function CreateSvg()
{
margin = {top: 79, right: 80, bottom: 160, left: 79};
//m = [79, 80, 160, 79];
w = 1280 - margin.right - margin.left;
h = 800 - margin.top - margin.bottom;
//Scales. Note the inverted domain for the y-scale: bigger is up!
x = d3.time.scale().range([0, w]);
y = d3.scale.linear().range([h, 0]);
xAxis = d3.svg.axis().scale(x).orient('bottom').tickPadding(6).tickFormat(d3.time.format('%Y/%m/%d %H:%M:%S')).ticks(30); //.tickSize(-h, 0)
yAxis = d3.svg.axis().scale(y).orient('left').tickSize(w).tickPadding(6);
area = d3.svg.area()
.interpolate('step-after')
.x(function(d) { return x(d.date); })
.y0(y(0))
.y1(function(d) { return y(d.value); });
line = d3.svg.line()
.interpolate('step-after')
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });
svg = d3.select('#ChartContainer').append('svg:svg')
.attr('width', w + margin.right + margin.left)
.attr('height', h + margin.top + margin.bottom)
.append('svg:g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
gradient = svg.append('svg:defs').append('svg:linearGradient')
.attr('id', 'gradient')
.attr('x2', '0%')
.attr('y2', '100%');
gradient.append('svg:stop')
.attr('offset', '40%')
.attr('stop-color', '#f00')
.attr('stop-opacity', .5);
gradient.append('svg:stop')
.attr('offset', '100%')
.attr('stop-color', '#0f0')
.attr('stop-opacity', 1);
svg.append('svg:clipPath')
.attr('id', 'clip')
.append('svg:rect')
.attr('x', x(0))
.attr('y', y(1))
.attr('width', x(1) - x(0))
.attr('height', y(0) - y(1));
svg.append('svg:g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + w + ',0)');
svg.append('svg:path')
.attr('class', 'area')
.attr('clip-path', 'url(#clip)')
.style('fill', 'url(#gradient)');
svg.append('svg:g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + h + ')');
svg.append('svg:path')
.attr('class', 'line')
.attr('clip-path', 'url(#clip)');
svg.append('svg:rect')
.attr('class', 'pane')
.attr('width', w)
.attr('height', h)
.call(d3.behavior.zoom().on('zoom', zoom));
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 0-margin.left)
.attr('x', 0-(h/2))
.attr('dy', '1em')
.style('text-anchor', 'middle')
.text('Noise (dB)');
svg.append('text')
.attr('y', w/2)
.attr('x', h)
.attr('dx', '1em')
.style('text-anchor', 'middle')
.text('Time');
}
function CreateData()
{
//.csv() function is async!
d3.csv('data-noise-example.csv', function(data)
{
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
//Adds two random data. ''Getting started experimentation code.'
//data.reverse();
data.push({date:parseDate(1433160989), value:Math.random() * 180});
data.push({date:parseDate(1433160990), value:Math.random() * 180});
data.push({date:parseDate(1433160991), value:179});
data.push({date:parseDate(1433160992), value:1});
//data.reverse();
varData = data;
ReDraw(varData);
});
}
function ReDrawTest()
{
varData.push({date:parseDate(1433160993), value:Math.random() * 180});
varData.push({date:parseDate(1433160994), value:Math.random() * 180});
ReDraw(varData);
}
function FirstDraw()
{
CreateData();
//ReDraw(varData);
}
function ReDraw(data)
{
y.domain([0, 180]);
x.domain([parseDate(1433160660), parseDate(1433160780)]);
//Bind the data to our path elements
svg.select('path.area').data([data]);
svg.select('path.line').data([data]);
var t = svg.select('g.x.axis').call(xAxis).selectAll('text')
.style('text-anchor', 'end')
.attr('dx', '-.8em')
.attr('dy', '.15em');
t.attr('transform', 'translate(-2,0)').attr('transform', 'rotate(-90)');
svg.select('g.y.axis').call(yAxis);
svg.select('path.area').attr('d', area);
svg.select('path.line').attr('d', line); //.on('click', clickPath).on('mouseover', onMouseOverPath);
//d3.select('#footer span').text('U.S. Commercial Flights, ' + x.domain().map(format).join('-'));
}
/*function clickPath(e){
console.log('onclickPath', this);
//console.log('onclickPath', this.attr("d"));
var coordinates = d3.mouse(this);
console.log(coordinates[0],coordinates[1]);
}
function findData(x,y)
{
var relY = Math.abs(height-y)/height;
var valY = relY*(chartMaxY-chartMinY);
return [valY,''];
}
function onMouseOverPath(e){
var coordinates = d3.mouse(this);
var x = coordinates[0];
var y = coordinates[1];
var coordValue = 'Coord.: x:' + x + ',y:' + y;
$('#coordValue').text(coordValue);
//Probably not the cleanest way, but that way gives result ...
//console.log(svg.select('title'));
//console.log(coordinates[0] + ',' +coordinates[1]);
var retrievedData = findData(x,y);
var noiseValue = 'Noise: '+ retrievedData[0]+','+retrievedData[1];
$('#noiseValue').text(noiseValue);
svg.append('svg:title').text(noiseValue + "\r\n" + coordValue);
svg.select('title').text(noiseValue + "\r\n" + coordValue);
}
function onMouseOutPath(){alert('mouseOutPath');}
function click() {alert('onclick');}
function onMouseOver(){alert('mouseOver');}
function onMouseOut(){alert('mouseOut');}*/
function zoom() {
d3.event.transform(x); //TODO d3.behavior.zoom should support extents
ReDraw(varData);
}
$(document).ready(function() {
CreateSvg();
FirstDraw();
});
Solution found:
Moving
y.domain([0, 180]);
x.domain([parseDate(1433160660), parseDate(1433160780)]);
to
function FirstDraw(){...}
(I thought I had tested it already ...)

Can't remove rotation in D3's radial tree layout

I have this D3 radial tree graph and what I need is the images to not being rotated, but appear straight together it's corresponding blue circle. Here is the code working in Codepen and I copy it here:
var radius = 960 / 2;
var tree = d3.layout.tree()
.size([360, radius - 120])
.separation(function (a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var diagonal = d3.svg.diagonal.radial()
.projection(function (d) { return [d.y, d.x / 180 * Math.PI]; })
var vis = d3.select('#graph').append('svg:svg')
.attr('width', radius * 2)
.attr('height', radius * 2 - 150)
.append('g')
.attr('transform', 'translate(' + radius + ',' + radius + ')');
d3.json('flare2.json', function (json) {
var nodes = tree.nodes(json);
var link = vis.selectAll('path.link')
.data(tree.links(nodes))
.enter().append('path')
.attr('class', 'link')
.attr('d', diagonal);
var node = vis.selectAll('g.node')
.data(nodes)
.enter().append('g')
.attr('class', 'node')
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; });
node.append('circle')
.attr('r', 4.5);
node.append('image')
.attr('xlink:href', 'img/avatar.40.gif')
.attr('width', 40)
.attr('height', 40)
.attr('x', 10);
node.append('image')
.attr('xlink:href', 'img/avatar.41.gif')
.attr('width', 40)
.attr('height', 40)
.attr('x', 50 );
});
Your nodes are rotated
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
And your images are appended to your nodes
node.append('image')
So you need to rotate the images back
.attr("transform", function(d) { return "rotate(" + (90 - d.x) + ")"; })
I'm not sure exactly how you want to position them, but you need to translate them on both x and y.
See a working example: http://codepen.io/anon/pen/qiCeG

Categories

Resources