How to create next level of flow chart in d3js - javascript

I have created a basic flow chart but I am not getting that how to create next level of flow chart.
I am attaching the image and the jsfiddle link.
Fiddle
here is the data
"process":[
{
"ProcessName" : "nivprocess.exe",
"Username" : "Joh Doe",
"Created" : "10:00:00",
"processDescription" : null,
"process_parent" : null,
"operation" : [
{
"operationDescription":"OP1",
"operationTime":"10:15:15",
"response":"Fail"
},{
"operationDescription":"OP2",
"operationTime":"10:20:00",
"response":"Success"
}
],
},
{
"ProcessName" : "Process2.exe",
"Username" : "Some One",
"Created" : "11:00:00",
"processDescription" : null,
"process_parent" : "process1",
"operation" : [
{
"operationDescription":"OP1",
"operationTime":"10:15:15",
"response":"Fail"
},{
"operationDescription":"OP2",
"operationTime":"10:20:00",
"response":"Success"
}],
},
{
"ProcessName" : "Process3.exe",
"Username" : "Nika Boka",
"Created" : "12:00:00",
"processDescription" : null,
"process_parent" : "process2",
"operation" : [
{
"operationDescription":"OP1",
"operationTime":"10:15:15",
"response":"Fail"
},{
"operationDescription":"OP2",
"operationTime":"10:20:00",
"response":"Success"
}],
}
]}

You're drawing this manually (I assumed the flow chart meant a chart meaning a d3 layout), your data array has 3 data points so this will map to 3 drawn objects directly. I can see your code (which you should attach to the questions too) is drawing lines with two rects (under label text) and four pieces of text for each data point, however it's not processing any of the operation arrays in the data point.
An aside: I'm noticing some clipping, in JS fiddle it helped me to temporarily set the svg tag with a width:
<svg style="padding-top: 100px; width:100%" class="chart">
There's two approaches forward I might try:
Create an empty group associated with each process rect, var ops = chart.selectAll("g g"); then figure out the right way to get a reference to the data point bound to each parent g, lets refer to it by dp. Then do ops.selectAll("g").data(dp.operation).enter().append("g"); On each enter draw that first line to the fork. Then work with each operation within this groups' groups' group to draw the two operation lines, the operation circle and labels similar to work you did before. Notice I'm fuzzy on getting the reference to dp. It might be something like: bar.each(function(dp,i,t){d3.selectAll(t).data(dp.operation).enter().etc;});
Possibly manually setup the right selections. Assuming you made that empty second g like in the "append test", manual setup would look a bit like: data.forEach(function(dp, idx, arr){bar[idx].data(dp.operation).enter().etc;}) where I'm hoping the bar selectAll's indexes are in the same order as the data's. They will match in quantity.
While trying to go with #1, I ended up getting this to get part of the way to where you wanted. It certainly isn't pretty, but you get 1 line to a group for each process, then in each group 1 circle and 1 line for each operation (you'll have to add lines, arrows and labels, and it's a bit weird how I get the offsets):
//appending test
var ops = bar.append("g");
ops
.attr("transform", function(d, i) {
return "translate("+width+",0)";
});
ops
.append('line')
.attr("x1","0")
.attr("y1",lineHeight/2)
.attr("x2",width/8)
.attr("y2",lineHeight/2)
//.attr("transform","translate(0,-"+(lineHeight*.85)+")")
.attr("stroke","#FF0000")
.attr("stroke-width","4");
ops.each(
function(d,i,t){
if ('object'===typeof this) {
var op = d3.select(this).selectAll('g').data(d.operation).enter().append("g");
var xc=1;
op.append("circle")
.attr("cx",lineHeight)
.attr("cy",function(d){return lineHeight/2*xc++-lineHeight/4})
.attr("r",width/4)
.attr("fill", "#ff0000");
var xl1s=1;
var xl1e=1;
op.append("line")
.attr("x1",width/8)
.attr("y1",function(d){return lineHeight/2-width/4-lineHeight/4*xl1s++})
.attr("x2",lineHeight)
.attr("y2",function(d){return lineHeight/2-width/4-lineHeight/4*xl1e++})
.attr("stroke","#FF0000")
.attr("stroke-width","4");
}});

Related

C3 Stacked chart loaded from CSV with dynamic categories

I'm trying to draw a stacked (area) line chart using C3.
My code, as it stands, allows me to create a line chart without stacking :
var chart = c3.generate({
data: {
x: 'x',
url: 'GeneratedData.csv',
type: 'area',
/* groups: [ ['data1', 'data2'] ] */
},
axis : {
x : {
type : 'timeseries',
tick : {
format : "%y-%m-%d"
}
}
}
});
My problem is that the data is generated in such a way that I do not know the name of the columns in advance, so I cannot set their type or group them
(hence the comments around groups: [ ['data1', 'data2'] ])
My CSV looks something like this :
x,LT62Ag,5NwafDw,Pac0dA
2017-01-22,85797,145417,626803
2017-01-23,71837,105246,440776
2017-01-24,77650,108834,442359
...
2017-03-31,87359,102618,467113
How should I proceed to create the groups from the dynamic data to stack the charts ?
You could try adding this to your chart declaration, it'll pull out the names of the data series (apart from x) and turn them into one big group:
onrendered: function () {
var seriesNames = this.data.targets.map (function (d) {
return d.id;
}).filter (function (sname) {
return sname !== "x";
});
this.api.groups ([seriesNames]);
},
Ideally it should be done with the 'oninit' declaration rather than the groups reset on every rendering, but there seems to be some sort of bug that makes the bars go 1 pixel wide when you do that...
I guess a flag that decides whether the groups have already been set could be employed though...
https://jsfiddle.net/1bb60dd9/

d3 v4: Tree map is giving NaN for x and y

I have some tree-ish data that I stratify using d3.stratify, which gives me what I assume is a proper data structure (it has children, data and parents). However, when I pass it through d3.tree(), the x and y values are all NaNs, which makes plotting them impossible. Based on examples I've seen, I don't need to run d3.hierarchy() since stratify does that for me, and I've tried using hierarchy() without success anyway.
I tried doing JSON.stringify(data) to paste the data here, but it gave me an error about converting circular structures to JSON not being possible, so that didn't work either. What I do know is that each layer (except for the top one) has a children array, a data object and a parent object, so it all seems to be right.
edit: I tried some test data (from this link) and I still get NaNs for x and y. I copied the treeData, put it through d3.hierarchy and then put it through this tree() call and x and y are still NaN.
var treeMap = d3.tree()
.size(width, height2); // 1020, 170 in my case.
var treeData =
{
"name": "Top Level",
"children": [
{
"name": "Level 2: A",
"children": [
{ "name": "Son of A" },
{ "name": "Daughter of A" }
]
},
{ "name": "Level 2: B" }
]
};
treeData = d3.hierarchy(treeData, function(d) { return d.children; });
var nodes = treeMap(treeData); // gives NaN x and y values.
Ahh, so simple yet so silly. Instead of passing ([height, width]) I was passing (height, width) to the tree function, so of course it failed wildly. Giving it the proper array fixes everything.

C3 stacked chart maintain data order

I'm following the instructions from the reference and from this answer, but am having no success.
I've got a stacked bar chart, I want the data in the stack to appear in the order it is in in the data, but it's getting re-ordered and I can't figure out how to prevent it.
Here's a jsfiddle.
Here's the code
var chartOptions = {
element: 'chart',
data: {
"rows":[["0-1","2-3","4-5","6","7"],[25,56,14,2,1],[6,66,27,0,0],[0,70,30,0,0],[27,54,14,5,0],[0,54,30,8,8],[29,64,7,0,0]],
"type":"bar",
"groups":[["0-1","2-3","4-5","6","7"]],
"order":null
},
axis: {
"x":{
"type":"category",
"categories":["Whole List","committed","community","congregation","core","crowd"]
},
"y":{
"padding":{
"top":0
}
}
},
stacked: true,
size: {"height":300}
}
var chart = c3.generate(chartOptions);
I would like the series to be in the order 0-1, 2-3, 4-5, etc
Turns out this is a known issue. If any one of the headers is an integer (or a string that is an integer), then c3 will sort the columns.
To work around I'm appending a space to the end of the column names so c3 interprets them as a string and not a number.
eg
chartOptions['data']['rows'][0] = ["0-1","2-3","4-5",
"6 ", "7 "]; // Spaces appended to these
chartOptions['data']["groups"] = [["0-1","2-3","4-5","6 ", "7 "]];
I've updated the jsfiddle with the workaround.

Unable to re-produce valid data for d attribute of a path

When I create the first set of sectors in my pie chart, it works great. Especially, the attribute d of each path is set correctly.
var grx = chart.selectAll(".sector").data(pie(dataPoints))
.enter().append("g").attr("class", "sector");
grx.append("path").attr("d", arc)
.style("fill", function(d) { return colorsFull(d.value); });
Then, I try to use the same pattern to add a new, inner pie chart. The elements are created, which I can confirm by investigating the DOM structure. However, they're not displayed and, even though it's not shown in the console of the JsFiddle, I got it to have a bunch of NaN.
var gry = chart.selectAll(".subSector").data(pie(drillData))
.enter().append("g").attr("class", "subSector");
gry.append("path").attr("d", sub)
.style("fill", function(d) {return colorsDrill(d.value); });
So, I've got an invalid data for the path but I can't see how it goes wrong. Suggestions?
The fiddle is here.
Your drillData is not in the correct format to pass to your pie function. It looks like this:
[
{
"key": "Category 1",
"val": [{ "Category": "", "Key": "", Value: 1}, ... ]
}
...
]
Your pie function, though, is expecting an array of objects with a property val that's a number, not an array (this is what the .value does).
I'm guessing you need to subset your drillData to the one you clicked on something like:
var subData = null;
drillData.forEach(function(d,i){
if (d.key === key) subData = drillData[i].val;
});
You now have in subData an array of objects with a property Value that's a number. We are getting closer but now we need to redefine our pie function since it's expecting val, not Value:
pie.value(function(d){
return d.Value;
});
So, now we can finally call:
pie(subData)
without error. But, we still got a problem, now you are trying to build an inner donut chart with 300+ wedges (it ain't going to be pretty).
Here's an updated fiddle where I started fixing things.

Force ChartJS to show Doughnut chart with null values

I have a grid with 4 doughtnut charts on each column for different periods of time: last 90 days, last 60 days, last 7 days and today.
The problem with today is that it doesn't always show data, especially in the morning. Is there a way to force ChartJS to show the chart even if it doesn't have any data?
Here's an example: http://jsfiddle.net/6xV78/219/
var pieData = [
{
value: 0,
color:"#3F9F3F"
},
{
value : 0,
color : "#222"
}
];
I found a quick work-around, not sure how "good" or "valid" way it is but it's working for me. If the values are null/zero I replaced them with -1 to retain the looks of the chart and then use the custom tooltip function to override the output.
{
...
data: [earned == 0 ? -1 : earned, pending == 0 ? -1 : pending]
...
},
options: {
tooltip: {
callbacks: {
label: function (tooltipItem, data) {
const value = data['datasets'][0]['data'][tooltipItem['index']];
return '$' + (value == -1 ? 0 : value);
}
}
}
}
Obviously I have 2 slices and when both are 0 the chart is displayed with 2 equal halves both showing $0 income (both earned and pending).
*Do note that this will still take 1 into account when others aren't null so you need to take care of that on your end. I added a method to verify if ALL values are null and that's the only case I display it like this.
A pie chart with all values equal to zero is ill-defined. Because the angle (and the area) of each slice is proportionate to the ratio of the slice's respective value over the sum of all values. If all values are equal to zero, then their sum is zero. Division by zero should be rightfully avoided by the library (hopefully by design), resulting in the no-pie-chart case you encounter. It should be the programmer's responsibility to detect the all-zeros case before populating the chart, if such a case has a possibility of occurring. Then the programmer could either display a "No data yet. What are you doing up so early? Go to sleep." message, if all values are zero. Or, maybe, if they terribly need to keep the looks consistent (having a chart there all the time), they could show a special all-black no-data pie chart with the following dummy data:
var pieNoData = [
{
value: 1,
color: "#000000"
}
];
There is no shame in disclosing that no data exists yet, though.

Categories

Resources