1

I am trying to edit someone else's code written in d3.js v3 to v5 to get a interactive and responsive table with my dataset. Could anyone tell us why it is not working although I think I have edited lines need to be done? Thank you. http://bl.ocks.org/AMDS/4a61497182b8fcb05906 this is the orginal code.

<title>D3.js Sortable & Responsive Table</title>

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!--[if !IE]><!-->
<style>
* { 
  margin: 0; 
  padding: 0; 
 }
 body { 
   font: 14px/1.4 Georgia, Serif; 
 }
#page-wrap {
  margin: 50px;
}
p {
 margin: 20px 0; 
}

/* 
Generic Styling, for Desktops/Laptops 
*/
table { 
    width: 100%; 
    border-collapse: collapse; 
}
/* Zebra striping */
tr:nth-of-type(odd) { 
    background: #eee; 
}
th { 
    background: #333; 
    color: white; 
    font-weight: bold; 
    cursor: s-resize;
    background-repeat: no-repeat;
    background-position: 3% center;
}
td, th { 
    padding: 6px; 
    border: 1px solid #ccc; 
    text-align: left; 
}

th.des:after {
  content: "\21E9";
}

th.aes:after {
  content: "\21E7";
}

/* 
Max width before this PARTICULAR table gets nasty
This query will take effect for any screen smaller than 760px
and also iPads specifically.
*/
@media 
only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px)  {

    /* Force table to not be like tables anymore */
    table, thead, tbody, th, td, tr { 
        display: block; 
    }

    /* Hide table headers (but not display: none;, for accessibility) */
    thead tr { 
        position: absolute;
        top: -9999px;
        left: -9999px;
    }

    tr { border: 1px solid #ccc; }

    td { 
        /* Behave  like a "row" */
        border: none;
        border-bottom: 1px solid #eee; 
        position: relative;
        padding-left: 50%; 
    }

    td:before { 
        /* Now like a table header */
        position: absolute;
        /* Top/left values mimic padding */
        top: 6px;
        left: 6px;
        width: 45%; 
        padding-right: 10px; 
        white-space: nowrap;
    }

    /*
    Label the data
    */
    td:before {
      content: attr(data-th) ": ";
      font-weight: bold;
      width: 6.5em;
      display: inline-block;
    }
}

/* Smartphones (portrait and landscape) ----------- */
@media only screen
and (min-device-width : 320px)
and (max-device-width : 480px) {
    body { 
        padding: 0; 
        margin: 0; 
        width: 320px; }
    }

/* iPads (portrait and landscape) ----------- */
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
    body { 
        width: 495px; 
    }
}

</style>
<!--<![endif]-->

<div id="page-wrap">

<h1>D3.js Sortable & Responsive Table</h1>

<p>Click the table header to sort data according to that column</p>

</div>
<script type="text/javascript" src="http://d3js.org/d3.v5.min.js"></script>
<script type="text/javascript">
  d3.csv("E2allProcEff.csv".then(function(data) {
      d3.tsv(tsv, type).then(function(data) {



      var sortAscending = true;
      var table = d3.select('#page-wrap').append('table');
      var titles = d3.keys(data[0]);
      var headers = table.append('thead').append('tr')
                       .selectAll('th')
                       .data(titles).enter()
                       .append('th')
                       .text(function (d) {
                            return d;
                        })
                       .on('click', function (d) {
                           headers.attr('class', 'header');

                           if (sortAscending) {
                             rows.sort(function(a, b) { return b[d] < a[d]; });
                             sortAscending = false;
                             this.className = 'aes';
                           } else {
                             rows.sort(function(a, b) { return b[d] > a[d]; });
                             sortAscending = true;
                             this.className = 'des';
                           }

                       });

      var rows = table.append('tbody').selectAll('tr')
                   .data(data).enter()
                   .append('tr');
      rows.selectAll('td')
        .data(function (d) {
            return titles.map(function (k) {
                return { 'value': d[k], 'name': k};
            });
        }).enter()
        .append('td')
        .attr('data-th', function (d) {
            return d.name;
        })
        .text(function (d) {
            return d.value;
        });
        })
  });
</script>

S. Young
  • 21
  • 4
  • It looks like the errors might be coming from the top of the script where the data is loaded -- where are `tsv` and `type` defined, and why are you loading a csv then a tsv file? You're also missing a close parenthesis ()) after the name of the csv file. – i alarmed alien Oct 15 '18 at 08:31

2 Answers2

0

I removed the top two lines, which were causing a parser error due to the missed ) in d3.csv("E2allProcEff.csv".then and the redundant loading of data by two different methods:

d3.csv("E2allProcEff.csv".then(function(data) {
  d3.tsv(tsv, type).then(function(data) {

and the sets of braces/parentheses at the bottom that go with them. When I created some data objects, the table displays fine:

var data = ['Blues','Greens','Greys','Purples','Reds','Oranges'].map( s => {
  var obj = { colours: s };
  d3['scheme' + s ][5].forEach( (c,i) => obj['position_' +  i] = c )
  return obj
} )

var sortAscending = true;
var table = d3.select('#page-wrap').append('table');
var titles = d3.keys(data[0]);
var headers = table.append('thead').append('tr')
  .selectAll('th')
  .data(titles).enter()
  .append('th')
  .text(function(d) {
    return d;
  })
  .on('click', function(d) {
    headers.attr('class', 'header');

    if (sortAscending) {
      rows.sort(function(a, b) {
        return b[d] < a[d];
      });
      sortAscending = false;
      this.className = 'aes';
    } else {
      rows.sort(function(a, b) {
        return b[d] > a[d];
      });
      sortAscending = true;
      this.className = 'des';
    }

  });

var rows = table.append('tbody').selectAll('tr')
  .data(data).enter()
  .append('tr')

rows.selectAll('td')
  .data(function(d) {
    return titles.map(function(k) {
      return {
        'value': d[k],
        'name': k
      };
    });
  })
  .enter()
  .append('td')
  .attr('data-th', function(d) {
    return d.name;
  })
  .text(function(d) {
    return d.value;
  });
* { 
  margin: 0; 
  padding: 0; 
 }
 body { 
   font: 14px/1.4 Georgia, Serif; 
 }
#page-wrap {
  margin: 50px;
}
p {
 margin: 20px 0; 
}

/* 
Generic Styling, for Desktops/Laptops 
*/
table { 
    width: 100%; 
    border-collapse: collapse; 
}
/* Zebra striping */
tr:nth-of-type(odd) { 
    background: #eee; 
}
th { 
    background: #333; 
    color: white; 
    font-weight: bold; 
    cursor: s-resize;
    background-repeat: no-repeat;
    background-position: 3% center;
}
td, th { 
    padding: 6px; 
    border: 1px solid #ccc; 
    text-align: left; 
}

th.des:after {
  content: "\21E9";
}

th.aes:after {
  content: "\21E7";
}

/* 
Max width before this PARTICULAR table gets nasty
This query will take effect for any screen smaller than 760px
and also iPads specifically.
*/
@media 
only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px)  {

    /* Force table to not be like tables anymore */
    table, thead, tbody, th, td, tr { 
        display: block; 
    }

    /* Hide table headers (but not display: none;, for accessibility) */
    thead tr { 
        position: absolute;
        top: -9999px;
        left: -9999px;
    }

    tr { border: 1px solid #ccc; }

    td { 
        /* Behave  like a "row" */
        border: none;
        border-bottom: 1px solid #eee; 
        position: relative;
        padding-left: 50%; 
    }

    td:before { 
        /* Now like a table header */
        position: absolute;
        /* Top/left values mimic padding */
        top: 6px;
        left: 6px;
        width: 45%; 
        padding-right: 10px; 
        white-space: nowrap;
    }

    /*
    Label the data
    */
    td:before {
      content: attr(data-th) ": ";
      font-weight: bold;
      width: 6.5em;
      display: inline-block;
    }
}

/* Smartphones (portrait and landscape) ----------- */
@media only screen
and (min-device-width : 320px)
and (max-device-width : 480px) {
    body { 
        padding: 0; 
        margin: 0; 
        width: 320px; }
    }

/* iPads (portrait and landscape) ----------- */
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
    body { 
        width: 495px; 
    }
}
<script type="text/javascript" src="http://d3js.org/d3.v5.min.js"></script>

<div id="page-wrap"></div>

You just need to add in the code that loads your csv data, and you're done:

d3.csv("E2allProcEff.csv").then( function(data) {

  var sortAscending = true;
  var table = d3.select('#page-wrap').append('table');
  var titles = d3.keys(data[0]);

  [... snip ...]

  rows.selectAll('td')
    .data(function (d) {
        return titles.map(function (k) {
            return { 'value': d[k], 'name': k};
        });
    }).enter()
    .append('td')
    .attr('data-th', function (d) {
        return d.name;
    })
    .text(function (d) {
        return d.value;
    });

})
i alarmed alien
  • 9,412
  • 3
  • 27
  • 40
  • Thanks but I'm not sure why it is not working with me. Isn't 'd3.csv("E2allProcEff.csv").then( function(data) {' this line enough for me to load my csv data? or should I add a line to read and store the data for example, 'var data= data.csvparse(data)'? When I go to the console on webpage, it says "cross origin requests are only supported for HTTP", "Fetch API cannot load file://~~/Downloads/E2allprocEFF.csv due to access control checks", and "Unhandled promise Rejection: TypeError: Cross origin requests are only supported for HTTP." – S. Young Oct 15 '18 at 15:25
  • you don't need to read and store data -- that's what `d3.csv('filename').then( function(data) {` does. Have a read of the documentation on [d3.fetch](https://github.com/d3/d3-fetch) because fetching and parsing data works differently in d3 v5. Your current error is because you're trying to access a document using the `file:` protocol, which is not permitted by the Fetch API. The quickest fix is to run a little server on your computer -- e.g. http://2ality.blogspot.com/2015/10/http-server-nodejs.html – i alarmed alien Oct 15 '18 at 16:07
0

Came across the same example, but the sorting is not working. After some research, I discovered it is due to bad sorting function (as explained in Sorting in JavaScript: Shouldn't returning a boolean be enough for a comparison function?)

My fixed version: http://bl.ocks.org/prusswan/cdc289db753810a3c537f8eb2603bda8

There is also a cleaner fix using d3's sort helpers:

rows.sort(function(a, b) { 
  //return b[d] < a[d]; // this is bad
  //return b[d] < a[d] ? 1 : b[d] == a[d] ? 0 : -1; // this is a valid fix
  return d3.ascending(a[d], b[d]); // this is more idiomatic
});

Interestingly, the original "bad" version works on my phone browser but not on my desktop Chrome, so the phone browser is probably using some kind of quirks mode...

prusswan
  • 6,853
  • 4
  • 40
  • 61