Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Enhance your career with this limited time 50% discount on Fabric and Power BI exams. Ends August 31st. Request your voucher.

Reply
Anonymous
Not applicable

Datacolor changing only after reloading visual

I have created a pie chart and added Data Color property to it.
But if i change the color of a data point,the change in color can be seen only after I reload the visual.
Why is it not instantaneous?
Please Help.

 

Here's my visual.ts

 

module powerbi.extensibility.visual {
    "use strict";
    
    
    
    interface Data 
    {        
    quantity: number;
    category: string;
    color:string;
    selectionId: powerbi.visuals.ISelectionId;
    }
    
    interface PieChartArc {
        datapoints: Data[];
        setting: pieChartSettings;
        dataview: DataView[];
    }
    
    interface pieChartSettings
    {
        Legend :
        {
            show:boolean;
        };
    }
    
    interface LegendValues
    {
        category:string;
        color:string;
        selection: powerbi.visuals.ISelectionId;
    }
    
    function visualTransform(options:VisualUpdateOptions,host:IVisualHost) : PieChartArc
    {
        let dataViews=options.dataViews;
    
        let defaultSetting : pieChartSettings = {
            Legend:{
                show:false,
            }
        };
    
        let viewModel: PieChartArc=
        {
            datapoints:[],
            setting : <pieChartSettings>{},
            dataview: dataViews
        };
    
    
        if (!dataViews
            || !dataViews[0]
            || !dataViews[0].categorical
            || !dataViews[0].categorical.categories
            || !dataViews[0].categorical.categories[0].source
            || !dataViews[0].categorical.values)
            return viewModel;
    
        let categorical=dataViews[0].categorical;
        let category=categorical.categories[0];
        let dataValue=categorical.values[0];
    
        let pieChartData: Data[]=[];
        let colorPalette:IColorPalette=host.colorPalette;
        let objects=dataViews[0].metadata.objects
            let pieChartSetting: pieChartSettings={
                Legend:{
                    show: getValue<boolean>(objects,'Legend','show',defaultSetting.Legend.show)
                }
            }
            
            for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) {
                let defaultColor: Fill = {
                    solid: {
                        color: colorPalette.getColor(<string>category.values[i]).value
                    }
                }
        for(let i=0;i<Math.max(category.values.length,dataValue.values.length);i++)
        {
            pieChartData.push({
           quantity:<number>dataValue.values[i],
           category:<string>category.values[i],
           color:getCategoricalObjectValue<Fill>(category, i, 'dataPoint', 'fill', defaultColor).solid.color==defaultColor.solid.color ?colorPalette.getColor(<string>category.values[i]).value : getCategoricalObjectValue<Fill>(category, i, 'dataPoint', 'fill', defaultColor).solid.color,
           //color: colorPalette.getColor(<string>category.values[i]).value,
           selectionId: host.createSelectionIdBuilder()
                         .withCategory(category, i)
                        .createSelectionId()    
            });
            console.log(pieChartData[i].color);
    
        }
        return {
            datapoints: pieChartData,
            setting: pieChartSetting,
            dataview:dataViews
        };
    }
}
    export class PieChart implements IVisual {
        private target: HTMLElement;        
        private settings: VisualSettings;
        private textNode: Text;
        private pieChartContainer: d3.Selection<SVGElement>;
        private arc: any;
        private host: IVisualHost;
        private selectionManager:ISelectionManager;
        private svg: d3.Selection<SVGElement>;
        private legend:d3.Selection<SVGElement>;
        private g: any;
        private pie: any;
        private color: string;
        private tooltipServiceWrapper: ITooltipServiceWrapper;
        private pieSettings: pieChartSettings;
        static data: DataView[];
        private datapoints: Data[]=[];
    
        static config=
    
        {
        solidOpacity:1,
        transparentOpacity:0.5,
        };
    
        constructor(options: VisualConstructorOptions) {
            console.log('Visual constructor', options);
    
            this.target = options.element;
            this.host=options.host;
            this.selectionManager=options.host.createSelectionManager();
            //this.legend=d3.select(options.element);
            let svg=this.svg=d3.select(options.element)
                                .append('svg')
                                .classed("pieChart",true)
                                ;
    
            this.pieChartContainer=svg.append('g').classed('pieChartContainer',true);//.attr('transform','translate('+100+',' +100+')');  
            this.tooltipServiceWrapper = createTooltipServiceWrapper(this.host.tooltipService, options.element);                      
        }
    
    
        public update(options: VisualUpdateOptions) {
          //  let legendModel : LegendValues[] = legendTransform(options,this.host);
            let viewModel: PieChartArc = visualTransform(options, this.host);        
            let settings=this.pieSettings=viewModel.setting;
            let category=options.dataViews[0].categorical.categories[0];
            let dataValue=options.dataViews[0].categorical.values[0];
           // let legend=this.legend;
            let legendEnumerate:LegendValues[];
           
            this.datapoints=viewModel.datapoints;
            PieChart.data=options.dataViews;
            let width=options.viewport.width;
            let height=options.viewport.height;
            let radius=Math.min(width,height)/2;
            //this.pieChartContainer.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
            this.svg.attr({
                width: width-20,
                height: height-20,                
    
            });
            //this.svg.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
            this.arc=d3.svg.arc()
            .innerRadius(0)
            .outerRadius(radius-20);
            this.pie = d3.layout.pie<Data>().value((d: Data):number => d.quantity).sort(null);
            let fill = ((d):string=> d.data.color);
            let tf   =  (d: Data) => `translate(${this.arc.centroid(d)})`;
            let text = d => d.data.category;
            this.svg.append('g');
    
            this.g=this.svg.selectAll('.arc')
                    .data(this.pie(viewModel.datapoints))
                    .enter()
                    .append('g')
                    .attr('class', 'arc')
                    .data(this.pie(viewModel.datapoints))
                   // .attr("fill",fill)
                    ;
    
           let path= this.g.append('path')
                    .attr('d', this.arc)
                    .attr('fill',fill)
                    .attr('fill-opacity',1)
                    //.style("stroke","black")
                    .attr("stroke-width","0.8");           
                    this.g.append('text').attr('transform', tf).text(text).attr('fill',"white");
    
                    this.tooltipServiceWrapper.addTooltip(path, 
                    (tooltipEvent: TooltipEventArgs<number>) => PieChart.getTooltipData(tooltipEvent.data),
                    (tooltipEvent: TooltipEventArgs<number>) => null);
            let selectionManager = this.selectionManager;
    
                path.on("click",function(d)
                 {
                    // path.attr('fill','blue');
                    selectionManager.select(d.data.selectionId).then((ids: powerbi.visuals.ISelectionId[])=>                    
                   {                     
                    path.attr('fill-opacity',ids.length>0? PieChart.config.transparentOpacity: PieChart.config.solidOpacity);
                    d3.select(this).attr('fill-opacity',PieChart.config.solidOpacity);
                        (<Event>d3.event).stopPropagation;
                    });
                });
                path.exit()
                    .remove();
                    //shows
                   if(settings.Legend.show)
                   {  //this.svg.append("text").text("Hello");
                   // console.log(settings.Legend.show);
                    for(let i=0;i<category.values.length;++i)
                    {   
                           legendEnumerate.push({
                               category:<string>category.values[i],
                               color:<string>dataValue.values[i],
                               selection:this.host.createSelectionIdBuilder()
                               .withCategory(category, i)
                              .createSelectionId()
                           });
                        }
                      let legend = this.svg.selectAll('.legend')
                                    .data(legendEnumerate)
                                    .enter()                                    
                                    .append('g')
                                    .attr('class','legend')
                                    .attr('x',20)
                                    .attr('y',20);
            
                        for(let i=0;i<Math.max(category.values.length,dataValue.values.length);++i)
                        {
                             //  this.legend.html(legendEnumerate[i].category).attr("transform","translate(" + i*20 +",0)")             
            
                           // leg.a
                           legend.append('circle')
                           .attr('cx',20)
                           .attr('cy',20)
                           .attr('r',8)
                           .attr('fill',legendEnumerate[i].color)
                           .attr("transform","translate(" + i*20 +",0)")
                           ;
                           legend.append('text')
                           .text(legendEnumerate[i].category)
                           .attr("transform","translate(" + i*30 +",0)")
                            ;
                            } 
            
                    }
        }
    
    
        private static parseSettings(dataView: DataView): VisualSettings {
    
            return VisualSettings.parse(dataView) as VisualSettings;
    
        }
    
        /** 
         * This function gets called for each of the objects defined in the capabilities files and allows you to select which of the 
         * objects and properties you want to expose to the users in the property pane.
         * 
         */
        public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {                   
           // return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
        let objectName=options.objectName;
        let objectEnumeration:VisualObjectInstance[]=[];
        switch(objectName)
        {
            case 'Legend':
            objectEnumeration.push({
                objectName: objectName,
                properties:{
                    show:this.pieSettings.Legend.show,
                },
                selector:null
            });
        
        case 'dataPoint':
        for(let DataPoint of this.datapoints ) {
            objectEnumeration.push({
                objectName: objectName,
                displayName: DataPoint.category,
                properties: {
                    fill: {
                        solid: {
                            color: DataPoint.color
                        }
                    }
                },
                selector: DataPoint.selectionId.getSelector()
                       });
        }
        break;
         };
        return objectEnumeration;
    
        }
    
        private static getTooltipData(value: any): VisualTooltipDataItem[] {
            return [{
                displayName: PieChart.data[0].metadata.columns[1].displayName,
                value: value.value.toString(),
                color: value.data.color,
                header:value.data.category
            }];
        }
    
    }
}
1 ACCEPTED SOLUTION

@Anonymous,

 

Change it as follows.

			let arcs = this.pieChartContainer.selectAll('.arc')
							.data(this.pie(this.datapoints))
							;
			
			arcs.enter()
				.append('path')
				.attr('class', 'arc')
				;
Community Support Team _ Sam Zha
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.

View solution in original post

8 REPLIES 8
v-chuncz-msft
Community Support
Community Support

@Anonymous,

 

If convenient, share us a complete project for a quick test.

Community Support Team _ Sam Zha
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Anonymous
Not applicable

@Anonymous,

 

Inspect the generated HTML in Web Console and change the code as Sample Bar Chart Repo does.

Community Support Team _ Sam Zha
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Anonymous
Not applicable

let radius=Math.min(width,height)/2;
 let arc=this.arc=d3.svg.arc()
            .innerRadius(0)
            .outerRadius(radius);
 console.log(radius);

@v-chuncz-msft,Actually the radius value is changing if I resize the visual. But the  d3.svg.arc retains the old value until the visual is reloaded.

@Anonymous,

 

See the code snippet below.

			let pies = this.pieChartContainer.selectAll('.arc')
							.data(this.pie(viewModel.datapoints));
							
			pies.enter()
				.append('path')
				.classed('arc', true);
			
			pies.attr('d', this.arc)
				.attr('fill', fill);
Community Support Team _ Sam Zha
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Anonymous
Not applicable

              this.arc = d3.svg.arc()
                         .innerRadius(0)
                         .outerRadius(radius);
            console.log(radius);
            this.pie = d3.layout.pie<Data>().value((d: Data):number => d.quantity).sort(null);
            let fill = ((d):string=> d.data.color);
           // let tf   =  (d: Data) => `translate(${this.arc.centroid(d)})`;
            //let text = d => d.data.category;            
             let arcs=this.pieChartContainer.selectAll('.arc')
                    .data(this.pie(this.datapoints))
                    .enter()
                    .append('path')
                    .attr('class', 'arc')                   
                    ;
    
                    arcs
                    .attr('d', this.arc)
                    .attr('fill',fill)
                    .attr('fill-opacity',1)
                    .attr("stroke-width","0.8")
                    ;   

This is my current code. Still not working. The radius also changes only after visual reload.

@Anonymous,

 

Change it as follows.

			let arcs = this.pieChartContainer.selectAll('.arc')
							.data(this.pie(this.datapoints))
							;
			
			arcs.enter()
				.append('path')
				.attr('class', 'arc')
				;
Community Support Team _ Sam Zha
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Anonymous
Not applicable

Thanks @v-chuncz-msft . This helped a lot. Could you please explain why it worked?

Helpful resources

Announcements
August Power BI Update Carousel

Power BI Monthly Update - August 2025

Check out the August 2025 Power BI update to learn about new features.

August 2025 community update carousel

Fabric Community Update - August 2025

Find out what's new and trending in the Fabric community.