Skip to main content
Announcements
Have questions about Qlik Connect? Join us live on April 10th, at 11 AM ET: SIGN UP NOW
cancel
Showing results for 
Search instead for 
Did you mean: 
wandapec
Partner - Contributor III
Partner - Contributor III

Extensions Help - D3Js.org

Hi guys,

I recently decided to try get a better understanding of extensions and try to use some of the D3js.org stuff in my models. I have managed to get the basics of extensions sorted.

However, after going through all the training manuals and examples on the web, I think I am really close, but seem to be missing something and I really don’t know what. I have attached a link to the example I am working on - trying to get a basic Bar Chart working… Would someone be able to take a look and see where I am going wrong, please?

Thanks in advance.

Dropbox - barexample.zip

19 Replies
Clever_Anjos
Employee
Employee

Do you have the original working version?

Not applicable

Steve,   

I think this is your issue

var data = _this.Data;

  for (var f=0; f < data.Rows.length; f++ ) {

var row = data.Rows;

  //Dimension 1 : Defined in the Definition.xml

  var dim1 = row[0].text;

  //Dimension 2 : Defined in the Definition.xml

  var measure1 = row[1].text;

  letter = textset.concat(dim1);

  frequency = dataset.concat(measure1);

      }

You are just looping through each Row and setting the vars: letter & frequency but never return the values to a parent object.

Whenever you reference the object data, you are referencing the original data object and not your new vars of letter & frequency.

Check out my other reply on this thread for additional detail.

wandapec
Partner - Contributor III
Partner - Contributor III
Author

Not a Qlikview one... I am trying to get this Bar Chart working in Qlikview to help me get a better understanding of using D3Js charts in Extensions...

In his version, he is getting the data out of a .tsv file. I am trying to get the data out of Qlikview.

d3.tsv("data.tsv", type, function(error, data) {

  x.domain(data.map(function(d) { return d.letter; }));

  y.domain([0, d3.max(data, function(d) { return d.frequency; })]);

So I moved the .domain lines that he had in the above script to the relevant axis (x. and y.). I am not sure what to replace the data.map() with if that doesn't work in my version.

wandapec
Partner - Contributor III
Partner - Contributor III
Author

Thanks Andrew. I think I am really close. I used your version to get the data:

        //Data Elements

        var row, letter, frequency = 0;

        var k, q;

        var dataJson =[];

        var data = _this.Data.Rows;

      

        for (q = 0, k = _this.Data.Rows.length; q < k; q++) {

            row = _this.Data.Rows;

            dataDimension = row[0].text;

            dataMeasure = parseFloat(row[1].text);

            dataJson.push({

                    'letter':dataDimension,

                    'frequency':dataMeasure

        });

        }

As I mentioned earlier to Clever, I moved the .domain lines to the relevant axis (.x and .y) but I must be doing something wrong... and not sure what it is. The original script on the web used x.domain(data.map(function(d) { return d.letter; })); to get the 'letter' for the x. axis - maybe data.map() isn't correct?

wandapec
Partner - Contributor III
Partner - Contributor III
Author

Hi guys,

I took Andrew's example and managed to get it working! Whoohoo... Thanks Andrew...

However, I am not sure what to do to get the chart to be interactive i.e. so that I can highlight and make selections on the chart that affects selections in the model. I have attached the .qar file of the version I have working so far....

Any ideas?

--------------------------

//AJL: will need to make sure this is updated whenever the final extension is packaged.  I.E. the folder name will need to be whatever the final product name will be

var extensionName = "d3Bar";

var extensionPath = Qva.Remote + "?public=only&name=Extensions/" + extensionName +"/";

var loadPath =  Qva.Remote + (Qva.Remote.indexOf('?') >= 0 ? '&' : '?') + 'public=only' + '&name=';

function Chart_Init(){

    Qva.AddExtension('d3Bar', function () {

  var jsFiles = [];

    var _this = this;

    _this.ExtSettings = {};

    console.log(_this);

    Qva.LoadCSS(loadPath + 'Extensions/d3Bar/css/style.css');

    if(typeof jQuery == 'undefined'){

    jsFiles.push('Extensions/d3Bar/js/jquery.js');

    }

    if (!Modernizr.svg) {

        jsFiles.push('Extensions/d3Bar/js/r2d3.min.js');

    } else {

        jsFiles.push('Extensions/d3Bar/js/d3.min.js');

    }

    function InitSettings() {

        _this.ExtSettings.UniqueID = _this.Layout.ObjectId.replace('\\', '_');       

           }

    function Init(){

        $(_this.Element).empty();

        chartcontainer = document.createElement("div");

        $(chartcontainer).attr('id','Chart_'+_this.ExtSettings.UniqueID)

        .attr('class','chart')

        .attr('width','100%')

        .attr('height','100%')

        $(_this.Element).append(chartcontainer);

    }

   

    function InitChart() {

        var row, dataDimension, dataMeasure = 0;

        var k, q;

        var dataJson =[];

        var data = _this.Data.Rows;

       

   for (q = 0, k = _this.Data.Rows.length; q < k; q++) {

            row = _this.Data.Rows;

            dataDimension = row[0].text;

            dataMeasure = parseFloat(row[1].text);

            dataJson.push({

            'id':dataDimension,

            'data':dataMeasure

        });

        }

//--------------New Script Start-------------------------------

// Chart dimensions.

var spacer = { right: 20 };

var margin = { top: 30, right: 50, bottom: 50, left: 30 };

    //{ top: 19.5, right: 19.5, bottom: 19.5, left: 39.5 },

var width = _this.GetWidth() - margin.right - spacer.right;

var height = _this.GetHeight() - margin.top - margin.bottom;   

var x = d3.scale.ordinal()

    .domain(dataJson.map(function(d) { return d.id; }))

    .rangeRoundBands([0, width], .1);

var y = d3.scale.linear()

    .domain([0, d3.max(dataJson, function(d) { return d.data; })])

    .range([height, 0]);

var xAxis = d3.svg.axis()

    .scale(x)

    .orient("bottom");

var yAxis = d3.svg.axis()

    .scale(y)

    .orient("left")

    .ticks(10, "%");

var svg = d3.select('#Chart_'+_this.ExtSettings.UniqueID).append("svg")

    .attr("width", width + margin.left + margin.right)

    .attr("height", height + margin.top + margin.bottom)

  .append("g")

    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  svg.append("g")

      .attr("class", "x axis")

      .attr("transform", "translate(0," + height + ")")

      .call(xAxis);

  svg.append("g")

      .attr("class", "y axis")

      .call(yAxis)

    .append("text")

      .attr("transform", "rotate(-90)")

      .attr("y", 6)

      .attr("dy", ".71em")

      .style("text-anchor", "end")

      .text("Frequency");

  svg.selectAll(".bar")

      .data(dataJson)

    .enter().append("rect")

      .attr("class", "bar")

      .attr("x", function(d) { return x(d.id); })

      .attr("width", x.rangeBand())

      .attr("y", function(d) { return y(d.data); })

      .attr("height", function(d) { return height - y(d.data); });

    

function type(d) {

  d.frequency = +d.frequency;

  return d;

}

//--------------New Script End-------------------------------

       

    }

    Qv.LoadExtensionScripts(jsFiles, function () {

        InitSettings();

        Init();

        InitChart();

    });

    });

}

console.log(extensionPath);

//Gotta load up the Modernizr library to see if the QV Desktop or browser can handle SVGs

//@todo AJL - Rework loading up the scripts

Qva.LoadScript(extensionPath + 'js/modernizr.svg.min.js', Chart_Init());

wandapec
Partner - Contributor III
Partner - Contributor III
Author

I have a feeling that I need to use... SelectTextsInColumn(Column, toggle, recordsToSelect)

Just not sure how to get the array into  recordsToSelect by selecting bars on the chart.

Can someone help me? Please...

Brian_Munz
Employee
Employee

Hi,

Your QAR isn't properly zipped.  When you zip the extension folder you need to zip the whole folder, not the contents.  As it is now, when you double click the QAR the extension doesn't install and your js and css directories are added to the root.

Brian_Munz
Employee
Employee

To add clicking on the individual bars, you need to attach a click even to the cars.  For the code you've posted here, you would change your bar code to this:

svg.selectAll(".bar").data(dataJson).enter().append("rect").attr("class", "bar").attr("x", function(d) {

  return x(d.id);

  }).attr("width", x.rangeBand()).attr("y", function(d) {

  return y(d.data);

  }).attr("height", function(d) {

  return height - y(d.data);

  }).on("click",function(d){

  _this.Data.SelectTextsInColumn(0, false, d.id);

  });

The new code is bolded.  It takes the bar ID and selects it in QlikView.  In order to allow the selection of multiple bars you'd need to code some sort of ability to select multiple bars like a select box, lasso, etc.

wandapec
Partner - Contributor III
Partner - Contributor III
Author

Oops. Thanks Brian.

Not applicable

Hello Steve,

d3Bar.qar file which you have shared is not working on my desktop version, can you please share the latest .qar file

Thanks and Regards,

Preethi