Skip to content

Support ragged tables and show full table borders #2511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 63 additions & 10 deletions src/traces/table/data_preparation_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,28 @@ var isNumeric = require('fast-isnumeric');

// pure functions, don't alter but passes on `gd` and parts of `trace` without deep copying
module.exports = function calc(gd, trace) {
var cellsValues = trace.cells.values;
var cellsValues = squareStringMatrix(trace.cells.values);
var slicer = function(a) {
return a.slice(trace.header.values.length, a.length);
};
var headerValues = trace.header.values.map(function(c) {
return Array.isArray(c) ? c : [c];
}).concat(slicer(cellsValues).map(function() {return [''];}));
var headerValuesIn = squareStringMatrix(trace.header.values);
if(headerValuesIn.length && !headerValuesIn[0].length) {
headerValuesIn[0] = [''];
headerValuesIn = squareStringMatrix(headerValuesIn);
}
var headerValues = headerValuesIn
.concat(slicer(cellsValues).map(function() {
return emptyStrings((headerValuesIn[0] || ['']).length);
}));

var domain = trace.domain;
var groupWidth = Math.floor(gd._fullLayout._size.w * (domain.x[1] - domain.x[0]));
var groupHeight = Math.floor(gd._fullLayout._size.h * (domain.y[1] - domain.y[0]));
var headerRowHeights = trace.header.values.length ? headerValues[0].map(function() {return trace.header.height;}) : [c.emptyHeaderHeight];
var rowHeights = cellsValues.length ? cellsValues[0].map(function() {return trace.cells.height;}) : [];
var headerHeight = headerRowHeights.reduce(function(a, b) {return a + b;}, 0);
var headerRowHeights = trace.header.values.length ?
headerValues[0].map(function() { return trace.header.height; }) :
[c.emptyHeaderHeight];
var rowHeights = cellsValues.length ? cellsValues[0].map(function() { return trace.cells.height; }) : [];
var headerHeight = headerRowHeights.reduce(sum, 0);
var scrollHeight = groupHeight - headerHeight;
var minimumFillHeight = scrollHeight + c.uplift;
var anchorToRowBlock = makeAnchorToRowBlock(rowHeights, minimumFillHeight);
Expand All @@ -41,24 +50,27 @@ module.exports = function calc(gd, trace) {
trace.columnwidth;
return isNumeric(value) ? Number(value) : 1;
});
var totalColumnWidths = columnWidths.reduce(function(p, n) {return p + n;}, 0);
var totalColumnWidths = columnWidths.reduce(sum, 0);

// fit columns in the available vertical space as there's no vertical scrolling now
columnWidths = columnWidths.map(function(d) {return d / totalColumnWidths * groupWidth;});
columnWidths = columnWidths.map(function(d) { return d / totalColumnWidths * groupWidth; });

var maxLineWidth = Math.max(arrayMax(trace.header.line.width), arrayMax(trace.cells.line.width));

var calcdata = {
key: trace.index,
translateX: domain.x[0] * gd._fullLayout._size.w,
translateY: gd._fullLayout._size.h * (1 - domain.y[1]),
size: gd._fullLayout._size,
width: groupWidth,
maxLineWidth: maxLineWidth,
height: groupHeight,
columnOrder: columnOrder, // will be mutated on column move, todo use in callback
groupHeight: groupHeight,
rowBlocks: rowBlocks,
headerRowBlocks: headerRowBlocks,
scrollY: 0, // will be mutated on scroll
cells: trace.cells,
cells: extendFlat({}, trace.cells, {values: cellsValues}),
headerCells: extendFlat({}, trace.header, {values: headerValues}),
gdColumns: headerValues.map(function(d) {return d[0];}),
gdColumnsOriginalOrder: headerValues.map(function(d) {return d[0];}),
Expand Down Expand Up @@ -89,6 +101,47 @@ module.exports = function calc(gd, trace) {
return calcdata;
};

function arrayMax(maybeArray) {
if(Array.isArray(maybeArray)) {
var max = 0;
for(var i = 0; i < maybeArray.length; i++) {
max = Math.max(max, arrayMax(maybeArray[i]));
}
return max;
}
return maybeArray;
}

function sum(a, b) { return a + b; }

// fill matrix in place to equal lengths
// and ensure it's uniformly 2D
function squareStringMatrix(matrixIn) {
var matrix = matrixIn.slice();
var minLen = Infinity;
var maxLen = 0;
var i;
for(i = 0; i < matrix.length; i++) {
if(!Array.isArray(matrix[i])) matrix[i] = [matrix[i]];
minLen = Math.min(minLen, matrix[i].length);
maxLen = Math.max(maxLen, matrix[i].length);
}

if(minLen !== maxLen) {
for(i = 0; i < matrix.length; i++) {
var padLen = maxLen - matrix[i].length;
if(padLen) matrix[i] = matrix[i].concat(emptyStrings(padLen));
}
}
return matrix;
}

function emptyStrings(len) {
var padArray = new Array(len);
for(var j = 0; j < len; j++) padArray[j] = '';
return padArray;
}

function xScale(d) {
return d.calcdata.columns.reduce(function(prev, next) {
return next.xIndex < d.xIndex ? prev + next.columnWidth : prev;
Expand Down
10 changes: 8 additions & 2 deletions src/traces/table/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,18 @@ module.exports = function plot(gd, wrappedTraceHolders) {
.attr('fill', 'none');

columnBoundaryRect
.attr('width', function(d) {return d.columnWidth;})
.attr('height', function(d) {return d.calcdata.height + c.uplift;});
.attr('width', function(d) { return d.columnWidth + 2 * roundHalfWidth(d); })
.attr('height', function(d) {return d.calcdata.height + 2 * roundHalfWidth(d) + c.uplift;})
.attr('x', function(d) { return -roundHalfWidth(d); })
.attr('y', function(d) { return -roundHalfWidth(d); });

updateBlockYPosition(null, cellsColumnBlock, tableControlView);
};

function roundHalfWidth(d) {
return Math.ceil(d.calcdata.maxLineWidth / 2);
}

function scrollAreaBottomClipKey(gd, d) {
return 'clip' + gd._fullLayout._uid + '_scrollAreaBottomClip_' + d.key;
}
Expand Down
Binary file modified test/image/baselines/grid_subplot_types.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed test/image/baselines/table_latex_multitrace.png
Binary file not shown.
Binary file modified test/image/baselines/table_latex_multitrace_scatter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/table_plain_birds.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/image/baselines/table_ragged.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/table_wrapped_birds.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
137 changes: 0 additions & 137 deletions test/image/mocks/table_latex_multitrace.json

This file was deleted.

8 changes: 4 additions & 4 deletions test/image/mocks/table_latex_multitrace_scatter.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"header": {
"values": [["<b>#</b>"], ["Half-angle form"], ["Equivalent"]],
"align": ["right", "center", "center"],
"line": {"width": 0.0},
"line": {"width": 1, "color": ["dimgray", "grey"]},
"fill": {"color": ["dimgray", "grey"]},
"font": {"family": "Arial", "size": 14, "color": "white"}
},
Expand Down Expand Up @@ -55,7 +55,7 @@
"header": {
"values": [["<b>#</b>"], ["$$\\theta$$"], ["Half-angle sine"], ["Half-angle cosine"]],
"align": "right",
"line": {"width": 0.0},
"line": {"width": 1, "color": ["dimgray", "grey"]},
"fill": {"color": ["dimgray", "grey"]},
"font": {"family": "Arial", "size": 14, "color": "white"}
},
Expand Down Expand Up @@ -88,7 +88,7 @@
"header": {
"values": [["Trig function"], ["Double-angle form"]],
"align": ["right", "left"],
"line": {"width": 0.0},
"line": {"width": 1, "color": ["dimgray", "grey"]},
"fill": {"color": ["dimgray", "grey"]},
"font": {"family": "Arial", "size": 14, "color": "white"}
},
Expand Down Expand Up @@ -117,7 +117,7 @@
"header": {
"values": [["<b>#</b>"], ["$$\\theta$$"], ["Double-angle sine"], ["Double-angle cosine"]],
"align": "right",
"line": {"width": 0.0},
"line": {"width": 1, "color": ["dimgray", "grey"]},
"fill": {"color": ["dimgray", "grey"]},
"font": {"family": "Arial", "size": 14, "color": "white"}
},
Expand Down
5 changes: 1 addition & 4 deletions test/image/mocks/table_plain_birds.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@

"align": ["right", "left", "right", "right", "left", "left", "left"],

"line": {
"color": "lightgray",
"width": 0.0
},
"line": {"width": 1, "color": ["dimgray", "grey"]},

"fill": {
"color": ["dimgray", "grey"]
Expand Down
13 changes: 13 additions & 0 deletions test/image/mocks/table_ragged.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"data": [{
"type": "table",
"header": {"values": ["z", ["a","b"], ["c"], []],
"line": {"width": 4}},
"cells": {
"values": [[1],[2,3],4,[],[5]],
"fill": {"color": "#eee"},
"line": {"width": [[1,9],[3,7],[5,5],[7,3],[9,1]]}
}
}],
"layout": {"width": 400, "height": 400}
}
5 changes: 1 addition & 4 deletions test/image/mocks/table_wrapped_birds.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@

"align": ["right", "left", "right", "right", "left", "left", "left"],

"line": {
"color": "lightgray",
"width": 0.0
},
"line": {"width": 1, "color": ["dimgray", "grey"]},

"fill": {
"color": ["dimgray", "grey"]
Expand Down
4 changes: 2 additions & 2 deletions test/jasmine/tests/table_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var supplyAllDefaults = require('../assets/supply_defaults');

var mockMulti = require('@mocks/table_latex_multitrace.json');
var mockMulti = require('@mocks/table_latex_multitrace_scatter.json');

// mock with two columns; lowest column count of general case
var mock2 = Lib.extendDeep({}, mockMulti);
Expand Down Expand Up @@ -305,7 +305,7 @@ describe('table', function() {
expect(gd.data[0].header.fill.color).toEqual('magenta');
expect(gd.data[0].header.values.length).toEqual(7);
expect(gd.data[0].cells.values.length).toEqual(7);
expect(gd.data[0].header.line.color).toEqual('lightgray'); // no change relative to original mock value
expect(gd.data[0].header.line.color).toEqual(['dimgray', 'grey']); // no change relative to original mock value
expect(gd.data[0].cells.line.color).toEqual(['grey']); // no change relative to original mock value

done();
Expand Down