1

Consider the following (with many thanks to Creating a table linked to a csv file):

var dataAsCsv = `Col1,Col2
Type1,"123,456"
Type2,"789,012"
Type3,"34,567"`;

var data = d3.csvParse(dataAsCsv);

var columns = ['Col1', 'Col2'];
 
var table = d3.select("#currentMonthTable").append("table"),
    thead = table.append("thead"),
    tbody = table.append("tbody");

// append the header row
thead.append("tr")
     .selectAll("th")
     .data(columns)
     .enter()
     .append("th")
     .text(function(column) { return column; });

var rows = tbody.selectAll("tr")
    // create a row for each object in the data
                .data(data)
                .enter()
                .append("tr");

// create a cell in each row for each column
var cells = rows.selectAll("td")
        .data(function(row) {
            return columns.map(function(column) {
                return {column: column, value: row[column]};
            });
        })
        .enter()
        .append("td")
            .text(function(d) { return d.value; });
<script src="https://d3js.org/d3.v4.js"></script>
<body>
<div id="currentMonthTable"></div>
</body>

I would like to right-justify all cells with numbers in them and keep the justification of all other cells the same. I.e.: the 123,456, 789,012, and 34,567 should all be right-justified, but all other justification should remain the same.

What is the easiest way to do this in D3? Note that I would like to keep this to D3 so as to maintain being able to use the csv data.

Intuitively, I believe the correct solution probably entails giving all cells with numbers a CSS class and then setting text-align:right;, but I'm not sure how to specifically target these cells using D3.

Clarinetist
  • 975
  • 13
  • 36

2 Answers2

2

Here's one approach of doing that: Use a RegEx to determine if the string is a number or not

I've used this answer to check that and added a class accordingly:

.attr('class', function(d) {
    return /^[0-9,.]*$/.test(d.value) ? 'integer' : null;
});

And CSS:

#currentMonthTable table td.integer {
  text-align: right;
}

Here's a code snippet:

var dataAsCsv = `Col1,Col2
Type1,"123,456"
Type2,"789,012"
Type3,"34,567"`;

var data = d3.csvParse(dataAsCsv);

var columns = ['Col1', 'Col2'];
 
var table = d3.select("#currentMonthTable").append("table"),
    thead = table.append("thead"),
    tbody = table.append("tbody");

// append the header row
thead.append("tr")
     .selectAll("th")
     .data(columns)
     .enter()
     .append("th")
     .text(function(column) { return column; });

var rows = tbody.selectAll("tr")
    // create a row for each object in the data
                .data(data)
                .enter()
                .append("tr");

// create a cell in each row for each column
var cells = rows.selectAll("td")
        .data(function(row) {
            return columns.map(function(column) {
                return {column: column, value: row[column]};
            });
        })
        .enter()
        .append("td")
            .text(function(d) { return d.value; })
            .attr('class', function(d) {
             return /^[0-9,.]*$/.test(d.value) ? 'integer' : null;
            }); 
#currentMonthTable table td.integer {
  text-align: right;
}
<script src="https://d3js.org/d3.v4.js"></script>
<body>
<div id="currentMonthTable"></div>
</body>

Hope this is helpful.

Shashank
  • 5,210
  • 1
  • 8
  • 16
  • Just to make sure I'm interpreting the RegEx correctly, `/^[0-9,.]*$` means any string that contains the characters `0` through `9`, commas, and periods, correct? – Clarinetist Jan 22 '18 at 14:53
  • The regex also matches the empty string or just punctuation. `/^[0-9,.]+$/` is closer because it requires at least one character but still allows just `,` or `.` - a correct number regex is more complex so I suppose it depends how accurate you need it to be. See https://stackoverflow.com/questions/2811031/decimal-or-numeric-values-in-regular-expression-validation – donaldh Jan 23 '18 at 12:04
  • Clarinetist: The RegEx can be improvised by using the [link](https://stackoverflow.com/questions/2811031/decimal-or-numeric-values-in-regular-expression-validation) mentioned by @donaldh – Shashank Jan 23 '18 at 14:48
1

You can write functions with two arguments, the datum and the current cell index, e.g. function(d, i) { ... }

The following addition sets the 'numeric' class for cells in column 1:

    .append("td")
        .classed('numeric', function(d,i) { return i == 1 } )
        .text(function(d) { return d.value; });

Here is your original code with the modification and the 'numeric' class:

var dataAsCsv = `Col1,Col2
Type1,"123,456"
Type2,"789,012"
Type3,"34,567"`;

var data = d3.csvParse(dataAsCsv);

var columns = ['Col1', 'Col2'];
 
var table = d3.select("#currentMonthTable").append("table"),
    thead = table.append("thead"),
    tbody = table.append("tbody");

// append the header row
thead.append("tr")
     .selectAll("th")
     .data(columns)
     .enter()
     .append("th")
     .text(function(column) { return column; });

var rows = tbody.selectAll("tr")
    // create a row for each object in the data
                .data(data)
                .enter()
                .append("tr");

// create a cell in each row for each column
var cells = rows.selectAll("td")
        .data(function(row) {
            return columns.map(function(column) {
                return {column: column, value: row[column]};
            });
        })
        .enter()
        .append("td")
            .classed('numeric', function(d,i) { return i == 1 } )
            .text(function(d) { return d.value; });
<style type="text/css">.numeric { text-align: right }</style>
<script src="https://d3js.org/d3.v4.js"></script>
<body>
<div id="currentMonthTable"></div>
</body>
donaldh
  • 760
  • 1
  • 7
  • 12
  • I thought of this too but then this wouldn't serve "_I would like to right-justify **all** cells with numbers in them_", right? – Shashank Jan 22 '18 at 15:01
  • @Shashank - Good point. I thought the question was ambiguous. I had written my answer at the same time as you, otherwise I would have just offered my alternative for when a column is known to contain numbers. – donaldh Jan 23 '18 at 12:07