svelteplot 0.5.1-pr-249.1 → 0.5.1-pr-238.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.
@@ -1,5 +1,6 @@
1
- import type { ScaleName, ScaleType, ScaledChannelName } from './types/index.js';
1
+ import type { ChannelName, ScaleName, ScaleType, ScaledChannelName } from './types/index.js';
2
2
  export declare const SCALE_TYPES: Record<ScaleName, symbol>;
3
+ export declare const ORIGINAL_NAME_KEYS: Record<ChannelName, symbol>;
3
4
  export declare const SCALES: ScaleName[];
4
5
  export declare const VALID_SCALE_TYPES: Record<ScaleName, Set<ScaleType>>;
5
6
  /**
package/dist/constants.js CHANGED
@@ -10,6 +10,28 @@ export const SCALE_TYPES = {
10
10
  fy: Symbol('fy'),
11
11
  projection: Symbol('projection')
12
12
  };
13
+ export const ORIGINAL_NAME_KEYS = {
14
+ x: Symbol('origName_x'),
15
+ x1: Symbol('origName_x1'),
16
+ x2: Symbol('origName_x2'),
17
+ y: Symbol('origName_y'),
18
+ y1: Symbol('origName_y1'),
19
+ y2: Symbol('origName_y2'),
20
+ fill: Symbol('origName_color'),
21
+ stroke: Symbol('origName_color'),
22
+ opacity: Symbol('origName_opacity'),
23
+ symbol: Symbol('origName_symbol'),
24
+ r: Symbol('origName_r'),
25
+ z: Symbol('origName_z'),
26
+ sort: Symbol('origName_sort'),
27
+ filter: Symbol('origName_filter'),
28
+ interval: Symbol('origName_interval'),
29
+ length: Symbol('origName_length'),
30
+ fx: Symbol('origName_fx'),
31
+ fy: Symbol('origName_fy'),
32
+ fillOpacity: Symbol('origName_opacity'),
33
+ strokeOpacity: Symbol('origName_opacity')
34
+ };
13
35
  export const SCALES = [
14
36
  'x',
15
37
  'y',
@@ -1,6 +1,7 @@
1
1
  import { min, max, mode, sum, mean, median, variance, deviation, quantile } from 'd3-array';
2
2
  import { resolveChannel } from './resolve.js';
3
3
  import { POSITION_CHANNELS } from './index.js';
4
+ import { ORIGINAL_NAME_KEYS } from '../constants.js';
4
5
  const niceReduceNames = {
5
6
  count: 'Frequency',
6
7
  deviation: 'Standard Deviation',
@@ -72,10 +73,10 @@ export function reduceOutputs(newDatum, data, options, outputs, channels, newCha
72
73
  if (typeof channels[k] === 'string') {
73
74
  // the named reducer is applied to a column name, so we can use a combination
74
75
  // of both as axis labels, e.g. MEAN(weight)
75
- newChannels[`__${k}_origField`] = `${reducerName} ( ${channels[k]} )`;
76
+ newChannels[ORIGINAL_NAME_KEYS[k]] = `${reducerName} ( ${channels[k]} )`;
76
77
  }
77
78
  else {
78
- newChannels[`__${k}_origField`] = reducerName;
79
+ newChannels[ORIGINAL_NAME_KEYS[k]] = reducerName;
79
80
  }
80
81
  }
81
82
  }
@@ -1,6 +1,6 @@
1
1
  import { extent, ascending } from 'd3-array';
2
2
  import { isColorOrNull, isDate, isDateOrNull, isNumberOrNull, isNumberOrNullOrNaN, isStringOrNull } from './typeChecks.js';
3
- import { CHANNEL_SCALE, VALID_SCALE_TYPES } from '../constants.js';
3
+ import { CHANNEL_SCALE, ORIGINAL_NAME_KEYS, VALID_SCALE_TYPES } from '../constants.js';
4
4
  import { isSymbolOrNull } from './typeChecks.js';
5
5
  import { resolveProp, toChannelOption } from './resolve.js';
6
6
  import isDataRecord from './isDataRecord.js';
@@ -126,9 +126,9 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
126
126
  }
127
127
  // special handling of marks using the stackX/stackY transform
128
128
  if ((name === 'x' || name === 'y') &&
129
- mark.options[`__${name}_origField`] &&
130
- !mark.options[`__${name}_origField`].startsWith('__')) {
131
- propNames.add(mark.options[`__${name}_origField`]);
129
+ mark.options[ORIGINAL_NAME_KEYS[name]] &&
130
+ !mark.options[ORIGINAL_NAME_KEYS[name]].startsWith('__')) {
131
+ propNames.add(mark.options[ORIGINAL_NAME_KEYS[name]]);
132
132
  }
133
133
  }
134
134
  else {
@@ -115,6 +115,7 @@
115
115
  {data}
116
116
  channels={['x1', 'x2', 'y1', 'y2', 'fill', 'stroke', 'opacity', 'fillOpacity', 'strokeOpacity']}
117
117
  required={['x1', 'y1']}
118
+ {...markProps}
118
119
  {...options}>
119
120
  {#snippet children({ mark, usedScales, scaledData })}
120
121
  {@const grouped = groupAndSort(scaledData)}
@@ -4,6 +4,15 @@ import { bin as d3Bin, extent, thresholdFreedmanDiaconis, thresholdScott, thresh
4
4
  import { reduceOutputs } from '../helpers/reduce.js';
5
5
  import { groupFacetsAndZ } from '../helpers/group.js';
6
6
  import { isDate } from '../helpers/typeChecks.js';
7
+ import { ORIGINAL_NAME_KEYS } from '../constants';
8
+ const CHANNELS = {
9
+ x: Symbol('x'),
10
+ x1: Symbol('x1'),
11
+ x2: Symbol('x2'),
12
+ y: Symbol('y'),
13
+ y1: Symbol('y1'),
14
+ y2: Symbol('y2')
15
+ };
7
16
  const ThresholdGenerators = {
8
17
  auto: thresholdScott,
9
18
  scott: thresholdScott,
@@ -41,19 +50,19 @@ function binBy(byDim, { data, ...channels }, options) {
41
50
  [byDim === 'x' ? 'insetLeft' : 'insetTop']: 0.5,
42
51
  [byDim === 'x' ? 'insetRight' : 'insetBottom']: 0.5,
43
52
  ...channels,
44
- [`${byDim}`]: `__${byDim}`,
45
- [`${byDim}1`]: `__${byDim}1`,
46
- [`${byDim}2`]: `__${byDim}2`,
47
- [`__${byDim}_origField`]: typeof channels[byDim] === 'string' ? channels[byDim] : null
53
+ [`${byDim}`]: CHANNELS[byDim], // `__${byDim}`,
54
+ [`${byDim}1`]: CHANNELS[`${byDim}1`],
55
+ [`${byDim}2`]: CHANNELS[`${byDim}2`],
56
+ [ORIGINAL_NAME_KEYS[byDim]]: typeof channels[byDim] === 'string' ? channels[byDim] : null
48
57
  };
49
58
  const newData = [];
50
59
  let passedGroups = [];
51
60
  const bins = bin(data);
52
61
  (options.cumulative < 0 ? bins.toReversed() : bins).forEach((group) => {
53
62
  const itemBinProps = {
54
- [`__${byDim}1`]: group.x0,
55
- [`__${byDim}2`]: group.x1,
56
- [`__${byDim}`]: isDate(group.x0)
63
+ [CHANNELS[`${byDim}1`]]: group.x0,
64
+ [CHANNELS[`${byDim}2`]]: group.x1,
65
+ [CHANNELS[`${byDim}`]]: isDate(group.x0)
57
66
  ? new Date(Math.round((group.x0.getTime() + group.x1.getTime()) * 0.5))
58
67
  : (group.x0 + group.x1) * 0.5
59
68
  };
@@ -101,11 +110,12 @@ export function bin({ data, ...channels }, options = { thresholds: 'auto', cumul
101
110
  // channels.x is the input
102
111
  binX.value((d) => resolveChannel('x', d, channels));
103
112
  binY.value((d) => resolveChannel('y', d, channels));
113
+ let yThresholds = [];
104
114
  if (interval) {
105
115
  const [xlo, xhi] = extent(data.map((d) => resolveChannel('x', d, channels)));
106
116
  const [ylo, yhi] = extent(data.map((d) => resolveChannel('y', d, channels)));
107
117
  binX.thresholds(maybeInterval(interval).range(xlo, xhi));
108
- binY.thresholds(maybeInterval(interval).range(ylo, yhi));
118
+ binY.thresholds((yThresholds = maybeInterval(interval).range(ylo, yhi)));
109
119
  }
110
120
  else if (thresholds) {
111
121
  // when binning in x and y, we need to ensure we are using consistent thresholds
@@ -114,7 +124,7 @@ export function bin({ data, ...channels }, options = { thresholds: 'auto', cumul
114
124
  : thresholds;
115
125
  binX.thresholds(t);
116
126
  binY.thresholds(t);
117
- const yThresholds = binY(data)
127
+ yThresholds = binY(data)
118
128
  .slice(1)
119
129
  .map((g) => g.x0);
120
130
  binY.thresholds(yThresholds);
@@ -124,14 +134,14 @@ export function bin({ data, ...channels }, options = { thresholds: 'auto', cumul
124
134
  let newChannels = {
125
135
  inset: 0.5,
126
136
  ...channels,
127
- x: '__x',
128
- x1: '__x1',
129
- x2: '__x2',
130
- y: '__y',
131
- y1: '__y1',
132
- y2: '__y2',
133
- __x_origField: typeof channels.x === 'string' ? channels.x : null,
134
- __y_origField: typeof channels.y === 'string' ? channels.y : null
137
+ x: CHANNELS.x,
138
+ x1: CHANNELS.x1,
139
+ x2: CHANNELS.x2,
140
+ y: CHANNELS.y,
141
+ y1: CHANNELS.y1,
142
+ y2: CHANNELS.y2,
143
+ [ORIGINAL_NAME_KEYS.x]: typeof channels.x === 'string' ? channels.x : null,
144
+ [ORIGINAL_NAME_KEYS.y]: typeof channels.y === 'string' ? channels.y : null
135
145
  };
136
146
  const groupBy = channels.z ? 'z' : channels.fill ? 'fill' : channels.stroke ? 'stroke' : true;
137
147
  const groupByPropName = groupBy !== true && typeof channels[groupBy] === 'string' ? channels[groupBy] : '__group';
@@ -141,20 +151,30 @@ export function bin({ data, ...channels }, options = { thresholds: 'auto', cumul
141
151
  const newData = [];
142
152
  binX(data).forEach((groupX) => {
143
153
  const newRecordBaseX = {
144
- __x1: groupX.x0,
145
- __x2: groupX.x1,
146
- __x: isDate(groupX.x0)
154
+ [CHANNELS.x1]: groupX.x0,
155
+ [CHANNELS.x2]: groupX.x1,
156
+ [CHANNELS.x]: isDate(groupX.x0)
147
157
  ? new Date(Math.round((groupX.x0.getTime() + groupX.x1.getTime()) * 0.5))
148
158
  : (groupX.x0 + groupX.x1) * 0.5
149
159
  };
150
- binY(groupX).forEach((groupY) => {
160
+ const [ylo, yhi] = extent(groupX.map((d) => resolveChannel('y', d, channels)));
161
+ const tExtentLo = yThresholds.filter((d) => d < ylo).at(-1);
162
+ const tExtentHi = yThresholds.filter((d) => d > yhi).at(0);
163
+ binY(groupX).forEach((groupY, i) => {
164
+ if (groupY.length === 0)
165
+ return;
166
+ // The first bin.x0 is always equal to the minimum domain value,
167
+ // and the last bin.x1 is always equal to the maximum domain value,
168
+ // therefore we need to align with the thresholds
169
+ const y1 = groupY.x0 === ylo ? tExtentLo : groupY.x0;
170
+ const y2 = groupY.x1 === yhi ? tExtentHi : groupY.x1;
151
171
  const newRecordBaseY = {
152
172
  ...newRecordBaseX,
153
- __y1: groupY.x0,
154
- __y2: groupY.x1,
155
- __y: isDate(groupY.x0)
156
- ? new Date(Math.round((groupY.x0.getTime() + groupY.x1.getTime()) * 0.5))
157
- : (groupY.x0 + groupY.x1) * 0.5
173
+ [CHANNELS.y1]: y1,
174
+ [CHANNELS.y2]: y2,
175
+ [CHANNELS.y]: isDate(y1)
176
+ ? new Date(Math.round((y1.getTime() + y2.getTime()) * 0.5))
177
+ : (y1 + y2) * 0.5
158
178
  };
159
179
  const newGroupChannels = groupFacetsAndZ(groupY, channels, (items, itemGroupProps) => {
160
180
  const newRecord = {
@@ -5,7 +5,7 @@ import { sum, groups as d3Groups, min, range } from 'd3-array';
5
5
  import { groupFacetsAndZ } from '../helpers/group';
6
6
  import { filter } from './filter.js';
7
7
  import { sort } from './sort.js';
8
- import { INDEX } from '../constants.js';
8
+ import { INDEX, ORIGINAL_NAME_KEYS } from '../constants.js';
9
9
  import { indexData, RAW_VALUE } from './recordize.js';
10
10
  const S = {
11
11
  x: Symbol('x'),
@@ -147,8 +147,8 @@ function stackXY(byDim, data, channels, options) {
147
147
  data: out,
148
148
  ...channels,
149
149
  [byDim]: undefined,
150
- ...(typeof channels[byDim] === 'string' && !channels[`__${byDim}_origField`]
151
- ? { [`__${byDim}_origField`]: channels[byDim] }
150
+ ...(typeof channels[byDim] === 'string' && !channels[ORIGINAL_NAME_KEYS[byDim]]
151
+ ? { [ORIGINAL_NAME_KEYS[byDim]]: channels[byDim] }
152
152
  : {}),
153
153
  ...{ [byLow]: S[byLow], [byHigh]: S[byHigh] }
154
154
  };
@@ -1,5 +1,5 @@
1
1
  import type { ConstantAccessor, RawValue } from './index.js';
2
- export type Channels<T> = Record<string, ChannelAccessor<T> | ConstantAccessor<T, string | number | boolean | symbol>>;
2
+ export type Channels<T> = Record<string | symbol, ChannelAccessor<T> | ConstantAccessor<T, string | number | boolean | symbol>>;
3
3
  export type ChannelAccessor<T = Record<string | symbol, RawValue>> = ChannelValue<T> | {
4
4
  /** the channel value */
5
5
  value: ChannelValue<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelteplot",
3
- "version": "0.5.1-pr-249.1",
3
+ "version": "0.5.1-pr-238.6",
4
4
  "license": "ISC",
5
5
  "author": {
6
6
  "name": "Gregor Aisch",
@@ -130,6 +130,6 @@
130
130
  "fast-equals": "^5.3.2",
131
131
  "interval-tree-1d": "^1.0.4",
132
132
  "merge-deep": "^3.0.3",
133
- "svelte": "5.41.3"
133
+ "svelte": "5.43.0"
134
134
  }
135
135
  }