From 4e1d6521a9ab833076e8e50c52e25128c591803a Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Fri, 10 May 2019 12:32:30 -0700 Subject: [PATCH 1/8] ENH: Make barplot widths customizable (close #99) --- q2_taxa/assets/barplot/src/init.js | 2 ++ q2_taxa/assets/barplot/src/render.js | 10 ++++++++-- q2_taxa/assets/barplot/src/toolbar.js | 24 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/q2_taxa/assets/barplot/src/init.js b/q2_taxa/assets/barplot/src/init.js index c0c1f72..6d85d31 100644 --- a/q2_taxa/assets/barplot/src/init.js +++ b/q2_taxa/assets/barplot/src/init.js @@ -4,6 +4,7 @@ import render from './render'; import { availableColorSchemes, addTaxaPicker, + addWidthSlider, addColorPicker, addSortByPicker, addDownloadLinks, @@ -62,4 +63,5 @@ export default function init(level) { addTaxaPicker(ctrlRowOne, levels, level + 1); addColorPicker(ctrlRowOne, svgBar, legendCol, data, dataMeta); addSortByPicker(ctrlRowOne, svgBar, data, dataMeta); + addWidthSlider(ctrlRowOne, svgBar, data, dataMeta); } diff --git a/q2_taxa/assets/barplot/src/render.js b/q2_taxa/assets/barplot/src/render.js index ced3640..b06d494 100644 --- a/q2_taxa/assets/barplot/src/render.js +++ b/q2_taxa/assets/barplot/src/render.js @@ -14,9 +14,15 @@ import { availableColorSchemes } from './toolbar'; export const transitionDur = 500; -export default function render(svg, colorScheme, xOrdering, dataMeta) { +/* barWidth is an optional argument. */ +export default function render(svg, colorScheme, xOrdering, dataMeta, barWidth) { const { sortMap, sortedSampleIDs } = xOrdering; - const width = sortedSampleIDs.length * 10; + // Uses the same default as the #barWidthSlider default value. + let newBarWidth = 10; + if (barWidth !== undefined) { + newBarWidth = barWidth; + } + const width = sortedSampleIDs.length * newBarWidth; const height = 600; const margin = { top: 20, left: 60, right: 0, bottom: 50 }; const { keys } = dataMeta; diff --git a/q2_taxa/assets/barplot/src/toolbar.js b/q2_taxa/assets/barplot/src/toolbar.js index 563107c..d94a0f3 100644 --- a/q2_taxa/assets/barplot/src/toolbar.js +++ b/q2_taxa/assets/barplot/src/toolbar.js @@ -125,6 +125,30 @@ export function addTaxaPicker(row, levels, selectedLevel) { return grp; } +/* Adds a slider to let users control the width of the barplot's bars. + * + * This function was cobbled together from parts of code from + * addColorPicker(), addSortByPicker(), and _updateSort(). + */ +export function addWidthSlider(row, svg, data, dataMeta) { + const grp = row.append('div').attr('class', 'col-lg-2 form-group widthSlider'); + grp.append('label').text('Bar Width'); + grp.append('input') + .attr('type', 'range') + .attr('id', 'barWidthSlider') + .attr('min', '5') + .attr('max', '50') + .attr('value', '10') + .attr('class', 'form-control') + .on('input', () => { + const xOrdering = _getSort(row, svg, data, dataMeta); + // This line derived from https://stackoverflow.com/a/20154105/10730311. + const newVal = select('#barWidthSlider').node().value; + render(svg, svg.property('colorScheme'), xOrdering, dataMeta, newVal); + }); + return grp; +} + export function addColorPicker(row, svg, legendCol, data, dataMeta) { const grp = row.append('div').attr('class', 'col-lg-2 form-group colorPicker'); grp.append('label').text('Color Palette'); From c72393a83923c60a3bd77b5b92a487ce839c6bec Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Fri, 10 May 2019 13:11:17 -0700 Subject: [PATCH 2/8] ENH: Remove default padding on width slider This looks a lot nicer. --- q2_taxa/assets/barplot/src/toolbar.js | 1 + 1 file changed, 1 insertion(+) diff --git a/q2_taxa/assets/barplot/src/toolbar.js b/q2_taxa/assets/barplot/src/toolbar.js index d94a0f3..8f9b74c 100644 --- a/q2_taxa/assets/barplot/src/toolbar.js +++ b/q2_taxa/assets/barplot/src/toolbar.js @@ -140,6 +140,7 @@ export function addWidthSlider(row, svg, data, dataMeta) { .attr('max', '50') .attr('value', '10') .attr('class', 'form-control') + .style('padding', '0px') .on('input', () => { const xOrdering = _getSort(row, svg, data, dataMeta); // This line derived from https://stackoverflow.com/a/20154105/10730311. From a29d383c61356382501d4ee0f1a78ed08610cead Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Fri, 10 May 2019 13:27:36 -0700 Subject: [PATCH 3/8] MAINT: Define the default bar width in one place Will make it easier to adjust this in the future, if desired. --- q2_taxa/assets/barplot/src/render.js | 7 +++++-- q2_taxa/assets/barplot/src/toolbar.js | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/q2_taxa/assets/barplot/src/render.js b/q2_taxa/assets/barplot/src/render.js index b06d494..7f1a2ff 100644 --- a/q2_taxa/assets/barplot/src/render.js +++ b/q2_taxa/assets/barplot/src/render.js @@ -13,12 +13,15 @@ import plotBars from './bar'; import { availableColorSchemes } from './toolbar'; export const transitionDur = 500; +export const defaultBarWidth = 10; -/* barWidth is an optional argument. */ +/* barWidth is an optional argument. + * If it is not provided, the bar width used will default to defaultBarWidth. + */ export default function render(svg, colorScheme, xOrdering, dataMeta, barWidth) { const { sortMap, sortedSampleIDs } = xOrdering; // Uses the same default as the #barWidthSlider default value. - let newBarWidth = 10; + let newBarWidth = defaultBarWidth; if (barWidth !== undefined) { newBarWidth = barWidth; } diff --git a/q2_taxa/assets/barplot/src/toolbar.js b/q2_taxa/assets/barplot/src/toolbar.js index 8f9b74c..ad80871 100644 --- a/q2_taxa/assets/barplot/src/toolbar.js +++ b/q2_taxa/assets/barplot/src/toolbar.js @@ -2,7 +2,9 @@ import { select } from 'd3'; import * as d3chromo from 'd3-scale-chromatic'; import init from './init'; -import render from './render'; +// We have to do the imports this way to accommodate for render() being a +// "default export." See https://stackoverflow.com/a/33611943/10730311. +import render, { defaultBarWidth } from './render'; import { sort } from './data'; import plotLegend from './legend'; @@ -138,7 +140,7 @@ export function addWidthSlider(row, svg, data, dataMeta) { .attr('id', 'barWidthSlider') .attr('min', '5') .attr('max', '50') - .attr('value', '10') + .attr('value', defaultBarWidth) .attr('class', 'form-control') .style('padding', '0px') .on('input', () => { From 67168baf139c01d26365f22267f7edf0486be2e8 Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Fri, 10 May 2019 14:19:37 -0700 Subject: [PATCH 4/8] MAINT: Increase min and max bar sizes The min size increase should at least prevent the labels from getting squished together. --- q2_taxa/assets/barplot/src/toolbar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/q2_taxa/assets/barplot/src/toolbar.js b/q2_taxa/assets/barplot/src/toolbar.js index ad80871..a67bfad 100644 --- a/q2_taxa/assets/barplot/src/toolbar.js +++ b/q2_taxa/assets/barplot/src/toolbar.js @@ -138,8 +138,8 @@ export function addWidthSlider(row, svg, data, dataMeta) { grp.append('input') .attr('type', 'range') .attr('id', 'barWidthSlider') - .attr('min', '5') - .attr('max', '50') + .attr('min', '10') + .attr('max', '60') .attr('value', defaultBarWidth) .attr('class', 'form-control') .style('padding', '0px') From 56eeaa11e2db6cab285ea934b7f732b47b6fadf2 Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Fri, 10 May 2019 14:29:17 -0700 Subject: [PATCH 5/8] BUG: Get width slider value from render() TODOs remaining: -Preserve the bar width on changing taxonomic level -When filtering the bar chart to show a certain taxon/level, ensure that this filtering is respected upon changing the bar width. --- q2_taxa/assets/barplot/src/render.js | 17 ++++++++--------- q2_taxa/assets/barplot/src/toolbar.js | 4 +--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/q2_taxa/assets/barplot/src/render.js b/q2_taxa/assets/barplot/src/render.js index 7f1a2ff..b166f13 100644 --- a/q2_taxa/assets/barplot/src/render.js +++ b/q2_taxa/assets/barplot/src/render.js @@ -6,6 +6,7 @@ import { axisBottom, axisLeft, format, + select, } from 'd3'; import { setupXAxis, setupYAxis } from './axis'; @@ -15,17 +16,15 @@ import { availableColorSchemes } from './toolbar'; export const transitionDur = 500; export const defaultBarWidth = 10; -/* barWidth is an optional argument. - * If it is not provided, the bar width used will default to defaultBarWidth. - */ -export default function render(svg, colorScheme, xOrdering, dataMeta, barWidth) { +export default function render(svg, colorScheme, xOrdering, dataMeta) { const { sortMap, sortedSampleIDs } = xOrdering; - // Uses the same default as the #barWidthSlider default value. - let newBarWidth = defaultBarWidth; - if (barWidth !== undefined) { - newBarWidth = barWidth; + let barWidth = defaultBarWidth; + // This line derived from https://stackoverflow.com/a/20154105/10730311. + const slider = select('#barWidthSlider').node(); + if (slider !== null && slider !== undefined) { + barWidth = slider.value; } - const width = sortedSampleIDs.length * newBarWidth; + const width = sortedSampleIDs.length * barWidth; const height = 600; const margin = { top: 20, left: 60, right: 0, bottom: 50 }; const { keys } = dataMeta; diff --git a/q2_taxa/assets/barplot/src/toolbar.js b/q2_taxa/assets/barplot/src/toolbar.js index a67bfad..0258da9 100644 --- a/q2_taxa/assets/barplot/src/toolbar.js +++ b/q2_taxa/assets/barplot/src/toolbar.js @@ -145,9 +145,7 @@ export function addWidthSlider(row, svg, data, dataMeta) { .style('padding', '0px') .on('input', () => { const xOrdering = _getSort(row, svg, data, dataMeta); - // This line derived from https://stackoverflow.com/a/20154105/10730311. - const newVal = select('#barWidthSlider').node().value; - render(svg, svg.property('colorScheme'), xOrdering, dataMeta, newVal); + render(svg, svg.property('colorScheme'), xOrdering, dataMeta); }); return grp; } From 8e1fa427c9616df95677625452da7db997ce019a Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Thu, 13 Jun 2019 12:16:09 -0700 Subject: [PATCH 6/8] ENH: Increase max bar width value --- q2_taxa/assets/barplot/src/toolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/q2_taxa/assets/barplot/src/toolbar.js b/q2_taxa/assets/barplot/src/toolbar.js index 0258da9..df20143 100644 --- a/q2_taxa/assets/barplot/src/toolbar.js +++ b/q2_taxa/assets/barplot/src/toolbar.js @@ -139,7 +139,7 @@ export function addWidthSlider(row, svg, data, dataMeta) { .attr('type', 'range') .attr('id', 'barWidthSlider') .attr('min', '10') - .attr('max', '60') + .attr('max', '80') .attr('value', defaultBarWidth) .attr('class', 'form-control') .style('padding', '0px') From 30a17d2b9dac62dd67e556d6be8496e2a15ff09f Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Mon, 22 Jul 2019 01:08:18 -0700 Subject: [PATCH 7/8] BUG: Preserve bar width when tax. level changed This is done by passing bar width to init(), which in turn is now done by a "state" object that init() accepts as an argument. It seems like some of the open problems in the bar plot visualization (e.g. #91) could be addressed by storing more information about the visualization's state. (Not sure just passing this around between functions is the *best* way to structure things, though.) --- q2_taxa/assets/barplot/src/init.js | 23 ++++++++++++++------- q2_taxa/assets/barplot/src/main.js | 4 ++-- q2_taxa/assets/barplot/src/render.js | 10 +-------- q2_taxa/assets/barplot/src/toolbar.js | 29 ++++++++++++++++++--------- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/q2_taxa/assets/barplot/src/init.js b/q2_taxa/assets/barplot/src/init.js index 6d85d31..d100a23 100644 --- a/q2_taxa/assets/barplot/src/init.js +++ b/q2_taxa/assets/barplot/src/init.js @@ -13,9 +13,18 @@ import { setupData, sort } from './data'; import plotLegend from './legend'; -export default function init(level) { +/* Re-initializes the display. + * + * "state" is an object that should contain the following entries: + * + * level -- an integer indicating the currently selected index in the + * "Taxonomic Level" dropdown (starts at 0) + * + * barWidth -- an integer indicating the currently selected bar width value + */ +export default function init(state) { /* global d */ - const data = d[level].data; + const data = d[state.level].data; // DOM const body = select('body .container-fluid'); @@ -49,19 +58,19 @@ export default function init(level) { .text('Sample'); const initialColorScheme = availableColorSchemes[0].name; - const dataMeta = setupData(d[level], svgBar); + const dataMeta = setupData(d[state.level], svgBar); const { sortedKeysReverse, levels } = dataMeta; const initialSort = sort(data, [sortedKeysReverse[0]], ['Ascending'], [false], dataMeta); - const chartInfo = render(svgBar, initialColorScheme, initialSort, dataMeta); + const chartInfo = render(svgBar, initialColorScheme, initialSort, dataMeta, state.barWidth); plotLegend(legendCol, chartInfo); // Controls const ctrlRowOne = controls.append('div').attr('class', 'row'); - addDownloadLinks(ctrlRowOne, svgBar, legendCol.select('svg'), level + 1); - addTaxaPicker(ctrlRowOne, levels, level + 1); + addDownloadLinks(ctrlRowOne, svgBar, legendCol.select('svg'), state.level + 1); + addTaxaPicker(ctrlRowOne, levels, state.level + 1); addColorPicker(ctrlRowOne, svgBar, legendCol, data, dataMeta); addSortByPicker(ctrlRowOne, svgBar, data, dataMeta); - addWidthSlider(ctrlRowOne, svgBar, data, dataMeta); + addWidthSlider(ctrlRowOne, svgBar, data, dataMeta, state.barWidth); } diff --git a/q2_taxa/assets/barplot/src/main.js b/q2_taxa/assets/barplot/src/main.js index ae2e33d..f563d90 100644 --- a/q2_taxa/assets/barplot/src/main.js +++ b/q2_taxa/assets/barplot/src/main.js @@ -1,4 +1,4 @@ import init from './init'; +import { getBarWidth } from './toolbar'; - -init(0); +init({ level: 0, barWidth: getBarWidth() }); diff --git a/q2_taxa/assets/barplot/src/render.js b/q2_taxa/assets/barplot/src/render.js index b166f13..5afd19b 100644 --- a/q2_taxa/assets/barplot/src/render.js +++ b/q2_taxa/assets/barplot/src/render.js @@ -6,7 +6,6 @@ import { axisBottom, axisLeft, format, - select, } from 'd3'; import { setupXAxis, setupYAxis } from './axis'; @@ -14,16 +13,9 @@ import plotBars from './bar'; import { availableColorSchemes } from './toolbar'; export const transitionDur = 500; -export const defaultBarWidth = 10; -export default function render(svg, colorScheme, xOrdering, dataMeta) { +export default function render(svg, colorScheme, xOrdering, dataMeta, barWidth) { const { sortMap, sortedSampleIDs } = xOrdering; - let barWidth = defaultBarWidth; - // This line derived from https://stackoverflow.com/a/20154105/10730311. - const slider = select('#barWidthSlider').node(); - if (slider !== null && slider !== undefined) { - barWidth = slider.value; - } const width = sortedSampleIDs.length * barWidth; const height = 600; const margin = { top: 20, left: 60, right: 0, bottom: 50 }; diff --git a/q2_taxa/assets/barplot/src/toolbar.js b/q2_taxa/assets/barplot/src/toolbar.js index df20143..b4c5d2d 100644 --- a/q2_taxa/assets/barplot/src/toolbar.js +++ b/q2_taxa/assets/barplot/src/toolbar.js @@ -2,9 +2,7 @@ import { select } from 'd3'; import * as d3chromo from 'd3-scale-chromatic'; import init from './init'; -// We have to do the imports this way to accommodate for render() being a -// "default export." See https://stackoverflow.com/a/33611943/10730311. -import render, { defaultBarWidth } from './render'; +import render from './render'; import { sort } from './data'; import plotLegend from './legend'; @@ -29,7 +27,19 @@ export const availableColorSchemes = [ { name: 'Spectral', scheme: d3chromo.interpolateSpectral, type: 's' }, ]; +export const defaultBarWidth = 10; + // HELPERS +export function getBarWidth() { + let barWidth = defaultBarWidth; + // This line derived from https://stackoverflow.com/a/20154105/10730311. + const slider = select('#barWidthSlider').node(); + if (slider !== null && slider !== undefined) { + barWidth = slider.value; + } + return barWidth; +} + function _getSort(sel, svg, data, dataMeta) { const sorts = sel.selectAll('.xCtrl').nodes().map(d => d.options[d.selectedIndex].value); const orders = sel.selectAll('.xOrder').nodes().map(d => d.options[d.selectedIndex].value); @@ -39,7 +49,7 @@ function _getSort(sel, svg, data, dataMeta) { function _updateSort(sel, svg, data, dataMeta) { const xOrdering = _getSort(sel, svg, data, dataMeta); - render(svg, svg.property('colorScheme'), xOrdering, dataMeta); + render(svg, svg.property('colorScheme'), xOrdering, dataMeta, getBarWidth()); } function _appendSortByPicker(sel, svg, data, dataMeta) { @@ -113,9 +123,10 @@ export function addTaxaPicker(row, levels, selectedLevel) { grp.append('select') .attr('class', 'form-control') .on('change', function appendTaxaPicker() { + const currBarWidth = getBarWidth(); const container = select('.container-fluid'); container.select('.viz.row').remove(); - init(this.selectedIndex); + init({ level: this.selectedIndex, barWidth: currBarWidth }); }) .selectAll('option') .data(levels) @@ -132,7 +143,7 @@ export function addTaxaPicker(row, levels, selectedLevel) { * This function was cobbled together from parts of code from * addColorPicker(), addSortByPicker(), and _updateSort(). */ -export function addWidthSlider(row, svg, data, dataMeta) { +export function addWidthSlider(row, svg, data, dataMeta, currentValue) { const grp = row.append('div').attr('class', 'col-lg-2 form-group widthSlider'); grp.append('label').text('Bar Width'); grp.append('input') @@ -140,12 +151,12 @@ export function addWidthSlider(row, svg, data, dataMeta) { .attr('id', 'barWidthSlider') .attr('min', '10') .attr('max', '80') - .attr('value', defaultBarWidth) + .attr('value', currentValue) .attr('class', 'form-control') .style('padding', '0px') .on('input', () => { const xOrdering = _getSort(row, svg, data, dataMeta); - render(svg, svg.property('colorScheme'), xOrdering, dataMeta); + render(svg, svg.property('colorScheme'), xOrdering, dataMeta, getBarWidth()); }); return grp; } @@ -166,7 +177,7 @@ export function addColorPicker(row, svg, legendCol, data, dataMeta) { .on('change', function changeColorPicker() { const colorScheme = this.options[this.selectedIndex].value; const xOrdering = _getSort(row, svg, data, dataMeta); - const chartInfo = render(svg, colorScheme, xOrdering, dataMeta); + const chartInfo = render(svg, colorScheme, xOrdering, dataMeta, getBarWidth()); plotLegend(legendCol, chartInfo); }); From ef72b557671e54a418da08301e71584d9acd3c21 Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Mon, 22 Jul 2019 01:52:42 -0700 Subject: [PATCH 8/8] BUG: Make color scheme persist across tax levels Previously, changing the taxonomic level would revert the color scheme back to the default (schemeAccent). Now, it should stick with whatever the user had selected. This is done by using the new "state" option of init(). I imagine we could also use this in the future for outstanding issues like #87. --- q2_taxa/assets/barplot/src/init.js | 8 ++++---- q2_taxa/assets/barplot/src/main.js | 4 ++-- q2_taxa/assets/barplot/src/toolbar.js | 25 +++++++++++++++++++++++-- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/q2_taxa/assets/barplot/src/init.js b/q2_taxa/assets/barplot/src/init.js index d100a23..b9f4ca5 100644 --- a/q2_taxa/assets/barplot/src/init.js +++ b/q2_taxa/assets/barplot/src/init.js @@ -2,7 +2,6 @@ import { select } from 'd3'; import render from './render'; import { - availableColorSchemes, addTaxaPicker, addWidthSlider, addColorPicker, @@ -20,6 +19,8 @@ import plotLegend from './legend'; * level -- an integer indicating the currently selected index in the * "Taxonomic Level" dropdown (starts at 0) * + * colorScheme -- the name of the current color scheme + * * barWidth -- an integer indicating the currently selected bar width value */ export default function init(state) { @@ -57,12 +58,11 @@ export default function init(state) { .style('font', '12px sans-serif') .text('Sample'); - const initialColorScheme = availableColorSchemes[0].name; const dataMeta = setupData(d[state.level], svgBar); const { sortedKeysReverse, levels } = dataMeta; const initialSort = sort(data, [sortedKeysReverse[0]], ['Ascending'], [false], dataMeta); - const chartInfo = render(svgBar, initialColorScheme, initialSort, dataMeta, state.barWidth); + const chartInfo = render(svgBar, state.colorScheme, initialSort, dataMeta, state.barWidth); plotLegend(legendCol, chartInfo); @@ -70,7 +70,7 @@ export default function init(state) { const ctrlRowOne = controls.append('div').attr('class', 'row'); addDownloadLinks(ctrlRowOne, svgBar, legendCol.select('svg'), state.level + 1); addTaxaPicker(ctrlRowOne, levels, state.level + 1); - addColorPicker(ctrlRowOne, svgBar, legendCol, data, dataMeta); + addColorPicker(ctrlRowOne, svgBar, legendCol, data, dataMeta, state.colorScheme); addSortByPicker(ctrlRowOne, svgBar, data, dataMeta); addWidthSlider(ctrlRowOne, svgBar, data, dataMeta, state.barWidth); } diff --git a/q2_taxa/assets/barplot/src/main.js b/q2_taxa/assets/barplot/src/main.js index f563d90..df8ca39 100644 --- a/q2_taxa/assets/barplot/src/main.js +++ b/q2_taxa/assets/barplot/src/main.js @@ -1,4 +1,4 @@ import init from './init'; -import { getBarWidth } from './toolbar'; +import { getBarWidth, getColorScheme } from './toolbar'; -init({ level: 0, barWidth: getBarWidth() }); +init({ level: 0, colorScheme: getColorScheme(), barWidth: getBarWidth() }); diff --git a/q2_taxa/assets/barplot/src/toolbar.js b/q2_taxa/assets/barplot/src/toolbar.js index b4c5d2d..e0f9005 100644 --- a/q2_taxa/assets/barplot/src/toolbar.js +++ b/q2_taxa/assets/barplot/src/toolbar.js @@ -40,6 +40,17 @@ export function getBarWidth() { return barWidth; } +export function getColorScheme() { + // this is just how initialColorScheme was set in init() -- default to the + // first listed color scheme (currently, this is schemeAccent) + let scheme = availableColorSchemes[0].name; + const sel = select('#colorPickerSelect').node(); + if (sel !== null && sel !== undefined) { + scheme = sel.value; + } + return scheme; +} + function _getSort(sel, svg, data, dataMeta) { const sorts = sel.selectAll('.xCtrl').nodes().map(d => d.options[d.selectedIndex].value); const orders = sel.selectAll('.xOrder').nodes().map(d => d.options[d.selectedIndex].value); @@ -124,9 +135,10 @@ export function addTaxaPicker(row, levels, selectedLevel) { .attr('class', 'form-control') .on('change', function appendTaxaPicker() { const currBarWidth = getBarWidth(); + const currColorScheme = getColorScheme(); const container = select('.container-fluid'); container.select('.viz.row').remove(); - init({ level: this.selectedIndex, barWidth: currBarWidth }); + init({ level: this.selectedIndex, colorScheme: currColorScheme, barWidth: currBarWidth }); }) .selectAll('option') .data(levels) @@ -161,7 +173,7 @@ export function addWidthSlider(row, svg, data, dataMeta, currentValue) { return grp; } -export function addColorPicker(row, svg, legendCol, data, dataMeta) { +export function addColorPicker(row, svg, legendCol, data, dataMeta, currentValue) { const grp = row.append('div').attr('class', 'col-lg-2 form-group colorPicker'); grp.append('label').text('Color Palette'); grp.append('a') @@ -174,6 +186,7 @@ export function addColorPicker(row, svg, legendCol, data, dataMeta) { .attr('class', 'glyphicon glyphicon-info-sign'); const sel = grp.append('select') .attr('class', 'form-control') + .attr('id', 'colorPickerSelect') .on('change', function changeColorPicker() { const colorScheme = this.options[this.selectedIndex].value; const xOrdering = _getSort(row, svg, data, dataMeta); @@ -201,6 +214,14 @@ export function addColorPicker(row, svg, legendCol, data, dataMeta) { .attr('value', d => d.name) .text(d => d.name); + // Set the selected color scheme + // (useful if init() is called after the user has been playing with the + // visualization -- for example, when the taxonomic level is adjusted) + // + // Also, note that we have to use .property() instead of .attr() here. See + // https://stackoverflow.com/a/28933863/10730311 for context. + sel.property('value', currentValue); + return grp; }