@cdc/chart 4.26.4 → 4.26.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/CONFIG.md +353 -29
  2. package/LICENSE +201 -0
  3. package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
  4. package/dist/cdcchart.js +37885 -35117
  5. package/examples/feature/heatmap/average-age-categorical.json +313 -0
  6. package/examples/feature/heatmap/calendar-heatmap.json +134 -0
  7. package/examples/feature/heatmap/cell-values-bottom-axis.json +181 -0
  8. package/examples/feature/heatmap/sparse-aggregation.json +158 -0
  9. package/examples/private/bad-y-axis.json +543 -0
  10. package/examples/private/bar-chart-negative-value.json +455 -0
  11. package/examples/private/bump-chart.json +1116 -0
  12. package/examples/private/test-123.json +624 -0
  13. package/package.json +4 -3
  14. package/src/CdcChart.tsx +5 -4
  15. package/src/CdcChartComponent.tsx +166 -62
  16. package/src/_stories/Chart.AltText.stories.tsx +136 -0
  17. package/src/_stories/Chart.HeatMap.stories.tsx +187 -0
  18. package/src/_stories/Chart.Sankey.smoke.stories.tsx +62 -0
  19. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +183 -0
  20. package/src/_stories/Chart.SmallMultiples.smoke.stories.tsx +29 -0
  21. package/src/_stories/Chart.YAxisAutoMaxStrategy.stories.tsx +52 -0
  22. package/src/_stories/Chart.YAxisFilterDomain.stories.tsx +90 -0
  23. package/src/_stories/ChartAnnotation.smoke.stories.tsx +10 -0
  24. package/src/_stories/ChartAxisTitles.smoke.stories.tsx +13 -0
  25. package/src/_stories/ChartBar.Editor.stories.tsx +63 -0
  26. package/src/_stories/ChartBrush.Interaction.stories.tsx +112 -0
  27. package/src/_stories/ChartBrush.smoke.stories.tsx +13 -4
  28. package/src/_stories/_mock/alt_text_metadata.json +38 -0
  29. package/src/_stories/_mock/annotation_event-line_mock.json +1064 -0
  30. package/src/_stories/_mock/heatmap-average-age-categorical.json +315 -0
  31. package/src/_stories/_mock/heatmap.json +156 -0
  32. package/src/_stories/_mock/reported_pertussis_cases.json +1643 -0
  33. package/src/_stories/_mock/sankey_mock.json +78 -0
  34. package/src/_stories/_mock/small_multiples/small_multiples_lines.json +1 -1
  35. package/src/components/Annotations/components/AnnotationDraggable.styles.css +22 -1
  36. package/src/components/Annotations/components/AnnotationDraggable.tsx +220 -120
  37. package/src/components/Annotations/components/AnnotationDropdown.tsx +5 -2
  38. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +198 -0
  39. package/src/components/Axis/LeftAxis.tsx +17 -11
  40. package/src/components/Axis/LeftAxisGridlines.tsx +22 -12
  41. package/src/components/Axis/RightAxis.tsx +3 -0
  42. package/src/components/Axis/tests/AxisTickValues.test.tsx +86 -0
  43. package/src/components/Brush/BrushSelector.tsx +88 -187
  44. package/src/components/Brush/brushInteraction.ts +22 -0
  45. package/src/components/Brush/tests/brushInteraction.test.ts +38 -0
  46. package/src/components/EditorPanel/EditorPanel.tsx +677 -185
  47. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +114 -52
  48. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +105 -13
  49. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +1 -0
  50. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +5 -0
  51. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -2
  52. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.test.tsx +98 -0
  53. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +10 -0
  54. package/src/components/EditorPanel/components/Panels/Panel.Visual.test.tsx +484 -0
  55. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -1
  56. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +262 -0
  57. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +32 -0
  58. package/src/components/EditorPanel/components/panels.scss +10 -0
  59. package/src/components/EditorPanel/editor-panel.scss +47 -0
  60. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +61 -0
  61. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +74 -0
  62. package/src/components/EditorPanel/useEditorPermissions.test.tsx +315 -0
  63. package/src/components/EditorPanel/useEditorPermissions.ts +77 -21
  64. package/src/components/HeatMap/components/HeatMap.tsx +767 -0
  65. package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +128 -0
  66. package/src/components/HeatMap/heatmap.constants.ts +13 -0
  67. package/src/components/HeatMap/heatmap.css +85 -0
  68. package/src/components/HeatMap/helpers/index.ts +261 -0
  69. package/src/components/HeatMap/index.tsx +5 -0
  70. package/src/components/HeatMap/tests/HeatMap.test.tsx +1072 -0
  71. package/src/components/HeatMap/tests/helpers.test.ts +167 -0
  72. package/src/components/Legend/Legend.Component.tsx +2 -2
  73. package/src/components/Legend/helpers/createFormatLabels.test.ts +88 -0
  74. package/src/components/Legend/helpers/createFormatLabels.tsx +6 -1
  75. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +19 -22
  76. package/src/components/LineChart/helpers.test.ts +574 -0
  77. package/src/components/LineChart/helpers.ts +39 -16
  78. package/src/components/LineChart/index.tsx +28 -5
  79. package/src/components/LinearChart/tests/LinearChart.test.tsx +137 -33
  80. package/src/components/LinearChart/tests/mockConfigContext.ts +1 -0
  81. package/src/components/LinearChart.tsx +103 -47
  82. package/src/components/PieChart/PieChart.tsx +4 -1
  83. package/src/components/RadarChart/RadarChart.tsx +3 -1
  84. package/src/components/Regions/components/Regions.tsx +195 -41
  85. package/src/components/Sankey/components/Sankey.tsx +7 -3
  86. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +7 -6
  87. package/src/components/ScatterPlot/ScatterPlot.jsx +3 -3
  88. package/src/components/SmallMultiples/SmallMultipleTile.tsx +33 -3
  89. package/src/components/SmallMultiples/SmallMultiples.css +12 -0
  90. package/src/components/SmallMultiples/SmallMultiples.tsx +50 -15
  91. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +152 -0
  92. package/src/components/SmallMultiples/tests/SmallMultiples.test.tsx +170 -0
  93. package/src/components/Sparkline/components/SparkLine.tsx +4 -9
  94. package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +1 -1
  95. package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +2 -2
  96. package/src/data/initial-state.js +12 -0
  97. package/src/helpers/axisLabelFontSize.ts +8 -0
  98. package/src/helpers/bumpChartTooltip.ts +54 -0
  99. package/src/helpers/calculateLeftYAxisWidth.ts +13 -3
  100. package/src/helpers/colorAssignmentHelpers.ts +102 -0
  101. package/src/helpers/dataHelpers.ts +11 -1
  102. package/src/helpers/ensureSpecialChartAxisTypes.ts +11 -0
  103. package/src/helpers/getAxisMaxOverride.ts +16 -0
  104. package/src/helpers/getCleanTopTickMax.ts +64 -0
  105. package/src/helpers/getColorScale.ts +18 -9
  106. package/src/helpers/getHasBoundarySuppression.ts +26 -0
  107. package/src/helpers/getMinMax.ts +26 -25
  108. package/src/helpers/getYAxisDomainData.ts +38 -0
  109. package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
  110. package/src/helpers/handleChartAriaLabels.ts +23 -10
  111. package/src/helpers/hasSpacedInlineLabel.ts +10 -0
  112. package/src/helpers/seriesColumnSettings.ts +5 -4
  113. package/src/helpers/seriesHighlight.ts +26 -0
  114. package/src/helpers/smallMultiplesHelpers.ts +5 -0
  115. package/src/helpers/tests/axisLabelFontSize.test.ts +15 -0
  116. package/src/helpers/tests/bumpChartTooltip.test.ts +75 -0
  117. package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -0
  118. package/src/helpers/tests/dataHelpers.test.ts +135 -0
  119. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +30 -0
  120. package/src/helpers/tests/getAxisMaxOverride.test.ts +36 -0
  121. package/src/helpers/tests/getCleanTopTickMax.test.ts +165 -0
  122. package/src/helpers/tests/getColorScale.test.ts +197 -0
  123. package/src/helpers/tests/getMinMax.test.ts +211 -0
  124. package/src/helpers/tests/getYAxisDomainData.test.ts +119 -0
  125. package/src/helpers/tests/getYAxisFinalizationEligibility.test.ts +185 -0
  126. package/src/helpers/tests/handleChartAriaLabels.test.ts +71 -0
  127. package/src/helpers/tests/hasSpacedInlineLabel.test.ts +75 -0
  128. package/src/helpers/tests/seriesColumnSettings.test.ts +16 -2
  129. package/src/helpers/tests/seriesHighlight.test.ts +61 -0
  130. package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
  131. package/src/hooks/tests/useRightAxis.test.tsx +127 -0
  132. package/src/hooks/tests/useScales.test.tsx +383 -0
  133. package/src/hooks/useRightAxis.ts +30 -13
  134. package/src/hooks/useScales.ts +48 -21
  135. package/src/hooks/useTooltip.tsx +3 -1
  136. package/src/index.jsx +5 -2
  137. package/src/scss/main.scss +32 -49
  138. package/src/test/CdcChart.dataTable.test.tsx +122 -0
  139. package/src/types/ChartConfig.ts +24 -1
  140. package/src/types/ChartContext.ts +5 -0
  141. package/src/helpers/getYAxisAutoPadding.ts +0 -53
@@ -61,6 +61,11 @@ import { paletteMigrationMap, twoColorPaletteMigrationMap } from '@cdc/core/help
61
61
  import { isV1Palette, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
62
62
  import { USE_V2_MIGRATION } from '@cdc/core/helpers/constants'
63
63
  import { getSeriesOwnedColumnNames } from '../../helpers/seriesColumnSettings'
64
+ import {
65
+ HEATMAP_CONFIG_DEFAULTS,
66
+ MAX_HEATMAP_COLOR_BUCKETS,
67
+ MIN_HEATMAP_COLOR_BUCKETS
68
+ } from '../HeatMap/heatmap.constants'
64
69
 
65
70
  interface PreliminaryProps {
66
71
  config: ChartConfig
@@ -137,7 +142,8 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
137
142
  hideBarSymbol: false,
138
143
  hideLineStyle: false,
139
144
  circleSize: 6,
140
- displayGray: true
145
+ displayGray: true,
146
+ weight: undefined
141
147
  }
142
148
  preliminaryData.push(defaultValues)
143
149
  updateConfig({ ...config, preliminaryData })
@@ -192,7 +198,8 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
192
198
  type,
193
199
  value,
194
200
  hideBarSymbol,
195
- hideLineStyle
201
+ hideLineStyle,
202
+ weight
196
203
  },
197
204
  i
198
205
  ) => (
@@ -291,6 +298,16 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
291
298
  updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
292
299
  options={getStyleOptions(type)}
293
300
  />
301
+ <TextField
302
+ type='number'
303
+ min={1}
304
+ max={9}
305
+ value={weight}
306
+ fieldName='weight'
307
+ label='Line Weight'
308
+ placeholder='Default'
309
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
310
+ />
294
311
  <CheckBox
295
312
  value={hideLineStyle}
296
313
  fieldName='hideLineStyle'
@@ -491,6 +508,18 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
491
508
  updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
492
509
  />
493
510
  )}
511
+ {style && !style.includes('Circles') && (
512
+ <TextField
513
+ type='number'
514
+ min={1}
515
+ max={9}
516
+ value={weight}
517
+ fieldName='weight'
518
+ label='Line Weight'
519
+ placeholder='Default'
520
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
521
+ />
522
+ )}
494
523
  {style !== 'Filled Circles' && (
495
524
  <TextField
496
525
  value={label}
@@ -862,6 +891,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
862
891
  visSupportsDateCategoryNumTicks,
863
892
  visSupportsDateCategoryTickRotation,
864
893
  visSupportsDynamicSeries,
894
+ visSupportsAutoMaxStrategy,
895
+ visSupportsFilterDomainBehavior,
865
896
  visSupportsFilters,
866
897
  visSupportsLeftValueAxis,
867
898
  visSupportsPreliminaryData,
@@ -1189,12 +1220,23 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1189
1220
  return filter ? filteredColumns : allColumns
1190
1221
  }
1191
1222
 
1223
+ const isHeatMap = config.visualizationType === 'HeatMap'
1224
+ const heatMapOwnedColumnNames = useMemo(
1225
+ () => [config.xAxis?.dataKey, ...(config.series || []).map(series => series.dataKey)].filter(Boolean),
1226
+ [config.xAxis?.dataKey, config.series]
1227
+ )
1228
+
1192
1229
  const getLegendStyleOptions = (option: 'style' | 'subStyle' | 'shapes' | 'groupBy'): string[] => {
1193
1230
  const options: string[] = []
1194
1231
 
1195
1232
  switch (option) {
1196
1233
  case 'style':
1197
1234
  options.push('circles', 'boxes')
1235
+ if (config.visualizationType === 'HeatMap') {
1236
+ if (!['right', 'left'].includes(config.legend.position) && config.legend.position) {
1237
+ options.push('gradient')
1238
+ }
1239
+ }
1198
1240
  if (
1199
1241
  config.visualizationType === 'Bar' &&
1200
1242
  (!['right', 'left'].includes(config.legend.position) || !config.legend.position)
@@ -1209,7 +1251,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1209
1251
  }
1210
1252
  break
1211
1253
  case 'subStyle':
1212
- if (config.visualizationType === 'Bar') {
1254
+ if (config.visualizationType === 'Bar' || config.visualizationType === 'HeatMap') {
1213
1255
  options.push('linear blocks')
1214
1256
  } else {
1215
1257
  options.push('linear blocks', 'smooth')
@@ -1242,6 +1284,11 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1242
1284
  return unique ? [...new Set(values)] : values
1243
1285
  }
1244
1286
 
1287
+ const getAvailableExclusionValues = dataKey => {
1288
+ const excludedKeys = (config.exclusions.keys || []).map(String)
1289
+ return getDataValues(dataKey, true).filter(value => !excludedKeys.includes(String(value)))
1290
+ }
1291
+
1245
1292
  // prettier-ignore
1246
1293
  const {
1247
1294
  highlightedBarValues,
@@ -1338,6 +1385,15 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1338
1385
  if (config.isLollipopChart && config?.series?.length === 0) {
1339
1386
  config.runtime.editorErrorMessage = 'Add a data series'
1340
1387
  }
1388
+ if (config.visualizationType === 'HeatMap') {
1389
+ const missingMappings = [
1390
+ !config.xAxis?.dataKey && 'Date/Category Axis',
1391
+ (!config.series || config.series.length === 0) && 'Data Series'
1392
+ ].filter(Boolean)
1393
+
1394
+ config.runtime.editorErrorMessage =
1395
+ missingMappings.length > 0 ? `${missingMappings.join(', ')} must be set for heatmaps.` : ''
1396
+ }
1341
1397
 
1342
1398
  const section = config.orientation === 'horizontal' ? 'xAxis' : 'yAxis'
1343
1399
  const [warningMsg, setWarningMsg] = useState({ maxMsg: '', minMsg: '', rightMaxMessage: '', minMsgRight: '' })
@@ -1737,6 +1793,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1737
1793
  'Bump Chart',
1738
1794
  'Area Chart',
1739
1795
  'Combo',
1796
+ 'HeatMap',
1740
1797
  'Line',
1741
1798
  'Bar',
1742
1799
  'Forecasting',
@@ -1920,6 +1977,76 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1920
1977
  return strippedState
1921
1978
  }
1922
1979
 
1980
+ const renderHeatMapSettingsAccordion = () => {
1981
+ if (config.visualizationType !== 'HeatMap') return null
1982
+
1983
+ return (
1984
+ <AccordionItem>
1985
+ <AccordionItemHeading>
1986
+ <AccordionItemButton>HeatMap Settings</AccordionItemButton>
1987
+ </AccordionItemHeading>
1988
+ <AccordionItemPanel>
1989
+ <p className='helper-text'>Selected data series columns provide the heatmap cell values.</p>
1990
+ <CheckBox
1991
+ value={Boolean(config.heatmap?.showCellValues ?? HEATMAP_CONFIG_DEFAULTS.showCellValues)}
1992
+ section='heatmap'
1993
+ fieldName='showCellValues'
1994
+ label='Show Cell Values'
1995
+ updateField={updateFieldDeprecated}
1996
+ />
1997
+ <TextField
1998
+ value={config.heatmap?.cellPadding ?? HEATMAP_CONFIG_DEFAULTS.cellPadding}
1999
+ type='number'
2000
+ min={0}
2001
+ section='heatmap'
2002
+ fieldName='cellPadding'
2003
+ label='Cell Padding'
2004
+ updateField={updateFieldDeprecated}
2005
+ />
2006
+ <TextField
2007
+ value={config.heatmap?.rowLabelGap ?? HEATMAP_CONFIG_DEFAULTS.rowLabelGap}
2008
+ type='number'
2009
+ min={0}
2010
+ section='heatmap'
2011
+ fieldName='rowLabelGap'
2012
+ label='Row Label Gap'
2013
+ updateField={updateFieldDeprecated}
2014
+ />
2015
+ <TextField
2016
+ value={config.heatmap?.columnLabelGap ?? HEATMAP_CONFIG_DEFAULTS.columnLabelGap}
2017
+ type='number'
2018
+ min={0}
2019
+ section='heatmap'
2020
+ fieldName='columnLabelGap'
2021
+ label='Column Label Gap'
2022
+ updateField={updateFieldDeprecated}
2023
+ />
2024
+ <TextField
2025
+ value={config.heatmap?.colorBucketCount ?? HEATMAP_CONFIG_DEFAULTS.colorBucketCount}
2026
+ type='number'
2027
+ min={MIN_HEATMAP_COLOR_BUCKETS}
2028
+ max={MAX_HEATMAP_COLOR_BUCKETS}
2029
+ step={1}
2030
+ section='heatmap'
2031
+ fieldName='colorBucketCount'
2032
+ label='Data Grouping'
2033
+ updateField={updateFieldDeprecated}
2034
+ tooltip={
2035
+ <Tooltip style={{ textTransform: 'none' }}>
2036
+ <Tooltip.Target>
2037
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2038
+ </Tooltip.Target>
2039
+ <Tooltip.Content>
2040
+ Choose the number of value groups used to color the heatmap. Values are limited to 1-9.
2041
+ </Tooltip.Content>
2042
+ </Tooltip>
2043
+ }
2044
+ />
2045
+ </AccordionItemPanel>
2046
+ </AccordionItem>
2047
+ )
2048
+ }
2049
+
1923
2050
  return (
1924
2051
  <EditorPanelContext.Provider value={editorContextValues}>
1925
2052
  <BaseEditorPanel
@@ -1950,7 +2077,10 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1950
2077
  {(!config.series ||
1951
2078
  config.series.length === 0 ||
1952
2079
  (config.visualizationType === 'Paired Bar' && config.series.length < 2)) &&
1953
- !config.dynamicSeries && <WarningImage width='25' className='warning-icon' />}
2080
+ !config.dynamicSeries &&
2081
+ config.visualizationType !== 'HeatMap' && (
2082
+ <WarningImage width='25' className='warning-icon' />
2083
+ )}
1954
2084
  </AccordionItemButton>
1955
2085
  </AccordionItemHeading>
1956
2086
  <AccordionItemPanel>
@@ -1987,9 +2117,21 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1987
2117
  )}
1988
2118
  {(!visSupportsDynamicSeries() || !config.dynamicSeries) && (
1989
2119
  <>
2120
+ {config.visualizationType === 'HeatMap' && (
2121
+ <p className='helper-text'>
2122
+ Add one or more data series to create heatmap rows. Each selected series becomes a row
2123
+ in the heatmap, while the Date/Category Axis provides the columns.
2124
+ </p>
2125
+ )}
1990
2126
  {(!config.series || config.series.length === 0) &&
1991
2127
  !config.dynamicSeries &&
1992
- config.visualizationType !== 'Paired Bar' && (
2128
+ config.visualizationType !== 'Paired Bar' &&
2129
+ config.visualizationType !== 'HeatMap' && (
2130
+ <p className='warning'>At least one series is required</p>
2131
+ )}
2132
+ {(!config.series || config.series.length === 0) &&
2133
+ !config.dynamicSeries &&
2134
+ config.visualizationType === 'HeatMap' && (
1993
2135
  <p className='warning'>At least one series is required</p>
1994
2136
  )}
1995
2137
  {(!config.series || config.series.length === 0 || config.series.length < 2) &&
@@ -2010,7 +2152,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2010
2152
  }
2011
2153
  e.target.value = ''
2012
2154
  }}
2013
- options={getColumns()}
2155
+ options={getColumns().filter(column => column !== config.xAxis?.dataKey)}
2014
2156
  />
2015
2157
  {config.series && config.series.length !== 0 && (
2016
2158
  <Panels.Series.Wrapper
@@ -2022,16 +2164,23 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2022
2164
  droppableId='chart-series-order'
2023
2165
  label={
2024
2166
  <>
2025
- Displaying
2167
+ {config.visualizationType === 'HeatMap' ? 'Displaying Rows' : 'Displaying'}
2026
2168
  <Tooltip style={{ textTransform: 'none' }}>
2027
2169
  <Tooltip.Target>
2028
2170
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2029
2171
  </Tooltip.Target>
2030
2172
  <Tooltip.Content>
2031
- <p>
2032
- A data series is a set of related data points plotted in a chart and
2033
- typically represented in the chart legend.
2034
- </p>
2173
+ {config.visualizationType === 'HeatMap' ? (
2174
+ <p>
2175
+ Each selected data series becomes a row in the heatmap. Reorder these
2176
+ entries to change the row order shown in the visualization.
2177
+ </p>
2178
+ ) : (
2179
+ <p>
2180
+ A data series is a set of related data points plotted in a chart and
2181
+ typically represented in the chart legend.
2182
+ </p>
2183
+ )}
2035
2184
  </Tooltip.Content>
2036
2185
  </Tooltip>
2037
2186
  </>
@@ -2108,9 +2257,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2108
2257
  : config.orientation === 'vertical'
2109
2258
  ? 'Left Value Axis'
2110
2259
  : 'Value Axis'}
2111
- {config.visualizationType === 'Pie' && !config.yAxis.dataKey && (
2260
+ {config.visualizationType === 'Pie' && !config.yAxis.dataKey ? (
2112
2261
  <WarningImage width='25' className='warning-icon' />
2113
- )}
2262
+ ) : null}
2114
2263
  </AccordionItemButton>
2115
2264
  </AccordionItemHeading>
2116
2265
  <AccordionItemPanel>
@@ -2158,7 +2307,86 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2158
2307
  />
2159
2308
  </>
2160
2309
  )}
2161
- {config.visualizationType !== 'Pie' && (
2310
+ {config.visualizationType === 'HeatMap' && (
2311
+ <>
2312
+ <TextField
2313
+ value={config.yAxis.label}
2314
+ section='yAxis'
2315
+ fieldName='label'
2316
+ label='Label'
2317
+ updateField={updateFieldDeprecated}
2318
+ maxLength={35}
2319
+ tooltip={
2320
+ <Tooltip style={{ textTransform: 'none' }}>
2321
+ <Tooltip.Target>
2322
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2323
+ </Tooltip.Target>
2324
+ <Tooltip.Content>
2325
+ <p>35 character limit</p>
2326
+ </Tooltip.Content>
2327
+ </Tooltip>
2328
+ }
2329
+ />
2330
+ <Select
2331
+ value={config.yAxis.titlePlacement || 'side'}
2332
+ section='yAxis'
2333
+ fieldName='titlePlacement'
2334
+ label='Label Placement'
2335
+ updateField={updateFieldDeprecated}
2336
+ options={[
2337
+ { value: 'side', label: 'Side' },
2338
+ { value: 'top', label: 'Top' }
2339
+ ]}
2340
+ />
2341
+ <TextField
2342
+ value={config.yAxis.size}
2343
+ type='number'
2344
+ section='yAxis'
2345
+ fieldName='size'
2346
+ label='Size (Width)'
2347
+ className='number-narrow'
2348
+ updateField={updateFieldDeprecated}
2349
+ tooltip={
2350
+ <Tooltip style={{ textTransform: 'none' }}>
2351
+ <Tooltip.Target>
2352
+ <Icon
2353
+ display='question'
2354
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2355
+ />
2356
+ </Tooltip.Target>
2357
+ <Tooltip.Content>
2358
+ <p>Increase the size if month labels are crowded or overlap the chart area.</p>
2359
+ </Tooltip.Content>
2360
+ </Tooltip>
2361
+ }
2362
+ />
2363
+ <CheckBox
2364
+ value={config.yAxis.hideAxis}
2365
+ section='yAxis'
2366
+ fieldName='hideAxis'
2367
+ label='Hide Axis'
2368
+ updateField={updateFieldDeprecated}
2369
+ />
2370
+ <CheckBox
2371
+ value={config.yAxis.hideTicks}
2372
+ section='yAxis'
2373
+ fieldName='hideTicks'
2374
+ label='Hide Ticks'
2375
+ updateField={updateFieldDeprecated}
2376
+ />
2377
+ <TextField
2378
+ value={config.yAxis.tickRotation || 0}
2379
+ type='number'
2380
+ min={0}
2381
+ section='yAxis'
2382
+ fieldName='tickRotation'
2383
+ label='Tick rotation (Degrees)'
2384
+ className='number-narrow'
2385
+ updateField={updateFieldDeprecated}
2386
+ />
2387
+ </>
2388
+ )}
2389
+ {config.visualizationType !== 'Pie' && config.visualizationType !== 'HeatMap' && (
2162
2390
  <>
2163
2391
  <Select
2164
2392
  label='Axis Type'
@@ -2209,18 +2437,30 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2209
2437
  fieldName='label'
2210
2438
  label='Label'
2211
2439
  updateField={updateFieldDeprecated}
2212
- maxLength={35}
2440
+ maxLength={config.yAxis.titlePlacement === 'side' ? 35 : undefined}
2213
2441
  tooltip={
2214
2442
  <Tooltip style={{ textTransform: 'none' }}>
2215
2443
  <Tooltip.Target>
2216
2444
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2217
2445
  </Tooltip.Target>
2218
2446
  <Tooltip.Content>
2219
- <p>35 character limit</p>
2447
+ <p>35 character limit when Label Placement is Side</p>
2220
2448
  </Tooltip.Content>
2221
2449
  </Tooltip>
2222
2450
  }
2223
2451
  />
2452
+ <Select
2453
+ display={!visHasCategoricalAxis()}
2454
+ value={config.yAxis.titlePlacement}
2455
+ section='yAxis'
2456
+ fieldName='titlePlacement'
2457
+ label='Label Placement'
2458
+ updateField={updateField}
2459
+ options={[
2460
+ { value: 'side', label: 'Side' },
2461
+ { value: 'top', label: 'Top' }
2462
+ ]}
2463
+ />
2224
2464
  <TextField
2225
2465
  display={!visHasCategoricalAxis()}
2226
2466
  value={config.yAxis.inlineLabel}
@@ -2349,26 +2589,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2349
2589
  title={!config.yAxis.gridLines ? 'Show gridlines to enable' : ''}
2350
2590
  />
2351
2591
  )}
2352
- {visSupportsYPadding() && (
2353
- <CheckBox
2354
- value={config.yAxis.enablePadding}
2355
- section='yAxis'
2356
- fieldName='enablePadding'
2357
- label='Add Padding to Value Axis Scale'
2358
- updateField={updateFieldDeprecated}
2359
- />
2360
- )}
2361
- {config.yAxis.enablePadding && visSupportsYPadding() && (
2362
- <TextField
2363
- type='number'
2364
- section='yAxis'
2365
- fieldName='scalePadding'
2366
- label='Padding Percentage'
2367
- className='number-narrow'
2368
- updateField={updateFieldDeprecated}
2369
- value={config.yAxis.scalePadding}
2370
- />
2371
- )}
2372
2592
  </>
2373
2593
  )}
2374
2594
  <span className='divider-heading'>Number Formatting</span>
@@ -2550,32 +2770,41 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2550
2770
  updateField={updateFieldDeprecated}
2551
2771
  />
2552
2772
  )}
2553
- {visSupportsValueAxisMax() && (
2554
- <TextField
2555
- value={config.xAxis.max}
2556
- section='xAxis'
2557
- fieldName='max'
2558
- label='max value'
2559
- type='number'
2560
- placeholder='Auto'
2561
- updateField={updateFieldDeprecated}
2562
- />
2563
- )}
2564
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
2565
- {visSupportsValueAxisMin() && (
2566
- <TextField
2567
- value={config.xAxis.min}
2568
- section='xAxis'
2569
- fieldName='min'
2570
- type='number'
2571
- label='min value'
2572
- placeholder='Auto'
2573
- updateField={updateFieldDeprecated}
2574
- />
2575
- )}
2576
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
2577
- {config.visualizationType === 'Deviation Bar' && (
2578
- <>
2773
+ <div className='axis-domain-group'>
2774
+ <span className='axis-domain-group__title'>Value Axis Domain</span>
2775
+ <div className='axis-domain-group__row'>
2776
+ {visSupportsValueAxisMax() && (
2777
+ <div className='axis-domain-group__field'>
2778
+ <TextField
2779
+ value={config.xAxis.max}
2780
+ section='xAxis'
2781
+ fieldName='max'
2782
+ label='axis max value'
2783
+ type='number'
2784
+ placeholder='Auto'
2785
+ className='axis-domain-number'
2786
+ updateField={updateFieldDeprecated}
2787
+ />
2788
+ <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
2789
+ </div>
2790
+ )}
2791
+ {visSupportsValueAxisMin() && (
2792
+ <div className='axis-domain-group__field'>
2793
+ <TextField
2794
+ value={config.xAxis.min}
2795
+ section='xAxis'
2796
+ fieldName='min'
2797
+ type='number'
2798
+ label='axis min value'
2799
+ placeholder='Auto'
2800
+ className='axis-domain-number'
2801
+ updateField={updateFieldDeprecated}
2802
+ />
2803
+ <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
2804
+ </div>
2805
+ )}
2806
+ </div>
2807
+ {config.visualizationType === 'Deviation Bar' && (
2579
2808
  <TextField
2580
2809
  value={config.xAxis.target}
2581
2810
  section='xAxis'
@@ -2583,8 +2812,104 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2583
2812
  type='number'
2584
2813
  label='Deviation point'
2585
2814
  placeholder='Auto'
2815
+ className='axis-domain-number'
2586
2816
  updateField={updateFieldDeprecated}
2587
2817
  />
2818
+ )}
2819
+ <TextField
2820
+ value={config.yAxis.smallestLeftAxisMax}
2821
+ section='yAxis'
2822
+ fieldName='smallestLeftAxisMax'
2823
+ type='number'
2824
+ label='Smallest axis maximum'
2825
+ placeholder='Auto'
2826
+ className='axis-domain-number'
2827
+ tooltip={
2828
+ <Tooltip style={{ textTransform: 'none' }}>
2829
+ <Tooltip.Target>
2830
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2831
+ </Tooltip.Target>
2832
+ <Tooltip.Content>
2833
+ <p>
2834
+ Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
2835
+ 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
2836
+ </p>
2837
+ </Tooltip.Content>
2838
+ </Tooltip>
2839
+ }
2840
+ updateField={updateFieldDeprecated}
2841
+ />
2842
+ {visSupportsAutoMaxStrategy() && (
2843
+ <Select
2844
+ value={config.yAxis.autoMaxStrategy || 'default'}
2845
+ section='yAxis'
2846
+ fieldName='autoMaxStrategy'
2847
+ label='Automatic max strategy'
2848
+ updateField={updateFieldDeprecated}
2849
+ options={[
2850
+ { value: 'default', label: 'Default' },
2851
+ { value: 'clean-top-tick', label: 'Clean top tick' }
2852
+ ]}
2853
+ tooltip={
2854
+ <Tooltip style={{ textTransform: 'none' }}>
2855
+ <Tooltip.Target>
2856
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2857
+ </Tooltip.Target>
2858
+ <Tooltip.Content>
2859
+ {config.visualizationType === 'Combo' ? (
2860
+ <p>
2861
+ Clean top tick rounds automatic left and right axis maximums up to cleaner
2862
+ tick steps before axis padding is applied.
2863
+ </p>
2864
+ ) : (
2865
+ <p>
2866
+ Clean top tick rounds the automatic value axis maximum up to a cleaner tick
2867
+ step before axis padding is applied.
2868
+ </p>
2869
+ )}
2870
+ </Tooltip.Content>
2871
+ </Tooltip>
2872
+ }
2873
+ />
2874
+ )}
2875
+ {visSupportsFilterDomainBehavior() && (
2876
+ <Select
2877
+ value={config.yAxis.filterDomainBehavior || 'dynamic'}
2878
+ section='yAxis'
2879
+ fieldName='filterDomainBehavior'
2880
+ label='Filter Domain Behavior'
2881
+ updateField={updateFieldDeprecated}
2882
+ options={[
2883
+ { value: 'dynamic', label: 'Dynamic' },
2884
+ { value: 'stable', label: 'Stable' }
2885
+ ]}
2886
+ tooltip={
2887
+ <Tooltip style={{ textTransform: 'none' }}>
2888
+ <Tooltip.Target>
2889
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2890
+ </Tooltip.Target>
2891
+ <Tooltip.Content>
2892
+ {config.visualizationType === 'Combo' ? (
2893
+ <p>
2894
+ Dynamic rescales the value axes to the currently filtered data. Stable keeps
2895
+ the left and right axes based on the full eligible dataset while still
2896
+ rendering filtered rows.
2897
+ </p>
2898
+ ) : (
2899
+ <p>
2900
+ Dynamic rescales the value axis to the currently filtered data. Stable keeps
2901
+ the value axis based on the full eligible dataset while still rendering
2902
+ filtered rows.
2903
+ </p>
2904
+ )}
2905
+ </Tooltip.Content>
2906
+ </Tooltip>
2907
+ }
2908
+ />
2909
+ )}
2910
+ </div>
2911
+ {config.visualizationType === 'Deviation Bar' && (
2912
+ <>
2588
2913
  <TextField
2589
2914
  value={config.xAxis.targetLabel || 'Target'}
2590
2915
  section='xAxis'
@@ -2604,7 +2929,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2604
2929
  )}
2605
2930
  </>
2606
2931
  ) : (
2607
- config.visualizationType !== 'Pie' && (
2932
+ config.visualizationType !== 'Pie' &&
2933
+ config.visualizationType !== 'HeatMap' && (
2608
2934
  <>
2609
2935
  <CheckBox
2610
2936
  display={!visHasCategoricalAxis()}
@@ -2631,52 +2957,151 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2631
2957
  updateField={updateFieldDeprecated}
2632
2958
  />
2633
2959
 
2634
- <TextField
2635
- value={config.yAxis.max}
2636
- section='yAxis'
2637
- fieldName='max'
2638
- type='number'
2639
- label='left axis max value'
2640
- placeholder='Auto'
2641
- updateField={updateFieldDeprecated}
2642
- />
2643
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
2644
- {config.visualizationType !== 'Area Chart' && config.visualizationSubType !== 'stacked' && (
2645
- <>
2646
- <TextField
2647
- value={config.yAxis.min}
2960
+ <div className='axis-domain-group'>
2961
+ <span className='axis-domain-group__title'>Value Axis Domain</span>
2962
+ <div className='axis-domain-group__row'>
2963
+ <div className='axis-domain-group__field'>
2964
+ <TextField
2965
+ value={config.yAxis.max}
2966
+ section='yAxis'
2967
+ fieldName='max'
2968
+ type='number'
2969
+ label='axis max value'
2970
+ placeholder='Auto'
2971
+ className='axis-domain-number'
2972
+ updateField={updateFieldDeprecated}
2973
+ />
2974
+ <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
2975
+ </div>
2976
+ {config.visualizationType !== 'Area Chart' &&
2977
+ config.visualizationSubType !== 'stacked' && (
2978
+ <div className='axis-domain-group__field'>
2979
+ <TextField
2980
+ value={config.yAxis.min}
2981
+ section='yAxis'
2982
+ fieldName='min'
2983
+ type='number'
2984
+ label='axis min value'
2985
+ placeholder='Auto'
2986
+ className='axis-domain-number'
2987
+ updateField={updateFieldDeprecated}
2988
+ />
2989
+ <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
2990
+ </div>
2991
+ )}
2992
+ </div>
2993
+ <TextField
2994
+ value={config.yAxis.smallestLeftAxisMax}
2995
+ section='yAxis'
2996
+ fieldName='smallestLeftAxisMax'
2997
+ type='number'
2998
+ label='Smallest axis maximum'
2999
+ placeholder='Auto'
3000
+ className='axis-domain-number'
3001
+ tooltip={
3002
+ <Tooltip style={{ textTransform: 'none' }}>
3003
+ <Tooltip.Target>
3004
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3005
+ </Tooltip.Target>
3006
+ <Tooltip.Content>
3007
+ <p>
3008
+ Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
3009
+ 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
3010
+ </p>
3011
+ </Tooltip.Content>
3012
+ </Tooltip>
3013
+ }
3014
+ updateField={updateFieldDeprecated}
3015
+ />
3016
+ {visSupportsAutoMaxStrategy() && (
3017
+ <Select
3018
+ value={config.yAxis.autoMaxStrategy || 'default'}
3019
+ section='yAxis'
3020
+ fieldName='autoMaxStrategy'
3021
+ label='Automatic max strategy'
3022
+ updateField={updateFieldDeprecated}
3023
+ options={[
3024
+ { value: 'default', label: 'Default' },
3025
+ { value: 'clean-top-tick', label: 'Clean top tick' }
3026
+ ]}
3027
+ tooltip={
3028
+ <Tooltip style={{ textTransform: 'none' }}>
3029
+ <Tooltip.Target>
3030
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3031
+ </Tooltip.Target>
3032
+ <Tooltip.Content>
3033
+ {config.visualizationType === 'Combo' ? (
3034
+ <p>
3035
+ Clean top tick rounds automatic left and right axis maximums up to cleaner
3036
+ tick steps before axis padding is applied.
3037
+ </p>
3038
+ ) : (
3039
+ <p>
3040
+ Clean top tick rounds the automatic value axis maximum up to a cleaner tick
3041
+ step before axis padding is applied.
3042
+ </p>
3043
+ )}
3044
+ </Tooltip.Content>
3045
+ </Tooltip>
3046
+ }
3047
+ />
3048
+ )}
3049
+ {visSupportsFilterDomainBehavior() && (
3050
+ <Select
3051
+ value={config.yAxis.filterDomainBehavior || 'dynamic'}
3052
+ section='yAxis'
3053
+ fieldName='filterDomainBehavior'
3054
+ label='Filter Domain Behavior'
3055
+ updateField={updateFieldDeprecated}
3056
+ options={[
3057
+ { value: 'dynamic', label: 'Dynamic' },
3058
+ { value: 'stable', label: 'Stable' }
3059
+ ]}
3060
+ tooltip={
3061
+ <Tooltip style={{ textTransform: 'none' }}>
3062
+ <Tooltip.Target>
3063
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3064
+ </Tooltip.Target>
3065
+ <Tooltip.Content>
3066
+ {config.visualizationType === 'Combo' ? (
3067
+ <p>
3068
+ Dynamic rescales the value axes to the currently filtered data. Stable keeps
3069
+ the left and right axes based on the full eligible dataset while still
3070
+ rendering filtered rows.
3071
+ </p>
3072
+ ) : (
3073
+ <p>
3074
+ Dynamic rescales the value axis to the currently filtered data. Stable keeps
3075
+ the value axis based on the full eligible dataset while still rendering
3076
+ filtered rows.
3077
+ </p>
3078
+ )}
3079
+ </Tooltip.Content>
3080
+ </Tooltip>
3081
+ }
3082
+ />
3083
+ )}
3084
+ {visSupportsYPadding() && (
3085
+ <CheckBox
3086
+ value={config.yAxis.enablePadding}
2648
3087
  section='yAxis'
2649
- fieldName='min'
3088
+ fieldName='enablePadding'
3089
+ label='Add Padding to Value Axis Scale'
3090
+ updateField={updateFieldDeprecated}
3091
+ />
3092
+ )}
3093
+ {config.yAxis.enablePadding && visSupportsYPadding() && (
3094
+ <TextField
2650
3095
  type='number'
2651
- label='left axis min value'
2652
- placeholder='Auto'
3096
+ section='yAxis'
3097
+ fieldName='scalePadding'
3098
+ label='Padding Percentage'
3099
+ className='axis-domain-number'
2653
3100
  updateField={updateFieldDeprecated}
3101
+ value={config.yAxis.scalePadding}
2654
3102
  />
2655
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
2656
- </>
2657
- )}
2658
- <TextField
2659
- value={config.yAxis.smallestLeftAxisMax}
2660
- section='yAxis'
2661
- fieldName='smallestLeftAxisMax'
2662
- type='number'
2663
- label='Smallest Left Axis Maximum'
2664
- placeholder='Auto'
2665
- tooltip={
2666
- <Tooltip style={{ textTransform: 'none' }}>
2667
- <Tooltip.Target>
2668
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2669
- </Tooltip.Target>
2670
- <Tooltip.Content>
2671
- <p>
2672
- Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
2673
- 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
2674
- </p>
2675
- </Tooltip.Content>
2676
- </Tooltip>
2677
- }
2678
- updateField={updateFieldDeprecated}
2679
- />
3103
+ )}
3104
+ </div>
2680
3105
  </>
2681
3106
  )
2682
3107
  )}
@@ -2844,48 +3269,60 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2844
3269
  updateField={updateFieldDeprecated}
2845
3270
  />
2846
3271
 
2847
- <TextField
2848
- value={config.yAxis.rightMax}
2849
- section='yAxis'
2850
- fieldName='rightMax'
2851
- type='number'
2852
- label='right axis max value'
2853
- placeholder='Auto'
2854
- updateField={updateFieldDeprecated}
2855
- />
2856
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.rightMaxMessage}</span>
2857
- <TextField
2858
- value={config.yAxis.rightMin}
2859
- section='yAxis'
2860
- fieldName='rightMin'
2861
- type='number'
2862
- label='right axis min value'
2863
- placeholder='Auto'
2864
- updateField={updateFieldDeprecated}
2865
- />
2866
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
2867
- <TextField
2868
- value={config.yAxis.smallestRightAxisMax}
2869
- section='yAxis'
2870
- fieldName='smallestRightAxisMax'
2871
- type='number'
2872
- label='Smallest Right Axis Maximum'
2873
- placeholder='Auto'
2874
- tooltip={
2875
- <Tooltip style={{ textTransform: 'none' }}>
2876
- <Tooltip.Target>
2877
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2878
- </Tooltip.Target>
2879
- <Tooltip.Content>
2880
- <p>
2881
- Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6, 0.8, 1.
2882
- Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
2883
- </p>
2884
- </Tooltip.Content>
2885
- </Tooltip>
2886
- }
2887
- updateField={updateFieldDeprecated}
2888
- />
3272
+ <div className='axis-domain-group'>
3273
+ <span className='axis-domain-group__title'>Right Axis Domain</span>
3274
+ <div className='axis-domain-group__row'>
3275
+ <div className='axis-domain-group__field'>
3276
+ <TextField
3277
+ value={config.yAxis.rightMax}
3278
+ section='yAxis'
3279
+ fieldName='rightMax'
3280
+ type='number'
3281
+ label='axis max value'
3282
+ placeholder='Auto'
3283
+ className='axis-domain-number'
3284
+ updateField={updateFieldDeprecated}
3285
+ />
3286
+ <span className='axis-domain-warning'>{warningMsg.rightMaxMessage}</span>
3287
+ </div>
3288
+ <div className='axis-domain-group__field'>
3289
+ <TextField
3290
+ value={config.yAxis.rightMin}
3291
+ section='yAxis'
3292
+ fieldName='rightMin'
3293
+ type='number'
3294
+ label='axis min value'
3295
+ placeholder='Auto'
3296
+ className='axis-domain-number'
3297
+ updateField={updateFieldDeprecated}
3298
+ />
3299
+ <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
3300
+ </div>
3301
+ </div>
3302
+ <TextField
3303
+ value={config.yAxis.smallestRightAxisMax}
3304
+ section='yAxis'
3305
+ fieldName='smallestRightAxisMax'
3306
+ type='number'
3307
+ label='Smallest axis maximum'
3308
+ placeholder='Auto'
3309
+ className='axis-domain-number'
3310
+ tooltip={
3311
+ <Tooltip style={{ textTransform: 'none' }}>
3312
+ <Tooltip.Target>
3313
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3314
+ </Tooltip.Target>
3315
+ <Tooltip.Content>
3316
+ <p>
3317
+ Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6, 0.8, 1.
3318
+ Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
3319
+ </p>
3320
+ </Tooltip.Content>
3321
+ </Tooltip>
3322
+ }
3323
+ updateField={updateFieldDeprecated}
3324
+ />
3325
+ </div>
2889
3326
  </AccordionItemPanel>
2890
3327
  </AccordionItem>
2891
3328
  )}
@@ -3060,6 +3497,16 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3060
3497
  </Tooltip>
3061
3498
  }
3062
3499
  />
3500
+ {config.visualizationType === 'HeatMap' && (
3501
+ <Select
3502
+ value={config.heatmap?.xAxisPosition ?? HEATMAP_CONFIG_DEFAULTS.xAxisPosition}
3503
+ section='heatmap'
3504
+ fieldName='xAxisPosition'
3505
+ label='X-Axis Position'
3506
+ updateField={updateFieldDeprecated}
3507
+ options={['top', 'bottom']}
3508
+ />
3509
+ )}
3063
3510
 
3064
3511
  {config.xAxis.type === 'continuous' && (
3065
3512
  <>
@@ -3319,38 +3766,71 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3319
3766
  }
3320
3767
  />
3321
3768
  {config.xAxis.brushActive && (
3322
- <TextField
3323
- value={config.xAxis.brushDefaultRecentDateCount ?? ''}
3324
- placeholder='Default (35%)'
3325
- type='number'
3326
- min={1}
3327
- section='xAxis'
3328
- fieldName='brushDefaultRecentDateCount'
3329
- label='Show Last X Dates by Default'
3330
- className='number-narrow'
3331
- updateField={updateFieldDeprecated}
3332
- tooltip={
3333
- <Tooltip style={{ textTransform: 'none' }}>
3334
- <Tooltip.Target>
3335
- <Icon
3336
- display='question'
3337
- style={{
3338
- marginLeft: '0.5rem',
3339
- display: 'inline-block',
3340
- whiteSpace: 'nowrap'
3341
- }}
3342
- />
3343
- </Tooltip.Target>
3344
- <Tooltip.Content>
3345
- <p>
3346
- When set, the brush slider will initially select this many recent data points
3347
- instead of the default 35%. Leave empty to use the default percentage-based
3348
- selection.
3349
- </p>
3350
- </Tooltip.Content>
3351
- </Tooltip>
3352
- }
3353
- />
3769
+ <>
3770
+ <CheckBox
3771
+ value={!!config.xAxis.brushDynamicYAxis}
3772
+ section='xAxis'
3773
+ fieldName='brushDynamicYAxis'
3774
+ label='Dynamic Y-Axis'
3775
+ className='ms-4'
3776
+ updateField={updateFieldDeprecated}
3777
+ tooltip={
3778
+ <Tooltip style={{ textTransform: 'none' }}>
3779
+ <Tooltip.Target>
3780
+ <Icon
3781
+ display='question'
3782
+ style={{
3783
+ marginLeft: '0.5rem',
3784
+ display: 'inline-block',
3785
+ whiteSpace: 'nowrap'
3786
+ }}
3787
+ />
3788
+ </Tooltip.Target>
3789
+ <Tooltip.Content>
3790
+ <p>
3791
+ When enabled, the Y-axis rescales to fit only the data visible in the
3792
+ current brush selection. When disabled, the Y-axis shows the full data
3793
+ range.
3794
+ </p>
3795
+ </Tooltip.Content>
3796
+ </Tooltip>
3797
+ }
3798
+ />
3799
+ <div className='ms-4 mt-2'>
3800
+ <TextField
3801
+ value={config.xAxis.brushDefaultRecentDateCount ?? ''}
3802
+ placeholder='Default (35%)'
3803
+ type='number'
3804
+ min={1}
3805
+ section='xAxis'
3806
+ fieldName='brushDefaultRecentDateCount'
3807
+ label='Show Last X Dates by Default'
3808
+ className='number-narrow'
3809
+ updateField={updateFieldDeprecated}
3810
+ tooltip={
3811
+ <Tooltip style={{ textTransform: 'none' }}>
3812
+ <Tooltip.Target>
3813
+ <Icon
3814
+ display='question'
3815
+ style={{
3816
+ marginLeft: '0.5rem',
3817
+ display: 'inline-block',
3818
+ whiteSpace: 'nowrap'
3819
+ }}
3820
+ />
3821
+ </Tooltip.Target>
3822
+ <Tooltip.Content>
3823
+ <p>
3824
+ When set, the brush slider will initially select this many recent data
3825
+ points instead of the default 35%. Leave empty to use the default
3826
+ percentage-based selection.
3827
+ </p>
3828
+ </Tooltip.Content>
3829
+ </Tooltip>
3830
+ }
3831
+ />
3832
+ </div>
3833
+ </>
3354
3834
  )}
3355
3835
  </>
3356
3836
  )}
@@ -3378,7 +3858,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3378
3858
  }
3379
3859
  e.target.value = ''
3380
3860
  }}
3381
- options={getDataValues(config.xAxis.dataKey, true)}
3861
+ options={getAvailableExclusionValues(config.xAxis.dataKey)}
3382
3862
  />
3383
3863
  </>
3384
3864
  )}
@@ -3814,7 +4294,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3814
4294
  }
3815
4295
  e.target.value = ''
3816
4296
  }}
3817
- options={getDataValues(config.xAxis.dataKey, true)}
4297
+ options={getAvailableExclusionValues(config.xAxis.dataKey)}
3818
4298
  />
3819
4299
  </>
3820
4300
  )}
@@ -3866,6 +4346,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3866
4346
  </AccordionItemPanel>
3867
4347
  </AccordionItem>
3868
4348
  )}
4349
+ {renderHeatMapSettingsAccordion()}
3869
4350
  <Panels.Regions name='Regions' />
3870
4351
 
3871
4352
  {/* Columns */}
@@ -3879,7 +4360,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3879
4360
  config={config}
3880
4361
  updateField={updateFieldDeprecated}
3881
4362
  deleteColumn={removeAdditionalColumn}
3882
- hiddenColumnNames={seriesOwnedColumnNames}
4363
+ hiddenColumnNames={
4364
+ isHeatMap ? [...seriesOwnedColumnNames, ...heatMapOwnedColumnNames] : seriesOwnedColumnNames
4365
+ }
3883
4366
  />{' '}
3884
4367
  </AccordionItemPanel>
3885
4368
  </AccordionItem>
@@ -3898,7 +4381,11 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3898
4381
  label='Position'
3899
4382
  updateField={updateFieldDeprecated}
3900
4383
  options={
3901
- config.visualizationType === 'Warming Stripes'
4384
+ config.visualizationType === 'HeatMap'
4385
+ ? config.legend.style === 'gradient'
4386
+ ? ['bottom', 'top']
4387
+ : ['right', 'left', 'bottom', 'top']
4388
+ : config.visualizationType === 'Warming Stripes'
3902
4389
  ? ['bottom']
3903
4390
  : ['right', 'left', 'bottom', 'top']
3904
4391
  }
@@ -3938,7 +4425,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3938
4425
  options={getLegendStyleOptions('style')}
3939
4426
  />
3940
4427
 
3941
- {config.visualizationType !== 'Warming Stripes' && (
4428
+ {config.visualizationType !== 'Warming Stripes' && config.visualizationType !== 'HeatMap' && (
3942
4429
  <Select
3943
4430
  value={config.legend.groupBy}
3944
4431
  section='legend'
@@ -3982,7 +4469,11 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3982
4469
  options={getLegendStyleOptions('subStyle')}
3983
4470
  />
3984
4471
  <TextField
3985
- display={config.legend.style === 'gradient' && !config.legend.hide}
4472
+ display={
4473
+ config.visualizationType !== 'HeatMap' &&
4474
+ config.legend.style === 'gradient' &&
4475
+ !config.legend.hide
4476
+ }
3986
4477
  className='number-narrow'
3987
4478
  type='number'
3988
4479
  value={config.legend.tickRotation}
@@ -4347,6 +4838,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4347
4838
  loadConfig={updateConfig}
4348
4839
  config={config}
4349
4840
  convertStateToConfig={chartConvertStateToConfig}
4841
+ defaultExpanded={config.visualizationType === 'HeatMap'}
4350
4842
  />
4351
4843
  )}
4352
4844
  </>