shap-svg 0.2.0 → 0.2.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.
- package/README.md +39 -0
- package/dist/{chunk-OXFKP5I3.js → chunk-4X6PMJYT.js} +235 -34
- package/dist/chunk-4X6PMJYT.js.map +1 -0
- package/dist/index.cjs +240 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +104 -7
- package/dist/index.d.ts +104 -7
- package/dist/index.js +13 -1
- package/dist/{format-wEav_cPe.d.cts → labels-7wofev8M.d.cts} +44 -1
- package/dist/{format-wEav_cPe.d.ts → labels-7wofev8M.d.ts} +44 -1
- package/dist/react.cjs +369 -126
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +33 -5
- package/dist/react.d.ts +33 -5
- package/dist/react.js +143 -92
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-OXFKP5I3.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
beeswarmLayout,
|
|
8
8
|
beeswarmRows,
|
|
9
9
|
collapseToDisplay,
|
|
10
|
+
formatLevel,
|
|
10
11
|
formatShapValue,
|
|
11
12
|
globalImportance,
|
|
12
13
|
groupExplanationByGenus,
|
|
@@ -14,10 +15,10 @@ import {
|
|
|
14
15
|
heatmapRows,
|
|
15
16
|
orderFeatures,
|
|
16
17
|
parseExplanation,
|
|
17
|
-
|
|
18
|
+
resolveLabels,
|
|
18
19
|
waterfallLayout,
|
|
19
20
|
waterfallRows
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-4X6PMJYT.js";
|
|
21
22
|
|
|
22
23
|
// src/react/ShapBar.tsx
|
|
23
24
|
import { useMemo, useState } from "react";
|
|
@@ -91,9 +92,11 @@ function ShapBar({
|
|
|
91
92
|
classIndex = 1,
|
|
92
93
|
width = 720,
|
|
93
94
|
rowHeight = 26,
|
|
95
|
+
labels,
|
|
94
96
|
onFeatureClick
|
|
95
97
|
}) {
|
|
96
98
|
const [hovered, setHovered] = useState(null);
|
|
99
|
+
const words = useMemo(() => resolveLabels(labels), [labels]);
|
|
97
100
|
const layout = useMemo(() => {
|
|
98
101
|
const raw = parseExplanation(explanation, { classIndex });
|
|
99
102
|
const parsed = groupByGenus ? groupExplanationByGenus(raw) : raw;
|
|
@@ -104,23 +107,25 @@ function ShapBar({
|
|
|
104
107
|
importance,
|
|
105
108
|
order,
|
|
106
109
|
maxDisplay,
|
|
107
|
-
faithfulOtherRow
|
|
110
|
+
faithfulOtherRow,
|
|
111
|
+
words
|
|
108
112
|
);
|
|
109
113
|
return barLayout(rows, {
|
|
110
114
|
width,
|
|
111
115
|
rowHeight,
|
|
112
116
|
marginLeft: 260,
|
|
113
117
|
marginRight: 90,
|
|
114
|
-
marginTop: 8
|
|
118
|
+
marginTop: 8,
|
|
119
|
+
labels: words
|
|
115
120
|
});
|
|
116
|
-
}, [groupByGenus, explanation, maxDisplay, faithfulOtherRow, classIndex, width, rowHeight]);
|
|
121
|
+
}, [groupByGenus, explanation, maxDisplay, faithfulOtherRow, classIndex, width, rowHeight, words]);
|
|
117
122
|
return /* @__PURE__ */ jsxs2(
|
|
118
123
|
"svg",
|
|
119
124
|
{
|
|
120
125
|
width,
|
|
121
126
|
height: layout.height,
|
|
122
127
|
role: "img",
|
|
123
|
-
"aria-label":
|
|
128
|
+
"aria-label": `Mean absolute ${words.shapValue} per feature`,
|
|
124
129
|
children: [
|
|
125
130
|
/* @__PURE__ */ jsx2(
|
|
126
131
|
"line",
|
|
@@ -208,7 +213,61 @@ function ShapBar({
|
|
|
208
213
|
|
|
209
214
|
// src/react/ShapBeeswarm.tsx
|
|
210
215
|
import { useMemo as useMemo2, useState as useState2 } from "react";
|
|
216
|
+
|
|
217
|
+
// src/react/ColorBar.tsx
|
|
211
218
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
219
|
+
function ColorBar({ bar }) {
|
|
220
|
+
return /* @__PURE__ */ jsxs3("g", { role: "img", "aria-label": `${bar.label.text}: ${bar.ticks[0].label} to ${bar.ticks[1].label}`, children: [
|
|
221
|
+
bar.steps.map((step, index) => /* @__PURE__ */ jsx3(
|
|
222
|
+
"rect",
|
|
223
|
+
{
|
|
224
|
+
x: bar.x,
|
|
225
|
+
y: step.y,
|
|
226
|
+
width: bar.width,
|
|
227
|
+
height: step.height,
|
|
228
|
+
fill: step.color
|
|
229
|
+
},
|
|
230
|
+
`colorbar-step-${index}`
|
|
231
|
+
)),
|
|
232
|
+
bar.ticks.map((tick, index) => /* @__PURE__ */ jsx3(
|
|
233
|
+
"text",
|
|
234
|
+
{
|
|
235
|
+
x: bar.tickX,
|
|
236
|
+
y: tick.y,
|
|
237
|
+
dominantBaseline: "middle",
|
|
238
|
+
fontSize: bar.tickFontSize,
|
|
239
|
+
fill: "#333333",
|
|
240
|
+
children: tick.label
|
|
241
|
+
},
|
|
242
|
+
`colorbar-tick-${index}`
|
|
243
|
+
)),
|
|
244
|
+
bar.offsetText && /* @__PURE__ */ jsx3(
|
|
245
|
+
"text",
|
|
246
|
+
{
|
|
247
|
+
x: bar.offsetText.x,
|
|
248
|
+
y: bar.offsetText.y,
|
|
249
|
+
fontSize: bar.tickFontSize,
|
|
250
|
+
fill: "#333333",
|
|
251
|
+
children: bar.offsetText.text
|
|
252
|
+
}
|
|
253
|
+
),
|
|
254
|
+
/* @__PURE__ */ jsx3(
|
|
255
|
+
"text",
|
|
256
|
+
{
|
|
257
|
+
x: bar.label.x,
|
|
258
|
+
y: bar.label.y,
|
|
259
|
+
transform: `rotate(-90 ${bar.label.x} ${bar.label.y})`,
|
|
260
|
+
textAnchor: "middle",
|
|
261
|
+
fontSize: bar.label.fontSize,
|
|
262
|
+
fill: "#333333",
|
|
263
|
+
children: bar.label.text
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
] });
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// src/react/ShapBeeswarm.tsx
|
|
270
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
212
271
|
function ShapBeeswarm({
|
|
213
272
|
explanation,
|
|
214
273
|
maxDisplay = 10,
|
|
@@ -220,25 +279,32 @@ function ShapBeeswarm({
|
|
|
220
279
|
rowHeight = 28,
|
|
221
280
|
seed = 0,
|
|
222
281
|
dotRadius = 3,
|
|
282
|
+
colorBar = true,
|
|
283
|
+
labels,
|
|
223
284
|
onFeatureClick
|
|
224
285
|
}) {
|
|
225
286
|
const [hovered, setHovered] = useState2(null);
|
|
287
|
+
const words = useMemo2(() => resolveLabels(labels), [labels]);
|
|
226
288
|
const marginTop = 8;
|
|
227
289
|
const layout = useMemo2(() => {
|
|
228
290
|
const raw = parseExplanation(explanation, { classIndex });
|
|
229
291
|
const parsed = groupByGenus ? groupExplanationByGenus(raw) : raw;
|
|
230
|
-
const rows = beeswarmRows(parsed, maxDisplay, faithfulOtherRow, seed, rowSort);
|
|
292
|
+
const rows = beeswarmRows(parsed, maxDisplay, faithfulOtherRow, seed, rowSort, words);
|
|
231
293
|
return beeswarmLayout(rows, {
|
|
232
294
|
width,
|
|
233
295
|
rowHeight,
|
|
234
296
|
marginLeft: 260,
|
|
235
297
|
marginRight: 90,
|
|
236
298
|
marginTop,
|
|
237
|
-
dotRadius
|
|
299
|
+
dotRadius,
|
|
300
|
+
colorBar,
|
|
301
|
+
labels: words
|
|
238
302
|
});
|
|
239
303
|
}, [
|
|
240
304
|
groupByGenus,
|
|
241
305
|
rowSort,
|
|
306
|
+
colorBar,
|
|
307
|
+
words,
|
|
242
308
|
explanation,
|
|
243
309
|
maxDisplay,
|
|
244
310
|
faithfulOtherRow,
|
|
@@ -258,9 +324,8 @@ function ShapBeeswarm({
|
|
|
258
324
|
const fallbackRow = layout.rows[0];
|
|
259
325
|
const activeRow = hovered ? layout.rows[hovered.rowIndex] : fallbackRow;
|
|
260
326
|
const activePoint = hovered ? activeRow == null ? void 0 : activeRow.points[hovered.pointIndex] : activeRow == null ? void 0 : activeRow.points[0];
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
/* @__PURE__ */ jsx3(
|
|
327
|
+
return /* @__PURE__ */ jsxs4("svg", { width, height: layout.height, role: "img", "aria-label": "Global SHAP beeswarm", children: [
|
|
328
|
+
/* @__PURE__ */ jsx4(
|
|
264
329
|
"line",
|
|
265
330
|
{
|
|
266
331
|
x1: layout.xZero,
|
|
@@ -271,7 +336,7 @@ function ShapBeeswarm({
|
|
|
271
336
|
strokeWidth: 1
|
|
272
337
|
}
|
|
273
338
|
),
|
|
274
|
-
layout.rows.map((row, rowIndex) => /* @__PURE__ */
|
|
339
|
+
layout.rows.map((row, rowIndex) => /* @__PURE__ */ jsxs4(
|
|
275
340
|
"g",
|
|
276
341
|
{
|
|
277
342
|
onMouseOver: (event) => handlePointHover(rowIndex, event),
|
|
@@ -279,7 +344,7 @@ function ShapBeeswarm({
|
|
|
279
344
|
onClick: () => onFeatureClick == null ? void 0 : onFeatureClick(row.featureIndex),
|
|
280
345
|
style: { cursor: onFeatureClick ? "pointer" : "default" },
|
|
281
346
|
children: [
|
|
282
|
-
/* @__PURE__ */
|
|
347
|
+
/* @__PURE__ */ jsx4(
|
|
283
348
|
"rect",
|
|
284
349
|
{
|
|
285
350
|
x: 0,
|
|
@@ -289,7 +354,7 @@ function ShapBeeswarm({
|
|
|
289
354
|
fill: (hovered == null ? void 0 : hovered.rowIndex) === rowIndex ? "#00000008" : "transparent"
|
|
290
355
|
}
|
|
291
356
|
),
|
|
292
|
-
/* @__PURE__ */
|
|
357
|
+
/* @__PURE__ */ jsx4(
|
|
293
358
|
"text",
|
|
294
359
|
{
|
|
295
360
|
x: 250,
|
|
@@ -302,7 +367,7 @@ function ShapBeeswarm({
|
|
|
302
367
|
children: row.label
|
|
303
368
|
}
|
|
304
369
|
),
|
|
305
|
-
row.points.map((point, pointIndex) => /* @__PURE__ */
|
|
370
|
+
row.points.map((point, pointIndex) => /* @__PURE__ */ jsx4(
|
|
306
371
|
"circle",
|
|
307
372
|
{
|
|
308
373
|
"data-point-index": pointIndex,
|
|
@@ -318,7 +383,7 @@ function ShapBeeswarm({
|
|
|
318
383
|
},
|
|
319
384
|
`row-${rowIndex}`
|
|
320
385
|
)),
|
|
321
|
-
/* @__PURE__ */
|
|
386
|
+
/* @__PURE__ */ jsx4(
|
|
322
387
|
XAxis,
|
|
323
388
|
{
|
|
324
389
|
ticks: layout.xTicks,
|
|
@@ -328,42 +393,18 @@ function ShapBeeswarm({
|
|
|
328
393
|
tickFontSize: 11
|
|
329
394
|
}
|
|
330
395
|
),
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
"rect",
|
|
334
|
-
{
|
|
335
|
-
x: width - 160 + index * 4,
|
|
336
|
-
y: layout.height - 22,
|
|
337
|
-
width: 4,
|
|
338
|
-
height: 7,
|
|
339
|
-
fill: sampleColormap("red_blue", index / (legendSteps - 1))
|
|
340
|
-
},
|
|
341
|
-
`legend-${index}`
|
|
342
|
-
)),
|
|
343
|
-
/* @__PURE__ */ jsx3("text", { x: width - 160, y: layout.height - 3, fontSize: 10, fill: "#555555", children: formatShapValue(activeRow.vmin) }),
|
|
344
|
-
/* @__PURE__ */ jsx3(
|
|
345
|
-
"text",
|
|
346
|
-
{
|
|
347
|
-
x: width - 32,
|
|
348
|
-
y: layout.height - 3,
|
|
349
|
-
textAnchor: "end",
|
|
350
|
-
fontSize: 10,
|
|
351
|
-
fill: "#555555",
|
|
352
|
-
children: formatShapValue(activeRow.vmax)
|
|
353
|
-
}
|
|
354
|
-
)
|
|
355
|
-
] }),
|
|
356
|
-
activeRow && activePoint && /* @__PURE__ */ jsxs3(
|
|
396
|
+
layout.colorBar && /* @__PURE__ */ jsx4(ColorBar, { bar: layout.colorBar }),
|
|
397
|
+
activeRow && activePoint && /* @__PURE__ */ jsxs4(
|
|
357
398
|
"g",
|
|
358
399
|
{
|
|
359
400
|
opacity: hovered ? 1 : 0,
|
|
360
401
|
pointerEvents: "none",
|
|
361
402
|
transform: `translate(${activePoint.x + 8} ${activePoint.y - 8})`,
|
|
362
403
|
children: [
|
|
363
|
-
/* @__PURE__ */
|
|
364
|
-
/* @__PURE__ */
|
|
365
|
-
/* @__PURE__ */
|
|
366
|
-
/* @__PURE__ */
|
|
404
|
+
/* @__PURE__ */ jsx4("rect", { x: 0, y: -16, width: 210, height: 54, rx: 3, fill: "#ffffff", stroke: "#cccccc" }),
|
|
405
|
+
/* @__PURE__ */ jsx4("text", { x: 7, y: 0, fontSize: 11, fill: "#222222", children: activeRow.label }),
|
|
406
|
+
/* @__PURE__ */ jsx4("text", { x: 7, y: 15, fontSize: 11, fill: "#222222", children: `${words.shapValue}: ${formatShapValue(activePoint.valueX)}` }),
|
|
407
|
+
/* @__PURE__ */ jsx4("text", { x: 7, y: 30, fontSize: 11, fill: "#222222", children: `${words.featureValue}: ${Number.isFinite(activePoint.featureValue) ? formatLevel(activePoint.featureValue) : words.missingFeatureValue}` })
|
|
367
408
|
]
|
|
368
409
|
}
|
|
369
410
|
)
|
|
@@ -372,7 +413,7 @@ function ShapBeeswarm({
|
|
|
372
413
|
|
|
373
414
|
// src/react/ShapHeatmap.tsx
|
|
374
415
|
import { useMemo as useMemo3, useState as useState3 } from "react";
|
|
375
|
-
import { jsx as
|
|
416
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
376
417
|
function ShapHeatmap({
|
|
377
418
|
explanation,
|
|
378
419
|
maxDisplay = 10,
|
|
@@ -382,33 +423,38 @@ function ShapHeatmap({
|
|
|
382
423
|
classIndex = 1,
|
|
383
424
|
width = 720,
|
|
384
425
|
rowHeight = 26,
|
|
426
|
+
colorBar = true,
|
|
427
|
+
labels,
|
|
385
428
|
onFeatureClick,
|
|
386
429
|
onSampleClick
|
|
387
430
|
}) {
|
|
388
431
|
const [hoveredColumn, setHoveredColumn] = useState3(null);
|
|
432
|
+
const words = useMemo3(() => resolveLabels(labels), [labels]);
|
|
389
433
|
const marginTop = 72;
|
|
390
434
|
const layout = useMemo3(() => {
|
|
391
435
|
const raw = parseExplanation(explanation, { classIndex });
|
|
392
436
|
const parsed = groupByGenus ? groupExplanationByGenus(raw) : raw;
|
|
393
|
-
const rows = heatmapRows(parsed, maxDisplay, faithfulOtherRow, rowSort);
|
|
437
|
+
const rows = heatmapRows(parsed, maxDisplay, faithfulOtherRow, rowSort, words);
|
|
394
438
|
return heatmapLayout(rows, {
|
|
395
439
|
width,
|
|
396
440
|
rowHeight,
|
|
397
441
|
marginLeft: 260,
|
|
398
442
|
marginRight: 100,
|
|
399
|
-
marginTop
|
|
443
|
+
marginTop,
|
|
444
|
+
colorBar,
|
|
445
|
+
labels: words
|
|
400
446
|
});
|
|
401
|
-
}, [groupByGenus, rowSort, explanation, maxDisplay, faithfulOtherRow, classIndex, width, rowHeight]);
|
|
447
|
+
}, [groupByGenus, rowSort, colorBar, words, explanation, maxDisplay, faithfulOtherRow, classIndex, width, rowHeight]);
|
|
402
448
|
const activeColumn = hoveredColumn === null ? void 0 : layout.columns[hoveredColumn];
|
|
403
449
|
const nameOf = (column) => {
|
|
404
|
-
if (!column.sampleLabel) return
|
|
450
|
+
if (!column.sampleLabel) return words.sampleFallback(column.sampleIndex + 1);
|
|
405
451
|
return layout.sampleLabelColumn ? `${layout.sampleLabelColumn}: ${column.sampleLabel}` : column.sampleLabel;
|
|
406
452
|
};
|
|
407
453
|
const tooltipWidth = activeColumn ? Math.max(190, nameOf(activeColumn).length * 6.5 + 16) : 190;
|
|
408
454
|
const tooltipX = activeColumn ? Math.max(0, Math.min(activeColumn.centerX + 8, width - tooltipWidth - 8)) : 0;
|
|
409
|
-
return /* @__PURE__ */
|
|
410
|
-
layout.fxAxisMarks.map((mark) => /* @__PURE__ */
|
|
411
|
-
/* @__PURE__ */
|
|
455
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height: layout.height, role: "img", "aria-label": "Global SHAP heatmap", children: [
|
|
456
|
+
layout.fxAxisMarks.map((mark) => /* @__PURE__ */ jsxs5("g", { children: [
|
|
457
|
+
/* @__PURE__ */ jsx5(
|
|
412
458
|
"line",
|
|
413
459
|
{
|
|
414
460
|
x1: layout.gridLeft - 4,
|
|
@@ -419,7 +465,7 @@ function ShapHeatmap({
|
|
|
419
465
|
strokeWidth: 1
|
|
420
466
|
}
|
|
421
467
|
),
|
|
422
|
-
/* @__PURE__ */
|
|
468
|
+
/* @__PURE__ */ jsx5(
|
|
423
469
|
"text",
|
|
424
470
|
{
|
|
425
471
|
x: layout.gridLeft - 8,
|
|
@@ -432,7 +478,7 @@ function ShapHeatmap({
|
|
|
432
478
|
}
|
|
433
479
|
)
|
|
434
480
|
] }, `fx-axis-${mark.value}`)),
|
|
435
|
-
/* @__PURE__ */
|
|
481
|
+
/* @__PURE__ */ jsx5(
|
|
436
482
|
"polyline",
|
|
437
483
|
{
|
|
438
484
|
points: layout.fxLine.map((point) => `${point.x},${point.y}`).join(" "),
|
|
@@ -441,7 +487,7 @@ function ShapHeatmap({
|
|
|
441
487
|
strokeWidth: 1.5
|
|
442
488
|
}
|
|
443
489
|
),
|
|
444
|
-
/* @__PURE__ */
|
|
490
|
+
/* @__PURE__ */ jsx5(
|
|
445
491
|
"line",
|
|
446
492
|
{
|
|
447
493
|
x1: layout.gridLeft,
|
|
@@ -453,7 +499,7 @@ function ShapHeatmap({
|
|
|
453
499
|
strokeDasharray: "4 4"
|
|
454
500
|
}
|
|
455
501
|
),
|
|
456
|
-
/* @__PURE__ */
|
|
502
|
+
/* @__PURE__ */ jsx5(
|
|
457
503
|
XAxis,
|
|
458
504
|
{
|
|
459
505
|
ticks: layout.xTicks,
|
|
@@ -463,8 +509,8 @@ function ShapHeatmap({
|
|
|
463
509
|
tickFontSize: 10
|
|
464
510
|
}
|
|
465
511
|
),
|
|
466
|
-
/* @__PURE__ */
|
|
467
|
-
[layout.spines.left, layout.spines.right].map((spine, index) => /* @__PURE__ */
|
|
512
|
+
/* @__PURE__ */ jsxs5("g", { "aria-hidden": "true", children: [
|
|
513
|
+
[layout.spines.left, layout.spines.right].map((spine, index) => /* @__PURE__ */ jsx5(
|
|
468
514
|
"line",
|
|
469
515
|
{
|
|
470
516
|
x1: spine.x,
|
|
@@ -476,7 +522,7 @@ function ShapHeatmap({
|
|
|
476
522
|
},
|
|
477
523
|
`spine-${index}`
|
|
478
524
|
)),
|
|
479
|
-
layout.yTicks.map((tick, index) => /* @__PURE__ */
|
|
525
|
+
layout.yTicks.map((tick, index) => /* @__PURE__ */ jsx5(
|
|
480
526
|
"line",
|
|
481
527
|
{
|
|
482
528
|
x1: tick.x1,
|
|
@@ -489,13 +535,14 @@ function ShapHeatmap({
|
|
|
489
535
|
`ytick-${index}`
|
|
490
536
|
))
|
|
491
537
|
] }),
|
|
492
|
-
layout.
|
|
538
|
+
layout.colorBar && /* @__PURE__ */ jsx5(ColorBar, { bar: layout.colorBar }),
|
|
539
|
+
layout.rows.map((row, rowIndex) => /* @__PURE__ */ jsxs5(
|
|
493
540
|
"g",
|
|
494
541
|
{
|
|
495
542
|
onClick: () => onFeatureClick == null ? void 0 : onFeatureClick(row.featureIndex),
|
|
496
543
|
style: { cursor: onFeatureClick ? "pointer" : "default" },
|
|
497
544
|
children: [
|
|
498
|
-
/* @__PURE__ */
|
|
545
|
+
/* @__PURE__ */ jsx5(
|
|
499
546
|
"text",
|
|
500
547
|
{
|
|
501
548
|
x: 250,
|
|
@@ -508,7 +555,7 @@ function ShapHeatmap({
|
|
|
508
555
|
children: row.label
|
|
509
556
|
}
|
|
510
557
|
),
|
|
511
|
-
row.cells.map((cell, columnIndex) => /* @__PURE__ */
|
|
558
|
+
row.cells.map((cell, columnIndex) => /* @__PURE__ */ jsx5(
|
|
512
559
|
"rect",
|
|
513
560
|
{
|
|
514
561
|
x: cell.x,
|
|
@@ -519,7 +566,7 @@ function ShapHeatmap({
|
|
|
519
566
|
},
|
|
520
567
|
`cell-${columnIndex}`
|
|
521
568
|
)),
|
|
522
|
-
/* @__PURE__ */
|
|
569
|
+
/* @__PURE__ */ jsx5(
|
|
523
570
|
"rect",
|
|
524
571
|
{
|
|
525
572
|
x: row.sideBar.x,
|
|
@@ -533,7 +580,7 @@ function ShapHeatmap({
|
|
|
533
580
|
},
|
|
534
581
|
`row-${rowIndex}`
|
|
535
582
|
)),
|
|
536
|
-
activeColumn && /* @__PURE__ */
|
|
583
|
+
activeColumn && /* @__PURE__ */ jsx5(
|
|
537
584
|
"rect",
|
|
538
585
|
{
|
|
539
586
|
x: activeColumn.x,
|
|
@@ -545,7 +592,7 @@ function ShapHeatmap({
|
|
|
545
592
|
pointerEvents: "none"
|
|
546
593
|
}
|
|
547
594
|
),
|
|
548
|
-
layout.columns.map((column, columnIndex) => /* @__PURE__ */
|
|
595
|
+
layout.columns.map((column, columnIndex) => /* @__PURE__ */ jsx5(
|
|
549
596
|
"rect",
|
|
550
597
|
{
|
|
551
598
|
x: column.x,
|
|
@@ -553,7 +600,7 @@ function ShapHeatmap({
|
|
|
553
600
|
width: column.width,
|
|
554
601
|
height: layout.plotBottom - 8,
|
|
555
602
|
fill: "transparent",
|
|
556
|
-
"aria-label": `${nameOf(column)}, total
|
|
603
|
+
"aria-label": `${nameOf(column)}, total ${words.shapValue} ${formatShapValue(column.total)}`,
|
|
557
604
|
onMouseEnter: () => setHoveredColumn(columnIndex),
|
|
558
605
|
onMouseLeave: () => setHoveredColumn(null),
|
|
559
606
|
onClick: () => {
|
|
@@ -563,17 +610,17 @@ function ShapHeatmap({
|
|
|
563
610
|
},
|
|
564
611
|
`column-hit-${column.sampleIndex}`
|
|
565
612
|
)),
|
|
566
|
-
activeColumn && /* @__PURE__ */
|
|
567
|
-
/* @__PURE__ */
|
|
568
|
-
/* @__PURE__ */
|
|
569
|
-
/* @__PURE__ */
|
|
613
|
+
activeColumn && /* @__PURE__ */ jsxs5("g", { pointerEvents: "none", transform: `translate(${tooltipX} 10)`, children: [
|
|
614
|
+
/* @__PURE__ */ jsx5("rect", { x: 0, y: 0, width: tooltipWidth, height: 42, rx: 3, fill: "#ffffff", stroke: "#cccccc" }),
|
|
615
|
+
/* @__PURE__ */ jsx5("text", { x: 7, y: 15, fontSize: 11, fill: "#222222", children: nameOf(activeColumn) }),
|
|
616
|
+
/* @__PURE__ */ jsx5("text", { x: 7, y: 31, fontSize: 11, fill: "#222222", children: `${words.sampleTotal}: ${formatShapValue(activeColumn.total)}` })
|
|
570
617
|
] })
|
|
571
618
|
] });
|
|
572
619
|
}
|
|
573
620
|
|
|
574
621
|
// src/react/ShapWaterfall.tsx
|
|
575
622
|
import { useMemo as useMemo4, useState as useState4 } from "react";
|
|
576
|
-
import { jsx as
|
|
623
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
577
624
|
function ShapWaterfall({
|
|
578
625
|
explanation,
|
|
579
626
|
sampleIndex = 0,
|
|
@@ -584,21 +631,24 @@ function ShapWaterfall({
|
|
|
584
631
|
width = 720,
|
|
585
632
|
rowHeight = 30,
|
|
586
633
|
decimals = 2,
|
|
634
|
+
labels,
|
|
587
635
|
onFeatureClick
|
|
588
636
|
}) {
|
|
589
637
|
const [hovered, setHovered] = useState4(null);
|
|
638
|
+
const words = useMemo4(() => resolveLabels(labels), [labels]);
|
|
590
639
|
const marginTop = 34;
|
|
591
640
|
const layout = useMemo4(() => {
|
|
592
641
|
const raw = parseExplanation(explanation, { classIndex });
|
|
593
642
|
const parsed = groupByGenus ? groupExplanationByGenus(raw) : raw;
|
|
594
|
-
const rows = waterfallRows(parsed, sampleIndex, maxDisplay, faithfulOtherRow);
|
|
643
|
+
const rows = waterfallRows(parsed, sampleIndex, maxDisplay, faithfulOtherRow, words);
|
|
595
644
|
return waterfallLayout(rows, {
|
|
596
645
|
width,
|
|
597
646
|
rowHeight,
|
|
598
647
|
marginLeft: 260,
|
|
599
648
|
marginRight: 110,
|
|
600
649
|
marginTop,
|
|
601
|
-
decimals
|
|
650
|
+
decimals,
|
|
651
|
+
labels: words
|
|
602
652
|
});
|
|
603
653
|
}, [
|
|
604
654
|
groupByGenus,
|
|
@@ -609,9 +659,10 @@ function ShapWaterfall({
|
|
|
609
659
|
classIndex,
|
|
610
660
|
width,
|
|
611
661
|
rowHeight,
|
|
612
|
-
decimals
|
|
662
|
+
decimals,
|
|
663
|
+
words
|
|
613
664
|
]);
|
|
614
|
-
return /* @__PURE__ */
|
|
665
|
+
return /* @__PURE__ */ jsxs6(
|
|
615
666
|
"svg",
|
|
616
667
|
{
|
|
617
668
|
width,
|
|
@@ -619,7 +670,7 @@ function ShapWaterfall({
|
|
|
619
670
|
role: "img",
|
|
620
671
|
"aria-label": `Local SHAP waterfall for Sample ${sampleIndex}`,
|
|
621
672
|
children: [
|
|
622
|
-
layout.separators.map((separator, index) => /* @__PURE__ */
|
|
673
|
+
layout.separators.map((separator, index) => /* @__PURE__ */ jsx6(
|
|
623
674
|
"line",
|
|
624
675
|
{
|
|
625
676
|
x1: separator.x1,
|
|
@@ -632,8 +683,8 @@ function ShapWaterfall({
|
|
|
632
683
|
},
|
|
633
684
|
`separator-${index}`
|
|
634
685
|
)),
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */
|
|
686
|
+
/* @__PURE__ */ jsxs6("g", { "aria-hidden": "true", children: [
|
|
687
|
+
/* @__PURE__ */ jsx6(
|
|
637
688
|
"line",
|
|
638
689
|
{
|
|
639
690
|
x1: layout.plotLeft,
|
|
@@ -644,8 +695,8 @@ function ShapWaterfall({
|
|
|
644
695
|
strokeWidth: 1
|
|
645
696
|
}
|
|
646
697
|
),
|
|
647
|
-
layout.xTicks.map((tick) => /* @__PURE__ */
|
|
648
|
-
/* @__PURE__ */
|
|
698
|
+
layout.xTicks.map((tick) => /* @__PURE__ */ jsxs6("g", { children: [
|
|
699
|
+
/* @__PURE__ */ jsx6(
|
|
649
700
|
"line",
|
|
650
701
|
{
|
|
651
702
|
x1: tick.x,
|
|
@@ -656,7 +707,7 @@ function ShapWaterfall({
|
|
|
656
707
|
strokeWidth: 1
|
|
657
708
|
}
|
|
658
709
|
),
|
|
659
|
-
/* @__PURE__ */
|
|
710
|
+
/* @__PURE__ */ jsx6(
|
|
660
711
|
"text",
|
|
661
712
|
{
|
|
662
713
|
x: tick.x,
|
|
@@ -669,7 +720,7 @@ function ShapWaterfall({
|
|
|
669
720
|
)
|
|
670
721
|
] }, `tick-${tick.value}`))
|
|
671
722
|
] }),
|
|
672
|
-
layout.connectors.map((connector, index) => /* @__PURE__ */
|
|
723
|
+
layout.connectors.map((connector, index) => /* @__PURE__ */ jsx6(
|
|
673
724
|
"line",
|
|
674
725
|
{
|
|
675
726
|
x1: connector.x,
|
|
@@ -682,8 +733,8 @@ function ShapWaterfall({
|
|
|
682
733
|
},
|
|
683
734
|
`connector-${index}`
|
|
684
735
|
)),
|
|
685
|
-
layout.axisMarks.map((mark) => /* @__PURE__ */
|
|
686
|
-
/* @__PURE__ */
|
|
736
|
+
layout.axisMarks.map((mark) => /* @__PURE__ */ jsxs6("g", { children: [
|
|
737
|
+
/* @__PURE__ */ jsx6(
|
|
687
738
|
"line",
|
|
688
739
|
{
|
|
689
740
|
x1: mark.x,
|
|
@@ -695,7 +746,7 @@ function ShapWaterfall({
|
|
|
695
746
|
strokeDasharray: "4 4"
|
|
696
747
|
}
|
|
697
748
|
),
|
|
698
|
-
/* @__PURE__ */
|
|
749
|
+
/* @__PURE__ */ jsx6(
|
|
699
750
|
"text",
|
|
700
751
|
{
|
|
701
752
|
x: mark.x,
|
|
@@ -707,7 +758,7 @@ function ShapWaterfall({
|
|
|
707
758
|
}
|
|
708
759
|
)
|
|
709
760
|
] }, mark.kind)),
|
|
710
|
-
layout.arrows.map((arrow, index) => /* @__PURE__ */
|
|
761
|
+
layout.arrows.map((arrow, index) => /* @__PURE__ */ jsxs6(
|
|
711
762
|
"g",
|
|
712
763
|
{
|
|
713
764
|
onMouseEnter: () => setHovered(index),
|
|
@@ -715,7 +766,7 @@ function ShapWaterfall({
|
|
|
715
766
|
onClick: () => onFeatureClick == null ? void 0 : onFeatureClick(arrow.featureIndex),
|
|
716
767
|
style: { cursor: onFeatureClick ? "pointer" : "default" },
|
|
717
768
|
children: [
|
|
718
|
-
/* @__PURE__ */
|
|
769
|
+
/* @__PURE__ */ jsx6(
|
|
719
770
|
"rect",
|
|
720
771
|
{
|
|
721
772
|
x: 0,
|
|
@@ -725,7 +776,7 @@ function ShapWaterfall({
|
|
|
725
776
|
fill: hovered === index ? "#00000008" : "transparent"
|
|
726
777
|
}
|
|
727
778
|
),
|
|
728
|
-
/* @__PURE__ */
|
|
779
|
+
/* @__PURE__ */ jsx6(
|
|
729
780
|
"text",
|
|
730
781
|
{
|
|
731
782
|
x: 250,
|
|
@@ -738,7 +789,7 @@ function ShapWaterfall({
|
|
|
738
789
|
children: arrow.label
|
|
739
790
|
}
|
|
740
791
|
),
|
|
741
|
-
/* @__PURE__ */
|
|
792
|
+
/* @__PURE__ */ jsx6(
|
|
742
793
|
"polygon",
|
|
743
794
|
{
|
|
744
795
|
points: arrow.points.map((point) => `${point.x},${point.y}`).join(" "),
|
|
@@ -747,7 +798,7 @@ function ShapWaterfall({
|
|
|
747
798
|
strokeWidth: 1
|
|
748
799
|
}
|
|
749
800
|
),
|
|
750
|
-
/* @__PURE__ */
|
|
801
|
+
/* @__PURE__ */ jsx6(
|
|
751
802
|
"text",
|
|
752
803
|
{
|
|
753
804
|
x: arrow.valueLabel.x,
|