diff --git a/web/gui-v2/src/components/DetailViewPatents.jsx b/web/gui-v2/src/components/DetailViewPatents.jsx index da64d248..a8a84409 100644 --- a/web/gui-v2/src/components/DetailViewPatents.jsx +++ b/web/gui-v2/src/components/DetailViewPatents.jsx @@ -159,6 +159,7 @@ const DetailViewPatents = ({ ]} id="ai-subfield-patents" layoutChanges={chartLayoutChanges} + partialStartIndex={endIx} title={ <> Trends in {data.name}'s patenting in diff --git a/web/gui-v2/src/components/DetailViewPublications.jsx b/web/gui-v2/src/components/DetailViewPublications.jsx index ddd3032e..e8ca9e70 100644 --- a/web/gui-v2/src/components/DetailViewPublications.jsx +++ b/web/gui-v2/src/components/DetailViewPublications.jsx @@ -146,6 +146,7 @@ const DetailViewPublications = ({ ]} id="ai-subfield-research" layoutChanges={chartLayoutChanges} + partialStartIndex={endIx} title={ <> Trends in {data.name}'s research in @@ -169,6 +170,7 @@ const DetailViewPublications = ({ ]} id="ai-top-conference-pubs-2" layoutChanges={chartLayoutChanges} + partialStartIndex={endIx} title={<>{data.name}'s top AI conference publications} years={overall.years} /> diff --git a/web/gui-v2/src/components/TrendsChart.jsx b/web/gui-v2/src/components/TrendsChart.jsx index 3d22f517..d8c8aab0 100644 --- a/web/gui-v2/src/components/TrendsChart.jsx +++ b/web/gui-v2/src/components/TrendsChart.jsx @@ -41,9 +41,9 @@ const styles = { * @param {object} props * @param {Array<[string, Array]>} props.data * @param {object} props.layoutChanges - * @param {boolean|undefined} props.partialStartsIndex + * @param {boolean|undefined} props.partialStartIndex + * @param {string} props.title * @param {Array} props.years - * // * @returns {JSX.Element} */ const TrendsChart = ({ @@ -52,13 +52,11 @@ const TrendsChart = ({ data: dataRaw, id: appliedId, layoutChanges, - partialStartsIndex=undefined, + partialStartIndex=undefined, title, years, }) => { - console.info("TrendsChart:", {dataRaw, layoutChanges, years}); // DEBUG - - const { config, data, layout } = assemblePlotlyParams(years, dataRaw, layoutChanges); + const { config, data, layout } = assemblePlotlyParams(years, dataRaw, layoutChanges, { partialStartIndex }); return (
{ - return { +const assembleChartData = (name, years, vals, otherParams, options={}) => { + const { partialStartIndex } = options; + + const common = { hovertemplate: "%{y}", - mode: 'lines+markers', - type: 'scatter', - ...otherParams, + legendgroup: name, + mode: "lines+markers", name, - x: years, - y: vals, - }; + type: "scatter", + } + + // TODO / QUESTION: How do we want to handle the line/shading style for the + // year specified in `year*End`? Think about and adjust if desired. + const endSolidIx = partialStartIndex ? (partialStartIndex + 1) : undefined; + + const result = [ + { + ...common, + ...otherParams, + x: years.slice(0, endSolidIx), + y: vals.slice(0, endSolidIx), + } + ]; + + if ( partialStartIndex !== undefined ) { + result.push({ + ...common, + ...otherParams, + fill: "tozeroy", + line: { dash: "dash" }, + marker: { color: "lightgray" }, + showlegend: false, + x: years.slice(partialStartIndex), + y: vals.slice(partialStartIndex), + }); + } + + return result; }; /** @@ -23,12 +51,19 @@ const assembleChartData = (name, years, vals, otherParams) => { * title and an array of values (which must be the same length as `years`). * @param {object} layoutChanges Any changes that should be merged into the * ETO-standard `layout` object provided by `PlotlyDefaults`. + * @param {object} options + * @param {number} options.partialStartIndex * @returns {object} An object containing the parameters for this Plotly chart: * `{ config, data, layout }` */ -export const assemblePlotlyParams = (years, data, layoutChanges={}) => { - const preparedData = data.map(([traceTitle, traceData, otherParams={}]) => { - return assembleChartData(traceTitle, years, traceData, otherParams); +export const assemblePlotlyParams = ( + years, + data, + layoutChanges={}, + options={}, +) => { + const preparedData = data.flatMap(([traceTitle, traceData, otherParams={}]) => { + return assembleChartData(traceTitle, years, traceData, otherParams, options); }); const maxY = Math.max( ...data.map(e => Math.max(...e[1])) @@ -42,4 +77,3 @@ export const assemblePlotlyParams = (years, data, layoutChanges={}) => { layout, }; }; - diff --git a/web/gui-v2/src/util/plotly-helpers.test.js b/web/gui-v2/src/util/plotly-helpers.test.js new file mode 100644 index 00000000..f892e80d --- /dev/null +++ b/web/gui-v2/src/util/plotly-helpers.test.js @@ -0,0 +1,71 @@ +import { assemblePlotlyParams } from './plotly-helpers'; + + +const TITLE = "AI top conference publications"; +const YEARS = [ 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 ]; +const INPUT_DATA = [ + [ TITLE, [ 850, 928, 845, 843, 838, 1040, 1357, 1551, 1507, 461, 2 ] ], +]; +const LAYOUT_CHANGES = { + legend: { y: 1.15 }, + margin: { b: 50, l: 50, pad: 4, r: 50, t: 0 }, +}; +const PARTIAL_START = YEARS.findIndex(e => e === 2022); + +describe("Plotly helpers", () => { + it("create the parameters as expected", () => { + + const { config, data, layout } = assemblePlotlyParams(YEARS, INPUT_DATA, LAYOUT_CHANGES, { partialStartIndex: PARTIAL_START }); + + expect(config).toEqual({ + displayModeBar: false, + responsive: true, + }); + expect(data).toEqual([ + { + hovertemplate: "%{y}", + legendgroup: TITLE, + mode: "lines+markers", + name: TITLE, + type: "scatter", + x: [ 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 ], + y: [ 850, 928, 845, 843, 838, 1040, 1357, 1551, 1507, 461 ], + }, + { + fill: "tozeroy", + hovertemplate: "%{y}", + legendgroup: TITLE, + line: { dash: "dash" }, + marker: { color: "lightgray" }, + mode: "lines+markers", + name: TITLE, + showlegend: false, + type: "scatter", + x: [ 2022, 2023 ], + y: [ 461, 2 ], + }, + ]); + expect(layout).toEqual({ + autosize: true, + xaxis: { + fixedrange: true, + }, + yaxis: { + fixedrange: true, + }, + font: { + family: "GTZirkonRegular, Arial" + }, + legend: { + orientation: "h", + yanchor: "top", + xanchor: "center", + y: 1.15, + x: 0.5 + }, + margin: { b: 50, l: 50, pad: 4, r: 50, t: 0 }, + paper_bgcolor: "rgba(0,0,0,0)", + plot_bgcolor: "rgba(0,0,0,0)", + }); + }); +});