@fundar/data-chart-telling 1.15.0 → 1.17.0

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 (197) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/configuration/ConfigVars.svelte +14 -0
  3. package/dist/configuration/ConfigVars.svelte.d.ts +3 -0
  4. package/dist/configuration/config.svelte.d.ts +5 -0
  5. package/dist/configuration/config.svelte.js +18 -4
  6. package/dist/configuration/themes/dark.js +1 -1
  7. package/dist/configuration/themes/editorial.js +1 -1
  8. package/dist/index.d.ts +6 -3
  9. package/dist/index.js +2 -1
  10. package/dist/layout/base/BasePlotLayout.svelte +1 -1
  11. package/dist/layout/figure/Figure.svelte +5 -12
  12. package/dist/layout/figure/FigureChrome.svelte +2 -10
  13. package/dist/layout/geometry/GeometryLayout.svelte +42 -1
  14. package/dist/layout/hover/HoverSettings.d.ts +3 -1
  15. package/dist/layout/hover/HoverSettings.js +4 -2
  16. package/dist/layout/legend/DisabledStyle.d.ts +1 -1
  17. package/dist/layout/legend/DisabledStyle.js +1 -1
  18. package/dist/layout/legend/DiscreteBadgeItem.svelte +1 -1
  19. package/dist/layout/legend/DiscreteSection.svelte +1 -1
  20. package/dist/layout/legend/LegendState.svelte.d.ts +12 -2
  21. package/dist/layout/legend/LegendState.svelte.js +18 -4
  22. package/dist/layout/legend/LegendText.d.ts +4 -1
  23. package/dist/layout/legend/LegendText.js +7 -1
  24. package/dist/layout/margins/PlotMargins.svelte.d.ts +2 -2
  25. package/dist/layout/margins/PlotMargins.svelte.js +2 -2
  26. package/dist/layout/plot/Plot.svelte +4 -2
  27. package/dist/layout/plot/Plot.svelte.d.ts +2 -1
  28. package/dist/layout/scales/ScalesLayout.svelte +1 -1
  29. package/dist/layout/styles/ValueLabels.d.ts +33 -2
  30. package/dist/layout/styles/ValueLabels.js +67 -8
  31. package/dist/layout/timeline/Timeline.svelte +5 -1
  32. package/dist/layout/timeline/TimelineLayout.svelte +4 -1
  33. package/dist/layout/timeline/TimelineSteps.d.ts +6 -2
  34. package/dist/layout/timeline/TimelineSteps.js +9 -3
  35. package/dist/markers/area/AreaMarker.svelte +3 -0
  36. package/dist/markers/arrow/ArrowMarker.svelte +9 -5
  37. package/dist/markers/bar/BarMarker.svelte +45 -48
  38. package/dist/markers/bollinger/BollingerMarker.svelte +3 -0
  39. package/dist/markers/box/BoxMarker.svelte +3 -1
  40. package/dist/markers/cell/CellMarker.svelte +11 -7
  41. package/dist/markers/contour/ContourMarker.svelte +3 -0
  42. package/dist/markers/delaunay/DelaunayLinkMarker.svelte +9 -5
  43. package/dist/markers/delaunay/DelaunayMeshMarker.svelte +3 -0
  44. package/dist/markers/density/DensityMarker.svelte +3 -0
  45. package/dist/markers/difference/DifferenceMarker.svelte +3 -0
  46. package/dist/markers/dot/DotMarker.svelte +11 -6
  47. package/dist/markers/geo/GraticuleMarker.svelte +3 -0
  48. package/dist/markers/geo/SphereMarker.svelte +3 -0
  49. package/dist/markers/hover/HoverMarker.svelte +22 -6
  50. package/dist/markers/hull/HullMarker.svelte +3 -0
  51. package/dist/markers/image/ImageMarker.svelte +3 -0
  52. package/dist/markers/line/LineMarker.svelte +3 -0
  53. package/dist/markers/link/LinkMarker.svelte +3 -0
  54. package/dist/markers/raster/RasterMarker.svelte +3 -0
  55. package/dist/markers/rect/RectMarker.svelte +25 -17
  56. package/dist/markers/regression/RegressionMarker.svelte +3 -0
  57. package/dist/markers/rule/RuleMarker.svelte +15 -5
  58. package/dist/markers/text/TextFit.d.ts +44 -0
  59. package/dist/markers/text/TextFit.js +86 -0
  60. package/dist/markers/text/TextMarker.svelte +186 -90
  61. package/dist/markers/text/TextMarker.svelte.d.ts +2 -0
  62. package/dist/markers/tick/TickMarker.svelte +9 -3
  63. package/dist/markers/trail/TrailMarker.svelte +3 -0
  64. package/dist/markers/utils/BoxLabel.d.ts +58 -0
  65. package/dist/markers/utils/BoxLabel.js +175 -0
  66. package/dist/markers/utils/MarkerEvents.d.ts +23 -0
  67. package/dist/markers/utils/MarkerEvents.js +44 -0
  68. package/dist/markers/utils/MarkerLabel.svelte +33 -0
  69. package/dist/markers/utils/MarkerLabel.svelte.d.ts +10 -0
  70. package/dist/markers/utils/RowStroke.d.ts +9 -21
  71. package/dist/markers/utils/RowStroke.js +10 -21
  72. package/dist/markers/utils/RowStyle.d.ts +26 -0
  73. package/dist/markers/utils/RowStyle.js +55 -0
  74. package/dist/markers/vector/VectorMarker.svelte +3 -0
  75. package/dist/markers/voronoi/VoronoiMarker.svelte +9 -5
  76. package/dist/markers/voronoi/VoronoiMeshMarker.svelte +3 -0
  77. package/dist/markers/waffle/WaffleMarker.svelte +9 -5
  78. package/dist/phases/Pipeline.d.ts +3 -1
  79. package/dist/phases/Pipeline.js +1 -0
  80. package/dist/phases/data/DataPhase.js +51 -10
  81. package/dist/phases/hover/HoverPhase.js +9 -1
  82. package/dist/phases/mapping/MappingPhase.js +2 -1
  83. package/dist/phases/markers/MarkerStyles.d.ts +18 -0
  84. package/dist/phases/markers/MarkerStyles.js +111 -0
  85. package/dist/phases/markers/MarkersPhase.d.ts +1 -1
  86. package/dist/phases/markers/MarkersPhase.js +7 -5
  87. package/dist/phases/statistics/StatisticsPhase.js +1 -1
  88. package/dist/phases/transforms/Transforms.js +3 -1
  89. package/dist/phases/transforms/TransformsPhase.js +58 -4
  90. package/dist/phases/transforms/methods/TreemapTransform.d.ts +28 -0
  91. package/dist/phases/transforms/methods/TreemapTransform.js +119 -0
  92. package/dist/plots/correlation/heatmap/defaults.js +2 -2
  93. package/dist/plots/correlation/heatmap/markers.d.ts +0 -8
  94. package/dist/plots/correlation/heatmap/markers.js +8 -35
  95. package/dist/plots/correlation/scatter/markers.d.ts +1 -1
  96. package/dist/plots/correlation/scatter/markers.js +2 -2
  97. package/dist/plots/distribution/histogram/defaults.js +2 -2
  98. package/dist/plots/distribution/histogram/markers.d.ts +1 -10
  99. package/dist/plots/distribution/histogram/markers.js +17 -59
  100. package/dist/plots/distribution/pyramid/defaults.js +3 -3
  101. package/dist/plots/distribution/pyramid/markers.d.ts +0 -10
  102. package/dist/plots/distribution/pyramid/markers.js +13 -64
  103. package/dist/plots/distribution/violin/markers.js +1 -1
  104. package/dist/plots/map/geo/phases/markers.js +3 -2
  105. package/dist/plots/part-of-a-whole/treemap/Plot.svelte +47 -0
  106. package/dist/plots/part-of-a-whole/treemap/Plot.svelte.d.ts +26 -0
  107. package/dist/plots/part-of-a-whole/treemap/defaults.d.ts +10 -0
  108. package/dist/plots/part-of-a-whole/treemap/defaults.js +167 -0
  109. package/dist/plots/ranking/bar/defaults.js +2 -2
  110. package/dist/plots/ranking/bar/markers.d.ts +1 -11
  111. package/dist/plots/ranking/bar/markers.js +38 -80
  112. package/dist/plots/ranking/bullet/markers.js +2 -3
  113. package/dist/plots/ranking/cleveland/ClevelandMarkers.js +17 -13
  114. package/dist/types/configuration/styling.d.ts +33 -2
  115. package/dist/types/layout/legend.d.ts +8 -1
  116. package/dist/types/layout/mapping.d.ts +12 -3
  117. package/dist/types/layout/scales.d.ts +6 -0
  118. package/dist/types/layout/tooltip.d.ts +16 -4
  119. package/dist/types/markers/axis/arrow.d.ts +2 -8
  120. package/dist/types/markers/axis/bar.d.ts +4 -8
  121. package/dist/types/markers/axis/cell.d.ts +5 -5
  122. package/dist/types/markers/axis/delaunayLink.d.ts +2 -2
  123. package/dist/types/markers/axis/rect.d.ts +4 -8
  124. package/dist/types/markers/axis/rule.d.ts +2 -16
  125. package/dist/types/markers/axis/tick.d.ts +2 -2
  126. package/dist/types/markers/axis/voronoi.d.ts +2 -2
  127. package/dist/types/markers/axis/waffle.d.ts +4 -3
  128. package/dist/types/markers/basic/dot.d.ts +2 -2
  129. package/dist/types/markers/basic/text.d.ts +56 -14
  130. package/dist/types/markers/channels/commonMarkerConfig.d.ts +4 -1
  131. package/dist/types/markers/channels/commonMarkerConfigWithArea.d.ts +1 -2
  132. package/dist/types/markers/channels/commonMarkerConfigWithLabel.d.ts +10 -0
  133. package/dist/types/markers/channels/commonMarkerConfigWithLabel.js +1 -0
  134. package/dist/types/markers/channels/commonMarkerEvents.d.ts +17 -0
  135. package/dist/types/markers/channels/commonMarkerEvents.js +13 -0
  136. package/dist/types/markers/geo/contour.d.ts +2 -1
  137. package/dist/types/markers/geo/graticule.d.ts +2 -1
  138. package/dist/types/markers/geo/link.d.ts +2 -1
  139. package/dist/types/markers/geo/sphere.d.ts +2 -1
  140. package/dist/types/markers/geo/vector.d.ts +2 -1
  141. package/dist/types/phases/data/phase.d.ts +5 -0
  142. package/dist/types/phases/hover/phase.d.ts +2 -0
  143. package/dist/types/phases/state.d.ts +7 -0
  144. package/dist/types/phases/statistics/phase.d.ts +2 -1
  145. package/dist/types/phases/transforms/phase.d.ts +11 -0
  146. package/dist/types/plots/constants.d.ts +14 -14
  147. package/dist/types/plots/correlation/heatmap/props.d.ts +3 -3
  148. package/dist/types/plots/correlation/scatter/props.d.ts +3 -3
  149. package/dist/types/plots/data/common.d.ts +19 -6
  150. package/dist/types/plots/data/geo.d.ts +1 -1
  151. package/dist/types/plots/distribution/box/props.d.ts +3 -3
  152. package/dist/types/plots/distribution/density/props.d.ts +3 -11
  153. package/dist/types/plots/distribution/histogram/props.d.ts +3 -11
  154. package/dist/types/plots/distribution/pyramid/props.d.ts +3 -3
  155. package/dist/types/plots/distribution/violin/props.d.ts +3 -3
  156. package/dist/types/plots/evolution/area/props.d.ts +3 -3
  157. package/dist/types/plots/evolution/line/props.d.ts +3 -3
  158. package/dist/types/plots/part-of-a-whole/treemap/props.d.ts +19 -0
  159. package/dist/types/plots/part-of-a-whole/treemap/props.js +1 -0
  160. package/dist/types/plots/part-of-a-whole/treemap/state.d.ts +6 -0
  161. package/dist/types/plots/part-of-a-whole/treemap/state.js +1 -0
  162. package/dist/types/plots/props.d.ts +7 -4
  163. package/dist/types/plots/ranking/bar/props.d.ts +3 -3
  164. package/dist/types/plots/ranking/cleveland/props.d.ts +3 -3
  165. package/dist/types/plots/ranking/dumbbell/props.d.ts +3 -3
  166. package/dist/types/plots/ranking/forest/props.d.ts +3 -3
  167. package/dist/types/plots/ranking/lollipop/props.d.ts +3 -3
  168. package/dist/types/plots/styling.d.ts +24 -0
  169. package/dist/types/transforms/index.d.ts +3 -1
  170. package/dist/types/transforms/treemap.d.ts +32 -0
  171. package/dist/types/transforms/treemap.js +5 -0
  172. package/dist/utils/color/ColorTones.d.ts +19 -0
  173. package/dist/utils/color/ColorTones.js +64 -0
  174. package/dist/utils/color/CssColor.d.ts +14 -5
  175. package/dist/utils/color/CssColor.js +69 -27
  176. package/dist/utils/color/index.d.ts +4 -0
  177. package/dist/utils/color/index.js +4 -0
  178. package/dist/utils/grouping.d.ts +18 -1
  179. package/dist/utils/grouping.js +31 -0
  180. package/docs/concepts.md +3 -2
  181. package/docs/legend.md +8 -5
  182. package/docs/markers.md +76 -26
  183. package/docs/plots/part-of-a-whole/treemap.md +69 -0
  184. package/docs/plots/ranking/bar.md +1 -1
  185. package/docs/plots.md +21 -20
  186. package/docs/scales.md +3 -0
  187. package/docs/state.md +1 -1
  188. package/docs/styles-and-segments.md +19 -18
  189. package/docs/theming.md +5 -12
  190. package/docs/tooltip-and-hover.md +1 -1
  191. package/docs/transforms-and-statistics.md +17 -16
  192. package/examples/Treemap.svelte +13 -0
  193. package/examples/datasets/economic-activity.ts +40 -0
  194. package/examples/datasets/index.ts +1 -0
  195. package/llms-full.txt +5 -5
  196. package/llms.txt +2 -0
  197. package/package.json +3 -1
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { BarSegmentStyle } from '../../segments/common';
2
+ import type { AxisPlotState, AxisPlotCtx } from '../../../phases';
3
+ /** TreemapPlot's pipeline state: the shared axis-based state, over a unit square its tiles are laid out in. */
4
+ export type TreemapPlotState<TData extends Record<string, unknown>> = AxisPlotState<TData, BarSegmentStyle>;
5
+ /** The environment every TreemapPlot phase reads from, alongside the growing state. */
6
+ export type TreemapPlotCtx = AxisPlotCtx;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,6 @@
1
1
  import type { Pipeline } from '../../phases/Pipeline';
2
2
  import type { Snippet } from 'svelte';
3
- import type { TooltipOptions, TooltipProp } from '../layout/tooltip';
3
+ import type { TooltipContext, TooltipOptions, TooltipProp } from '../layout/tooltip';
4
4
  import type { HoverPoint, HoverStrategy } from '../layout/hover';
5
5
  import type { LegendExtension, LegendSection } from '../layout/legend';
6
6
  import type { FacetConfig, FacetScoped } from '../layout/facet';
@@ -188,9 +188,12 @@ export type FigureBoxProps = GridPlacement & {
188
188
  width?: number;
189
189
  height?: number;
190
190
  };
191
- /** A plot component's public props: its core props, chrome, `timeline`, `facet` and an author-facing `tooltip`. */
192
- export type BasePlotProps<TDataContract, TRow extends Record<string, unknown>, TStyles extends object, TSegmentStyle extends object, TMarker, TScales extends ScalesConfig<TRow>, TCoordinates = undefined> = TDataContract & Omit<PlotCommonProps<TStyles, TSegmentStyle, TMarker, TScales, TCoordinates>, 'width' | 'height'> & FigureBoxProps & PlotChromeProps & {
193
- tooltip?: TooltipProp<TRow>;
191
+ /**
192
+ * A plot component's public props: its core props, chrome, `timeline`, `facet` and an author-facing `tooltip`,
193
+ * whose `format` gets the kind's `TTooltipContext`.
194
+ */
195
+ export type BasePlotProps<TDataContract, TRow extends Record<string, unknown>, TStyles extends object, TSegmentStyle extends object, TMarker, TScales extends ScalesConfig<TRow>, TCoordinates = undefined, TTooltipContext extends TooltipContext = TooltipContext> = TDataContract & Omit<PlotCommonProps<TStyles, TSegmentStyle, TMarker, TScales, TCoordinates>, 'width' | 'height'> & FigureBoxProps & PlotChromeProps & {
196
+ tooltip?: TooltipProp<TRow, TTooltipContext>;
194
197
  timeline?: TimelineConfig<TRow>;
195
198
  facet?: FacetConfig<TRow>;
196
199
  };
@@ -1,10 +1,10 @@
1
1
  import type { BasePlotProps, PlotCoreProps } from '../../props';
2
2
  import type { AxisBasedScalesConfig } from '../../../layout/scales';
3
3
  import type { AxisBasedMarkersConfig } from '../../../markers/common';
4
- import type { SeriesProps, DataProps } from '../../data/common';
4
+ import type { SeriesProps, DualAxisDataProps } from '../../data/common';
5
5
  import type { GapsAwarePlotStylesConfig } from '../../../layout/styles';
6
6
  import type { BarSegmentStyle } from '../../segments/common';
7
7
  /** `BarPlot`'s public props. */
8
- export type BarPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, GapsAwarePlotStylesConfig<BarSegmentStyle>, BarSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
8
+ export type BarPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, GapsAwarePlotStylesConfig<BarSegmentStyle>, BarSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
9
9
  /** What `BarPlot`'s core draws from. */
10
- export type BarPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DataProps<TData>, TData, GapsAwarePlotStylesConfig<BarSegmentStyle>, BarSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
10
+ export type BarPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, GapsAwarePlotStylesConfig<BarSegmentStyle>, BarSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
@@ -1,10 +1,10 @@
1
1
  import type { BasePlotProps, PlotCoreProps } from '../../props';
2
2
  import type { AxisBasedScalesConfig } from '../../../layout/scales';
3
3
  import type { AxisBasedMarkersConfig } from '../../../markers/common';
4
- import type { SeriesProps, DataProps } from '../../data/common';
4
+ import type { SeriesProps, DualAxisDataProps } from '../../data/common';
5
5
  import type { ConnectorBasedStylesConfig } from '../../../layout/styles';
6
6
  import type { LineSegmentStyle } from '../../segments/common';
7
7
  /** `ClevelandPlot`'s public props. */
8
- export type ClevelandPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
8
+ export type ClevelandPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
9
9
  /** What `ClevelandPlot`'s core draws from. */
10
- export type ClevelandPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
10
+ export type ClevelandPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
@@ -1,10 +1,10 @@
1
1
  import type { BasePlotProps, PlotCoreProps } from '../../props';
2
2
  import type { AxisBasedScalesConfig } from '../../../layout/scales';
3
3
  import type { AxisBasedMarkersConfig } from '../../../markers/common';
4
- import type { SeriesProps, DataProps } from '../../data/common';
4
+ import type { SeriesProps, DualAxisDataProps } from '../../data/common';
5
5
  import type { ConnectorBasedStylesConfig } from '../../../layout/styles';
6
6
  import type { LineSegmentStyle } from '../../segments/common';
7
7
  /** `DumbbellPlot`'s public props. */
8
- export type DumbbellPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
8
+ export type DumbbellPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
9
9
  /** What `DumbbellPlot`'s core draws from. */
10
- export type DumbbellPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
10
+ export type DumbbellPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
@@ -1,7 +1,7 @@
1
1
  import type { BasePlotProps, PlotCoreProps } from '../../props';
2
2
  import type { AxisBasedScalesConfig } from '../../../layout/scales';
3
3
  import type { AxisBasedMarkersConfig } from '../../../markers/common';
4
- import type { SeriesProps, DataProps, Accessor } from '../../data/common';
4
+ import type { SeriesProps, DualAxisDataProps, Accessor } from '../../data/common';
5
5
  import type { ConnectorBasedStylesConfig } from '../../../layout/styles';
6
6
  import type { LineSegmentStyle } from '../../segments/common';
7
7
  /**
@@ -18,6 +18,6 @@ export type ForestIntervalProps<TData extends Record<string, unknown>> = {
18
18
  error?: Accessor<TData, number>;
19
19
  };
20
20
  /** `ForestPlot`'s public props. */
21
- export type ForestPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>> & ForestIntervalProps<TData>;
21
+ export type ForestPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>> & ForestIntervalProps<TData>;
22
22
  /** What `ForestPlot`'s core draws from. */
23
- export type ForestPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>> & ForestIntervalProps<TData>;
23
+ export type ForestPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>> & ForestIntervalProps<TData>;
@@ -1,10 +1,10 @@
1
1
  import type { BasePlotProps, PlotCoreProps } from '../../props';
2
2
  import type { AxisBasedScalesConfig } from '../../../layout/scales';
3
3
  import type { AxisBasedMarkersConfig } from '../../../markers/common';
4
- import type { SeriesProps, DataProps } from '../../data/common';
4
+ import type { SeriesProps, DualAxisDataProps } from '../../data/common';
5
5
  import type { ConnectorBasedStylesConfig } from '../../../layout/styles';
6
6
  import type { LineSegmentStyle } from '../../segments/common';
7
7
  /** `LollipopPlot`'s public props. */
8
- export type LollipopPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
8
+ export type LollipopPlotProps<TData extends Record<string, unknown>> = BasePlotProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
9
9
  /** What `LollipopPlot`'s core draws from. */
10
- export type LollipopPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
10
+ export type LollipopPlotCoreProps<TData extends Record<string, unknown>> = PlotCoreProps<SeriesProps<TData> | DualAxisDataProps<TData>, TData, ConnectorBasedStylesConfig, LineSegmentStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
@@ -53,3 +53,27 @@ export type AreaStyle = {
53
53
  strokeDasharray?: string | LineStyle;
54
54
  borderRadius?: number;
55
55
  };
56
+ /** How far a shape is pulled in from its edges, in pixels (a bar's, as a fraction of its band): `inset` on all sides, or each side's own. */
57
+ export type InsetStyle = {
58
+ inset?: number;
59
+ insetTop?: number;
60
+ insetRight?: number;
61
+ insetBottom?: number;
62
+ insetLeft?: number;
63
+ };
64
+ /** How far a shape with a direction (an arrow) is pulled in from its ends, in pixels: `inset` at both, or `insetStart` and `insetEnd` each. */
65
+ export type DirectedInsetStyle = {
66
+ inset?: number;
67
+ insetStart?: number;
68
+ insetEnd?: number;
69
+ };
70
+ /**
71
+ * A style as a value, or as a function of the row a shape draws - a different value for each one.
72
+ * A number can also be the name of a field of the rows; so can a color, when the rows have a field
73
+ * of that name.
74
+ */
75
+ export type RowValue<T> = T | (T extends number ? string : never) | ((row: any) => T);
76
+ /** A style whose every field can be a function of the row ({@link RowValue}). */
77
+ export type PerRow<TStyle> = {
78
+ [K in keyof TStyle]?: RowValue<NonNullable<TStyle[K]>>;
79
+ };
@@ -12,6 +12,7 @@ import type { SortTransform, ShuffleTransform, ReverseTransform } from './sort';
12
12
  import type { FilterTransform } from './filter';
13
13
  import type { SelectTransform, SelectShorthandTransform } from './select';
14
14
  import type { GroupXTransform, GroupYTransform, GroupZTransform, Group2DTransform } from './group';
15
+ import type { TreemapTransform } from './treemap';
15
16
  export type { TransformChannel, TransformReducer, PositionChannels } from './common';
16
17
  export type { StackXTransform, StackYTransform, StackMosaicXTransform, StackMosaicYTransform } from './stack';
17
18
  export type { BinXTransform, BinYTransform, Bin2DTransform } from './bin';
@@ -27,10 +28,11 @@ export type { SortBy, SortTransform, ShuffleTransform, ReverseTransform } from '
27
28
  export type { FilterTransform } from './filter';
28
29
  export type { SelectBy, SelectTransform, SelectShorthandTransform } from './select';
29
30
  export type { GroupXTransform, GroupYTransform, GroupZTransform, Group2DTransform } from './group';
31
+ export type { TreemapTile, TreemapTransform } from './treemap';
30
32
  /**
31
33
  * Every svelteplot transform a marker (via `CommonMarkerConfig.transforms`) or
32
34
  * a plot (via its `transforms` prop) can run on its rows before they're drawn.
33
35
  * Each one is a flat object: `type` picks the transform, and the rest are its
34
36
  * own channels and options, by svelteplot's own names.
35
37
  */
36
- export type MarkerTransform = StackYTransform | StackXTransform | StackMosaicXTransform | StackMosaicYTransform | BinXTransform | BinYTransform | Bin2DTransform | DensityXTransform | DensityYTransform | WindowXTransform | WindowYTransform | BollingerXTransform | BollingerYTransform | NormalizeXTransform | NormalizeYTransform | NormalizeParallelXTransform | NormalizeParallelYTransform | MapXTransform | MapYTransform | IntervalXTransform | IntervalYTransform | JitterXTransform | JitterYTransform | ShiftXTransform | ShiftYTransform | SortTransform | ShuffleTransform | ReverseTransform | FilterTransform | SelectTransform | SelectShorthandTransform | GroupXTransform | GroupYTransform | GroupZTransform | Group2DTransform;
38
+ export type MarkerTransform = StackYTransform | StackXTransform | StackMosaicXTransform | StackMosaicYTransform | BinXTransform | BinYTransform | Bin2DTransform | DensityXTransform | DensityYTransform | WindowXTransform | WindowYTransform | BollingerXTransform | BollingerYTransform | NormalizeXTransform | NormalizeYTransform | NormalizeParallelXTransform | NormalizeParallelYTransform | MapXTransform | MapYTransform | IntervalXTransform | IntervalYTransform | JitterXTransform | JitterYTransform | ShiftXTransform | ShiftYTransform | SortTransform | ShuffleTransform | ReverseTransform | FilterTransform | SelectTransform | SelectShorthandTransform | GroupXTransform | GroupYTransform | GroupZTransform | Group2DTransform | TreemapTransform;
@@ -0,0 +1,32 @@
1
+ import type { TransformChannel } from './common';
2
+ /** How a treemap splits a rectangle among its children. */
3
+ export type TreemapTile = 'squarify' | 'binary' | 'slice' | 'dice' | 'sliceDice';
4
+ /** Channels the treemap reads: the rows, and each one's `value` - what its tile's area is. */
5
+ export type TreemapChannels = {
6
+ data?: Record<string, unknown>[];
7
+ value?: TransformChannel;
8
+ };
9
+ /** The keys of {@link TreemapChannels}, at runtime. */
10
+ export declare const TREEMAP_CHANNEL_KEYS: Record<keyof TreemapChannels, true>;
11
+ /** Options the treemap takes, flat next to the channels. */
12
+ type TreemapOptions = {
13
+ /**
14
+ * What the tiles nest by: one reader per level, outermost first. Rows with the same value at every
15
+ * level are one tile, whose area is their values' sum, and the last level names it. Without levels,
16
+ * every row is part of a single tile.
17
+ */
18
+ levels?: TransformChannel[];
19
+ /** How a rectangle is split among its tiles. Defaults to `'squarify'`, which keeps them close to squares. */
20
+ tile?: TreemapTile;
21
+ /** The width over the height of the box the tiles fill, which squarified tiles aim to be square in. Defaults to `1`. */
22
+ aspect?: number;
23
+ };
24
+ /**
25
+ * `treemap` as a marker transform: a tile per distinct path of `levels`, laid out in the unit square with
26
+ * d3-hierarchy, its area its summed `value`. Produces `x1`/`x2`/`y1`/`y2` for a `rect` marker, and `x`/`y`
27
+ * at each tile's centre; each row also carries its tile's name, path, value and share (see `TREEMAP_ROW`).
28
+ */
29
+ export type TreemapTransform = {
30
+ type: 'treemap';
31
+ } & TreemapChannels & TreemapOptions;
32
+ export {};
@@ -0,0 +1,5 @@
1
+ /** The keys of {@link TreemapChannels}, at runtime. */
2
+ export const TREEMAP_CHANNEL_KEYS = {
3
+ data: true,
4
+ value: true
5
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Tones of a color, and the colors of a hierarchy made of them: each outermost value keeps its categorical
3
+ * color, and the values under it take tones of it, so the parts of one group read as one family. For any plot
4
+ * whose rows nest (a treemap, an icicle, a sunburst, a map of the votes of several parties).
5
+ */
6
+ export declare class ColorTones {
7
+ /** How far the lightest tone goes from the color toward white. */
8
+ static readonly LIGHTEST = 0.6;
9
+ /** `count` tones of `color`: the color itself first, then lighter ones; a single one is the color itself. */
10
+ static of(color: string, count: number): string[];
11
+ /**
12
+ * The color of every path of a hierarchy, its levels outermost first, colored down to level `depth`: the
13
+ * outermost value takes the color `colorOf` gives it, and each distinct path down to `depth` under it a
14
+ * tone of that color - the first of them the color itself - siblings next to each other in the order they
15
+ * first appear. `depth` 1 is the
16
+ * outermost color alone; a path shorter than `depth` is colored by all of it.
17
+ */
18
+ static hierarchy(paths: readonly (readonly string[])[], depth: number, colorOf: (outermost: string) => string): (path: readonly string[]) => string;
19
+ }
@@ -0,0 +1,64 @@
1
+ import { interpolateLab, interpolateRgb } from 'd3-interpolate';
2
+ import { CssColor } from './CssColor';
3
+ /**
4
+ * Tones of a color, and the colors of a hierarchy made of them: each outermost value keeps its categorical
5
+ * color, and the values under it take tones of it, so the parts of one group read as one family. For any plot
6
+ * whose rows nest (a treemap, an icicle, a sunburst, a map of the votes of several parties).
7
+ */
8
+ export class ColorTones {
9
+ /** How far the lightest tone goes from the color toward white. */
10
+ static LIGHTEST = 0.6;
11
+ /** `count` tones of `color`: the color itself first, then lighter ones; a single one is the color itself. */
12
+ static of(color, count) {
13
+ const base = CssColor.resolve(color);
14
+ if (count <= 1)
15
+ return count === 1 ? [base] : [];
16
+ const ramp = interpolateLab(base, interpolateRgb(base, '#fff')(ColorTones.LIGHTEST));
17
+ return Array.from({ length: count }, (_, i) => (i === 0 ? base : ramp(i / (count - 1))));
18
+ }
19
+ /**
20
+ * The color of every path of a hierarchy, its levels outermost first, colored down to level `depth`: the
21
+ * outermost value takes the color `colorOf` gives it, and each distinct path down to `depth` under it a
22
+ * tone of that color - the first of them the color itself - siblings next to each other in the order they
23
+ * first appear. `depth` 1 is the
24
+ * outermost color alone; a path shorter than `depth` is colored by all of it.
25
+ */
26
+ static hierarchy(paths, depth, colorOf) {
27
+ const keyOf = (path) => JSON.stringify(path.slice(0, Math.max(1, Math.floor(depth))));
28
+ if (depth <= 1)
29
+ return (path) => colorOf(path[0]);
30
+ // Where each partial path first appears, so siblings sort together and in the data's own order.
31
+ const first = new Map();
32
+ const prefixes = new Map();
33
+ for (const path of paths) {
34
+ const own = JSON.parse(keyOf(path));
35
+ own.forEach((_, i) => {
36
+ const partial = JSON.stringify(own.slice(0, i + 1));
37
+ if (!first.has(partial))
38
+ first.set(partial, first.size);
39
+ });
40
+ prefixes.set(keyOf(path), own);
41
+ }
42
+ const rank = (path) => path.map((_, i) => first.get(JSON.stringify(path.slice(0, i + 1))) ?? 0);
43
+ const byOutermost = new Map();
44
+ for (const prefix of prefixes.values()) {
45
+ const group = byOutermost.get(prefix[0]) ?? [];
46
+ group.push(prefix);
47
+ byOutermost.set(prefix[0], group);
48
+ }
49
+ const colors = new Map();
50
+ for (const [outermost, group] of byOutermost) {
51
+ group.sort((a, b) => {
52
+ const [ra, rb] = [rank(a), rank(b)];
53
+ for (let i = 0; i < Math.max(ra.length, rb.length); i++) {
54
+ if ((ra[i] ?? -1) !== (rb[i] ?? -1))
55
+ return (ra[i] ?? -1) - (rb[i] ?? -1);
56
+ }
57
+ return 0;
58
+ });
59
+ const tones = ColorTones.of(colorOf(outermost), group.length);
60
+ group.forEach((prefix, i) => colors.set(JSON.stringify(prefix), tones[i]));
61
+ }
62
+ return (path) => colors.get(keyOf(path)) ?? colorOf(path[0]);
63
+ }
64
+ }
@@ -8,12 +8,21 @@ export declare class CssColor {
8
8
  static parse(color: string): Rgb | null;
9
9
  /** WCAG contrast ratio between two colors, from 1 (no contrast) to 21 (black on white). */
10
10
  static contrastRatio(colorA: string, colorB: string): number;
11
+ /** The WCAG 2 AA contrast ratio for normal text. */
12
+ static readonly AA = 4.5;
11
13
  /**
12
- * The `candidates` entry with the highest WCAG contrast ratio against
13
- * `background`. Defaults to plain white/black; pass a grayscale or other
14
- * palette to widen the choice. Falls back to the first candidate when
15
- * `background` can't be parsed.
14
+ * The `candidates` entry with the highest WCAG contrast ratio against an opaque `background`. Defaults to plain
15
+ * white/black; pass a grayscale or other palette to widen the choice. When none reaches `minRatio` (WCAG AA for
16
+ * normal text by default), white or black is taken instead, whichever reads better - one of them always reaches
17
+ * 4.5 on an opaque color. Falls back to the first candidate when `background` can't be parsed.
16
18
  */
17
- static contrastText(background: string, candidates?: string[]): string;
19
+ static contrastText(background: string, candidates?: string[], minRatio?: number): string;
20
+ /** The opacity of a CSS color, from 0 to 1: its alpha (`rgba()`, `#rrggbbaa`...), 0 for `transparent`, else 1. */
21
+ static alpha(color: string): number;
22
+ /**
23
+ * The opaque color `color` is seen as, drawn at `opacity` (times its own alpha) over `backdrop`, as a browser
24
+ * blends it. A backdrop that is not opaque counts as white, the page under it. `color` as it is when unreadable.
25
+ */
26
+ static composite(color: string, opacity?: number, backdrop?: string): string;
18
27
  }
19
28
  export {};
@@ -13,17 +13,9 @@ export class CssColor {
13
13
  }
14
14
  /** Parses any CSS color syntax (hex, rgb(), oklch(), named colors, hsl(), ...) into an `[r, g, b]` (0-255) triple, or `null` if it can't be resolved. */
15
15
  static parse(color) {
16
- const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color.trim());
17
- if (hex) {
18
- const digits = hex[1].length === 3
19
- ? hex[1]
20
- .split('')
21
- .map((c) => c + c)
22
- .join('')
23
- : hex[1];
24
- const num = parseInt(digits, 16);
25
- return [(num >> 16) & 255, (num >> 8) & 255, num & 255];
26
- }
16
+ const hex = CssColor.#hex(color);
17
+ if (hex)
18
+ return [hex[0], hex[1], hex[2]];
27
19
  const rgb = /^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i.exec(color);
28
20
  if (rgb)
29
21
  return [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];
@@ -53,30 +45,80 @@ export class CssColor {
53
45
  const lB = CssColor.#luminance(b);
54
46
  return (Math.max(lA, lB) + 0.05) / (Math.min(lA, lB) + 0.05);
55
47
  }
48
+ /** The WCAG 2 AA contrast ratio for normal text. */
49
+ static AA = 4.5;
56
50
  /**
57
- * The `candidates` entry with the highest WCAG contrast ratio against
58
- * `background`. Defaults to plain white/black; pass a grayscale or other
59
- * palette to widen the choice. Falls back to the first candidate when
60
- * `background` can't be parsed.
51
+ * The `candidates` entry with the highest WCAG contrast ratio against an opaque `background`. Defaults to plain
52
+ * white/black; pass a grayscale or other palette to widen the choice. When none reaches `minRatio` (WCAG AA for
53
+ * normal text by default), white or black is taken instead, whichever reads better - one of them always reaches
54
+ * 4.5 on an opaque color. Falls back to the first candidate when `background` can't be parsed.
61
55
  */
62
- static contrastText(background, candidates = ['#ffffff', '#000000']) {
56
+ static contrastText(background, candidates = ['#ffffff', '#000000'], minRatio = CssColor.AA) {
57
+ const best = (colors) => colors.reduce((top, color) => {
58
+ const ratio = CssColor.contrastRatio(background, color);
59
+ return ratio > top.ratio ? { color, ratio } : top;
60
+ }, { color: colors[0], ratio: -Infinity });
63
61
  if (candidates.length === 0)
64
62
  return '#000000';
65
- let best = candidates[0];
66
- let bestRatio = -Infinity;
67
- for (const candidate of candidates) {
68
- const ratio = CssColor.contrastRatio(background, candidate);
69
- if (ratio > bestRatio) {
70
- bestRatio = ratio;
71
- best = candidate;
72
- }
73
- }
74
- return best;
63
+ const own = best(candidates);
64
+ if (own.ratio >= minRatio)
65
+ return own.color;
66
+ const plain = best(['#ffffff', '#000000']);
67
+ return plain.ratio > own.ratio ? plain.color : own.color;
68
+ }
69
+ /** The opacity of a CSS color, from 0 to 1: its alpha (`rgba()`, `#rrggbbaa`...), 0 for `transparent`, else 1. */
70
+ static alpha(color) {
71
+ const trimmed = CssColor.resolve(color).trim();
72
+ if (trimmed === 'transparent')
73
+ return 0;
74
+ const hex = CssColor.#hex(trimmed);
75
+ if (hex)
76
+ return hex[3];
77
+ const own = /^(?:rgba?|hsla?|oklch|oklab|lab|lch)\(([^)]*)\)$/i.exec(trimmed);
78
+ if (!own)
79
+ return 1;
80
+ const parts = own[1].split(/[\s,/]+/).filter(Boolean);
81
+ const slashed = own[1].includes('/');
82
+ const value = slashed || parts.length === 4 ? parts.at(-1) : undefined;
83
+ if (value === undefined)
84
+ return 1;
85
+ const alpha = value.endsWith('%') ? Number(value.slice(0, -1)) / 100 : Number(value);
86
+ return Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1;
87
+ }
88
+ /**
89
+ * The opaque color `color` is seen as, drawn at `opacity` (times its own alpha) over `backdrop`, as a browser
90
+ * blends it. A backdrop that is not opaque counts as white, the page under it. `color` as it is when unreadable.
91
+ */
92
+ static composite(color, opacity = 1, backdrop = '#ffffff') {
93
+ const own = CssColor.parse(CssColor.resolve(color));
94
+ if (!own)
95
+ return color;
96
+ const alpha = Math.max(0, Math.min(1, CssColor.alpha(color) * opacity));
97
+ if (alpha >= 1)
98
+ return `rgb(${own.join(', ')})`;
99
+ const under = CssColor.alpha(backdrop) >= 1 ? CssColor.parse(CssColor.resolve(backdrop)) : undefined;
100
+ const base = under ?? [255, 255, 255];
101
+ const mixed = own.map((c, i) => Math.round(c * alpha + base[i] * (1 - alpha)));
102
+ return `rgb(${mixed.join(', ')})`;
103
+ }
104
+ /** A hex color's `[r, g, b]` (0-255) and alpha (0-1), in its 3, 4, 6 or 8 digit form. */
105
+ static #hex(color) {
106
+ const match = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(color.trim());
107
+ if (!match)
108
+ return null;
109
+ const digits = match[1].length <= 4
110
+ ? match[1]
111
+ .split('')
112
+ .map((c) => c + c)
113
+ .join('')
114
+ : match[1];
115
+ const byte = (i) => parseInt(digits.slice(i, i + 2), 16);
116
+ return [byte(0), byte(2), byte(4), digits.length === 8 ? byte(6) / 255 : 1];
75
117
  }
76
118
  static #luminance([r, g, b]) {
77
119
  const [rs, gs, bs] = [r, g, b].map((c) => {
78
120
  const s = c / 255;
79
- return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
121
+ return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
80
122
  });
81
123
  return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
82
124
  }
@@ -1,7 +1,9 @@
1
1
  export { CssColor } from './CssColor';
2
2
  export { ColorRamp } from './ColorRamp';
3
3
  export { Palette } from './Palette';
4
+ export { ColorTones } from './ColorTones';
4
5
  import { ColorRamp } from './ColorRamp';
6
+ import { ColorTones } from './ColorTones';
5
7
  export declare const resolveCssColor: (color: string) => string;
6
8
  export declare const contrastRatio: (colorA: string, colorB: string) => number;
7
9
  export declare const contrastTextColor: (background: string, candidates?: string[]) => string;
@@ -9,3 +11,5 @@ export declare const normalize: (v: number, min: number, max: number) => number;
9
11
  export declare const makeColorScale: (min: number, max: number, colorMin: string, colorMax: string) => (v: number) => string;
10
12
  export declare const resolveColorScale: typeof ColorRamp.resolve;
11
13
  export declare const paletteColor: (index: number, palette: string[]) => string;
14
+ export declare const colorTones: (color: string, count: number) => string[];
15
+ export declare const hierarchicalColors: typeof ColorTones.hierarchy;
@@ -1,9 +1,11 @@
1
1
  export { CssColor } from './CssColor';
2
2
  export { ColorRamp } from './ColorRamp';
3
3
  export { Palette } from './Palette';
4
+ export { ColorTones } from './ColorTones';
4
5
  import { CssColor } from './CssColor';
5
6
  import { ColorRamp } from './ColorRamp';
6
7
  import { Palette } from './Palette';
8
+ import { ColorTones } from './ColorTones';
7
9
  // The package's public function names, over the classes above.
8
10
  export const resolveCssColor = (color) => CssColor.resolve(color);
9
11
  export const contrastRatio = (colorA, colorB) => CssColor.contrastRatio(colorA, colorB);
@@ -12,3 +14,5 @@ export const normalize = (v, min, max) => ColorRamp.normalize(v, min, max);
12
14
  export const makeColorScale = (min, max, colorMin, colorMax) => ColorRamp.between(min, max, colorMin, colorMax);
13
15
  export const resolveColorScale = ColorRamp.resolve;
14
16
  export const paletteColor = (index, palette) => Palette.at(index, palette);
17
+ export const colorTones = (color, count) => ColorTones.of(color, count);
18
+ export const hierarchicalColors = ColorTones.hierarchy;
@@ -1,5 +1,22 @@
1
- import type { AxisValue } from '../types/layout/mapping';
1
+ import type { AxisValue, GroupingAccessor } from '../types/layout/mapping';
2
2
  import type { Series, Accessor } from '../types/plots/data/common';
3
+ /**
4
+ * A plot's `grouping`, read into its levels. A dotted name is a field of the rows when they have one by that
5
+ * name, and the fields of its levels otherwise. Rows grouped by several levels make one key of them, dotted
6
+ * too (`'Tertiary.Finance'`), which is how `segments` names them.
7
+ */
8
+ export declare class Grouping {
9
+ /** The separator between the levels of a grouping, and of the key they make together. */
10
+ static readonly SEPARATOR = ".";
11
+ /** The levels `grouping` names, outermost first: none when it is unset. */
12
+ static levels<TRow extends Record<string, unknown>>(grouping: GroupingAccessor<TRow> | undefined, rows?: readonly TRow[]): Accessor<TRow, unknown>[];
13
+ /**
14
+ * The key rows split into series by: a single level as it is - a field stays its name - and several as
15
+ * the key their values make together. `nested` takes the outermost level alone, for a plot that draws
16
+ * the inner ones itself (a treemap).
17
+ */
18
+ static key<TRow extends Record<string, unknown>>(grouping: GroupingAccessor<TRow> | undefined, rows?: readonly TRow[], nested?: boolean): Accessor<TRow, unknown> | undefined;
19
+ }
3
20
  /**
4
21
  * Splits rows into ordered groups keyed by the stringified accessor value.
5
22
  * Insertion order of first appearance is preserved, which keeps colours stable
@@ -1,4 +1,35 @@
1
1
  import { resolveAccessor } from './accessors';
2
+ /**
3
+ * A plot's `grouping`, read into its levels. A dotted name is a field of the rows when they have one by that
4
+ * name, and the fields of its levels otherwise. Rows grouped by several levels make one key of them, dotted
5
+ * too (`'Tertiary.Finance'`), which is how `segments` names them.
6
+ */
7
+ export class Grouping {
8
+ /** The separator between the levels of a grouping, and of the key they make together. */
9
+ static SEPARATOR = '.';
10
+ /** The levels `grouping` names, outermost first: none when it is unset. */
11
+ static levels(grouping, rows = []) {
12
+ if (grouping === undefined)
13
+ return [];
14
+ if (typeof grouping !== 'string' || !grouping.includes(Grouping.SEPARATOR))
15
+ return [grouping];
16
+ if (rows.some((row) => grouping in row))
17
+ return [grouping];
18
+ return grouping.split(Grouping.SEPARATOR);
19
+ }
20
+ /**
21
+ * The key rows split into series by: a single level as it is - a field stays its name - and several as
22
+ * the key their values make together. `nested` takes the outermost level alone, for a plot that draws
23
+ * the inner ones itself (a treemap).
24
+ */
25
+ static key(grouping, rows = [], nested = false) {
26
+ const levels = Grouping.levels(grouping, rows);
27
+ if (levels.length <= 1 || nested)
28
+ return levels[0];
29
+ const reads = levels.map((level) => resolveAccessor(level));
30
+ return (row) => reads.map((read) => String(read(row))).join(Grouping.SEPARATOR);
31
+ }
32
+ }
2
33
  /**
3
34
  * Splits rows into ordered groups keyed by the stringified accessor value.
4
35
  * Insertion order of first appearance is preserved, which keeps colours stable
package/docs/concepts.md CHANGED
@@ -39,13 +39,14 @@ A **channel** maps a field of each row to a visual property. Each channel takes
39
39
  | ---------- | ----------------------------------------------------------- | ---------------------- |
40
40
  | `x`, `y` | Position on the horizontal and vertical axis | `scales.x`, `scales.y` |
41
41
  | `color` | A color: categorical (one per value) or continuous (a ramp) | `scales.color` |
42
- | `grouping` | Which series the row belongs to | `scales.grouping` |
42
+ | `grouping` | Which series the row belongs to (`'a.b'`: several levels) | `scales.grouping` |
43
43
  | `opacity` | A fill or stroke opacity | `scales.opacity` |
44
44
  | `symbol` | A marker shape (categorical) | `scales.symbol` |
45
45
  | `r` | A dot radius, scaled so that area follows the value | `scales.r` |
46
46
  | `length` | A vector or spike length | `scales.length` |
47
+ | `value` | What a row amounts to as a part of a whole (a treemap tile) | - |
47
48
 
48
- `grouping` splits `data` into series. When it is unset, `color` groups too, so one accessor both separates and colors the series - the usual case. Pass both to group by one field and color by another:
49
+ `grouping` splits `data` into series. Fields joined by dots are one grouping of several levels, outermost first: a plot that nests its rows ([TreemapPlot](plots/part-of-a-whole/treemap.md)) nests them by those levels, and any other splits them by the combination of the levels (`'region.sex'` is one series per region and sex, named `'CABA.F'`, which is how `segments` keys it). A dotted name is a field when the rows have one by that name; a function is a single level. When it is unset, `color` groups too, so one accessor both separates and colors the series - the usual case. Pass both to group by one field and color by another:
49
50
 
50
51
  ```svelte
51
52
  <ScatterPlot data={rows} x="gdp" y="life" grouping="country" color="temperature" {width} {height} />
package/docs/legend.md CHANGED
@@ -71,11 +71,14 @@ Items become clickable with `interactive` on the series section. `disabled` says
71
71
 
72
72
  ![Legend items as toggles](images/legend-toggle.png)
73
73
 
74
- | `disabled.mode` | A hidden series... |
75
- | ----------------- | ------------------------------------------------------------------------------------- |
76
- | `'dim'` (default) | stays, faded (`style` sets how: opacity, fill, ...; default `legend.disabledOpacity`) |
77
- | `'hide'` | becomes transparent, the axes keep its range |
78
- | `'omit'` | is removed and the axes refit to the rest |
74
+ | `disabled.mode` | A hidden series... |
75
+ | ----------------- | -------------------------------------------------------------------------------------- |
76
+ | `'dim'` (default) | stays, faded (`style` sets how: opacity, fill, ...; default `legend.disabledOpacity`) |
77
+ | `'hide'` | becomes transparent, the axes keep its range |
78
+ | `'omit'` | is removed and the axes refit to the rest; a part of a whole keeps its share and place |
79
+ | `'rescale'` | is removed, and the parts left make the whole again (see below) |
80
+
81
+ A plot uses one mode for all its series. `'omit'` and `'rescale'` differ on a plot of parts of a whole. With `'omit'` the other parts keep their values: a stack closes over the hidden series and its top drops, and a [treemap](plots/part-of-a-whole/treemap.md)'s tiles keep their place and their share of the whole economy, leaving the room empty. With `'rescale'` the parts left are the new 100%: each category of a stack (`stackY`/`stackX`) is scaled back up to the total it had, and a treemap's tiles fill the plot again, each share of what is left. On any other plot, `'rescale'` is an `'omit'`.
79
82
 
80
83
  `interactive.legendStyle` is `'badge'` (default: pills filled with the series color and an eye toggle) or `'basic'` (swatches). `showIcon` toggles the symbol in a badge.
81
84