2 votes

D3 : diagramme de Sunburst avec nœud de racine sur l'anneau extérieur.

Je fais des recherches pour rationaliser la création de graphiques de marketing dans mon entreprise.

L'un d'eux en particulier, un graphique ensoleillé, est produit en Illustrator (difficile à mettre à jour) et je veux le transformer en un graphique D3 (facile à mettre à jour via un fichier JSON ou CSV). Le problème est que le diagramme en étoile est en format ordre inverse ... le nœud racine se trouve sur l'anneau extérieur et les données circulent vers l'intérieur. Note : Je ne peux pas changer l'ordre des données, c'est a d'être comme ça.

Est-il possible d'inverser l'ordre d'affichage d'un diagramme ensoleillé dans D3 ? J'ai fait des expériences avec la fonction de tri... elle a inversé l'ordre de tri d'un graphique à racine d'arbre comme prévu... mais ne semble pas affecter l'ordre de tri d'un graphique ensoleillé.

Voici le diagramme d'insolation avec lequel je travaille (à partir de aquí ) :

    // JSON data
    var nodeData = {
        "name": "TOPICS", "children": [{
            "name": "Topic A",
            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
        }, {
            "name": "Topic B",
            "children": [{"name": "Sub B1", "size": 3}, {"name": "Sub B2", "size": 3}, {
                "name": "Sub B3", "size": 3}]
        }, {
            "name": "Topic C",
            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
        }]
    };

    // Variables
    var width = 500;
    var height = 500;
    var radius = Math.min(width, height) / 2;
    var color = d3.scaleOrdinal(d3.schemeCategory20b);

    // Create primary <g> element
    var g = d3.select('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');

    // Data strucure
    var partition = d3.partition()
        .size([2 * Math.PI, radius]);

    // Find data root
    var root = d3.hierarchy(nodeData)
        .sum(function (d) { return d.size});

    // Size arcs
    partition(root);
    var arc = d3.arc()
        .startAngle(function (d) { return d.x0 })
        .endAngle(function (d) { return d.x1 })
        .innerRadius(function (d) { return d.y0 })
        .outerRadius(function (d) { return d.y1 });

    // Put it all together
    g.selectAll('path')
        .data(root.descendants())
        .enter().append('path')
        .attr("display", function (d) { return d.depth ? null : "none"; })
        .attr("d", arc)
        .style('stroke', '#fff')
        .style("fill", function (d) { return color((d.children ? d : d.parent).data.name); });

<script src="https://d3js.org/d3.v4.min.js"></script>
 <svg></svg>

Merci beaucoup ! jB

1voto

Andrew Reid Points 16844

Cela devrait être assez simple, le rayon intérieur et extérieur de chaque arc doit être modifié. Dans l'original, ils sont définis ici :

var arc = d3.arc()
    .startAngle(function (d) { return d.x0 })
    .endAngle(function (d) { return d.x1 })
    .innerRadius(function (d) { return d.y0 })
    .outerRadius(function (d) { return d.y1 });

Plutôt que de prendre d.y0 et d.y1 comme rayons intérieur et extérieur, nous devons prendre ces valeurs et les soustraire du rayon final de l'éclatement. Ce rayon est trouvé lors de la mise à l'échelle de la taille de l'éclatement :

var partition = d3.partition()
    .size([2 * Math.PI, radius]);

Donc, nous pouvons utiliser :

var arc = d3.arc()
    .startAngle(function (d) { return d.x0 })
    .endAngle(function (d) { return d.x1 })
    .innerRadius(function (d) { return radius - d.y1 })
    .outerRadius(function (d) { return radius - d.y0 });

Cela place les parents à l'extérieur de leurs enfants.

J'ai échangé d.y1 et d.y0 car d.y0 se réfère au plus petit nombre ; c'est le rayon intérieur lorsqu'on se déplace vers l'extérieur normalement, mais avec la valeur retournée égale à radius-d.y0, il est maintenant utilisé pour définir le rayon extérieur

Voici un exemple :

    // JSON data
    var nodeData = {
        "name": "TOPICS", "children": [{
            "name": "Topic A",
            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
        }, {
            "name": "Topic B",
            "children": [{"name": "Sub B1", "size": 3}, {"name": "Sub B2", "size": 3}, {
                "name": "Sub B3", "size": 3}]
        }, {
            "name": "Topic C",
            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
        }]
    };

    // Variables
    var width = 500;
    var height = 500;
    var radius = Math.min(width, height) / 2;
    var color = d3.scaleOrdinal(d3.schemeCategory20b);

    // Create primary <g> element
    var g = d3.select('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');

    // Data strucure
    var partition = d3.partition()
        .size([2 * Math.PI, radius]);

    // Find data root
    var root = d3.hierarchy(nodeData)
        .sum(function (d) { return d.size});

    // Size arcs
    partition(root);

    var arc = d3.arc()
        .startAngle(function (d) { return d.x0 })
        .endAngle(function (d) { return d.x1 })
        .innerRadius(function (d) { return radius - d.y1; })
        .outerRadius(function (d) { return radius - d.y0; });

    // Put it all together
    g.selectAll('path')
        .data(root.descendants())
        .enter().append('path')
        .attr("d", arc)
        .style('stroke', '#fff')
        .style("fill", function (d) { return color((d.children ? d : d.parent).data.name); });

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<svg></svg>

Notez, j'affiche le noeud racine ici, dans l'original il n'est pas montré (créant un donut). Si vous voulez garder l'effet beignet, nous pouvons continuer à cacher la racine, mais ajouter un peu de remplissage aux valeurs des rayons :

  // JSON data
    var nodeData = {
        "name": "TOPICS", "children": [{
            "name": "Topic A",
            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
        }, {
            "name": "Topic B",
            "children": [{"name": "Sub B1", "size": 3}, {"name": "Sub B2", "size": 3}, {
                "name": "Sub B3", "size": 3}]
        }, {
            "name": "Topic C",
            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
        }]
    };

    // Variables
    var width = 500;
    var height = 500;
    var radius = Math.min(width, height) / 2;
    var color = d3.scaleOrdinal(d3.schemeCategory20b);

    // Create primary <g> element
    var g = d3.select('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');

    // Data strucure
    var partition = d3.partition()
        .size([2 * Math.PI, radius]);

    // Find data root
    var root = d3.hierarchy(nodeData)
        .sum(function (d) { return d.size});

    // Size arcs
    partition(root);
    var arc = d3.arc()
        .startAngle(function (d) { return d.x0 })
        .endAngle(function (d) { return d.x1 })
        .innerRadius(function (d) { return radius - d.y1 + root.y1; })
        .outerRadius(function (d) { return radius - d.y0 + root.y1; });

    // Put it all together
    g.selectAll('path')
        .data(root.descendants())
        .enter().append('path')
        .attr("display", function (d) { return d.depth ? null : "none"; })
        .attr("d", arc)
        .style('stroke', '#fff')
        .style("fill", function (d) { return color((d.children ? d : d.parent).data.name); });

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<svg></svg>

Ici, j'ajoute simplement le rayon extérieur du nœud Root (qui correspond à la largeur de l'arc, le rayon intérieur étant égal à 0) aux valeurs des rayons. Notez que si vous souhaitez conserver le donut et afficher le nœud Root, vous devrez ajuster la taille du diagramme sunburst en conséquence. Bien que je sois plus enclin à appeler cela un diagramme d'implosion solaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X