Skip to content

Instantly share code, notes, and snippets.

@deldersveld
Last active October 26, 2021 11:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save deldersveld/2e12892c516d5b189dfdfe0067622b78 to your computer and use it in GitHub Desktop.
Save deldersveld/2e12892c516d5b189dfdfe0067622b78 to your computer and use it in GitHub Desktop.
Sample Power BI bar chart custom visual adapted from https://bl.ocks.org/mbostock/3885304

Sample Power BI bar chart custom visual adapted from https://bl.ocks.org/mbostock/3885304

  • Follow the instructions at https://github.com/Microsoft/PowerBI-visuals-docs to install the Power BI Custom Visual CLI Tool
  • Follow the steps on the same site to create a new visual and install the typings for D3
  • Copy and paste the code from this gist's "visual.ts" into "src/visual.ts"
  • Copy and paste the code from this gist's "visual.less" into "style/visual.less"
  • Start the visual in CLI and view it using the Developer Visual in Power BI service

Adapting a visual like this from a static D3 example is not a simple matter of copying and pasting. If you look through the original D3 example and compare it with the Power BI version, you will see some changes where the original was split between constructor() and update(). The original D3 also only used enter(), but for a dynamic visual in Power BI, code for transition() and exit() were also added. Some other tweaks were needed to get it working decently outside of a static block. No adjustments were made for label formatting or other fine tuning. This was just a quick example to help illustrate how some existing D3 code compares to a comparable Power BI version, and you can modify from there.

Full source can be found here: barChartExample

.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
// add the following in addition to the CSS provided
.y.axis path {
display: none;
}
module powerbi.extensibility.visual {
export interface CategoryViewModel {
value: string;
identity: string;
}
export interface ValueViewModel {
values: any[];
}
export interface ViewModel {
categories: CategoryViewModel[];
values: ValueViewModel[];
}
export class Visual implements IVisual {
public static converter(dataView: DataView): ViewModel {
var viewModel: ViewModel = {
categories: [],
values: []
}
if (dataView) {
var categorical = dataView.categorical;
if (categorical) {
var categories = categorical.categories;
var series = categorical.values;
var formatString = dataView.metadata.columns[0].format;
if (categories && series && categories.length > 0 && series.length > 0) {
for (var i = 0, catLength = categories[0].values.length; i < catLength; i++) {
viewModel.categories.push({
value: categories[0].values[i],
identity: ''
})
for (var k = 0, seriesLength = series.length; k < seriesLength; k++) {
var value = series[k].values[i];
if (k == 0) {
viewModel.values.push({ values: [] });
}
viewModel.values[i].values.push(value);
}
}
}
}
}
return viewModel;
}
private target: HTMLElement;
private updateCount: number;
private svg: d3.Selection<SVGAElement>;
private group: d3.Selection<SVGAElement>;
private xAxis: d3.Selection<SVGAElement>;
private yAxis: d3.Selection<SVGAElement>;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.target = options.element;
var svg = this.svg = d3.select(this.target)
.append("svg")
.attr("class", "tutorial-svg");
var group = this.group = svg.append("g")
.attr("class", "tutorial-g");
var xAxis = this.xAxis = svg.append("g")
.attr("class", "x axis");
var yAxis = this.yAxis = svg.append("g")
.attr("class", "y axis");
}
public update(options: VisualUpdateOptions) {
console.log('Visual update', options);
var dataViews = options.dataViews;
if (!dataViews) return;
var viewModel = Visual.converter(dataViews[0]);
console.log(viewModel);
var data = [];
for(var i in viewModel.categories){
var dataPoint = {
cat: viewModel.categories[i].value,
val:viewModel.values[i].values[0]
};
data.push(dataPoint);
}
var margin = {top: 20, right: 20, bottom: 30, left: 40};
var width = options.viewport.width - margin.left - margin.right;
var height = options.viewport.height - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(data.map(function(d) { return d.cat; }))
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.val; })])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(height / 50)
.tickFormat(d3.format(".0s"));
var svg = this.svg;
var group = this.group;
svg.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
group
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var yAxisLabel = this.yAxis
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis);
var xAxisLabel = this.xAxis
.attr("transform", "translate(" + margin.left + "," + height + ")")
.call(xAxis);
var bar = svg.selectAll(".bar")
.data(data);
bar.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { console.log(d.cat); return x(d.cat);})
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.val);})
.attr("height", function(d) { return height-y(d.val);})
.attr("transform", "translate(" + margin.left + ",0)");
bar.transition()
.duration(2)
.attr("x", function(d) { console.log(d.cat); return x(d.cat);})
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.val);})
.attr("height", function(d) { return height-y(d.val);});
bar.exit()
.transition()
.duration(2)
.remove();
}
public destroy(): void {
this.svg.remove();
}
}
}
@OneidaAlmodovar
Copy link

Hello, Is it possible to show several barcharts in a single powerbi custom visual?
I've a requirement that must show several bar graphs in the same visual custom, they are metrics connected to each other.
For example:
Chart A --> Chart B
|
Chart D --> Chart E --> Chart Z

Please let me know your comments. Thank You.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment