@cdc/chart 4.22.11 → 4.23.2

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 (65) hide show
  1. package/dist/cdcchart.js +54569 -16
  2. package/examples/Barchart_with_negative.json +34 -0
  3. package/examples/box-plot-data.json +71 -0
  4. package/examples/box-plot.csv +5 -0
  5. package/examples/box-plot.json +124 -0
  6. package/examples/dynamic-legends.json +1 -1
  7. package/examples/example-bar-chart-nonnumeric.json +36 -0
  8. package/examples/example-bar-chart.json +33 -0
  9. package/examples/example-combo-bar-nonnumeric.json +105 -0
  10. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +3 -1
  11. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +1 -1
  12. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +86 -17
  13. package/examples/gallery/paired-bar/paired-bar-chart.json +65 -13
  14. package/examples/line-chart-nonnumeric.json +32 -0
  15. package/examples/line-chart.json +21 -63
  16. package/examples/new-data.csv +17 -0
  17. package/examples/newdata.json +90 -0
  18. package/examples/planet-combo-example-config.json +143 -20
  19. package/examples/planet-example-data-nonnumeric.json +56 -0
  20. package/examples/planet-example-data.json +2 -2
  21. package/examples/planet-pie-example-config-nonnumeric.json +30 -0
  22. package/examples/scatterplot-continuous.csv +17 -0
  23. package/examples/{private/yaxis-test.json → scatterplot.json} +53 -50
  24. package/examples/sparkline-chart-nonnumeric.json +76 -0
  25. package/examples/stacked-vertical-bar-example-negative.json +154 -0
  26. package/examples/stacked-vertical-bar-example-nonnumerics.json +154 -0
  27. package/{src/index.html → index.html} +18 -11
  28. package/package.json +29 -22
  29. package/src/{CdcChart.tsx → CdcChart.jsx} +193 -119
  30. package/src/components/BarChart.jsx +517 -0
  31. package/src/components/BoxPlot.jsx +88 -0
  32. package/src/components/{DataTable.tsx → DataTable.jsx} +125 -32
  33. package/src/components/{EditorPanel.js → EditorPanel.jsx} +376 -115
  34. package/src/components/Filters.jsx +125 -0
  35. package/src/components/Legend.jsx +303 -0
  36. package/src/components/{LineChart.tsx → LineChart.jsx} +87 -22
  37. package/src/components/{LinearChart.tsx → LinearChart.jsx} +172 -113
  38. package/src/components/{PairedBarChart.tsx → PairedBarChart.jsx} +46 -79
  39. package/src/components/{PieChart.tsx → PieChart.jsx} +29 -34
  40. package/src/components/ScatterPlot.jsx +48 -0
  41. package/src/components/{SparkLine.js → SparkLine.jsx} +49 -18
  42. package/src/components/useIntersectionObserver.jsx +29 -0
  43. package/src/data/initial-state.js +44 -8
  44. package/src/hooks/{useColorPalette.ts → useColorPalette.js} +10 -28
  45. package/src/hooks/{useReduceData.ts → useReduceData.js} +27 -13
  46. package/src/hooks/useRightAxis.js +3 -1
  47. package/src/index.jsx +16 -0
  48. package/src/scss/DataTable.scss +23 -1
  49. package/src/scss/main.scss +83 -32
  50. package/vite.config.js +4 -0
  51. package/examples/private/filters.json +0 -170
  52. package/examples/private/line-test-data.json +0 -22
  53. package/examples/private/line-test-two.json +0 -210
  54. package/examples/private/line-test.json +0 -102
  55. package/examples/private/new.json +0 -48800
  56. package/examples/private/newtest.csv +0 -101
  57. package/examples/private/shawn.json +0 -1106
  58. package/examples/private/test.json +0 -10124
  59. package/examples/private/yaxis-testing.csv +0 -27
  60. package/examples/private/yaxis.json +0 -28
  61. package/src/components/BarChart.tsx +0 -579
  62. package/src/components/Legend.js +0 -284
  63. package/src/components/useIntersectionObserver.tsx +0 -27
  64. package/src/index.tsx +0 -18
  65. /package/src/{context.tsx → ConfigContext.jsx} +0 -0
@@ -1,29 +1,24 @@
1
1
  import React, { useState, useEffect, useCallback, memo, useContext } from 'react'
2
- import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
2
+ import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
3
3
 
4
4
  import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
5
5
 
6
- import { timeParse, timeFormat } from 'd3-time-format'
7
- import { useDebounce, useDebouncedCallback } from 'use-debounce'
6
+ import { useDebounce } from 'use-debounce'
8
7
 
9
- import Context from '../context'
8
+ import ConfigContext from '../ConfigContext'
10
9
  import WarningImage from '../images/warning.svg'
11
10
  import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
12
11
 
13
12
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
14
- import Waiting from '@cdc/core/components/Waiting'
15
- import QuestionIcon from '@cdc/core/assets/icon-question-circle.svg' //TODO: Update with Icon component
16
13
  import { useColorPalette } from '../hooks/useColorPalette'
17
14
 
18
- import InputCheckbox from '@cdc/core/components/inputs/InputCheckbox'
19
15
  import InputToggle from '@cdc/core/components/inputs/InputToggle'
20
16
  import Tooltip from '@cdc/core/components/ui/Tooltip'
21
17
  import Icon from '@cdc/core/components/ui/Icon'
22
18
  import useReduceData from '../hooks/useReduceData'
23
19
  import useRightAxis from '../hooks/useRightAxis'
24
20
 
25
- // TODO: Remove unused imports
26
- // TDOO: Move inline styles to a scss file
21
+ /* eslint-disable react-hooks/rules-of-hooks */
27
22
 
28
23
  const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
29
24
  const [value, setValue] = useState(stateValue)
@@ -34,7 +29,7 @@ const TextField = memo(({ label, tooltip, section = null, subsection = null, fie
34
29
  if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
35
30
  updateField(section, subsection, fieldName, debouncedValue, i)
36
31
  }
37
- }, [debouncedValue])
32
+ }, [debouncedValue]) // eslint-disable-line
38
33
 
39
34
  let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
40
35
 
@@ -211,17 +206,17 @@ const Regions = memo(({ config, updateConfig }) => {
211
206
  const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
212
207
 
213
208
  const EditorPanel = () => {
214
- const { config, updateConfig, transformedData: data, loading, colorPalettes, unfilteredData, excludedData, transformedData, isDashboard, setParentConfig, missingRequiredSections, setFilteredData } = useContext(Context)
209
+ const { config, updateConfig, transformedData: data, loading, colorPalettes, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections } = useContext(ConfigContext)
215
210
 
216
- const { minValue, maxValue, existPositiveValue } = useReduceData(config, unfilteredData)
211
+ const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
217
212
  const { paletteName, isPaletteReversed, filteredPallets, filteredQualitative, dispatch } = useColorPalette(colorPalettes, config)
218
213
  useEffect(() => {
219
214
  if (paletteName) updateConfig({ ...config, palette: paletteName })
220
- }, [paletteName])
215
+ }, [paletteName]) // eslint-disable-line
221
216
 
222
217
  useEffect(() => {
223
218
  dispatch({ type: 'GET_PALETTE', payload: colorPalettes, paletteName: config.palette })
224
- }, [dispatch, config.palette])
219
+ }, [dispatch, config.palette]) // eslint-disable-line
225
220
 
226
221
  // when the visualization type changes we
227
222
  // have to update the individual series type & axis details
@@ -243,7 +238,7 @@ const EditorPanel = () => {
243
238
  ...config,
244
239
  series: newSeries
245
240
  })
246
- }, [config.visualizationType])
241
+ }, [config.visualizationType]) // eslint-disable-line
247
242
 
248
243
  const { hasRightAxis } = useRightAxis({ config: config, yMax: config.yAxis.size, data: config.data, updateConfig })
249
244
 
@@ -292,12 +287,38 @@ const EditorPanel = () => {
292
287
  }
293
288
 
294
289
  const updateField = (section, subsection, fieldName, newValue) => {
295
- // Top level
290
+
291
+ if (section === 'boxplot' && subsection === 'legend') {
292
+ updateConfig({
293
+ ...config,
294
+ [section]: {
295
+ ...config[section],
296
+ [subsection]: {
297
+ ...config.boxplot[subsection],
298
+ [fieldName]: newValue
299
+ }
300
+ }
301
+ })
302
+ return
303
+ }
304
+
305
+ if (section === 'boxplot' && subsection === 'labels') {
306
+ updateConfig({
307
+ ...config,
308
+ [section]: {
309
+ ...config[section],
310
+ [subsection]: {
311
+ ...config.boxplot[subsection],
312
+ [fieldName]: newValue
313
+ }
314
+ }
315
+ })
316
+ return
317
+ }
318
+
296
319
  if (null === section && null === subsection) {
297
320
  let updatedConfig = { ...config, [fieldName]: newValue }
298
-
299
321
  enforceRestrictions(updatedConfig)
300
-
301
322
  updateConfig(updatedConfig)
302
323
  return
303
324
  }
@@ -306,6 +327,8 @@ const EditorPanel = () => {
306
327
 
307
328
  let sectionValue = isArray ? [...config[section], newValue] : { ...config[section], [fieldName]: newValue }
308
329
 
330
+ console.log('section value', sectionValue)
331
+
309
332
  if (null !== subsection) {
310
333
  if (isArray) {
311
334
  sectionValue = [...config[section]]
@@ -325,7 +348,6 @@ const EditorPanel = () => {
325
348
  }
326
349
 
327
350
  const [displayPanel, setDisplayPanel] = useState(true)
328
- const [lollipopColorStyle, setLollipopColorStyle] = useState('two-tone')
329
351
 
330
352
  if (loading) {
331
353
  return null
@@ -442,14 +464,11 @@ const EditorPanel = () => {
442
464
  const getColumns = (filter = true) => {
443
465
  let columns = {}
444
466
 
445
- unfilteredData.map(row => {
467
+ unfilteredData.forEach(row => {
446
468
  Object.keys(row).forEach(columnName => (columns[columnName] = true))
447
469
  })
448
470
 
449
471
  if (filter) {
450
- let confidenceUpper = config.confidenceKeys?.upper && config.confidenceKeys?.upper !== '' // TODO: remove?
451
- let confidenceLower = config.confidenceKeys?.lower && config.confidenceKeys?.lower !== '' // TODO: remove?
452
-
453
472
  Object.keys(columns).forEach(key => {
454
473
  if (
455
474
  (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
@@ -471,7 +490,7 @@ const EditorPanel = () => {
471
490
  if (!data) return []
472
491
  const set = new Set()
473
492
  for (let i = 0; i < data.length; i++) {
474
- for (const [key, value] of Object.entries(data[i])) {
493
+ for (const [key] of Object.entries(data[i])) {
475
494
  set.add(key)
476
495
  }
477
496
  }
@@ -480,7 +499,7 @@ const EditorPanel = () => {
480
499
 
481
500
  const getDataValues = (dataKey, unique = false) => {
482
501
  let values = []
483
- excludedData.map(e => {
502
+ excludedData.forEach(e => {
484
503
  values.push(e[dataKey])
485
504
  })
486
505
  return unique ? [...new Set(values)] : values
@@ -560,7 +579,7 @@ const EditorPanel = () => {
560
579
  orientation: 'horizontal'
561
580
  })
562
581
  }
563
- }, [])
582
+ }, []) // eslint-disable-line
564
583
 
565
584
  useEffect(() => {
566
585
  if (config.orientation === 'horizontal') {
@@ -569,7 +588,7 @@ const EditorPanel = () => {
569
588
  lollipopShape: config.lollipopShape
570
589
  })
571
590
  }
572
- }, [config.isLollipopChart, config.lollipopShape])
591
+ }, [config.isLollipopChart, config.lollipopShape]) // eslint-disable-line
573
592
 
574
593
  const ExclusionsList = useCallback(() => {
575
594
  const exclusions = [...config.exclusions.keys]
@@ -589,18 +608,7 @@ const EditorPanel = () => {
589
608
  })}
590
609
  </ul>
591
610
  )
592
- }, [config])
593
-
594
- const ErrorWithLolliopChart = ({ message }) => {
595
- return (
596
- <section className='waiting'>
597
- <section className='waiting-container'>
598
- <h3>Error With Configuration</h3>
599
- <p>{message}</p>
600
- </section>
601
- </section>
602
- )
603
- }
611
+ }, [config]) // eslint-disable-line
604
612
 
605
613
  const checkIsLine = type => {
606
614
  return type === ('Line' || 'dashed-sm')
@@ -616,7 +624,14 @@ const EditorPanel = () => {
616
624
  filterItem.orderedValues = filterOrder
617
625
  filterItem.order = 'cust'
618
626
  filters[filterIndex] = filterItem
619
- updateConfig({ ...config, filters });
627
+ updateConfig({ ...config, filters })
628
+ }
629
+
630
+ const handleSeriesChange = (idx1, idx2) => {
631
+ let seriesOrder = config.series
632
+ let [movedItem] = seriesOrder.splice(idx1, 1)
633
+ seriesOrder.splice(idx2, 0, movedItem)
634
+ updateConfig({ ...config, series: seriesOrder })
620
635
  }
621
636
 
622
637
  if (config.isLollipopChart && config?.series?.length > 1) {
@@ -658,7 +673,10 @@ const EditorPanel = () => {
658
673
  case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue && parseFloat(enteredValue) > minVal:
659
674
  message = 'Value must be less than ' + minValue
660
675
  break
661
- case (config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
676
+ case config.visualizationType === 'Combo' && isAllLine && enteredValue && parseFloat(enteredValue) > minVal:
677
+ message = 'Value must be less than ' + minValue
678
+ break
679
+ case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
662
680
  message = 'Value must be less than or equal to 0'
663
681
  break
664
682
  case enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal:
@@ -671,11 +689,10 @@ const EditorPanel = () => {
671
689
  return { ...prevMsg, minMsg: message }
672
690
  })
673
691
  }
674
-
675
692
  useEffect(() => {
676
693
  validateMinValue()
677
694
  validateMaxValue()
678
- }, [minValue, maxValue, config])
695
+ }, [minValue, maxValue, config]) // eslint-disable-line
679
696
 
680
697
  return (
681
698
  <ErrorBoundary component='EditorPanel'>
@@ -697,6 +714,7 @@ const EditorPanel = () => {
697
714
  </AccordionItemHeading>
698
715
  <AccordionItemPanel>
699
716
  <Select value={config.visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={['Pie', 'Line', 'Bar', 'Combo', 'Paired Bar', 'Spark Line']} />
717
+
700
718
  {(config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && <Select value={config.visualizationSubType || 'Regular'} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['regular', 'stacked']} />}
701
719
  {config.visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName='orientation' label='Orientation' updateField={updateField} options={['vertical', 'horizontal']} />}
702
720
  {config.visualizationType === 'Bar' && <Select value={config.isLollipopChart ? 'lollipop' : config.barStyle || 'flat'} fieldName='barStyle' label='bar style' updateField={updateField} options={showBarStyleOptions()} />}
@@ -709,8 +727,8 @@ const EditorPanel = () => {
709
727
  config.visualizationType !== 'Pie' && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
710
728
  )}
711
729
  {config.visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
712
- <TextField value={config.title} fieldName='title' label='Title' updateField={updateField} />
713
730
 
731
+ <TextField value={config.title} fieldName='title' label='Title' updateField={updateField} />
714
732
  <TextField
715
733
  value={config.superTitle}
716
734
  updateField={updateField}
@@ -783,7 +801,7 @@ const EditorPanel = () => {
783
801
  }
784
802
  />
785
803
 
786
- {config.visualizationSubType !== 'horizontal' && <TextField type='number' value={config.height} fieldName='height' label='Chart Height' updateField={updateField} />}
804
+ {config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
787
805
  </AccordionItemPanel>
788
806
  </AccordionItem>
789
807
 
@@ -808,69 +826,95 @@ const EditorPanel = () => {
808
826
  </Tooltip.Content>
809
827
  </Tooltip>
810
828
  </fieldset>
811
- <ul className='series-list'>
812
- {config.series &&
813
- config.series.map((series, i) => {
814
- if (config.visualizationType === 'Combo') {
815
- let changeType = (i, value) => {
816
- let series = [...config.series]
817
- series[i].type = value
818
-
819
- series[i].axis = 'Left'
820
-
821
- updateConfig({ ...config, series })
822
- }
823
-
824
- let typeDropdown = (
825
- <select
826
- value={series.type}
827
- onChange={event => {
828
- changeType(i, event.target.value)
829
- }}
830
- style={{ width: '100px', marginRight: '10px' }}
831
- >
832
- <option value='' default>
833
- Select
834
- </option>
835
- <option value='Bar'>Bar</option>
836
- <option value='Line'>Solid Line</option>
837
- <option value='dashed-sm'>Small Dashed</option>
838
- <option value='dashed-md'>Medium Dashed</option>
839
- <option value='dashed-lg'>Large Dashed</option>
840
- </select>
841
- )
842
829
 
843
- return (
844
- <li key={series.dataKey}>
845
- <div className={`series-list__name${series.dataKey.length > 15 ? ' series-list__name--truncate' : ''}`} data-title={series.dataKey}>
846
- <div className='series-list__name-text'>{series.dataKey}</div>
847
- </div>
848
- <span>
849
- <span className='series-list__dropdown'>{typeDropdown}</span>
850
- {config.series && config.series.length > 1 && (
851
- <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
852
- &#215;
853
- </button>
854
- )}
855
- </span>
856
- </li>
857
- )
858
- }
830
+ <DragDropContext onDragEnd={({ source, destination }) => handleSeriesChange(source.index, destination.index)}>
831
+ <Droppable droppableId='filter_order'>
832
+ {provided => (
833
+ <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
834
+ {config.series.map((series, i) => {
835
+ if (config.visualizationType === 'Combo') {
836
+ let changeType = (i, value) => {
837
+ let series = [...config.series]
838
+ series[i].type = value
839
+
840
+ series[i].axis = 'Left'
841
+
842
+ updateConfig({ ...config, series })
843
+ }
844
+
845
+ let typeDropdown = (
846
+ <select
847
+ value={series.type}
848
+ onChange={event => {
849
+ changeType(i, event.target.value)
850
+ }}
851
+ style={{ width: '100px', marginRight: '10px' }}
852
+ >
853
+ <option value='' default>
854
+ Select
855
+ </option>
856
+ <option value='Bar'>Bar</option>
857
+ <option value='Line'>Solid Line</option>
858
+ <option value='dashed-sm'>Small Dashed</option>
859
+ <option value='dashed-md'>Medium Dashed</option>
860
+ <option value='dashed-lg'>Large Dashed</option>
861
+ </select>
862
+ )
863
+
864
+ return (
865
+ <Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
866
+ {(provided, snapshot) => (
867
+ <li>
868
+ <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
869
+ <div className={`series-list__name${series.dataKey.length > 15 ? ' series-list__name--truncate' : ''}`} data-title={series.dataKey}>
870
+ <div className='series-list__name-text'>{series.dataKey}</div>
871
+ </div>
872
+ <span>
873
+ <span className='series-list__dropdown'>{typeDropdown}</span>
874
+ {config.series && config.series.length > 1 && (
875
+ <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
876
+ &#215;
877
+ </button>
878
+ )}
879
+ </span>
880
+ </div>
881
+ </li>
882
+ )}
883
+ </Draggable>
884
+ )
885
+ }
859
886
 
860
- return (
861
- <li key={series.dataKey}>
862
- <div className='series-list__name' data-title={series.dataKey}>
863
- <div className='series-list__name--text'>{series.dataKey}</div>
864
- </div>
865
- {config.series && config.series.length > 1 && (
866
- <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
867
- &#215;
868
- </button>
869
- )}
870
- </li>
871
- )
872
- })}
873
- </ul>
887
+ return (
888
+ <Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
889
+ {(provided, snapshot) => (
890
+ <li
891
+ key={series.dataKey}
892
+ className={snapshot.isDragging ? 'currently-dragging' : ''}
893
+ style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)}
894
+ ref={provided.innerRef}
895
+ {...provided.draggableProps}
896
+ {...provided.dragHandleProps}
897
+ >
898
+ {/*<div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>*/}
899
+ <div className='series-list__name' data-title={series.dataKey}>
900
+ <div className='series-list__name--text'>{series.dataKey}</div>
901
+ </div>
902
+ {config.series && config.series.length > 1 && (
903
+ <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
904
+ &#215;
905
+ </button>
906
+ )}
907
+ {/*</div>*/}
908
+ </li>
909
+ )}
910
+ </Draggable>
911
+ )
912
+ })}
913
+ {provided.placeholder}
914
+ </ul>
915
+ )}
916
+ </Droppable>
917
+ </DragDropContext>
874
918
  </>
875
919
  )}
876
920
 
@@ -899,6 +943,181 @@ const EditorPanel = () => {
899
943
  </AccordionItem>
900
944
  )}
901
945
 
946
+ {config.visualizationType === 'Box Plot' && (
947
+ <AccordionItem>
948
+ <AccordionItemHeading>
949
+ <AccordionItemButton>Measures</AccordionItemButton>
950
+ </AccordionItemHeading>
951
+ <AccordionItemPanel>
952
+ <h4>Labels for 5-Number Summary</h4>
953
+
954
+ {/* prettier-ignore */}
955
+ {/* max */}
956
+ <TextField
957
+ type='text'
958
+ value={config.boxplot.labels.maximum}
959
+ fieldName='maximum'
960
+ section='boxplot'
961
+ subsection='labels'
962
+ label='Maximum'
963
+ updateField={updateField}
964
+ tooltip={
965
+ <Tooltip style={{ textTransform: 'none' }}>
966
+ <Tooltip.Target>
967
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
968
+ </Tooltip.Target>
969
+ <Tooltip.Content>
970
+ <p>Highest value, excluding outliers</p>
971
+ </Tooltip.Content>
972
+ </Tooltip>
973
+ }
974
+ />
975
+
976
+ {/* prettier-ignore */}
977
+ {/* Q3 */}
978
+ <TextField
979
+ type='text'
980
+ value={config.boxplot.labels.q3}
981
+ fieldName='q3'
982
+ section='boxplot'
983
+ subsection='labels'
984
+ label='Upper Quartile'
985
+ updateField={updateField}
986
+ tooltip={
987
+ <Tooltip style={{ textTransform: 'none' }}>
988
+ <Tooltip.Target>
989
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
990
+ </Tooltip.Target>
991
+ <Tooltip.Content>
992
+ <p>Represented by top line of box. 25% of data are higher.</p>
993
+ </Tooltip.Content>
994
+ </Tooltip>
995
+ }
996
+ />
997
+
998
+ {/* prettier-ignore */}
999
+ {/* median */}
1000
+ <TextField
1001
+ type='text'
1002
+ value={config.boxplot.labels.median}
1003
+ fieldName='median'
1004
+ section='boxplot'
1005
+ subsection='labels'
1006
+ label='Median'
1007
+ updateField={updateField}
1008
+ tooltip={
1009
+ <Tooltip style={{ textTransform: 'none' }}>
1010
+ <Tooltip.Target>
1011
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1012
+ </Tooltip.Target>
1013
+ <Tooltip.Content>
1014
+ <p>Middle data point. Half of data are higher value.</p>
1015
+ </Tooltip.Content>
1016
+ </Tooltip>
1017
+ }
1018
+ />
1019
+
1020
+ {/* prettier-ignore */}
1021
+ {/* q1 */}
1022
+ <TextField
1023
+ type='text'
1024
+ value={config.boxplot.labels.q1}
1025
+ fieldName='q1'
1026
+ section='boxplot'
1027
+ subsection='labels'
1028
+ label='Lower Quartile'
1029
+ updateField={updateField}
1030
+ tooltip={
1031
+ <Tooltip style={{ textTransform: 'none' }}>
1032
+ <Tooltip.Target>
1033
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1034
+ </Tooltip.Target>
1035
+ <Tooltip.Content>
1036
+ <p>Represented by bottom line of box. 25% of data are lower.</p>
1037
+ </Tooltip.Content>
1038
+ </Tooltip>
1039
+ }
1040
+ />
1041
+
1042
+ {/* prettier-ignore */}
1043
+ {/* minimum */}
1044
+ <TextField
1045
+ type='text'
1046
+ value={config.boxplot.labels.minimum}
1047
+ fieldName='minimum'
1048
+ section='boxplot'
1049
+ subsection='labels'
1050
+ label='Minimum'
1051
+ updateField={updateField}
1052
+ tooltip={
1053
+ <Tooltip style={{ textTransform: 'none' }}>
1054
+ <Tooltip.Target>
1055
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1056
+ </Tooltip.Target>
1057
+ <Tooltip.Content>
1058
+ <p>Lowest value, excluding outliers</p>
1059
+ </Tooltip.Content>
1060
+ </Tooltip>
1061
+ }
1062
+ />
1063
+
1064
+ {/* iqr */}
1065
+ <TextField type='text' value={config.boxplot.labels.iqr} fieldName='iqr' section='boxplot' subsection='labels' label='Interquartile Range' updateField={updateField} />
1066
+
1067
+ {/* count */}
1068
+ <TextField type='text' value={config.boxplot.labels.count} fieldName='count' section='boxplot' subsection='labels' label='Count' updateField={updateField} />
1069
+
1070
+ {/* mean */}
1071
+ <TextField type='text' value={config.boxplot.labels.mean} fieldName='mean' section='boxplot' subsection='labels' label='Mean' updateField={updateField} />
1072
+ {/* outliers */}
1073
+ <TextField type='text' value={config.boxplot.labels.outliers} fieldName='outliers' section='boxplot' subsection='labels' label='Outliers' updateField={updateField} />
1074
+ {/* values */}
1075
+ <TextField type='text' value={config.boxplot.labels.values} fieldName='values' section='boxplot' subsection='labels' label='Values' updateField={updateField} />
1076
+ <br />
1077
+ <h4>Percentages for Quartiles</h4>
1078
+ <TextField
1079
+ type='number'
1080
+ value={config.boxplot.firstQuartilePercentage}
1081
+ fieldName='firstQuartilePercentage'
1082
+ section='boxplot'
1083
+ label='Lower Quartile'
1084
+ max={100}
1085
+ updateField={updateField}
1086
+ tooltip={
1087
+ <Tooltip style={{ textTransform: 'none' }}>
1088
+ <Tooltip.Target>
1089
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1090
+ </Tooltip.Target>
1091
+ <Tooltip.Content>
1092
+ <p>Represented by bottom line of box. 25% of data are lower.</p>
1093
+ </Tooltip.Content>
1094
+ </Tooltip>
1095
+ }
1096
+ />
1097
+
1098
+ <TextField
1099
+ type='number'
1100
+ value={config.boxplot.thirdQuartilePercentage}
1101
+ fieldName='thirdQuartilePercentage'
1102
+ label='Upper Quartile'
1103
+ section='boxplot'
1104
+ max={100}
1105
+ updateField={updateField}
1106
+ tooltip={
1107
+ <Tooltip style={{ textTransform: 'none' }}>
1108
+ <Tooltip.Target>
1109
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1110
+ </Tooltip.Target>
1111
+ <Tooltip.Content>
1112
+ <p>Represented by top line of box. 25% of data are higher.</p>
1113
+ </Tooltip.Content>
1114
+ </Tooltip>
1115
+ }
1116
+ />
1117
+ </AccordionItemPanel>
1118
+ </AccordionItem>
1119
+ )}
1120
+
902
1121
  {hasRightAxis && config.series && config.visualizationType === 'Combo' && (
903
1122
  <AccordionItem>
904
1123
  <AccordionItemHeading>
@@ -966,7 +1185,7 @@ const EditorPanel = () => {
966
1185
  <AccordionItem>
967
1186
  <AccordionItemHeading>
968
1187
  <AccordionItemButton>
969
- {config.visualizationType !== 'Pie' ? (config.visualizationType === 'Bar' ? 'Left Value Axis' : 'Left Value Axis') : 'Data Format'}
1188
+ {config.visualizationType !== 'Pie' ? (config.orientation !== 'horizontal' ? 'Left Value Axis' : 'Value Axis') : 'Data Format'}
970
1189
  {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
971
1190
  </AccordionItemButton>
972
1191
  </AccordionItemHeading>
@@ -996,8 +1215,9 @@ const EditorPanel = () => {
996
1215
  {config.visualizationType !== 'Pie' && (
997
1216
  <>
998
1217
  <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label' updateField={updateField} />
999
- <CheckBox value={config.yAxis.isLegendValue} section='yAxis' fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />
1218
+ {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />}
1000
1219
  <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1220
+ {config.visualizationType === 'Paired Bar' && <TextField value={config.yAxis.tickRotation || 0} type='number' min='0' section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1001
1221
  <TextField
1002
1222
  value={config.yAxis.size}
1003
1223
  type='number'
@@ -1017,11 +1237,30 @@ const EditorPanel = () => {
1017
1237
  </Tooltip>
1018
1238
  }
1019
1239
  />
1240
+ <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} />
1241
+ {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1020
1242
  {config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Display Gridlines' updateField={updateField} />}
1021
1243
  </>
1022
1244
  )}
1023
1245
  <span className='divider-heading'>Number Formatting</span>
1024
1246
  <CheckBox value={config.dataFormat.commas} section='dataFormat' fieldName='commas' label='Add commas' updateField={updateField} />
1247
+ <CheckBox
1248
+ value={config.dataFormat.abbreviated}
1249
+ section='dataFormat'
1250
+ fieldName='abbreviated'
1251
+ label='Abbreviate Axis Values'
1252
+ updateField={updateField}
1253
+ tooltip={
1254
+ <Tooltip style={{ textTransform: 'none' }}>
1255
+ <Tooltip.Target>
1256
+ <Icon display='question' />
1257
+ </Tooltip.Target>
1258
+ <Tooltip.Content>
1259
+ <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1260
+ </Tooltip.Content>
1261
+ </Tooltip>
1262
+ }
1263
+ />
1025
1264
  <TextField value={config.dataFormat.roundTo} type='number' section='dataFormat' fieldName='roundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1026
1265
  <div className='two-col-inputs'>
1027
1266
  <TextField
@@ -1157,7 +1396,7 @@ const EditorPanel = () => {
1157
1396
  <AccordionItemPanel>
1158
1397
  {config.visualizationType !== 'Pie' && (
1159
1398
  <>
1160
- <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={['categorical', 'date']} />
1399
+ <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'date', 'continuous']} />
1161
1400
  <Select
1162
1401
  value={config.xAxis.dataKey || ''}
1163
1402
  section='xAxis'
@@ -1279,6 +1518,7 @@ const EditorPanel = () => {
1279
1518
  <TextField value={config.xAxis.numTicks} placeholder='Auto' type='number' min='1' section='xAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1280
1519
 
1281
1520
  <TextField value={config.xAxis.size} type='number' min='0' section='xAxis' fieldName='size' label={config.orientation === 'horizontal' ? 'Size (Width)' : 'Size (Height)'} className='number-narrow' updateField={updateField} />
1521
+ <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} />
1282
1522
 
1283
1523
  {config.yAxis.labelPlacement !== 'Below Bar' && <TextField value={config.xAxis.tickRotation} type='number' min='0' section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1284
1524
  {config.orientation === 'horizontal' ? (
@@ -1390,6 +1630,7 @@ const EditorPanel = () => {
1390
1630
  </Tooltip>
1391
1631
  }
1392
1632
  />
1633
+ <CheckBox value={config.legend.showLegendValuesTooltip} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />
1393
1634
 
1394
1635
  {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
1395
1636
  <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
@@ -1524,11 +1765,21 @@ const EditorPanel = () => {
1524
1765
  </>
1525
1766
  )}
1526
1767
 
1527
- <Select value={config.fontSize} fieldName='fontSize' label='Font Size' updateField={updateField} options={['small', 'medium', 'large']} />
1768
+ {config.visualizationType === 'Box Plot' &&
1769
+ <fieldset fieldset className='fieldset fieldset--boxplot'>
1770
+ <legend className=''>Box Plot Settings</legend>
1771
+ {config.visualizationType === 'Box Plot' && <Select value={config.boxplot.borders} fieldName='borders' section='boxplot' label='Box Plot Borders' updateField={updateField} options={['true', 'false']} />}
1772
+ {config.visualizationType === 'Box Plot' && <CheckBox value={config.boxplot.plotOutlierValues} fieldName='plotOutlierValues' section='boxplot' label='Plot Outliers' updateField={updateField} />}
1773
+ {config.visualizationType === 'Box Plot' && <CheckBox value={config.boxplot.plotNonOutlierValues} fieldName='plotNonOutlierValues' section='boxplot' label='Plot non-outlier values' updateField={updateField} />}
1774
+ {config.visualizationType === 'Box Plot' && <CheckBox value={config.boxplot.legend.displayHowToReadText} fieldName='displayHowToReadText' section='boxplot' subsection='legend' label='Display How To Read Text' updateField={updateField} />}
1775
+ <TextField type='textarea' value={config.boxplot.legend.howToReadText} updateField={updateField} fieldName='howToReadText' section='boxplot' subsection='legend' label='How to read text' />
1776
+ </fieldset>
1777
+ }
1528
1778
 
1529
- {config.series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar') && <Select value={config.barHasBorder} fieldName='barHasBorder' label='Bar Borders' updateField={updateField} options={['true', 'false']} />}
1779
+ <Select value={config.fontSize} fieldName='fontSize' label='Font Size' updateField={updateField} options={['small', 'medium', 'large']} />
1780
+ {config.visualizationType !== 'Box Plot' && config.series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar') && <Select value={config.barHasBorder} fieldName='barHasBorder' label='Bar Borders' updateField={updateField} options={['true', 'false']} />}
1530
1781
 
1531
- {/* <CheckBox value={config.animate} fieldName="animate" label="Animate Visualization" updateField={updateField} /> */}
1782
+ <CheckBox value={config.animate} fieldName='animate' label='Animate Visualization' updateField={updateField} />
1532
1783
 
1533
1784
  {/*<CheckBox value={config.animateReplay} fieldName="animateReplay" label="Replay Animation When Filters Are Changed" updateField={updateField} />*/}
1534
1785
 
@@ -1536,6 +1787,7 @@ const EditorPanel = () => {
1536
1787
  <Select value={config.lineDatapointStyle} fieldName='lineDatapointStyle' label='Line Datapoint Style' updateField={updateField} options={['hidden', 'hover', 'always show']} />
1537
1788
  )}
1538
1789
 
1790
+ {/* eslint-disable */}
1539
1791
  <label className='header'>
1540
1792
  <span className='edit-label'>Header Theme</span>
1541
1793
  <ul className='color-palette'>
@@ -1555,6 +1807,7 @@ const EditorPanel = () => {
1555
1807
  <label>
1556
1808
  <span className='edit-label'>Chart Color Palette</span>
1557
1809
  </label>
1810
+ {/* eslint-enable */}
1558
1811
  {/* <InputCheckbox fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
1559
1812
  <InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} />
1560
1813
  <span>Sequential</span>
@@ -1644,9 +1897,9 @@ const EditorPanel = () => {
1644
1897
  />
1645
1898
  </>
1646
1899
  )}
1647
- {config.orientation === 'horizontal' && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label='Bar Thickness' updateField={updateField} min='15' />}
1900
+ {config.orientation === 'horizontal' && !config.isLollipopChart && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label=' Bar Thickness' updateField={updateField} min='15' />}
1648
1901
  {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
1649
-
1902
+ {(config.orientation === 'horizontal' || config.visualizationType === 'Paired Bar') && <TextField type='number' value={config.barSpace || '15'} fieldName='barSpace' label='Bar Space' updateField={updateField} min='0' />}
1650
1903
  {(config.visualizationType === 'Bar' || config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.topAxis.hasLine} section='topAxis' fieldName='hasLine' label='Add Top Axis Line' updateField={updateField} />}
1651
1904
 
1652
1905
  {config.visualizationType === 'Spark Line' && (
@@ -1658,6 +1911,11 @@ const EditorPanel = () => {
1658
1911
  <CheckBox value={config.visual?.hideBackgroundColor} section='visual' fieldName='hideBackgroundColor' label='Hide Background Color' updateField={updateField} />
1659
1912
  </div>
1660
1913
  )}
1914
+
1915
+ {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.showLineSeriesLabels} fieldName='showLineSeriesLabels' label='Append Series Name to End of Line Charts' updateField={updateField} />}
1916
+ {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && config.showLineSeriesLabels && (
1917
+ <CheckBox value={config.colorMatchLineSeriesLabels} fieldName='colorMatchLineSeriesLabels' label='Match Series Color to Name at End of Line Charts' updateField={updateField} />
1918
+ )}
1661
1919
  </AccordionItemPanel>
1662
1920
  </AccordionItem>
1663
1921
 
@@ -1706,6 +1964,9 @@ const EditorPanel = () => {
1706
1964
  {config.table.limitHeight && <TextField value={config.table.height} section='table' fieldName='height' label='Data Table Height' type='number' min='0' max='500' placeholder='Height(px)' updateField={updateField} />}
1707
1965
  <CheckBox value={config.table.expanded} section='table' fieldName='expanded' label='Expanded by Default' updateField={updateField} />
1708
1966
  <CheckBox value={config.table.download} section='table' fieldName='download' label='Display Download Button' updateField={updateField} />
1967
+ <CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Display Link to Dataset' updateField={updateField} />
1968
+ {/* <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} /> */}
1969
+ {/* <CheckBox value={config.table.showDownloadPdfButton} section='table' fieldName='showDownloadPdfButton' label='Display PDF Button' updateField={updateField} /> */}
1709
1970
  <TextField value={config.table.label} section='table' fieldName='label' label='Label' updateField={updateField} />
1710
1971
  {config.visualizationType !== 'Pie' && <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />}
1711
1972
  </AccordionItemPanel>
@@ -1715,7 +1976,7 @@ const EditorPanel = () => {
1715
1976
  {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />}
1716
1977
  </section>
1717
1978
  </section>
1718
- </ErrorBoundary>
1979
+ </ErrorBoundary >
1719
1980
  )
1720
1981
  }
1721
1982