Advance your Data & AI career with 50 days of live learning, dataviz contests, hands-on challenges, study groups & certifications and more!
Get registeredJoin us at FabCon Atlanta from March 16 - 20, 2026, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM. Register now.
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
}];
}
}
}
Solved! Go to Solution.
@Anonymous,
Change it as follows.
let arcs = this.pieChartContainer.selectAll('.arc')
.data(this.pie(this.datapoints))
;
arcs.enter()
.append('path')
.attr('class', 'arc')
;
@Anonymous,
If convenient, share us a complete project for a quick test.
@Anonymous,
Inspect the generated HTML in Web Console and change the code as Sample Bar Chart Repo does.
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);
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')
;
Thanks @v-chuncz-msft . This helped a lot. Could you please explain why it worked?
Join the Fabric FabCon Global Hackathon—running virtually through Nov 3. Open to all skill levels. $10,000 in prizes!
Check out the October 2025 Power BI update to learn about new features.
| User | Count |
|---|---|
| 2 | |
| 1 | |
| 1 | |
| 1 | |
| 1 |