How do I use a logo as a Axis tick label on a Bar Chart?

Shared by Tom L, one of our Technical Consultants in North America.

I was working with a prospect the other day and they had a very specific requirement that just couldn't be dropped: using company logos on the y-axis of a bar chart. I knew using native Yellowfin charts, this wasn't going to be possible. That's when I decided to use Yellowfin's JS Chart integration to solve this problem.

Now building a bar chart with a JS library is as simple as a few lines of code, but incorporating logos was going to take some finagling as no JS library out there allowed this functionality with a simple setting. With that in mind, I decided to use Plotly JS to help me build a bar chart easily and D3.js to add the logos.

The Data:

I decided to create a calculated field with links to svg images on the web. The code I used to create the calculated field was along the lines of this:

       CASE WHEN Demographics = 'Sport' THEN '{link to image}'...........

Now you can store the image location in your database or add the image in your JS code, but this is the way I chose to do it.

Generate the Bar Chart with PlotlyJS:

Plotly makes like easy to build visualizations with code. This was a breeze. Here is the processData function:

processData = function(dataset) {

        var first = [ ];

        var second = [ ];

        var third = [ ];

        for (var i = 0; i < dataset.demographics.length; i++) {

            first.push(

                dataset.demographics.formatted_data

            );

            third.push(

                dataset.url.formatted_data

            );

            second.push(

                parseFloat(dataset.invoiced_amount.raw_data)

            );

}

var trace1 = {

        x: second,

        y: first,

        type: 'bar',

        orientation: 'h',

        hoverinfo: 'none'

};

var data = [trace1, third]

return data

};

Yes I could name my variables a little better but PlotlyJS requires an object with x and y arrays to build a bar chart. That's what you are seeing here.

The Basic Bar Chart:

Now I simply need to use the data from processedData to build the plot with Plotly in the doDrawing function:

doDrawing = function(data, $chartDiv, height, width, 

errorFunction) {
        div = document.getElementById($chartDiv[0].id);
        div.style.width = width;
        div.style.height = height;
        require(['https://cdn.plot.ly/plotly-latest.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d... function(Plotly, d3) {
        var layout = {
                yaxis: {
                        fixedrange: true
},
xaxis: {
                fixedrange: true
            }
};
Plotly.newPlot($chartDiv[0], data, layout);
}); };

Nothing special here. All this can be found on the Plotly website. They have great documentation. Here is our output so far:

The Logos:

Or should I say "The Problem" is that there are a 100 different ways to skin a cat (of which I only know 56). I chose to attack the problem by finding the svg elements where the y-axis labels were and then appending the logos to the group. Finally, I removed the text labels to reveal a clean logo as the axis tick labels. To find the ticks and attach an svg canvas I did the following:

var svg = d3.selectAll(".yaxislayer-above g").append("svg")

                        .attr("transform", function( ) {

                                prevSib = this.previousSibling;

                                transform = 

d3.transform($(prevSib).attr("transform"));

                                return "translate(-55," + (transform.translate[1] - 10) + ")";

                           })

                            .attr("height", 20)

                              .attr("width", 50);

Now that the canvas is attached and in the right place, I added the images to the canvas:

images = [ ];

                            images.push({

                                "url": data[1]

                            })

                            iterator = -1

                            helper = function( ) {

                            iterator++

                            return iterator

}

            for (var i = 0; i < images.length; i++) {

                    svg.selectAll("#thisisit")

                            .data(images)

                            .enter()

                            .append("svg:image")

                            .attr('width', 50)

                            .attr('height', 20)

                            .attr("xlink:href", function(d) {

                                    return d.url[helper( )];

                            });

}

The final thing to do is remove the text labels:

d3.selectAll(".yaxislayer-above g text")

                        .remove( )

Conclusion:

It took a bit of what I like to call "flying by the seat of your pants," but we got the job done. Below is the final product and the complete code. Feel free to improve or ask questions!

//generateChart is a required function which will be called to generate your Javascript chart

generateChart = function(options) {

console.log(options.dataset.data);

// This will trigger a breakpoint in your browser debugger so you can debug your javascript

// This is the div you draw your chart into

var $chartDrawDiv = $(options.divSelector);

// To stop scrollbars in any portlets regardless of your javascript, use this css class

$chartDrawDiv.addClass('jsChartNoOverflow');

// This gets the height and width from the dataset. Use these when creating your chart so that

// it will fit the dashboard, canvas and storyboard correctly

var height = options.dataset.chart_information.height;

var width = options.dataset.chart_information.width;

// Convert the raw data JSON to the format required for the chart if required.

var processedData = processData(options.dataset.data);

// Do the actual drawing of the chart into $chartDiv.

doDrawing(processedData, $chartDrawDiv, height, width, options.errorCallback);

},

processData = function(dataset) {

var first = [ ];

var second = [ ];

var third = [ ];

for (var i = 0; i < dataset.demographics.length; i++) {

first.push(

dataset.demographics.formatted_data

);

third.push(dataset.url.formatted_data

);

second.push(parseFloat(dataset.invoiced_amount.raw_data)

);

}

var trace1 = {

x: second,

y: first,

type: 'bar',

orientation: 'h',

hoverinfo: 'none'

};

var data = [trace1, third]

return data

},

doDrawing = function(data, $chartDiv, height, width, errorFunction) {

console.log(data);

div = document.getElementById($chartDiv[0].id);

div.style.width = "600px";

div.style.height = height;

require(['https://cdn.plot.ly/plotly-latest.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d... function(Plotly, d3) {

var layout = {

yaxis: {

fixedrange: true

},

xaxis: {

fixedrange: true

}

};

Plotly.newPlot($chartDiv[0], data, layout);

var svg = d3.selectAll(".yaxislayer-above g").append("svg")

.attr("transform", function( ) {

prevSib = this.previousSibling;

transform = d3.transform($(prevSib).attr("transform"));

return "translate(-55," + (transform.translate[1] - 10) + ")";

})

.attr("height", 20)

.attr("width", 50);

images = [ ];

images.push({

"url": data[1]

})

iterator = -1

helper = function( ) {

iterator++

return iterator

}

for (var i = 0; i < images.length; i++) {

svg.selectAll("#thisisit")

.data(images)

.enter()

.append("svg:image")

.attr('width', 50)

.attr('height', 20)

.attr("xlink:href", function(d) {

return d.url[helper( )];

});

}

d3.selectAll(".yaxislayer-above g text")

.remove( )

});

}

Is article helpful?