diff --git a/q2_taxa/assets/barplot/src/init.js b/q2_taxa/assets/barplot/src/init.js index 6d85d31..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, @@ -13,9 +12,20 @@ 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) + * + * colorScheme -- the name of the current color scheme + * + * 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'); @@ -48,20 +58,19 @@ export default function init(level) { .style('font', '12px sans-serif') .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, state.colorScheme, 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); - addColorPicker(ctrlRowOne, svgBar, legendCol, data, dataMeta); + addDownloadLinks(ctrlRowOne, svgBar, legendCol.select('svg'), state.level + 1); + addTaxaPicker(ctrlRowOne, levels, state.level + 1); + addColorPicker(ctrlRowOne, svgBar, legendCol, data, dataMeta, state.colorScheme); 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..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, getColorScheme } from './toolbar'; - -init(0); +init({ level: 0, colorScheme: getColorScheme(), 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..e0f9005 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,30 @@ 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; +} + +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); @@ -39,7 +60,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 +134,11 @@ export function addTaxaPicker(row, levels, selectedLevel) { grp.append('select') .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(this.selectedIndex); + init({ level: this.selectedIndex, colorScheme: currColorScheme, barWidth: currBarWidth }); }) .selectAll('option') .data(levels) @@ -132,7 +155,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,17 +163,17 @@ 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; } -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') @@ -163,10 +186,11 @@ 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); - const chartInfo = render(svg, colorScheme, xOrdering, dataMeta); + const chartInfo = render(svg, colorScheme, xOrdering, dataMeta, getBarWidth()); plotLegend(legendCol, chartInfo); }); @@ -190,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; }