<commit_before>// ========== Adding Table code ============

var fieldHeight = 30;
var fieldWidth = 140;

var previousSort = null;
var format = d3.time.format("%m/%d/%Y");
//var dateFn = function(date) { return format.parse(d.created_at) };


var subjectGroups = false;
var sub_data = []

d3.json("/data/subjects.json", function (data) {
    data.forEach(function (d) {
        d.subjectID = "s" + d.subjectID.toString();
        sub_data.push(d);
    });
    refreshTable(null);
});

var table_svg = d3.select("#table").append("svg")
    .attr("width", 700)
    .attr("height", 400);

var ramp = null;

var headerGrp = table_svg.append("g").attr("class", "headerGrp");
var rowsGrp = table_svg.append("g").attr("class","rowsGrp");


var tableGuiConfigObj = function () {
    this.groupCount = 2;
};

var tableGui = new dat.GUI({
    autoplace: false,
    width: 350,
    scrollable: false
});

var tableControlBox = new tableGuiConfigObj();

// gui.domElement.id = 'gui';
var tableGuiContainer = $('.tableGUI').append($(tableGui.domElement));

var groupCountController = tableGui.add(tableControlBox, 'groupCount').min(2).step(1)
    .name('Number of Groups')
    .onChange(function () {
        return refreshTable(sortOn); // Not really sure why this isn't working
    });
tableGui.close()

var sortOn = null
refreshTable(sortOn)

function refreshTable(sortOn){

    // create the table header
    var header = headerGrp.selectAll("g")
        .data(d3.keys(sub_data[0]))
        .enter().append("g")
        .attr("class", "t_header")
        .attr("transform", function (d, i){
            return "translate(" + i * fieldWidth + ",0)";
        })
        .on("mouseover", function (d,i) {
            d3.select(this).style("cursor", "n-resize");
        })
        .on("click", function (d) { return refreshTable(d); }); // this is where the magic happens... (d) is the column being sorted

    header.append("rect")
        .attr("width", fieldWidth-1)
        .attr("height", fieldHeight);

    header.append("text")
        .attr("x", fieldWidth / 2)
        .attr("y", fieldHeight / 2)
        .attr("dy", ".35em")
        .text(String);

    // fill the table
    // select rows
    var rows = rowsGrp.selectAll("g.row").data(sub_data,
        function(d){ return d.subjectID; });

    // create rows
    var rowsEnter = rows.enter().append("svg:g")
        .attr("class","row")
        .attr("id", function(d){ return d.subjectID; })
        .attr("opacity",0.3)
        .attr("transform", function (d, i){
            return "translate(0," + (i+1) * (fieldHeight+1) + ")";
        })
        //.on('click', row_select )
        .on('mouseover', table_mouseDown )
        .on('mousedown', row_select );
    // select cells
    var cells = rows.selectAll("g.cell").data(function(d){return d3.values(d);});

    // create cells
    var cellsEnter = cells.enter().append("svg:g")
        .attr("class", "cell")
        .attr("transform", function (d, i){
            return "translate(" + i * fieldWidth + ",0)";
        });

    cellsEnter.append("rect")
        .attr("width", fieldWidth-1)
        .attr("height", fieldHeight);

    cellsEnter.append("text")
        .attr("x", fieldWidth / 2)
        .attr("y", fieldHeight / 2)
        .attr("dy", ".35em")
        .text(String);

    //update if not in initialisation
    if (sortOn !== null) {
        // update rows
        if(sortOn != previousSort){
            rows.sort(function(a,b){return sort(a[sortOn], b[sortOn]);});
            previousSort = sortOn;
        }
        else{
            rows.sort(function(a,b){return sort(b[sortOn], a[sortOn]);});
            previousSort = null;
        }

        // prepare to split on metadata
        var splitGroups = d3.nest()
            .key(function (d) { return d[sortOn]; })
            .sortKeys(d3.ascending)
            .entries(sub_data);

        var numGroups = tableControlBox.groupCount;
        var finalSplit = Math.min(numGroups, splitGroups.length)


        // push subject ids into respective groups
        subjectGroups = []
        var groupSize = Math.floor(sub_data.length / finalSplit);
        var splitSize = Math.floor(splitGroups.length / finalSplit);
        
        for (g = 0; g < finalSplit; g++) {
            var group_arr = [];
            if (splitSize == 1) { // corresponds to one group for each unique value in d[sortOn]
                for (j = 0; j < splitGroups[g].values.length; j++) {
                    group_arr.push(splitGroups[g].values[j].subjectID);
                }
            } else if (splitSize == groupSize) { // corresponds to all values unique in d[sortOn]
                var stopGroup = (g + 1) * groupSize;
                for (k = g * groupSize; k < stopGroup; k++) {
                    group_arr.push(splitGroups[k].values[0].subjectID);
                }
            } else { // mixed continuous and repeat values (splitSize < groupSize) This part's still messed up!
                var stopGroup = (g + 1) * splitSize;
                for (k = g * groupSize; k < stopGroup; k++) {
                    for (j = 0; j < splitGroups[g].values.length; j++) {
                        group_arr.push(splitGroups[k].values[j].subjectID);
                    }
                }
            };
            subjectGroups.push(group_arr);
        };

        ramp = d3.scale.linear().domain([0, finalSplit-1]).range(["red", "blue"]); // color ramp for subject groups

        function IDcolor(element, index, array) {
            for (i = 0; i < element.length; i++) {
                d3.selectAll('#' + element[i])
                //.transition()
                //.duration(500)
                .style("stroke", ramp(index));
            }
        }

        subjectGroups.forEach(IDcolor); // color lines

        console.log(JSON.stringify(subjectGroups[0]));

        d3.csv("data/nodes.csv", updatePlots); // call update -> noticed there is a delay here. update plots may be the slow down

        rows//.transition() // sort row position
           //.duration(500)
           .attr("transform", function (d, i) {
               return "translate(0," + (i + 1) * (fieldHeight + 1) + ")";
           });
<commit_msg>Fix sort logic.<commit_after>// ========== Adding Table code ============

var fieldHeight = 30;
var fieldWidth = 140;

var previousSort = null;
var format = d3.time.format("%m/%d/%Y");
//var dateFn = function(date) { return format.parse(d.created_at) };


var subjectGroups = false;
var sub_data = []

d3.json("/data/subjects.json", function (data) {
    data.forEach(function (d) {
        d.subjectID = "s" + d.subjectID.toString();
        sub_data.push(d);
    });
    refreshTable(null);
});

var table_svg = d3.select("#table").append("svg")
    .attr("width", 2000)
    .attr("height", 1500);

var ramp = null;

var headerGrp = table_svg.append("g").attr("class", "headerGrp");
var rowsGrp = table_svg.append("g").attr("class","rowsGrp");


var tableGuiConfigObj = function () {
    this.groupCount = 2;
};

var tableGui = new dat.GUI({
    autoplace: false,
    width: 350,
    scrollable: false
});

var tableControlBox = new tableGuiConfigObj();

// gui.domElement.id = 'gui';
var tableGuiContainer = $('.tableGUI').append($(tableGui.domElement));

var groupCountController = tableGui.add(tableControlBox, 'groupCount').min(2).step(1)
    .name('Number of Groups')
    .onChange(function () {
        return refreshTable(sortOn); // Not really sure why this isn't working
    });
tableGui.close()

var sortOn = null
refreshTable(sortOn)

function refreshTable(sortOn){

    // create the table header
    var header = headerGrp.selectAll("g")
        .data(d3.keys(sub_data[0]))
        .enter().append("g")
        .attr("class", "t_header")
        .attr("transform", function (d, i){
            return "translate(" + i * fieldWidth + ",0)";
        })
        .on("mouseover", function (d,i) {
            d3.select(this).style("cursor", "n-resize");
        })
        .on("click", function (d) { return refreshTable(d); }); // this is where the magic happens... (d) is the column being sorted

    header.append("rect")
        .attr("width", fieldWidth-1)
        .attr("height", fieldHeight);

    header.append("text")
        .attr("x", fieldWidth / 2)
        .attr("y", fieldHeight / 2)
        .attr("dy", ".35em")
        .text(String);

    // fill the table
    // select rows
    var rows = rowsGrp.selectAll("g.row").data(sub_data,
        function(d){ return d.subjectID; });

    // create rows
    var rowsEnter = rows.enter().append("svg:g")
        .attr("class","row")
        .attr("id", function(d){ return d.subjectID; })
        .attr("opacity",0.3)
        .attr("transform", function (d, i){
            return "translate(0," + (i+1) * (fieldHeight+1) + ")";
        })
        //.on('click', row_select )
        .on('mouseover', table_mouseDown )
        .on('mousedown', row_select );
    // select cells
    var cells = rows.selectAll("g.cell").data(function(d){return d3.values(d);});

    // create cells
    var cellsEnter = cells.enter().append("svg:g")
        .attr("class", "cell")
        .attr("transform", function (d, i){
            return "translate(" + i * fieldWidth + ",0)";
        });

    cellsEnter.append("rect")
        .attr("width", fieldWidth-1)
        .attr("height", fieldHeight);

    cellsEnter.append("text")
        .attr("x", fieldWidth / 2)
        .attr("y", fieldHeight / 2)
        .attr("dy", ".35em")
        .text(String);

    //update if not in initialisation
    if (sortOn !== null) {
        // update rows
        if(sortOn != previousSort){
            rows.sort(function(a,b){return sort(a[sortOn], b[sortOn]);});
            previousSort = sortOn;
        }
        else{
            rows.sort(function(a,b){return sort(b[sortOn], a[sortOn]);});
            previousSort = null;
        }

        // prepare to split on metadata
        var splitGroups = d3.nest()
            .key(function (d) { return d[sortOn]; })
            .sortKeys(d3.ascending)
            .entries(sub_data);

        var usrGroups = tableControlBox.groupCount;
        var numGroups = Math.min(usrGroups, splitGroups.length)


        // push subject ids into respective groups
        subjectGroups = []
        var groupSize = Math.round(sub_data.length / numGroups);
        var splitSize = Math.round(splitGroups.length / numGroups);

        for (g = 0; g < numGroups; g++) {
            var group_arr = [];
            if (splitSize == 1) { // corresponds to one group for each unique value in d[sortOn]
                for (j = 0; j < splitGroups[g].values.length; j++) {
                    group_arr.push(splitGroups[g].values[j].subjectID);
                }
            } else { // mixed continuous and repeat values (splitSize < groupSize) This part's still messed up!
                var stopGroup = (g + 1) * groupSize;
                for (k = g * groupSize; k < stopGroup; k++) {
                  if (k<splitGroups.length){
                    for (j = 0; j < splitGroups[k].values.length; j++) {
                        group_arr.push(splitGroups[k].values[j].subjectID);
                    }
                  }
                }
            };
            subjectGroups.push(group_arr);
        };

        ramp = d3.scale.linear().domain([0, numGroups-1]).range(["red", "blue"]); // color ramp for subject groups

        function IDcolor(element, index, array) {
            for (i = 0; i < element.length; i++) {
                d3.selectAll('#' + element[i])
                //.transition()
                //.duration(500)
                .style("stroke", ramp(index));
            }
        }

        subjectGroups.forEach(IDcolor); // color lines

        d3.csv("data/nodes.csv", updatePlots); // call update -> noticed there is a delay here. update plots may be the slow down

        rows//.transition() // sort row position
           //.duration(500)
           .attr("transform", function (d, i) {
               return "translate(0," + (i + 1) * (fieldHeight + 1) + ")";
           });

{'fraction_non_alphanumeric': 0.16414454643182005, 'fraction_numerical': 0.010832713139832962, 'mean_word_length': 2.1178138695540087, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1975727', 'n_tokens_mistral': 3764, 'n_tokens_neox': 3600, 'n_words': 851}