Skip to main content
Announcements
Join us at Qlik Connect for 3 magical days of learning, networking,and inspiration! REGISTER TODAY and save!
cancel
Showing results for 
Search instead for 
Did you mean: 
cahenson2
Contributor II
Contributor II

Set Analysis not working as expected in extension

I'm currently working on a custom visualization extension. In the extension I currently have two measures. The first measureis used to calculate quantiles for the dataset as a whole and then to translate the quantiles into a box plot.

  • (=Aggr({1<Student=>} NODISTINCT Max(Final_Score), Student, Domain)

The second measure is used to plot the individual data points on top of the box plot. 

  • (=Aggr(NODISTINCT Max(Final_Score), Student, Domain)

The set analysis and overall data structure appear correct when I look at the data in a table with the appropriate selections. In the visualization, however, initially everything appears correctly, but when I initiate a selection for Student the box plot calculated from Measure 1 disappears and only the data points for the selected student remain. I'm creating the extension in d3 and the code is included below.

Thanks in advance for any help.

 

define(["jquery", "./d3.v4.min", "./initialProperties", "./properties", "text!./CCP_Grouped_Multi.css"],
    function ($, d3, initProps, props, cssContent) {
        "use strict"
        $('<style>').html(cssContent).appendTo('head');
        return {
            initialProperties: initProps,
            definition: props,
            support: {
                snapshot: true,
                export: false,
                exportData: false
            },

            paint: function ($element, layout) {

                var hypercube = layout.cube1;
                console.log(hypercube);

                var margin = {
                    top: 20,
                    right: 20,
                    bottom: 60,
                    left: 40
                },
                    width = $element.width() - margin.left - margin.right,
                    height = $element.height() - margin.top - margin.bottom,
                    center = height / 2,
                    offset = 50;

                var id = "ID_D3" + layout.qInfo.qId;
                $element.attr("id", id); //assign to $element the attribute id set as "ID_D3"
                d3.select("#" + id).html(null);  //clear div so that it doesn't re-render with each run

                var dataset = layout.qHyperCube.qDataPages[0].qMatrix.map(function (d) {
                    return {
                        "d_1": d[0].qText, //Domain
                        "d_2": d[1].qText, //Student
                        "d_3": d[2].qNum, //Box plot measure (=Aggr({1<Student=>} NODISTINCT Max(Final_Score), Student, Domain)
                        "d_4": d[3].qNum //Data points measure (=Aggr(NODISTINCT Max(Final_Score), Student, Domain)
                    }
                });

                //Calculate distribution components (Adjust with d3.nest)
                var sumstat = d3.nest() // nest function allows to group the calculation per level of a factor
                    .key(function (d) { return d.d_1; })
                    .rollup(function (g) {
                        return {
                            "min": d3.quantile(g, 0, g => g.d_3),
                            "q1": d3.quantile(g, .25, g => g.d_3),
                            "med": d3.quantile(g, .5, g => g.d_3),
                            "q3": d3.quantile(g, .75, g => g.d_3),
                            "max": d3.quantile(g, 1, g => g.d_3)
                        }
                    })
                    .entries(dataset)
                console.log("sumstat:", sumstat)

                //Create svg object
                var svg = d3.select("#" + id)
                    .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 + ")");

                // Show the X scale (Need to find consistent way to translate the position: currently shifts at resizing)
                var x = d3.scaleLinear()
                    .domain([0, 1])
                    .range([0, width])
                svg
                    .append("g")
                    .attr("class", "axis")
                    .attr("transform", "translate(0," + height + ")")
                    .call(d3.axisBottom(x).tickValues([0, 1]).tickFormat(d3.format(".0%")));

                // Add X axis label:
                svg
                    .append("text")
                    .style("text-anchor", "middle")
                    .attr("x", width / 2)
                    .attr("y", height + margin.bottom - 15)
                    .text("Range");

                // Show the Y scale
                var y = d3.scaleBand()
                    .range([height, 0])
                    .domain(["CM", "CR", "HX", "PE"])
                    .padding(.4);
                svg.append("g")
                    .call(d3.axisLeft(y).tickSize(0))
                    .select(".domain").remove()

                // Show the boxes (shape outlines commented out)
                svg
                    .selectAll("boxes")
                    .data(sumstat)
                    .enter()
                    .append("rect")
                    .attr("y", function (d) { return y(d.key); })
                    .attr("x", function (d) { return (x(d.value.min)) })
                    .attr("width", function (d) { return (x(d.value.q1) - x(d.value.min)) })
                    .attr("height", center / 4)
                    // .attr("height", y.bandwidth())
                    // .attr("stroke", "gray")
                    .style("fill", "#EEEEEE")
                    .text("Minimum");


                svg
                    .selectAll("boxes")
                    .data(sumstat)
                    .enter()
                    .append("rect")
                    .attr("y", function (d) { return y(d.key); })
                    .attr("x", function (d) { return (x(d.value.q1)) })
                    .attr("width", function (d) { return (x(d.value.med) - x(d.value.q1)) })
                    .attr("height", center / 4)
                    // .attr("height", y.bandwidth())
                    // .attr("stroke", "gray")
                    .style("fill", "#CCCCCC");

                svg
                    .selectAll("boxes")
                    .data(sumstat)
                    .enter()
                    .append("rect")
                    .attr("y", function (d) { return y(d.key); })
                    .attr("x", function (d) { return (x(d.value.med)) })
                    .attr("width", function (d) { return (x(d.value.q3) - x(d.value.med)) })
                    .attr("height", center / 4)
                    // .attr("height", y.bandwidth())
                    // .attr("stroke", "gray")
                    .style("fill", "#999999");

                svg
                    .selectAll("boxes")
                    .data(sumstat)
                    .enter()
                    .append("rect")
                    .attr("y", function (d) { return y(d.key); })
                    .attr("x", function (d) { return (x(d.value.q3)) })
                    .attr("width", function (d) { return (x(d.value.max) - x(d.value.q3)) })
                    .attr("height", center / 4)
                    // .attr("height", y.bandwidth())
                    // .attr("stroke", "gray")
                    .style("fill", "#666666");

               
                //Adding individual data points (Change to rectangle with a value representing student store +- 5% of max-min) also: Convert to d3.nest() and sub for dataset (key/value)
                var color = d3.scaleLinear()
                    .domain([.5, 1])
                    .range(["#e7ecfc", "#1045e3"]);
                svg
                    .selectAll("indPoints")
                    .data(dataset)
                    .enter()
                    .append("circle")
                    .attr("cx", function (d) { return (x(d.d_4)) })
                    .attr("cy", function (d) { return (y(d.d_1) + (y.bandwidth() - (center / 7))) }) //Will have to adjust for flexibility
                    .attr("r", 4)
                    .style("fill", function (d) { return (color(+d.d_2)) });

               

            }
        }
    })

 

Labels (1)
0 Replies