I have a C3 xy chart, that I'm trying to add an onclick to. The onclick is commented out (lines 58-70) in the attached fiddle. Scatter Fiddle The chart does not show when I have the onclick code included, somewhere I've messed up the syntax.
var clickEvent = function(d) {
var clickData = d.id;
var clickValue = d.value; //y value ROS
var clickCat = [d.x]; //x value AU
var clickLegend = [d.name];
var clickYear = d.id == 'data1' ? tooltips.data1[d.index] : d.id == 'data2' ? tooltips.data2[d.index] : d.id == 'data3' ? tooltips.data3[d.index] : d.id == 'data4' ? tooltips.data4[d.index] : null;
var allTogether = clickData + "|" + clickValue + "|" + clickCat + "|" + clickLegend + "|" + clickYear;
var theURL = alert(allTogether);
}
onclick: clickEvent
After extracting your method declaration outside of your config I could see that you messed up your configuration. After your comment
//type: 'scatter' // uncoment to remove lines
were some closing brackets which closed your data property. So you actually placed your onclick function outside this property which is equivalent of no method being declared.
Here is your fixed fiddle.
Related
When I click on a dc.js stacked bar chart, my pie chart elsewhere on the same page doesn't show the correct groups.
I'm new to dc.js, so I've created a simple dataset to demo features I need: Alice and Bob write articles about fruit, and tag each article with a single tag. I've charted this data as follows:
Line chart showing number of articles per day
Pie chart showing total number of each tag used
Stacked bar chart showing number of tags used by author
The data set is as follows:
rawData = [
{"ID":"00000001","User":"Alice","Date":"20/02/2019","Tag":"apple"},
{"ID":"00000002","User":"Bob","Date":"17/02/2019","Tag":"dragonfruit"},
{"ID":"00000003","User":"Alice","Date":"21/02/2019","Tag":"banana"},
{"ID":"00000004","User":"Alice","Date":"22/02/2019","Tag":"cherry"},
{"ID":"00000005","User":"Bob","Date":"23/02/2019","Tag":"cherry"},
];
Illustrative JSFiddle here: https://jsfiddle.net/hv8sw6km/ and code snippet below:
/* Prepare data */
rawData = [
{"ID":"00000001","User":"Alice","Date":"20/02/2019","Tag":"apple"},
{"ID":"00000002","User":"Bob","Date":"17/02/2019","Tag":"dragonfruit"},
{"ID":"00000003","User":"Alice","Date":"21/02/2019","Tag":"banana"},
{"ID":"00000004","User":"Alice","Date":"22/02/2019","Tag":"cherry"},
{"ID":"00000005","User":"Bob","Date":"23/02/2019","Tag":"cherry"},
];
var data = [];
var parseDate = d3.timeParse("%d/%m/%Y");
rawData.forEach(function(d) {
d.Date = parseDate(d.Date);
data.push(d);
});
var ndx = crossfilter(data);
/* Set up dimensions, groups etc. */
var dateDim = ndx.dimension(function(d) {return d.Date;});
var dateGrp = dateDim.group();
var tagsDim = ndx.dimension(function(d) {return d.Tag;});
var tagsGrp = tagsDim.group();
var authorDim = ndx.dimension(function(d) { return d.User; });
/* Following stacked bar chart example at
https://dc-js.github.io/dc.js/examples/stacked-bar.html
adapted for context. */
var authorGrp = authorDim.group().reduce(
function reduceAdd(p,v) {
p[v.Tag] = (p[v.Tag] || 0) + 1;
p.total += 1;
return p;
},
function reduceRemove(p,v) {
p[v.Tag] = (p[v.Tag] || 0) - 1;
p.total -= 1;
return p;
},
function reduceInit() { return { total: 0 } }
);
var minDate = dateDim.bottom(1)[0].Date;
var maxDate = dateDim.top(1)[0].Date;
var fruitColors = d3
.scaleOrdinal()
.range(["#00CC00","#FFFF33","#CC0000","#CC00CC"])
.domain(["apple","banana","cherry","dragonfruit"]);
/* Create charts */
var articlesByDay = dc.lineChart("#chart-articlesperday");
articlesByDay
.width(500).height(200)
.dimension(dateDim)
.group(dateGrp)
.x(d3.scaleTime().domain([minDate,maxDate]));
var tagsPie = dc.pieChart("#chart-article-tags");
tagsPie
.width(150).height(150)
.dimension(tagsDim)
.group(tagsGrp)
.colors(fruitColors)
.ordering(function (d) { return d.key });
var reviewerOrdering = authorGrp
.all()
// .sort(function (a, b) { return a.value.total - b.value.total })
.map(function (d) { return d.key });
var tagsByAuthor = dc.barChart("#chart-tags-by-reviewer");
tagsByAuthor
.width(600).height(400)
.x(d3.scaleBand().domain(reviewerOrdering))
.xUnits(dc.units.ordinal)
.dimension(authorDim)
.colors(fruitColors)
.elasticY(true)
.title(function (d) { return d.key + ": " + this.layer + ": " + d.value[this.layer] });
function sel_stack(i) {
return function(d) {
return d.value[i];
};
}
var tags = tagsGrp
.all()
.sort(function(a,b) { return b.value - a.value})
.map(function (d) { return d.key });
tagsByAuthor.group(authorGrp, tags[0]);
tagsByAuthor.valueAccessor(sel_stack(tags[0]));
tags.shift(); // drop the first, as already added as .group()
tags.forEach(function (tag) {
tagsByAuthor.stack(authorGrp, tag, sel_stack(tag));
});
dc.renderAll();
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter2/1.4.7/crossfilter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.1/dc.min.js"></script>
<div id="chart-articlesperday"></div>
<div id="chart-article-tags"></div>
<div id="chart-tags-by-reviewer"></div>
As you can see, Alice has made three articles, each tagged with "apple", "banana" and "cherry" respectively, and her stacked bar chart shows this.
However whenever her column of the bar chart is clicked, the pie chart instead shows her as having 1 "apple" and 2 "cherry".
It took me a very long time even to get to this point, so it may be that there's something fundamental I'm not getting about crossfilter groupings, so any insights, tips or comments are very welcome.
Indeed, this is very weird behavior, and I wouldn't know what to think except that I have faced it a few times before.
If you look at the documentation for group.all(), it warns:
This method is faster than top(Infinity) because the entire group array is returned as-is rather than selecting into a new array and sorting. Do not modify the returned array!
I guess otherwise it might start modifying the wrong bins when aggregating. (Just a guess, I haven't traced through the code.)
You have:
var tags = tagsGrp
.all()
.sort(function(a,b) { return b.value - a.value})
.map(function (d) { return d.key });
Adding .slice(), to copy the array, fixes it:
var tags = tagsGrp
.all().slice()
.sort(function(a,b) { return b.value - a.value})
.map(function (d) { return d.key });
working fork of your fiddle
We actually have an open bug where the library does this itself. Ugh! (Easy enough to fix, but a little work to produce a test case.)
I am using d3-dagre to render the data. Initially i can render the data without any problem. When i try to update the same view in watch mode, it is updating the data but still some error is thrown in the console for "g" attribute transformation. Whenever i try to rewrite the SVG elements i am removing the "g" element inside the "svg" tag. I am trying this in vuejs2 ui library.
watch: {
workflowDetails: function (changes) {
console.log('Update component ==> ' + changes)
this.workflowName = changes.label
this.workflowDetails = changes
this.metricGraph = false
this.drawDAGView()
}
},
mounted () {
this.drawDAGView()
},
methods: {
getJobid: function (nodeId) {
console.log('Function to get graph api' + nodeId)
this.metricGraph = true
},
drawDAGView: function (isUpdate) {
/* eslint-disable */
d3.selectAll('svg > g').remove()
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({})
var DagNodes = this.workflowDetails.nodes
var fillColor
// Add states to the graph, set labels, and style
Object.keys(DagNodes).forEach(function(key) {
console.log("Nodes - "+ DagNodes[key].name)
var value = DagNodes[key]
value.label = DagNodes[key].name + " (" + DagNodes[key].exec_time + ")"
value.rx = value.ry = 5
g.setNode(DagNodes[key].name, value)
})
var DagEdges = this.workflowDetails.edges;
// Add states to the graph, set labels, and style
Object.keys(DagEdges).forEach(function(key) {
g.setEdge(DagEdges[key].startEdge, DagEdges[key].endEdge, { label: ""} )
})
// Create the renderer
var render = new dagreD3.render()
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select("svg"),
inner = svg.append("g")
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")")
})
svg.call(zoom)
// Simple function to style the tooltip for the given node.
var styleTooltip = function(name, description) {
return "<p class='name'>" + name + "</p><p class='description'>" + description + "</p>"
}
// Run the renderer. This is what draws the final graph.
render(inner, g)
inner.selectAll("g.node")
.attr("title", function(v) {
return styleTooltip(v, "Execution Time: "+g.node(v).label + " <br /> Description: "+g.node(v).label)
})
//.each(function(v) { $(this).tipsy({ gravity: "w", opacity: 1, html: true }) })
var self = this
inner.selectAll("g.node")
.on("click", function(v) {
console.log("Nodes --> "+ v + " -- "+ g.node(v).node_id)
// whatever
//window.location = "../dag/"+g.node(v).job_id
self.nodeId = g.node(v).node_id
console.log("Node id -- "+ self.nodeId)
self.getJobid(self.nodeId)
})
// Center the graph
var initialScale = 1.2
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 50, 20])
.scale(initialScale)
.event(svg)
svg.attr('height', g.graph().height * initialScale + 40)
svg.attr('width', "100%")
}
Error - Due to this below error newly loaded data not able to zoom
Error: <g> attribute transform: Expected number, "translate(NaN,20)
Have you tried removing the svg? After removing the svg you can add the new Graph.
https://bl.ocks.org/mbostock/4063269
I am using the same data as in the above mentioned example, but when I am trying to pass that data using foreach loop, It was not working fine. My input data is stored in object named data. I get the following error. Can someone please help me??? It's a request.
csv_converter.html:70 Uncaught TypeError: Cannot read property 'split' of undefined at SVGTextElement.....
data.forEach(function(d){
classes=d;
d.value = +d.value;
if (d.value) return d.value;
var root = d3.hierarchy({children: classes})
.sum(function(d) {if(d.value>0 && d.value!=null && d.value!=""){return d.value}})
.each(function(d) {
if (id = d.id) {
var id, i = id.lastIndexOf(".");
d.id = id;
d.package = id.slice(0, i);
console.log(d.package);
d.class = id.slice(i + 1);
}
});
I changed my code a bit, and its working fine.
classes=data;
data.forEach( function(d) {
d.value = +d.value;
});
var root = d3.hierarchy({children: classes})
.sum(function(d) { if(d.value>0){return d.value}; })
.each(function(d) {
if (id = d.data.id) {
var id, i = id.lastIndexOf(".");
d.id = id;
d.package = id.slice(0, i);
//console.log(d.package);
d.class = id.slice(i + 1);
}
});
Filter/Brush ranges are not working for some values in one of my charts.
The range of this chart starts at 0 and ends at 300.
brush selection for Ranges > 100 are not working and the other charts are not filtering and displaying relevant data.
It would be helpful if someone can point out possible issue.
Sample Data - Begin
ioi,analysis_date,closing_minutes,trade_time,window,price_channel,trade_quantity
No,02/28/2011,No,12:36.0,12:38:00,0.73,15,
No,02/28/2011,No,12:39.0,12:40:00,0.73,23,
No,02/28/2011,No,12:57.0,12:58:00,0.73,58,
No,02/25/2011,No,09:21.0,09:22:00,0.64,10,
No,02/25/2011,No,09:31.0,09:32:00,0.64,85,
Yes,11/30/2010,Yes,12:58.0,13:00:00,0.95,300,Long,
Yes,11/30/2010,Yes,12:58.0,13:00:00,0.95,200,Long,
END
NO or YES is start of new line
CODE BEGIN
var analysis_date_dimension;
var dimension_trade_qty;
var dim_time_of_day;
d3.csv("formatted_client_data.csv", function (error, response) {
var min_trade_quantity = 0
var max_trade_quantity = 310;
response.forEach(function (d, i) {
d.index = i;
d.analysis_date = d3.time.format("%m/%d/%Y").parse(d.analysis_date);
d.trade_time = d3.time.format("%I:%M").parse(d.trade_time.split('.')[0]);
d.date_time = getDateTime(d.analysis_date, d.trade_time);
});
function getDateTime(date, time) {
var dd = date.getDate();
var mm = date.getMonth() + 1;
var yy = date.getFullYear();
var hh = time.getHours();
var ms = time.getMinutes();
var x = yy + ',' + mm + ',' + dd + ' ' + hh + ':' + ms;
return new Date(x);
}
var responseData = crossfilter(response);
//Main Chart
analysis_date_dimension = responseData.dimension(
function (d) { return d.analysis_date; });
var day_total = analysis_date_dimension.group().reduceSum(
function (d) { return d.trade_quantity; });
//Trade Quantity Chart
dimension_trade_qty = responseData.dimension(
function (d) { return d.trade_quantity; });
var group_trade_qty = dimension_trade_qty.group().reduceCount(
function (d) { return d.trade_quantity; });
var day_chart = dc.barChart("#charts");
var trad_qty_chart = dc.barChart("#chart_trade_qty");
//Days chart
day_chart
.width(1024).height(340)
.dimension(analysis_date_dimension)
.group(day_total)
.brushOn(true)
.x(d3.time.scale().domain(d3.extent(response, function (d) { return d.analysis_date; })))
.yAxis().tickFormat(d3.format("d"));
//Trade Quantity Chart
trad_qty_chart
.width(600).height(200)
.dimension(dimension_trade_qty)
.group(group_trade_qty)
.brushOn(true)
.x(d3.scale.linear().domain([min_trade_quantity, max_trade_quantity + 10]))
.yAxis().ticks()
;
dc.renderAll();
});
CODE END
The data i had, had to be reformatted to number. d.trade_quantity = +d.trade_quantity; The brush filters are working as expected now.
When I hover on the lines on the cumulative line chart I get a tooltip message x value at some y time. I want to edit this message and add more content.
Since in my values array I have json containing {X:x, Y:y, Z:z, Dt:date} I wish to show a custom message listing X/Y/Z at date.
I'm using nvd3 veraion 1.1.15b.
Calling .tooltip() didn't work for me, but calling .tooltipContent() did, as in the following code:
var chart = nv.models.pieChart()
.x(function (d) { return d.file; })
.y(function (d) { return d.size; })
.tooltipContent(function (key, y, e, graph) {
return '<h3>' + key + '</h3>' +
'<p>' + e.value.toSizeFmt() + '</p>';
})
As Andrei points out above, the e parameter provides access to the raw values so you can format them, rather than working with y which is already formatted text. Hope this helps!
If you have not found a proper solution yet, here you try this -
nv.addGraph(function() {
var chart = nv.models.cumulativeLineChart().x(function(d) {
return d[0]
}).y(function(d) {
return d[1]
}).color(d3.scale.category10().range()).tooltip(function(key, x, y, e, graph) {
return '<h3>' + key + ' Custom Text Here ' + x + '</h3> here' + '<p> or here ,' + y + '</p>'
});
});
Hope it helps.