简体   繁体   中英

Donut chart in D3 JS Sankey diagram

I have a D3 Js Sankey diagram, with lots of data. At the end of the data are always companies. The company node is a simple circle. But around that circle i want a donut chart, with 2 values. The values are inside the company node as numsms and nummid. you can also see that in the picture below.

Example of the diagram: 在此输入图像描述

So I want around the company circles a donut chart. But I can't seem to get this to work, I've only found examples for donut charts as own svg.

My code for circles:

svg.selectAll(".node.circle")
        .append("circle")
        .attr("r", function(d) {
            if(d.node.indexOf("company-") > -1) {
                return company_circle_size(d);
            } else {
                return page_circle_size(d);
            }
        })
        .attr("cy", function(d) { return d.dy/2;})
        .attr("cx", function(d) {
            var cx = sankey.nodeWidth() - 30;
            if(d.node.indexOf("company-") > -1) {
                cx = cx + 15;
            }
            return cx;
        })
        .style("fill", function (d) {
            if(d.node.indexOf("company-") > -1) {
                if(d.name.indexOf("No data") > -1) {
                    return "grey";
                }
                var color = '';
                switch(d.status) {
                    case 'Approved':
                        color = 'green';
                        break;
                    case 'inactive ':
                        color = 'red';
                        break;
                    case 'initial':
                        color = 'yellow';
                        break;
                    case 'review':
                        color = 'blue';
                        break;
                    default:
                        color = 'grey';
                        break;
                }
                return color;
            }
            return "grey";
            //return d.color = color(d.name.replace(/ .*/, ""));
        })
        .style("fill-opacity", ".9")
        .style("shape-rendering", "auto")
        .style("stroke", function (d) {
            return d3.rgb(d.color).darker(2);
        })
        .append("title")
        .text(function (d) {
            if(d.node.indexOf("company-") > -1) {
                if(d.cpId != null) {
                    return d.name + "\n cpId: " + d.cpId;
                }
                return d.name;
            }
            return d.name + "\n" + format(d.value);
        });

In a for loop I replace the class name "node circle" to "node company".

$(selector).attr("class", "node company")

I've tried some things and I think the code needs to be placed here.

svg.selectAll('.company').each(function(companyNode) {
        var values = [[companyNode.numsms, companyNode.nummid]];
        var total = companyNode.numsms + companyNode.nummid;

        if(total > 0) {
            // create donut chart
        }
    });

You can append a div to the node using foriegnObject. In that div pass your values to an inline jquery sparkline chart (line, pie, etc). Set the transparency of the div so that it doesn't block the diagram. Add your values to the original sankey data array(ie source,target,value,numsms,numid) and then call them in the append with d.numsms).

//sparkline plugin and setup...  http://omnipotent.net/jquery.sparkline/#s-docs
//something like the following, look at the fiddle for more info

node.append("foreignObject")
.attr("width", sankey.nodeWidth()*2)
.attr("height", function(d) { return d.dy/2 })
.attr("transform", function(d) { return "translate(" + (d.x+20) + "," + (d.y+10) + ")"; })
.append("xhtml:body")
.style("font", "14px 'Helvetica Neue'")
.html("<div>Inline Sparkline: <span class='inlinesparkline'>1,4,4,7,5,9,10</span></div>");

After adding the div to each node call the plugin to activate the inline charts.

$('.inlinesparkline').sparkline(); 

Have a look at my fiddle. It's not a sankey but it does show you how to implement foriegnObject.

d3.js diagram with inline charts!

Hope this helps.

Finally got back to this question.

Here's a quick example combining a sankey diagram containing a donut chart. I didn't fit it to your data, this is a generic example.

// if no pie data, just use rects as normal
node.filter(function(d){
    return !d.pieData;
  })
  .append("rect")
  .attr("height", function(d) {
    return d.dy;
  })
  .attr("width", sankey.nodeWidth())
  .style("fill", function(d) {
    return d.color = color(d.name.replace(/ .*/, ""));
  })
  .style("stroke", function(d) {
    return d3.rgb(d.color).darker(2);
  })
  .append("title")
  .text(function(d) {
    return d.name + "\n" + format(d.value);
  });

// set up donut chart stuff
var pColor = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

var arc = d3.svg.arc()
    .outerRadius(50)
    .innerRadius(20);

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d.value; });

// if we have pie data, draw the donut chart
var g = node.filter(function(d){
    return d.pieData;
  })
  .append("g")
  .attr('transform', function(d,i){
     return 'translate('+d.dx/2+','+d.dy/2+')'; // proper position
  })
  .attr("class","donut")
  .selectAll(".arc")
  .data(function(d){
    return pie(d.pieData); // nested selection to assign data
  })
  .enter().append("g")
  .attr("class", "arc");

g.append("path")
  .attr("d", arc)
  .style("fill", function(d,i) { return color(i); });

Sankey + Piechart在这里实现: http ://food.csaladen.es(尽管饼图位于静态div中,因此每次唤起它时都会将其移动到节点上方)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM