diff --git a/package.json b/package.json index 926fff87d..f476a1b94 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-chart-editor", "description": "plotly.js chart editor react component UI", - "version": "0.37.2", + "version": "0.38.0", "author": "Plotly, Inc.", "bugs": { "url": "https://github.com/plotly/react-chart-editor/issues" @@ -15,7 +15,7 @@ "fast-isnumeric": "^1.1.2", "immutability-helper": "^3.0.0", "plotly-icons": "1.3.12", - "plotly.js": "1.48.1", + "plotly.js": "1.48.3", "prop-types": "^15.7.2", "raf": "^3.4.1", "react-color": "^2.17.0", diff --git a/src/components/containers/AnnotationAccordion.js b/src/components/containers/AnnotationAccordion.js index 0ce03d26d..87f07cc9b 100644 --- a/src/components/containers/AnnotationAccordion.js +++ b/src/components/containers/AnnotationAccordion.js @@ -22,7 +22,7 @@ class AnnotationAccordion extends Component { {children} diff --git a/src/components/containers/RangeSelectorAccordion.js b/src/components/containers/RangeSelectorAccordion.js index 539910db2..8e2c454ab 100644 --- a/src/components/containers/RangeSelectorAccordion.js +++ b/src/components/containers/RangeSelectorAccordion.js @@ -33,7 +33,7 @@ class RangeSelectorAccordion extends Component { {children} diff --git a/src/components/fields/AxesCreator.js b/src/components/fields/AxesCreator.js index ff1a8553b..d73d883ae 100644 --- a/src/components/fields/AxesCreator.js +++ b/src/components/fields/AxesCreator.js @@ -134,10 +134,9 @@ class UnconnectedAxesCreator extends Component { function getOptions(axisType) { return fullLayout._subplots[axisType].map(axisId => ({ - label: getParsedTemplateString( - getAxisTitle(fullLayout[axisIdToAxisName(axisId)]), - fullLayout.meta - ), + label: getParsedTemplateString(getAxisTitle(fullLayout[axisIdToAxisName(axisId)]), { + meta: fullLayout.meta, + }), value: axisId, })); } diff --git a/src/components/fields/AxesSelector.js b/src/components/fields/AxesSelector.js index 665d47623..b7a4f6c0b 100644 --- a/src/components/fields/AxesSelector.js +++ b/src/components/fields/AxesSelector.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import Dropdown from '../widgets/Dropdown'; import RadioBlocks from '../widgets/RadioBlocks'; import React, {Component} from 'react'; +import {getParsedTemplateString} from 'lib'; class AxesSelector extends Component { constructor(props, context) { @@ -30,7 +31,9 @@ class AxesSelector extends Component { option.value === 'allaxes' ? option : { - label: option.title, + label: getParsedTemplateString(option.title, { + meta: fullLayout.meta, + }), value: option.value, } ) diff --git a/src/components/fields/DataSelector.js b/src/components/fields/DataSelector.js index 59a676d5a..92ac3e6b1 100644 --- a/src/components/fields/DataSelector.js +++ b/src/components/fields/DataSelector.js @@ -5,6 +5,7 @@ import Field from './Field'; import nestedProperty from 'plotly.js/src/lib/nested_property'; import {connectToContainer, maybeAdjustSrc, maybeTransposeData} from 'lib'; import {TRANSFORMS_LIST} from 'lib/constants'; +import {getColumnNames} from 'lib/dereference'; export function attributeIsData(meta = {}) { return meta.valType === 'data_array' || meta.arrayOk; @@ -94,6 +95,14 @@ export class UnconnectedDataSelector extends Component { fromSrc: this.context.srcConverters ? this.context.srcConverters.fromSrc : null, }); + if (this.props.container.type) { + // this means we're at the top level of the trace + update['meta.columnNames.' + this.props.attr] = getColumnNames( + Array.isArray(adjustedValue) ? adjustedValue : [adjustedValue], + this.dataSourceOptions + ); + } + this.props.updateContainer(update); } diff --git a/src/components/fields/__tests__/DataSelector-test.js b/src/components/fields/__tests__/DataSelector-test.js index 1c0c2fc3e..1d83e01a1 100644 --- a/src/components/fields/__tests__/DataSelector-test.js +++ b/src/components/fields/__tests__/DataSelector-test.js @@ -45,7 +45,7 @@ describe('DataSelector', () => { beforeUpdateTraces.mockClear(); wrapper.prop('onChange')('y1'); expect(beforeUpdateTraces.mock.calls[0][0]).toEqual({ - update: {xsrc: 'y1', x: [2, 3, 4]}, + update: {'meta.columnNames.x': 'yCol', xsrc: 'y1', x: [2, 3, 4]}, traceIndexes: [1], }); }); diff --git a/src/lib/connectTraceToPlot.js b/src/lib/connectTraceToPlot.js index c4a72a45b..ac6a26c1f 100644 --- a/src/lib/connectTraceToPlot.js +++ b/src/lib/connectTraceToPlot.js @@ -29,7 +29,7 @@ export default function connectTraceToPlot(WrappedComponent) { setLocals(props, context) { const {traceIndexes} = props; - const {data, fullData, plotly, layout: meta} = context; + const {data, fullData, plotly} = context; const trace = data[traceIndexes[0]]; const fullTrace = getFullTrace(props, context); @@ -71,7 +71,7 @@ export default function connectTraceToPlot(WrappedComponent) { if (trace && fullTrace) { this.icon = renderTraceIcon(plotlyTraceToCustomTrace(trace)); - this.name = getParsedTemplateString(fullTrace.name, meta); + this.name = getParsedTemplateString(fullTrace.name, {meta: fullTrace.meta}); } } diff --git a/src/lib/dereference.js b/src/lib/dereference.js index 4232ac8a3..b9fac6551 100644 --- a/src/lib/dereference.js +++ b/src/lib/dereference.js @@ -3,7 +3,26 @@ import {maybeTransposeData} from './index'; const SRC_ATTR_PATTERN = /src$/; -export default function dereference(container, dataSources, config = {deleteKeys: false}) { +export function getColumnNames(srcArray, dataSourceOptions) { + return srcArray + .map(src => { + const columns = dataSourceOptions.filter(dso => dso.value === src); + if (columns.length === 1) { + return columns[0].columnName || columns[0].label; + } + return ''; + }) + .join(' - '); +} + +export default function dereference( + container, + dataSources, + config = {deleteKeys: false}, + dataSourceOptions = null +) { + const containerIsData = Array.isArray(container); + const replacer = (key, parent, srcPath) => { if (!SRC_ATTR_PATTERN.test(key)) { return; @@ -34,22 +53,31 @@ export default function dereference(container, dataSources, config = {deleteKeys return; } - if (Array.isArray(container)) { - // Case where we were originally given data to dereference - const traceType = parent.type; - parent[dataKey] = maybeTransposeData(dereferencedData, srcPath, traceType); + if (containerIsData) { + if (parent.type !== null) { + // we're at the top level of the trace + if (dataSourceOptions !== null) { + parent.meta = parent.meta || {}; + parent.meta.columnNames = parent.meta.columnNames || {}; + parent.meta.columnNames[dataKey] = getColumnNames(srcRef, dataSourceOptions); + } + parent[dataKey] = maybeTransposeData(dereferencedData, srcPath, parent.type); + } else { + parent[dataKey] = dereferencedData; + } } else { - // This means we're dereferencing layout + // container is layout parent[dataKey] = dereferencedData; } }; - if (Array.isArray(container)) { + if (containerIsData) { walkObject(container, replacer, { walkArraysMatchingKeys: ['data', 'transforms'], pathType: 'nestedProperty', }); } else { + // container is layout walkObject(container, replacer, {pathType: 'nestedProperty'}); } } diff --git a/src/lib/index.js b/src/lib/index.js index 2102ea5e3..afdcb997f 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -203,11 +203,11 @@ function getFullTrace(props, context) { return fullTrace; } -function getParsedTemplateString(originalString, meta) { +function getParsedTemplateString(originalString, context) { let text = originalString; - if (originalString && meta && meta.length) { - text = templateString(originalString, {meta}); + if (originalString && context) { + text = templateString(originalString, context); } return text === '' && originalString ? originalString : text;