Dc.js Boxplot not creating outlines - dc.js

Why is dc.js boxplot not creating any outlines? I am just created a simplified code based on http://dc-js.github.io/dc.js/examples/boxplot-basic.html
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<body>
<div id = 'boxch1'><br></div>
<script src="https://unpkg.com/crossfilter2#1.4.7/crossfilter.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="http://unpkg.com/dc#3/dc.js"></script>
<script>
let exp = [
{"Expt":1, "Speed":8},
{"Expt":1, "Speed":7},
{"Expt":1, "Speed":9},
{"Expt":1, "Speed":1},
{"Expt":2, "Speed":8},
{"Expt":2, "Speed":6},
{"Expt":2, "Speed":8}];
dc.config.defaultColors(d3.schemeSet1);
var ndx = crossfilter(exp)
runDimension = ndx.dimension(function(d) {return +d.Run;});
runGroup = runDimension.group();
experimentDimension = ndx.dimension(function(d) {return "exp-" + d.Expt;});
speedArrayGroup = experimentDimension.group().reduce(
function(p,v) {
// keep array sorted for efficiency
p.splice(d3.bisectLeft(p, v.Speed), 0, v.Speed);
return p;
},
function(p,v) {
p.splice(d3.bisectLeft(p, v.Speed), 1);
return p;
},
function() {
return [];
}
);
var bp01 = dc.boxPlot("#boxch1");
bp01
.width(768)
.height(480)
.margins({top: 10, right: 50, bottom: 30, left: 50})
.dimension(experimentDimension)
.group(speedArrayGroup)
.elasticY(true)
.elasticX(true);
bp01.render()
</script>
</body>
</html>
I am not getting the box outlines as in the chart drawn below.
https://imgur.com/a/ELH5xlX

Thanks for including a complete example.
These kinds of problems are usually because you are missing dc.css.
In dc.js, and D3 code in general, any static attributes of SVG elements that are not controlled by data can be specified in either JS code or in CSS. This includes axis lines, outlines, fonts, etc.
Generally it makes customization easier to use classnames and leave the static attributes to CSS. But you do need to include dc.css.

Related

NVD3 - Show all tick values

My chart needs to have tick values in multiples of 3. For example, if I have 5 data points, my x-axis should show (3, 6, 9, 12, 15). How do I get nvd3 to display all tick numbers? I pasted my code below for reference
var chart = nv.models.lineChart()
.options({
margin: {left: 100, bottom: 100},
x: function(d,i) { return i*3},
showXAxis: true,
showYAxis: true,
showLegend: true,
reduceXTicks: false,
showMaxMin: false,
//values: $scope.data.values.map( function(d,i) { return i*3; }),
useInteractiveGuideline: true,
transitionDuration: 2500,
showControls : true
})
;
chart.xAxis //Chart x-axis settings
.axisLabel('Ager')
.orient('bottom')
//.tickValues( function(d,i) { return i*3;})
.tickFormat(d3.format(',r'));
chart.yAxis //Chart y-axis settings
.axisLabel('Voltage (v)')
.tickFormat(d3.format('.02f')); nv.utils.windowResize(chart.update);
I've tried everything I can think of and read online to get nvd3 show all ticks in multiples of 3. Please help me out of this tricky situation.
Thanks in advance!
You could have read the d3 docs and see that .tickValues does not accept a function.
Construct the array of tick values based on the domain of the x-axis. Because the domain is not yet set you have to construct it yourself based on the data.
Using the SinCos example from the nvd3 site
var myData = sinAndCos();
var xExtent = d3.extent(myData[0].values, d=>d.x);
xExtent = [Math.floor(xExtent[0]), Math.ceil(xExtent[1])+1];
var xTicks = d3.range(xExtent[0], xExtent[1]).filter(n => n%3===0);
chart.xAxis
.axisLabel('Time (ms)')
.tickValues(xTicks)
.tickFormat(d3.format(',r'));
Complete example. It will not run directly from the browser (will not load nvd3 inside an iframe(??)). Copy it to a local file and run it from there.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link href="https://nvd3.org/assets/css/nv.d3.css" rel="stylesheet"/>
<script src="https://nvd3.org/assets/lib/d3.v3.js"></script>
<script src="https://nvd3.org/assets/js/nv.d3.js"></script>
</head>
<body>
<div id="chart">
<svg style="width:800px;height:500px;"></svg>
</div>
<script>
/*These lines are all chart setup. Pick and choose which chart features you want to utilize. */
nv.addGraph(function() {
var chart = nv.models.lineChart()
.margin({left: 100}) //Adjust chart margins to give the x-axis some breathing room.
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
.transitionDuration(350) //how fast do you want the lines to transition?
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
.showYAxis(true) //Show the y-axis
.showXAxis(true) //Show the x-axis
;
var myData = sinAndCos();
var xExtent = d3.extent(myData[0].values, d=>d.x);
xExtent = [Math.floor(xExtent[0]), Math.ceil(xExtent[1])+1];
var xTicks = d3.range(xExtent[0], xExtent[1]).filter(n => n%3===0);
chart.xAxis //Chart x-axis settings
.axisLabel('Time (ms)')
.tickValues(xTicks)
.tickFormat(d3.format(',r'));
chart.yAxis //Chart y-axis settings
.axisLabel('Voltage (v)')
.tickFormat(d3.format('.02f'));
d3.select('#chart svg') //Select the <svg> element you want to render the chart in.
.datum(myData) //Populate the <svg> element with chart data...
.call(chart); //Finally, render the chart!
//Update the chart when window resizes.
nv.utils.windowResize(function() { chart.update() });
return chart;
});
/**************************************
* Simple test data generator
*/
function sinAndCos() {
var sin = [],sin2 = [],
cos = [];
//Data is represented as an array of {x,y} pairs.
for (var i = 0; i < 100; i++) {
sin.push({x: i, y: Math.sin(i/10)});
sin2.push({x: i, y: Math.sin(i/10) *0.25 + 0.5});
cos.push({x: i, y: .5 * Math.cos(i/10)});
}
//Line chart data should be sent as an array of series objects.
return [
{
values: sin, //values - represents the array of {x,y} data points
key: 'Sine Wave', //key - the name of the series.
color: '#ff7f0e' //color - optional: choose your own line color.
},
{
values: cos,
key: 'Cosine Wave',
color: '#2ca02c'
},
{
values: sin2,
key: 'Another sine wave',
color: '#7777ff',
area: true //area - set to true if you want this line to turn into a filled area chart.
}
];
}
</script>
</body>
</html>

How to catch svg image fail to load in D3?

I am using D3 to create a visualization with rows of <image> svg elements.
Could anyone know how I can upload a replacement image if the image file is not available?
var images= imageGroup.append('svg:image')
.attr("xlink:href",function(d,i){
//lines of code to process filename
return "/img/" + filename + ".jpg"
})
This is more a JavaScript question then d3.js:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg width="100" height="100"></svg>
<script>
// set up svg image tag
var images = d3.select("svg")
.append('svg:image')
.attr('width', 50)
.attr('height', 50);
// create a test image
var imgTest = new Image();
// if it loads successfully add it to the svg image
imgTest.onload = function() {
images.attr("xlink:href", imgTest.src);
}
// if it fails test another image
imgTest.onerror = function() {
imgTest.src = "https://dummyimage.com/50x50/000/fff.png&text=An+Image!"
}
// this will fail
imgTest.src = "https://does.not/exist.png";
</script>
</body>
</html>
I know it's an old post but i found a simpler solution than Mark answer. So i post it for future users with the same issue.
In d3.js you can add events listeners on nodes (click, load, error, ...). So when the image fails to load you can change the link (with setAttribute() function) to a fallback image. Here is a working example (note that you should not add xlink: before href ):
var images = imageGroup.append('svg:image')
.attr("href", function(d){
return "ThisImageWillFailsToLoad.jpg"
})
.on("error", function(d){
this.setAttribute("href", "YourFallbackImage.jpg");
})
var images= imageGroup.append('svg:image')
.attr("xlink:href",function(d,i){
return "/img/" + filename + ".jpg"
})
// execute the callback function if the image fails to load
.on('error', function(d) {
// specify a default path for the image
d3.select(this).attr("xlink:href", "/defaultPath");
});

MouseClick node event on d3 graph

I need insert a mouseclick event on graph nodes, but all ways don't work with me.
My code that done the graph is this:
<!DOCTYPE html>
<html>
<head>
<title>01. Create Graph. Vivagraph SVG tutorial.</title>
<script type="text/javascript" src="VivaGraphJS-master/dist/vivagraph.js"></script>
<script type="text/javascript">
function main () {
// 1- criar um projeto de grafo
var graph = Viva.Graph.graph();
// 2 - adicionando nós e arestas
graph.addNode('natalia', 'ledlightblue.png');
graph.addNode('jessica', 'krec_record.png');
graph.addNode('lucas', 'ledyellow.png');
graph.addNode('leo', 'ledgreen.png');
graph.addNode('hcii', 'ledpurple.png');
graph.addNode('evento', 'krec_record.png');
graph.addLink('natalia', 'hcii');
graph.addLink('jessica', 'hcii');
graph.addLink('lucas', 'hcii');
graph.addLink('leo', 'hcii');
graph.addLink('jessica', 'evento');
var graphics = Viva.Graph.View.svgGraphics();
//var renderer = Viva.Graph.View.renderer(graph);
graphics.node(function(node) {
var ui = Viva.Graph.svg('image')
.attr('width', 32)
.attr('height', 32)
.link('https://cdn1.iconfinder.com/data/icons/nuvola2/32x32/actions/' + node.data);
return(ui);
});
graphics.link(function(link){
return Viva.Graph.svg('path')
.attr('stroke', 'black')
.attr('stroke-width',2);
}).placeLink(function(linkUI, fromPos, toPos) {
var data = 'M' + fromPos.x + ',' + fromPos.y +
'L' + toPos.x + ',' + toPos.y;
linkUI.attr("d", data);
})
var renderer = Viva.Graph.View.renderer(graph, {
graphics : graphics
});
renderer.run();
}
</script>
<style type="text/css" media="screen">
html, body, svg { width: 100%; height: 100%;}
</style>
I tried many ways like this that is used to do mouseover event
I'm using VivaGraph.js to do the graph
Some solution?
D3js and VivaGraphJS are two different libraries, and your question is only about VivaGraphJs (in the code D3 is not even imported), "d3.js" tag should be removed.
A possible solution is to import JQuery and change this portion of code:
graphics.node(function(node) {
var ui = Viva.Graph.svg('image')
.attr('width', 32)
.attr('height', 32)
.link('https://cdn1.iconfinder.com/data/icons/nuvola2/32x32/actions/' + node.data);
return(ui);
});
Into:
graphics.node(function(node) {
var ui = Viva.Graph.svg('image')
.attr('width', 32)
.attr('height', 32)
.link('https://cdn1.iconfinder.com/data/icons/nuvola2/32x32/actions/' + node.data);
$(ui).hover(function() { // mouse over
console.log("hovering in.", node.id);
}, function() { // mouse out
console.log("hovering out.", node.id);
});
$(ui).click(function() { // mouse click
console.log("click.", node.id);
});
return(ui);
});
$(ui).hover and $(ui).click come from JQuery.

dc.js: Multiple graphs in a single dimension

How do I create multiple graphs that graph one dimension such that they react to filters placed on the other graph. Example here: http://bl.ocks.org/pbutler/9356548
<html>
<head>
<link href="style.css" rel="stylesheet">
<link href="dc.css" rel="stylesheet">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="crossfilter.js"></script>
<script src="dc.js"></script>
</head>
<body>
<div id="chart1">
</div>
<div id="chart2">
</div>
<script>
var data = [];
for (var i = 0; i < 10; i++) {
data.push({'val' : 'a'})
}
for (var i = 0; i < 15; i++) {
data.push({'val' : 'b'})
}
var ndx = crossfilter(data);
var all = ndx.groupAll();
var val = ndx.dimension(function (d) { return d.val; });
var valGroup = val.group()
var chart1 = dc.pieChart("#chart1");
var chart2 = dc.pieChart("#chart2");
chart1.dimension(val)
.group(valGroup);
chart2.dimension(val)
.group(valGroup);
dc.renderAll();
</script>
</body>
</html>
In short the graphs seem to ignore each other in this example.
If you create a second dimension using the same property, the filtering will reflect across charts.
Here is an example of that: http://jsfiddle.net/djmartin_umich/nw8EV/.
// build charts
teamMemberChart
.width(270)
.height(220)
.dimension(teamMemberDimension)
.group(teamMemberGroup)
.valueAccessor(function (d) {
return d.value.projectCount;
})
.elasticX(true);
teamMemberChart2
.width(270)
.height(220)
.dimension(teamMemberDimension)
.group(teamMemberGroup)
.valueAccessor(function (d) {
return d.value.projectCount;
})
.elasticX(true);
teamMemberChart3
.width(270)
.height(220)
.dimension(teamMemberDimension2)
.group(teamMemberGroup2)
.valueAccessor(function (d) {
return d.value.projectCount;
})
.elasticX(true);
The first two charts use the same dimension - picking one option does not reflect the other. The third chart uses a different dimension on the same property - choosing an option on this chart updates the other two charts.
It seems the answer can be found here: https://groups.google.com/forum/#!topic/dc-js-user-group/1nIScnbY0vs . There are two possible ways, add another dimension as suggested by DJ Martin or use an on("click", ...) handler to call the filter on the second chart.

How do I get a topojson layer to show up in leaflet using d3?

I have been trying to make a very simple map on Leaflet for the past two days and am hitting a wall.
I have a topoJSON file with two layers made from previous geoJSON files: US zipcodes for 5 states, and the polygons of the 5 states.
I want to display these on Leaflet and it is important to use topoJSON instead of geoJSON due to the smaller file size with the zip codes layer.
The problem is I cannot for the life of me get even the smaller states layer in my topoJSON file to display on the map. I've looked at lots of examples on the web and followed Mike Bostock's example: https://github.com/mbostock/bost.ocks.org/blob/gh-pages/mike/leaflet/index.html#L131-171.
I can get the file to display in a web browser using just d3, so the file is fine. I'm using v1 of topoJSON along with the topojson.feature method in the script. The code is below. I can't make the topoJSON file available, but I'm assuming it's fine because I've used it with d3 before. If someone could spot something out of whack with the script, that'd be great.
Thanks.
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.2/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.6.2/leaflet.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="http://d3js.org/d3.v2.min.js?2.9.3"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<title>Gulf Zip Codes</title>
</head>
<div id="map"></div>
<style type="text/css">
#map {
height: 800px;
}
path {
fill: #000;
fill-opacity: .1;
stroke: #fff;
stroke-width: 1.5px;
}
path:hover {
fill: #1f77b4;
fill-opacity: .4;
}
</style>
<body>
<script>
var map = L.map('map').setView([32.546813, -88.374023], 6);
L.tileLayer('http://{s}.tile.cloudmade.com/1a1b06b230af4efdbb989ea99e9841af/998/256/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var svg = d3.select(map.getPanes().overlayPane).append("svg"),
g = svg.append("g").attr("class", "leaflet-zoom-hide");
d3.json("states_and_codes.json", function(error, states_and_codes) {
var bounds = d3.geo.bounds(states_and_codes);
path = d3.geo.path().projection(project);
var feature = g.selectAll("path")
.data(topojson.feature(states_and_codes, states_and_codes.objects.claim_states).features)
.enter().append("path")
.attr("class", "path")
.attr("d",path);
map.on("viewreset", reset);
reset();
// Reposition the SVG to cover the features.
function reset() {
var bottomLeft = project(bounds[0]),
topRight = project(bounds[1]);
svg .attr("width", topRight[0] - bottomLeft[0])
.attr("height", bottomLeft[1] - topRight[1])
.style("margin-left", bottomLeft[0] + "px")
.style("margin-top", topRight[1] + "px");
g .attr("transform", "translate(" + -bottomLeft[0] + "," + -topRight[1] + ")");
feature.attr("d", path);
}
// Use Leaflet to implement a D3 geographic projection.
function project(x) {
var point = map.latLngToLayerPoint(new L.LatLng(x[1], x[0]));
return [point.x, point.y];
}
});
</script>
</body>
In case your still searching, or for any others out there, this should be the missing piece - bounds of TopoJson;
var bounds = d3.geo.bounds(topojson.feature(states_and_codes, states_and_codes.objects.claim_states));
You will also find here a host of good TopoJson blocks from the source!

Resources