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

Earn the coveted Fabric Analytics Engineer certification. 100% off your exam for a limited time only!

Reply
Anonymous
Not applicable

Creating a Pie chart visual with Static Data.

Hi guys. I'm trying to create a pie chart power Bi visual for practicing custom visual creation.I have followed the tutorial given in the github repo for the environment setup and now is currently on the first step , ie creating visual with static data.

The visual is being built and served correctly.But when I insert the visual in the powerBi service,all i get is a blank  screen.
Can someone help? I'm new to d3 and TypeScript, so there may be a chance that I may have made some silly mistakes.
Here's my code: 

 

module powerbi.extensibility.visual {
    "use strict";

    interface Data 
    {        
    quantity: number;
    category: string;
    }

    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 svg:d3.Selection<SVGElement>;
        private g:any;
        private pie:any;
        private color:string;

        constructor(options: VisualConstructorOptions) {
            console.log('Visual constructor', options);
            this.target = options.element;
            this.host=options.host;
            let svg=this.svg=d3.select(options.element)
                                .append('svg')
                                .classed("pieChart",true);
            this.pieChartContainer=svg.append('g').classed('pieChartContainer',true);                        
        }


        public update(options: VisualUpdateOptions) {
            this.settings = PieChart.parseSettings(options && options.dataViews && options.dataViews[0]);
            let testData: Data[] = [
                {
                    quantity: 25,
                    category: 'a'
                },
                {
                    quantity: 50,
                    category: 'b'
                },
                {
                    quantity: 100,
                    category: 'c'
                },
                {
                    quantity: 200,
                    category: 'd'
                },
                {
                    quantity: 300,
                    category: 'e'
                }];
          
            let width=options.viewport.width;
            let height=options.viewport.height;
            let radius=Math.min(width,height)/2;
            this.svg.attr({
                width:width,
                height:height,
            });
            let colourValues = d3.scale.category20c();
            this.arc=d3.svg.arc()
            .innerRadius(0)
            .outerRadius(radius-20);
            this.pie = d3.layout.pie<Data>().value((d: Data):number => d.quantity);
            let fill = (d=> colourValues(d.category));
            let tf   =  d => `translate(${this.arc.centroid(d)})`;
            let text = d => d.data.category;
            this.svg.append('g')
            .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
            this.g=this.svg.selectAll('.arc')
                    .data(this.pie(testData))
                    .enter()
                    .append('g')
                    .attr('class', 'arc')
                    .data(this.pie(testData));

            this.g.append('path')
                    .attr('d', this.arc)
                    .attr('fill', fill)
                    .style("stroke","black")
                    .style("stroke-width","0.8")
                    .on("mouseover",d=>
                     {
                                            
                    d3.select(d)
                    .attr('fill','blue')
                    .style('opacity','0.6')
                    .attr('d',this.arc)
                    .style("stroke","black")
                    .style("stroke-width","3");
                    
                    this.color=d.getAttribute('fill');

                     })
                    
                    .on("mouseout",d=>
                     {   
                    d3.select(d)
                    .attr('fill',colourValues(this.color))
                    .style("opacity","1")
                    .attr('d',this.arc)
                    .style("stroke-width","0.8");
                   
                    
                    }).append("svg:title");
                    //.html(d=>'<p>Quantity :'+d=>d. + '</p>');           
                    this.g.append('text').attr('transform', tf).text(text);
        }


        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);
        }
    }
}
1 ACCEPTED SOLUTION
v-viig
Community Champion
Community Champion

Please take a look at this fixed version:

module powerbi.extensibility.visual {
    "use strict";

    interface Data {
        quantity: number;
        category: string;
    }

    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 svg: d3.Selection<SVGElement>;
        private g: any;
        private pie: any;
        private color: string;

        constructor(options: VisualConstructorOptions) {
            debugger;
            console.log('Visual constructor', options);
            this.target = options.element;
            this.host = options.host;
            let svg = this.svg = d3.select(options.element)
                .append('svg')
                .classed("pieChart", true);

            this.pieChartContainer = svg
                .append('g')
                .classed('pieChartContainer', true);
        }


        public update(options: VisualUpdateOptions) {
            console.log(options);

            this.settings = PieChart.parseSettings(options && options.dataViews && options.dataViews[0]);
            let testData: Data[] = [
                {
                    quantity: 25,
                    category: 'a'
                },
                {
                    quantity: 50,
                    category: 'b'
                },
                {
                    quantity: 100,
                    category: 'c'
                },
                {
                    quantity: 200,
                    category: 'd'
                },
                {
                    quantity: 300,
                    category: 'e'
                }];

            let width = options.viewport.width;
            let height = options.viewport.height;
            let radius = Math.min(width, height) / 2;

            this.svg.attr({
                width: width,
                height: height,
            });

            let colourValues = d3.scale.category20c();

            this.arc = d3.svg.arc()
                .innerRadius(0)
                .outerRadius(radius - 20);
            this.pie = d3.layout.pie<Data>().value((d: Data): number => d.quantity);
            let fill = (d => colourValues(d.category));
            let tf = d => `translate(${this.arc.centroid(d)})`;
            let text = d => d.data.category;

            this.pieChartContainer.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');


            this.g = this.pieChartContainer.selectAll('.arc')
                .data(this.pie(testData))
                .enter()
                .append('g')
                .attr('class', 'arc')
                .data(this.pie(testData));

            this.g.append('path')
                .attr('d', this.arc)
                .attr('fill', fill)
                .style("stroke", "black")
                .style("stroke-width", "0.8")
                .on("mouseover", d => {

                    d3.select(d)
                        .attr('fill', 'blue')
                        .style('opacity', '0.6')
                        .attr('d', this.arc)
                        .style("stroke", "black")
                        .style("stroke-width", "3");

                    this.color = d.getAttribute('fill');

                })

                .on("mouseout", d => {
                    d3.select(d)
                        .attr('fill', colourValues(this.color))
                        .style("opacity", "1")
                        .attr('d', this.arc)
                        .style("stroke-width", "0.8");


                }).append("svg:title");
            //.html(d=>'<p>Quantity :'+d=>d. + '</p>');           
            this.g.append('text').attr('transform', tf).text(text);
        }


        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);
        }
    }
}

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

View solution in original post

10 REPLIES 10
Anonymous
Not applicable

Hi guys. I'm trying to create a pie chart power Bi visual for practicing custom visual creation.I have followed the tutorial given in the github repo for the environment setup and now is currently on the first step , ie creating visual with static data.

The visual is being built and served correctly.But when I insert the visual in the powerBi service,all i get is a blank  screen.
Can someone help? I'm new to d3 and TypeScript, so there may be a chance that I may have made some silly mistakes.
Here's my code: 

module powerbi.extensibility.visual {
    "use strict";

    interface Data 
    {        
    quantity: number;
    category: string;
    }

    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 svg:d3.Selection<SVGElement>;
        private g:any;
        private pie:any;
        private color:string;

        constructor(options: VisualConstructorOptions) {
            console.log('Visual constructor', options);
            this.target = options.element;
            this.host=options.host;
            let svg=this.svg=d3.select(options.element)
                                .append('svg')
                                .classed("pieChart",true);
            this.pieChartContainer=svg.append('g').classed('pieChartContainer',true);                        
        }


        public update(options: VisualUpdateOptions) {
            this.settings = PieChart.parseSettings(options && options.dataViews && options.dataViews[0]);
            let testData: Data[] = [
                {
                    quantity: 25,
                    category: 'a'
                },
                {
                    quantity: 50,
                    category: 'b'
                },
                {
                    quantity: 100,
                    category: 'c'
                },
                {
                    quantity: 200,
                    category: 'd'
                },
                {
                    quantity: 300,
                    category: 'e'
                }];
          
            let width=options.viewport.width;
            let height=options.viewport.height;
            let radius=Math.min(width,height)/2;
            this.svg.attr({
                width:width,
                height:height,
            });
            let colourValues = d3.scale.category20c();
            this.arc=d3.svg.arc()
            .innerRadius(0)
            .outerRadius(radius-20);
            this.pie = d3.layout.pie<Data>().value((d: Data):number => d.quantity);
            let fill = (d=> colourValues(d.category));
            let tf   =  d => `translate(${this.arc.centroid(d)})`;
            let text = d => d.data.category;
            this.svg.append('g')
            .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
            this.g=this.svg.selectAll('.arc')
                    .data(this.pie(testData))
                    .enter()
                    .append('g')
                    .attr('class', 'arc')
                    .data(this.pie(testData));

            this.g.append('path')
                    .attr('d', this.arc)
                    .attr('fill', fill)
                    .style("stroke","black")
                    .style("stroke-width","0.8")
                    .on("mouseover",d=>
                     {
                                            
                    d3.select(d)
                    .attr('fill','blue')
                    .style('opacity','0.6')
                    .attr('d',this.arc)
                    .style("stroke","black")
                    .style("stroke-width","3");
                    
                    this.color=d.getAttribute('fill');

                     })
                    
                    .on("mouseout",d=>
                     {   
                    d3.select(d)
                    .attr('fill',colourValues(this.color))
                    .style("opacity","1")
                    .attr('d',this.arc)
                    .style("stroke-width","0.8");
                   
                    
                    }).append("svg:title");
                    //.html(d=>'<p>Quantity :'+d=>d. + '</p>');           
                    this.g.append('text').attr('transform', tf).text(text);
        }


        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);
        }
    }
}
v-viig
Community Champion
Community Champion

This topic is duplicate of that one.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

v-viig
Community Champion
Community Champion

Hello @Anonymous,

 

I'm wondering if you can clarify these items:

  • Did you install d3 by executing npm i d3@3.5.5 --save?
  • Did you include d3 into externalJS property of pbiviz.json? (example)

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

Anonymous
Not applicable

I'm using d3 3.5.17 and yes, i have included it into externalJS property.

v-viig
Community Champion
Community Champion

Your code actually works for me:

 

image.png

 

However, Pie chart is misplaced. I suppose that you should apply CSS transform-translate to fix position issue.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

 

Anonymous
Not applicable

I got it. Thank you for your patience.
By the way,which element should be given the transform-translate style?
I added it as a attribute for svg ,but no use.

v-viig
Community Champion
Community Champion

Please take a look at this fixed version:

module powerbi.extensibility.visual {
    "use strict";

    interface Data {
        quantity: number;
        category: string;
    }

    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 svg: d3.Selection<SVGElement>;
        private g: any;
        private pie: any;
        private color: string;

        constructor(options: VisualConstructorOptions) {
            debugger;
            console.log('Visual constructor', options);
            this.target = options.element;
            this.host = options.host;
            let svg = this.svg = d3.select(options.element)
                .append('svg')
                .classed("pieChart", true);

            this.pieChartContainer = svg
                .append('g')
                .classed('pieChartContainer', true);
        }


        public update(options: VisualUpdateOptions) {
            console.log(options);

            this.settings = PieChart.parseSettings(options && options.dataViews && options.dataViews[0]);
            let testData: Data[] = [
                {
                    quantity: 25,
                    category: 'a'
                },
                {
                    quantity: 50,
                    category: 'b'
                },
                {
                    quantity: 100,
                    category: 'c'
                },
                {
                    quantity: 200,
                    category: 'd'
                },
                {
                    quantity: 300,
                    category: 'e'
                }];

            let width = options.viewport.width;
            let height = options.viewport.height;
            let radius = Math.min(width, height) / 2;

            this.svg.attr({
                width: width,
                height: height,
            });

            let colourValues = d3.scale.category20c();

            this.arc = d3.svg.arc()
                .innerRadius(0)
                .outerRadius(radius - 20);
            this.pie = d3.layout.pie<Data>().value((d: Data): number => d.quantity);
            let fill = (d => colourValues(d.category));
            let tf = d => `translate(${this.arc.centroid(d)})`;
            let text = d => d.data.category;

            this.pieChartContainer.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');


            this.g = this.pieChartContainer.selectAll('.arc')
                .data(this.pie(testData))
                .enter()
                .append('g')
                .attr('class', 'arc')
                .data(this.pie(testData));

            this.g.append('path')
                .attr('d', this.arc)
                .attr('fill', fill)
                .style("stroke", "black")
                .style("stroke-width", "0.8")
                .on("mouseover", d => {

                    d3.select(d)
                        .attr('fill', 'blue')
                        .style('opacity', '0.6')
                        .attr('d', this.arc)
                        .style("stroke", "black")
                        .style("stroke-width", "3");

                    this.color = d.getAttribute('fill');

                })

                .on("mouseout", d => {
                    d3.select(d)
                        .attr('fill', colourValues(this.color))
                        .style("opacity", "1")
                        .attr('d', this.arc)
                        .style("stroke-width", "0.8");


                }).append("svg:title");
            //.html(d=>'<p>Quantity :'+d=>d. + '</p>');           
            this.g.append('text').attr('transform', tf).text(text);
        }


        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);
        }
    }
}

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

Anonymous
Not applicable

Thanks @v-viig.
And consider this as a Humble request from my side, Please consider improving the current documentation for creating custom visuals. Beginners like me struggle a lot following the current documentation.

v-viig
Community Champion
Community Champion

Yes, sure. Thank you for the feedback.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

Anonymous
Not applicable

Could you please share your .json files?
Did you make any change to my code?

Is there a need to fill the data fields when using static data?

 

Thank You

 

Vishnu Suresh

Helpful resources

Announcements
April AMA free

Microsoft Fabric AMA Livestream

Join us Tuesday, April 09, 9:00 – 10:00 AM PST for a live, expert-led Q&A session on all things Microsoft Fabric!

March Fabric Community Update

Fabric Community Update - March 2024

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

Top Solution Authors
Top Kudoed Authors