<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Problem with the order of donut's slice in Custom Visuals Development Discussion</title>
    <link>https://community.fabric.microsoft.com/t5/Custom-Visuals-Development/Problem-with-the-order-of-donut-s-slice/m-p/3593129#M8503</link>
    <description>&lt;P&gt;Hi everyone,&lt;/P&gt;&lt;P&gt;I am trying to build a custom visual that show 2 donut chart (inner and outer donuts), data and visual as below:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="stawpeed_0-1703059327208.png" style="width: 400px;"&gt;&lt;img src="https://community.fabric.microsoft.com/t5/image/serverpage/image-id/1013730i2EE038D20E5F1FEA/image-size/medium?v=v2&amp;amp;px=400" role="button" title="stawpeed_0-1703059327208.png" alt="stawpeed_0-1703059327208.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;I was expected that slice's order of outer donut to be sorted base on Categories and Subcategories. But it seems to be sorted base on Values.&lt;/P&gt;&lt;P&gt;In Show data as table view, it already sorted by 'Sum of Value':&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="stawpeed_1-1703059533660.png" style="width: 400px;"&gt;&lt;img src="https://community.fabric.microsoft.com/t5/image/serverpage/image-id/1013733i04319EA8BA70FFAC/image-size/medium?v=v2&amp;amp;px=400" role="button" title="stawpeed_1-1703059533660.png" alt="stawpeed_1-1703059533660.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;How could I get this problem fixed?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Below is my visual.ts and capabilities.json&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;"use strict";

import * as d3 from "d3";
import { group } from "d3-array";
import powerbi from "powerbi-visuals-api";
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import IVisual = powerbi.extensibility.visual.IVisual;
import DataView = powerbi.DataView;
import IVisualHost = powerbi.extensibility.IVisualHost;
type Selection&amp;lt;T extends d3.BaseType&amp;gt; = d3.Selection&amp;lt;T, any, any, any&amp;gt;;

export class Visual implements IVisual {
    private host: IVisualHost;
    private svg: Selection&amp;lt;SVGElement&amp;gt;;
    private container: Selection&amp;lt;SVGElement&amp;gt;;
    private firstDonutContainer: Selection&amp;lt;SVGElement&amp;gt;;
    private secondDonutContainer: Selection&amp;lt;SVGElement&amp;gt;;

    constructor(options: VisualConstructorOptions) {
        this.svg = d3.select(options.element)
            .append('svg')
            .classed('doubleDonutChart', true); // Change class to doubleDonutChart
        this.container = this.svg.append("g")
            .classed('container', true);

        // Create the first (inner) donut chart
        this.firstDonutContainer = this.container.append("g")
            .classed('firstDonutContainer', true);

        // Create the second (outer) donut chart
        this.secondDonutContainer = this.container.append("g")
            .classed('secondDonutContainer', true);
    }

    public update(options: VisualUpdateOptions) {
        // Assign the size of viewport
        let width: number = options.viewport.width;
        let height: number = options.viewport.height;
        this.svg.attr("width", width);
        this.svg.attr("height", height);

        // Assuming data contains a category field and a measure field
        let dataView: DataView = options.dataViews[0];
        let categoryValues = dataView.categorical.categories[0].values;
        let measureValues = dataView.categorical.values[0].values.map(val =&amp;gt; Number(val));

// Grouping data by categories and calculating the sum
let groupedData = Array.from(d3.group(measureValues, (d, i) =&amp;gt; categoryValues[i]), ([key, group]) =&amp;gt; ({ category: key, value: d3.sum(group) }));

// Sort the data based on the original order of categories
groupedData.sort((a, b) =&amp;gt; d3.descending(a.category, b.category));

// Create a color scale for categories
const categoryColorScale = d3.scaleOrdinal()
    .domain(categoryValues as string[])  // Assuming category values are strings
    .range(["#b4bbbf", "#717171", "#B4BDFF", "#83A2FF"]);  // Adjust the color range as needed

// Creating the first (inner) donut chart using d3 pie function with innerRadius
let pie = d3.pie&amp;lt;any&amp;gt;().value(d =&amp;gt; d.value);
let pieData = pie(groupedData).sort((a, b) =&amp;gt; d3.ascending(a.data.key, b.data.key));


        let radius: number = Math.min(width, height) / 3;
        let innerRadius: number = radius / 1.4; // Set inner radius for the first donut

        let firstArc: d3.Arc&amp;lt;any, d3.DefaultArcObject&amp;gt; = d3.arc()
            .innerRadius(innerRadius) // Set inner radius for the first donut
            .outerRadius(radius);

        // Update the first (inner) donut chart
        let firstDonutArcs = this.firstDonutContainer.selectAll("path")
            .data(pieData);

        firstDonutArcs.enter().append("path")
            .merge(firstDonutArcs as d3.Selection&amp;lt;SVGPathElement, any, SVGElement, any&amp;gt;)
            .attr("d", function (d: d3.DefaultArcObject | any) {
                return firstArc(d) as string;
            })
            .attr("fill", (d, i) =&amp;gt; String(categoryColorScale(d.data.category)))
            .attr('stroke', 'white')
            .style('stroke-width', '0.5px')
            .style('opacity', 1);

        firstDonutArcs.exit().remove();

        // Center the first (inner) donut chart in the middle of the SVG
        this.firstDonutContainer.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

        // Assuming there is a second category and measure in the data
        let subcategoryValues = dataView.categorical.categories[1].values;
        let secondMeasureValues = dataView.categorical.values[0].values.map(val =&amp;gt; Number(val));

// Grouping data by subcategories and calculating the sum
let groupedSecondData = Array.from(d3.group(secondMeasureValues, (d, i) =&amp;gt; subcategoryValues[i]), ([key, group]) =&amp;gt; ({ category: key, value: d3.sum(group) }));

// Sort the data based on the original order of subcategories
groupedSecondData.sort((a, b) =&amp;gt; d3.descending(a.category, b.category));

// Create a color scale for subcategories
const subcategoryColorScale = d3.scaleOrdinal()
    .domain(subcategoryValues as string[])  // Assuming subcategory values are strings
    .range(["#7D1D57", "#AD719A", "#8DA2AC", "#496E87", "#6d8b9e", "#F1E6EE", "#717171", "#E6E6E6"]);  // Adjust the color range as needed

// Creating the second (outer) donut chart using d3 pie function with innerRadius and outerRadius
let secondPie = d3.pie&amp;lt;any&amp;gt;().value(d =&amp;gt; d.value);
let secondPieData = secondPie(groupedSecondData).sort((a, b) =&amp;gt; d3.descending(a.data.key, b.data.key));


        let outerRadius: number = radius * 1.3; // Set outer radius for the second donut

        let secondArc: d3.Arc&amp;lt;any, d3.DefaultArcObject&amp;gt; = d3.arc()
            .innerRadius(radius) // Inner radius is the outer radius of the first donut
            .outerRadius(outerRadius);

        // Update the second (outer) donut chart
        let secondDonutArcs = this.secondDonutContainer.selectAll("path")
            .data(secondPieData);

        secondDonutArcs.enter().append("path")
            .merge(secondDonutArcs as d3.Selection&amp;lt;SVGPathElement, any, SVGElement, any&amp;gt;)
            .attr("d", function (d: d3.DefaultArcObject | any) {
                return secondArc(d) as string;
            })
            .attr("fill", (d, i) =&amp;gt; String(subcategoryColorScale(d.data.category)))
            .attr('stroke', 'white')
            .style('stroke-width', '0.5px')
            .style('opacity', 1);

        secondDonutArcs.exit().remove();

        // Center the second (outer) donut chart in the middle of the SVG
        this.secondDonutContainer.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    }
}&lt;/LI-CODE&gt;&lt;LI-CODE lang="javascript"&gt;{
    "dataRoles": [
        {
            "displayName": "Category Data",
            "name": "category",
            "kind": "Grouping"
        },
        {
            "displayName": "Measure Data",
            "name": "measure",
            "kind": "Measure"
        }
    ],
  
    "dataViewMappings": [
        {
            "categorical": {
                "categories": {
                    "for": {
                        "in": "category"
                    },
                    "dataReductionAlgorithm": {
                        "top": {}
                    }
                },
                "values": {
                    "select": [
                        {
                            "for": {
                                "in": "measure"
                            }
                        }
                    ]
                }
            }
        }
    ],    
    "sorting": {
        "implicit": {
            "clauses": [
                {
                    "role": "category",
                    "direction": 1
                },
                {
                    "role": "measure",
                    "direction": 2
                }
            ]
        }
    },
    "privileges": []
}&lt;/LI-CODE&gt;</description>
    <pubDate>Wed, 20 Dec 2023 08:11:12 GMT</pubDate>
    <dc:creator>stawpeed</dc:creator>
    <dc:date>2023-12-20T08:11:12Z</dc:date>
    <item>
      <title>Problem with the order of donut's slice</title>
      <link>https://community.fabric.microsoft.com/t5/Custom-Visuals-Development/Problem-with-the-order-of-donut-s-slice/m-p/3593129#M8503</link>
      <description>&lt;P&gt;Hi everyone,&lt;/P&gt;&lt;P&gt;I am trying to build a custom visual that show 2 donut chart (inner and outer donuts), data and visual as below:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="stawpeed_0-1703059327208.png" style="width: 400px;"&gt;&lt;img src="https://community.fabric.microsoft.com/t5/image/serverpage/image-id/1013730i2EE038D20E5F1FEA/image-size/medium?v=v2&amp;amp;px=400" role="button" title="stawpeed_0-1703059327208.png" alt="stawpeed_0-1703059327208.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;I was expected that slice's order of outer donut to be sorted base on Categories and Subcategories. But it seems to be sorted base on Values.&lt;/P&gt;&lt;P&gt;In Show data as table view, it already sorted by 'Sum of Value':&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="stawpeed_1-1703059533660.png" style="width: 400px;"&gt;&lt;img src="https://community.fabric.microsoft.com/t5/image/serverpage/image-id/1013733i04319EA8BA70FFAC/image-size/medium?v=v2&amp;amp;px=400" role="button" title="stawpeed_1-1703059533660.png" alt="stawpeed_1-1703059533660.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;How could I get this problem fixed?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Below is my visual.ts and capabilities.json&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;"use strict";

import * as d3 from "d3";
import { group } from "d3-array";
import powerbi from "powerbi-visuals-api";
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import IVisual = powerbi.extensibility.visual.IVisual;
import DataView = powerbi.DataView;
import IVisualHost = powerbi.extensibility.IVisualHost;
type Selection&amp;lt;T extends d3.BaseType&amp;gt; = d3.Selection&amp;lt;T, any, any, any&amp;gt;;

export class Visual implements IVisual {
    private host: IVisualHost;
    private svg: Selection&amp;lt;SVGElement&amp;gt;;
    private container: Selection&amp;lt;SVGElement&amp;gt;;
    private firstDonutContainer: Selection&amp;lt;SVGElement&amp;gt;;
    private secondDonutContainer: Selection&amp;lt;SVGElement&amp;gt;;

    constructor(options: VisualConstructorOptions) {
        this.svg = d3.select(options.element)
            .append('svg')
            .classed('doubleDonutChart', true); // Change class to doubleDonutChart
        this.container = this.svg.append("g")
            .classed('container', true);

        // Create the first (inner) donut chart
        this.firstDonutContainer = this.container.append("g")
            .classed('firstDonutContainer', true);

        // Create the second (outer) donut chart
        this.secondDonutContainer = this.container.append("g")
            .classed('secondDonutContainer', true);
    }

    public update(options: VisualUpdateOptions) {
        // Assign the size of viewport
        let width: number = options.viewport.width;
        let height: number = options.viewport.height;
        this.svg.attr("width", width);
        this.svg.attr("height", height);

        // Assuming data contains a category field and a measure field
        let dataView: DataView = options.dataViews[0];
        let categoryValues = dataView.categorical.categories[0].values;
        let measureValues = dataView.categorical.values[0].values.map(val =&amp;gt; Number(val));

// Grouping data by categories and calculating the sum
let groupedData = Array.from(d3.group(measureValues, (d, i) =&amp;gt; categoryValues[i]), ([key, group]) =&amp;gt; ({ category: key, value: d3.sum(group) }));

// Sort the data based on the original order of categories
groupedData.sort((a, b) =&amp;gt; d3.descending(a.category, b.category));

// Create a color scale for categories
const categoryColorScale = d3.scaleOrdinal()
    .domain(categoryValues as string[])  // Assuming category values are strings
    .range(["#b4bbbf", "#717171", "#B4BDFF", "#83A2FF"]);  // Adjust the color range as needed

// Creating the first (inner) donut chart using d3 pie function with innerRadius
let pie = d3.pie&amp;lt;any&amp;gt;().value(d =&amp;gt; d.value);
let pieData = pie(groupedData).sort((a, b) =&amp;gt; d3.ascending(a.data.key, b.data.key));


        let radius: number = Math.min(width, height) / 3;
        let innerRadius: number = radius / 1.4; // Set inner radius for the first donut

        let firstArc: d3.Arc&amp;lt;any, d3.DefaultArcObject&amp;gt; = d3.arc()
            .innerRadius(innerRadius) // Set inner radius for the first donut
            .outerRadius(radius);

        // Update the first (inner) donut chart
        let firstDonutArcs = this.firstDonutContainer.selectAll("path")
            .data(pieData);

        firstDonutArcs.enter().append("path")
            .merge(firstDonutArcs as d3.Selection&amp;lt;SVGPathElement, any, SVGElement, any&amp;gt;)
            .attr("d", function (d: d3.DefaultArcObject | any) {
                return firstArc(d) as string;
            })
            .attr("fill", (d, i) =&amp;gt; String(categoryColorScale(d.data.category)))
            .attr('stroke', 'white')
            .style('stroke-width', '0.5px')
            .style('opacity', 1);

        firstDonutArcs.exit().remove();

        // Center the first (inner) donut chart in the middle of the SVG
        this.firstDonutContainer.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

        // Assuming there is a second category and measure in the data
        let subcategoryValues = dataView.categorical.categories[1].values;
        let secondMeasureValues = dataView.categorical.values[0].values.map(val =&amp;gt; Number(val));

// Grouping data by subcategories and calculating the sum
let groupedSecondData = Array.from(d3.group(secondMeasureValues, (d, i) =&amp;gt; subcategoryValues[i]), ([key, group]) =&amp;gt; ({ category: key, value: d3.sum(group) }));

// Sort the data based on the original order of subcategories
groupedSecondData.sort((a, b) =&amp;gt; d3.descending(a.category, b.category));

// Create a color scale for subcategories
const subcategoryColorScale = d3.scaleOrdinal()
    .domain(subcategoryValues as string[])  // Assuming subcategory values are strings
    .range(["#7D1D57", "#AD719A", "#8DA2AC", "#496E87", "#6d8b9e", "#F1E6EE", "#717171", "#E6E6E6"]);  // Adjust the color range as needed

// Creating the second (outer) donut chart using d3 pie function with innerRadius and outerRadius
let secondPie = d3.pie&amp;lt;any&amp;gt;().value(d =&amp;gt; d.value);
let secondPieData = secondPie(groupedSecondData).sort((a, b) =&amp;gt; d3.descending(a.data.key, b.data.key));


        let outerRadius: number = radius * 1.3; // Set outer radius for the second donut

        let secondArc: d3.Arc&amp;lt;any, d3.DefaultArcObject&amp;gt; = d3.arc()
            .innerRadius(radius) // Inner radius is the outer radius of the first donut
            .outerRadius(outerRadius);

        // Update the second (outer) donut chart
        let secondDonutArcs = this.secondDonutContainer.selectAll("path")
            .data(secondPieData);

        secondDonutArcs.enter().append("path")
            .merge(secondDonutArcs as d3.Selection&amp;lt;SVGPathElement, any, SVGElement, any&amp;gt;)
            .attr("d", function (d: d3.DefaultArcObject | any) {
                return secondArc(d) as string;
            })
            .attr("fill", (d, i) =&amp;gt; String(subcategoryColorScale(d.data.category)))
            .attr('stroke', 'white')
            .style('stroke-width', '0.5px')
            .style('opacity', 1);

        secondDonutArcs.exit().remove();

        // Center the second (outer) donut chart in the middle of the SVG
        this.secondDonutContainer.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    }
}&lt;/LI-CODE&gt;&lt;LI-CODE lang="javascript"&gt;{
    "dataRoles": [
        {
            "displayName": "Category Data",
            "name": "category",
            "kind": "Grouping"
        },
        {
            "displayName": "Measure Data",
            "name": "measure",
            "kind": "Measure"
        }
    ],
  
    "dataViewMappings": [
        {
            "categorical": {
                "categories": {
                    "for": {
                        "in": "category"
                    },
                    "dataReductionAlgorithm": {
                        "top": {}
                    }
                },
                "values": {
                    "select": [
                        {
                            "for": {
                                "in": "measure"
                            }
                        }
                    ]
                }
            }
        }
    ],    
    "sorting": {
        "implicit": {
            "clauses": [
                {
                    "role": "category",
                    "direction": 1
                },
                {
                    "role": "measure",
                    "direction": 2
                }
            ]
        }
    },
    "privileges": []
}&lt;/LI-CODE&gt;</description>
      <pubDate>Wed, 20 Dec 2023 08:11:12 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Custom-Visuals-Development/Problem-with-the-order-of-donut-s-slice/m-p/3593129#M8503</guid>
      <dc:creator>stawpeed</dc:creator>
      <dc:date>2023-12-20T08:11:12Z</dc:date>
    </item>
  </channel>
</rss>

