Skip to content

Commit

Permalink
Full support for categoryorder, categoryarray, and categorylabels
Browse files Browse the repository at this point in the history
Mocks updated, but not tests yet.
  • Loading branch information
Jon M. Mease committed Aug 17, 2018
1 parent 7f90fc1 commit 5e60062
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 38 deletions.
12 changes: 9 additions & 3 deletions src/traces/parcats/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ module.exports = function calc(gd, trace) {
var cats = dimensionModels[d].categories;

if(cats[catInd] === undefined) {
var catValue = trace.dimensions[containerInd].categoryarray[catInd];
var catLabel = trace.dimensions[containerInd].categorylabels[catInd];
cats[catInd] = createCategoryModel(d, catInd, catLabel);
cats[catInd] = createCategoryModel(d, catInd, catValue, catLabel);
}

updateCategoryModel(cats[catInd], valueInd, count);
Expand Down Expand Up @@ -278,8 +279,11 @@ function createDimensionModel(dimensionInd, containerInd, displayInd, dimensionL
* The index of this categories dimension
* @property {Number} categoryInd
* The index of this category
* @property {Number} displayInd
* The display index of this category (where 0 is the topmost category)
* @property {String} categoryLabel
* The name of this category
* @property categoryValue: Raw value of the category
* @property {Array} valueInds
* Array of indices (into the original value array) of all samples in this category
* @property {Number} count
Expand All @@ -292,15 +296,17 @@ function createDimensionModel(dimensionInd, containerInd, displayInd, dimensionL
* Create and return a new CategoryModel object
* @param {Number} dimensionInd
* @param {Number} categoryInd
* @param {Number} displayInd
* The display index of this category (where 0 is the topmost category)
* @param {String} categoryValue
* @param {String} categoryLabel
* @return {CategoryModel}
*/
function createCategoryModel(dimensionInd, categoryInd, displayInd, categoryLabel) {
function createCategoryModel(dimensionInd, categoryInd, categoryValue, categoryLabel) {
return {
dimensionInd: dimensionInd,
categoryInd: categoryInd,
categoryValue: categoryValue,
displayInd: categoryInd,
categoryLabel: categoryLabel,
valueInds: [],
count: 0,
Expand Down
26 changes: 20 additions & 6 deletions src/traces/parcats/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,26 @@ function dimensionDefaults(dimensionIn, dimensionOut) {
coerce('displayindex', dimensionOut._index);

// Category level
// TODO: Make categoryorder and categoryarray consistent
// If valid array, set order to 'array'
// If order is 'array' but array is invalid set order to 'trace'
coerce('categoryorder');
coerce('categoryarray');
coerce('categorylabels');
var arrayIn = dimensionIn.categoryarray;
var isValidArray = (Array.isArray(arrayIn) && arrayIn.length > 0);

var orderDefault;
if(isValidArray) orderDefault = 'array';
var order = coerce('categoryorder', orderDefault);

// coerce 'categoryarray' only in array order case
if(order === 'array') {
coerce('categoryarray');
coerce('categorylabels');
} else {
delete dimensionIn.categoryarray;
delete dimensionIn.categorylabels;
}

// cannot set 'categoryorder' to 'array' with an invalid 'categoryarray'
if(!isValidArray && order === 'array') {
dimensionOut.categoryorder = 'trace';
}
}
}

Expand Down
92 changes: 64 additions & 28 deletions src/traces/parcats/parcats.js
Original file line number Diff line number Diff line change
Expand Up @@ -1014,11 +1014,11 @@ function dragDimension(d) {
var categoryY = dragCategory.model.dragY;

// Check for category drag swaps
var categoryInd = dragCategory.model.categoryInd;
var catDisplayInd = dragCategory.model.displayInd;
var dimCategoryViews = dragDimension.categories;

var catAbove = dimCategoryViews[categoryInd - 1];
var catBelow = dimCategoryViews[categoryInd + 1];
var catAbove = dimCategoryViews[catDisplayInd - 1];
var catBelow = dimCategoryViews[catDisplayInd + 1];

// Check for overlap above
if(catAbove !== undefined) {
Expand All @@ -1027,7 +1027,7 @@ function dragDimension(d) {

// Swap display inds
dragCategory.model.displayInd = catAbove.model.displayInd;
catAbove.model.displayInd = categoryInd;
catAbove.model.displayInd = catDisplayInd;
}
}

Expand All @@ -1037,7 +1037,7 @@ function dragDimension(d) {

// Swap display inds
dragCategory.model.displayInd = catBelow.model.displayInd;
catBelow.model.displayInd = categoryInd;
catBelow.model.displayInd = catDisplayInd;
}
}

Expand Down Expand Up @@ -1121,20 +1121,31 @@ function dragDimensionEnd(d) {
}

// ### Handle category reordering ###
// var anyCatsReordered = false;
// if(d.dragCategoryDisplayInd !== null) {
// var finalDragCategoryDisplayInds = d.model.categories.map(function(c) {
// return c.displayInd;
// });
//
// anyCatsReordered = d.initialDragCategoryDisplayInds.some(function(initCatDisplay, catInd) {
// return initCatDisplay !== finalDragCategoryDisplayInds[catInd];
// });
//
// if(anyCatsReordered) {
// restyleData['dimensions[' + d.model.containerInd + '].catDisplayInds'] = [finalDragCategoryDisplayInds];
// }
// }
var anyCatsReordered = false;
if(d.dragCategoryDisplayInd !== null) {
var finalDragCategoryDisplayInds = d.model.categories.map(function(c) {
return c.displayInd;
});

anyCatsReordered = d.initialDragCategoryDisplayInds.some(function(initCatDisplay, catInd) {
return initCatDisplay !== finalDragCategoryDisplayInds[catInd];
});

if(anyCatsReordered) {

// Sort a shallow copy of the category models by display index
var sortedCategoryModels = d.model.categories.slice().sort(
function (a, b) { return a.displayInd - b.displayInd });

// Get new categoryarray and categorylabels values
var newCategoryArray = sortedCategoryModels.map(function (v) { return v.categoryValue });
var newCategoryLabels = sortedCategoryModels.map(function (v) { return v.categoryLabel });

restyleData['dimensions[' + d.model.containerInd + '].categoryarray'] = [newCategoryArray];
restyleData['dimensions[' + d.model.containerInd + '].categorylabels'] = [newCategoryLabels];
restyleData['dimensions[' + d.model.containerInd + '].categoryorder'] = ['array'];
}
}

// Handle potential click event
// ----------------------------
Expand Down Expand Up @@ -1520,6 +1531,12 @@ function updatePathViewModels(parcatsViewModel) {
});
});

// Array from category index to category display index for each true dimension index
var catToDisplayIndPerDim = parcatsViewModel.model.dimensions.map(
function(d) {
return d.categories.map(function(c) {return c.displayInd;});
});

// Array from true dimension index to dimension display index
var dimToDisplayInd = parcatsViewModel.model.dimensions.map(function(d) {return d.displayInd;});
var displayToDimInd = parcatsViewModel.dimensions.map(function(d) {return d.model.dimensionInd;});
Expand All @@ -1541,12 +1558,21 @@ function updatePathViewModels(parcatsViewModel) {
}
}

// Compute category display inds to use for sorting paths
function pathDisplayCategoryInds(pathModel) {
var dimensionInds = pathModel.categoryInds.map(function(catInd, dimInd) {return catToDisplayIndPerDim[dimInd][catInd];});
var displayInds = displayToDimInd.map(function(dimInd) {
return dimensionInds[dimInd];
});
return displayInds;
}

// Sort in ascending order by display index array
pathModels.sort(function(v1, v2) {

// Build display inds for each path
var sortArray1 = v1.categoryInds;
var sortArray2 = v2.categoryInds;
var sortArray1 = pathDisplayCategoryInds(v1);
var sortArray2 = pathDisplayCategoryInds(v2);

// Handle path sort order
if(parcatsViewModel.sortpaths === 'backward') {
Expand Down Expand Up @@ -1599,14 +1625,15 @@ function updatePathViewModels(parcatsViewModel) {
var pathYs = new Array(nextYPositions.length);
for(var d = 0; d < pathModel.categoryInds.length; d++) {
var catInd = pathModel.categoryInds[d];
var catDisplayInd = catToDisplayIndPerDim[d][catInd];
var dimDisplayInd = dimToDisplayInd[d];

// Update next y position
pathYs[dimDisplayInd] = nextYPositions[dimDisplayInd][catInd];
nextYPositions[dimDisplayInd][catInd] += pathHeight;
pathYs[dimDisplayInd] = nextYPositions[dimDisplayInd][catDisplayInd];
nextYPositions[dimDisplayInd][catDisplayInd] += pathHeight;

// Update category color information
var catViewModle = parcatsViewModel.dimensions[dimDisplayInd].categories[catInd];
var catViewModle = parcatsViewModel.dimensions[dimDisplayInd].categories[catDisplayInd];
var numBands = catViewModle.bands.length;
var lastCatBand = catViewModle.bands[numBands - 1];

Expand Down Expand Up @@ -1641,7 +1668,7 @@ function updatePathViewModels(parcatsViewModel) {
}

pathViewModels[pathNumber] = {
key: pathModel.categoryInds + '-' + pathModel.valueInds[0],
key: pathModel.valueInds[0],
model: pathModel,
height: pathHeight,
leftXs: leftXPositions,
Expand Down Expand Up @@ -1730,14 +1757,23 @@ function createDimensionViewModel(parcatsViewModel, dimensionModel) {
nextCatHeight,
nextCatModel,
nextCat,
catInd;
catInd,
catDisplayInd;

// Compute starting Y offset
var nextCatY = (maxCats - numCats) * catSpacing / 2.0;

// Compute category ordering
for(catInd = 0; catInd < numCats; catInd++) {
var categoryIndInfo = dimensionModel.categories.map(function(c) {
return {displayInd: c.displayInd, categoryInd: c.categoryInd};
});

categoryIndInfo.sort(function(a, b) {
return a.displayInd - b.displayInd;
});

for(catDisplayInd = 0; catDisplayInd < numCats; catDisplayInd++) {
catInd = categoryIndInfo[catDisplayInd].categoryInd;
nextCatModel = dimensionModel.categories[catInd];

if(totalCount > 0) {
Expand All @@ -1747,7 +1783,7 @@ function createDimensionViewModel(parcatsViewModel, dimensionModel) {
}

nextCat = {
key: catInd,
key: nextCatModel.valueInds[0],
model: nextCatModel,
width: dimWidth,
height: nextCatHeight,
Expand Down
2 changes: 1 addition & 1 deletion test/image/mocks/parcats_reordered.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"dimensions": [
{"label": "One", "values": [1, 1, 2, 1, 2, 1, 1, 2, 1], "displayindex": 0},
{"label": "Two", "values": ["A", "B", "A", "B", "C", "C", "A", "B", "C"], "displayindex": 2,
"catDisplayInds": [1, 2, 0], "CatValues": ["A", "B", "C"]},
"categoryarray": ["B", "A", "C"]},
{"label": "Three", "values": [11, 11, 11, 11, 11, 11, 11, 11, 11], "displayindex": 1}]}
],
"layout": {
Expand Down

0 comments on commit 5e60062

Please sign in to comment.