@qe-libs/qeviz 0.5.7 → 0.6.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.
- package/README.md +188 -7
- package/dist/qeviz.es.js +1681 -1257
- package/dist/qeviz.es.js.map +1 -1
- package/dist/qeviz.umd.js +25 -5
- package/dist/qeviz.umd.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,6 +105,14 @@ p
|
|
|
105
105
|
qe_export_html(p, "output.html")
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
Install `QEViz` from the QE package registry:
|
|
109
|
+
|
|
110
|
+
```julia
|
|
111
|
+
using Pkg
|
|
112
|
+
Pkg.Registry.add(RegistrySpec(url = "https://gitlab.com/epistemic-analytics/qe-packages/cranqe.git#julia"))
|
|
113
|
+
Pkg.add("QEViz")
|
|
114
|
+
```
|
|
115
|
+
|
|
108
116
|
## Chain API
|
|
109
117
|
|
|
110
118
|
All three languages share the same chain operations, with the same argument
|
|
@@ -113,16 +121,16 @@ model data (checked by the shared fixtures in `tests/golden/`):
|
|
|
113
121
|
|
|
114
122
|
| Operation | R | Python | Julia |
|
|
115
123
|
|---|---|---|---|
|
|
116
|
-
| Create | `qe_plot(set, title=, range=, scale_points=, point_scale=, center=, palette=)` | `qeviz.plot(model, title=, range=, ...)` | `qe_plot(model; title=, range=, ...)` |
|
|
124
|
+
| Create | `qe_plot(set, title=, range=, scale_points=, point_scale=, center=, palette=, view_padding=)` | `qeviz.plot(model, title=, range=, ...)` | `qe_plot(model; title=, range=, ...)` |
|
|
117
125
|
| Group means | `qe_group(p, ...)` | `p.group(...)` | `qe_group(p, ...)` |
|
|
118
126
|
| Mean of a subset | `qe_group(p, points=, label=, color=, shape=, intervals=, outlier=)` | `p.group(points=, ...)` | `qe_group(p; points=, ...)` |
|
|
119
127
|
| Edge network | `qe_edges(p, group=, unit=, compare=, also=)` | `p.edges(group=, unit=, ...)` | `qe_edges(p; group=, unit=, ...)` |
|
|
120
128
|
| Network from data | `qe_edges(p, weights=, compare=, colors=, threshold=, name=)` | `p.edges(weights=, ...)` | `qe_edges(p; weights=, ...)` |
|
|
121
129
|
| Unit points | `qe_points(p)` | `p.points()` | `qe_points(p)` |
|
|
122
130
|
| Point set | `qe_points(p, units=/points=, color=, shape=, labels=, name=)` | `p.points(units=/points=, ...)` | `qe_points(p; units=/points=, ...)` |
|
|
123
|
-
| Nodes | `qe_nodes(p, show, unconnected=, positions=, labels=)` | `p.nodes(show, positions=, labels=)` | `qe_nodes(p; show=, positions=, labels=)` |
|
|
124
|
-
| Axes | `qe_axes(p, x=, y=)` | `p.axes(x=, y=)` | `qe_axes(p; x=, y=)` |
|
|
125
|
-
| Labels | `qe_labels(p, nodes=, means=, points=, font_size=, font_family=, font_color=)` | `p.labels(...)` | `qe_labels(p; ...)` |
|
|
131
|
+
| Nodes | `qe_nodes(p, show, unconnected=, positions=, labels=, sizes=, fixed_size=)` | `p.nodes(show, positions=, labels=, sizes=, fixed_size=)` | `qe_nodes(p; show=, positions=, labels=, sizes=, fixed_size=)` |
|
|
132
|
+
| Axes | `qe_axes(p, x=, y=, fixed_size=)` | `p.axes(x=, y=, fixed_size=)` | `qe_axes(p; x=, y=, fixed_size=)` |
|
|
133
|
+
| Labels | `qe_labels(p, nodes=, means=, points=, font_size=, font_family=, font_color=, font_weight=)` | `p.labels(...)` | `qe_labels(p; ...)` |
|
|
126
134
|
| Group colours | `qe_colors(p, A = "#hex")` | `p.colors(A="#hex")` | `qe_colors(p, "A" => "#hex")` |
|
|
127
135
|
| Axis range | `qe_range(p, range)` | `p.range(range)` | `qe_range(p, range)` |
|
|
128
136
|
| Default palette | `qe_palette()` | `qeviz.palette()` | `qe_palette()` |
|
|
@@ -145,8 +153,18 @@ model data (checked by the shared fixtures in `tests/golden/`):
|
|
|
145
153
|
| `color_scale` | Colour mapping (webENA ramps: saturation 0.25–1, opacity 0.3–1). `"model"` (default) rescales across the whole model, so plots of one model share a colour scale; `"plot"` rescales within the plot (webENA); `"absolute"` uses saturation = opacity = weight. |
|
|
146
154
|
| `edge_width` | Width of a weight-1 edge as a fraction of the plot width (default 0.04). Width is absolute — equal weights draw equally wide — and each node's diameter is the sum of its edges' widths. |
|
|
147
155
|
| `magnify` | Multiply this plot's widths and node sizes (not colour), e.g. for a faint subtraction. When set (even `1`), the plot is labelled "(scaled N.Nx)". |
|
|
156
|
+
| `fixed_size` | `TRUE` keeps edge widths (lines, directed triangles, self-connection dots, hover targets) at their zoom-1 on-screen width when the plot is zoomed. Applies to every network; kept until given again. |
|
|
157
|
+
| `self_size` | ONA self-connection dots: `"node"` draws each at half its node's radius (as webENA does), a number is that fraction; the self weight then only sets the colour. Applies to every network; kept until given again. |
|
|
148
158
|
|
|
149
|
-
Label modes: `"on"`, `"off"`, `"click"`, `"auto"`.
|
|
159
|
+
Label modes: `"on"`, `"off"`, `"click"`, `"auto"`. `qe_labels(font_weight =)`
|
|
160
|
+
takes one weight for node, mean and point labels (`"bold"`, `600`) or a named
|
|
161
|
+
vector / dict for some of them (`c(nodes = "bold")`, `{"nodes": "bold"}`,
|
|
162
|
+
`(nodes = "bold",)`).
|
|
163
|
+
|
|
164
|
+
`qe_nodes(sizes =)` sets node diameters in CSS pixels at zoom 1 per code
|
|
165
|
+
(`c(Data = 24)`, `{"Data": 24}`, `Dict("Data" => 24)`), and `fixed_size`
|
|
166
|
+
keeps node diameters constant on screen when zoomed. `qe_plot(view_padding =)`
|
|
167
|
+
is how far the view extends beyond `range` (default 1.2; `1` matches it).
|
|
150
168
|
|
|
151
169
|
### `qe_axes` / `.axes()` parameters
|
|
152
170
|
|
|
@@ -159,6 +177,7 @@ draws the lines with no labels. Each label is controlled independently:
|
|
|
159
177
|
| `x` | `FALSE` (default) omits the x-axis label, `TRUE` labels it with its dimension name (e.g. `SVD1`), a string sets custom text. |
|
|
160
178
|
| `y` | Same as `x`, for the y-axis. |
|
|
161
179
|
| `show` / `show=false` | Suppress the axes entirely. |
|
|
180
|
+
| `fixed_size` | `TRUE` keeps the axis lines and labels at their zoom-1 on-screen size when the plot is zoomed. |
|
|
162
181
|
|
|
163
182
|
```r
|
|
164
183
|
qe_plot(set) |> qe_edges("FirstGame") |> qe_axes(x = "Task focus", y = TRUE)
|
|
@@ -201,6 +220,34 @@ In the language adapters this is `fixed_size = TRUE` on `qe_points()` / `qe_grou
|
|
|
201
220
|
(R), `fixed_size=True` on `.points()` / `.group()` (Python), and
|
|
202
221
|
`fixed_size=true` on `qe_points` / `qe_group` (Julia).
|
|
203
222
|
|
|
223
|
+
Edges and code nodes take `fixed-size` too, but there it only undoes the zoom:
|
|
224
|
+
they keep the on-screen size they have at zoom 1 (which still follows the data
|
|
225
|
+
and the plot size) at any zoom level, as webENA's sigma plots do:
|
|
226
|
+
|
|
227
|
+
```html
|
|
228
|
+
<qe-nodes fixed-size></qe-nodes>
|
|
229
|
+
<qe-edges network="n1" fixed-size></qe-edges>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
- `<qe-edges fixed-size>`: the thickness of everything in that edge layer stays
|
|
233
|
+
constant on screen: lines, directed triangles (their base, and so their
|
|
234
|
+
chevrons), self-connection dots sized by weight, and the invisible hover
|
|
235
|
+
lines. Positions and the triangles' apex split still zoom; a chevron's width
|
|
236
|
+
follows the triangle where it sits, so it can change slightly.
|
|
237
|
+
- `<qe-nodes fixed-size>`: code-node diameters, including a `size` column,
|
|
238
|
+
stay constant on screen. `self-size="node"` dots follow their node.
|
|
239
|
+
- `setHighlight()` rings and glows around fixed-size marks and edges stay
|
|
240
|
+
constant on screen as well.
|
|
241
|
+
- `<qe-means fixed-size>` also keeps the confidence-interval boxes and
|
|
242
|
+
crosshairs and the outlier boxes at their zoom-1 stroke width and dash
|
|
243
|
+
lengths.
|
|
244
|
+
- `<qe-axes fixed-size>`: the axis lines and axis labels keep their zoom-1
|
|
245
|
+
size on screen.
|
|
246
|
+
|
|
247
|
+
Labels sized with `label-font-size` (CSS px) are constant on screen at any
|
|
248
|
+
zoom already; without it they scale with the plot. Trajectory strokes still
|
|
249
|
+
grow with the zoom.
|
|
250
|
+
|
|
204
251
|
#### Point scaling and centring
|
|
205
252
|
|
|
206
253
|
Unit points and means sit much closer to the origin than the code nodes, so
|
|
@@ -227,6 +274,23 @@ In R these are `qe_plot(scale_points =, point_scale =, center =)`; in Python
|
|
|
227
274
|
`qeviz.plot(..., scale_points=, point_scale=, center=)` and in Julia
|
|
228
275
|
`qe_plot(model; scale_points=, point_scale=, center=)`.
|
|
229
276
|
|
|
277
|
+
#### View range and padding
|
|
278
|
+
|
|
279
|
+
`range` sets the symmetric axis range the view is framed on: `"network"`
|
|
280
|
+
(± the farthest node × 1.2), `"points"` (± the farthest drawn point × 1.2) or a
|
|
281
|
+
number. Without it, the range is 1.3 × the farthest drawn mark. The view then
|
|
282
|
+
shows `range × view-padding` in every direction; `view-padding` defaults to
|
|
283
|
+
`1.2`, and `view-padding="1"` makes the view match the range exactly, for a
|
|
284
|
+
host that does its own framing:
|
|
285
|
+
|
|
286
|
+
```html
|
|
287
|
+
<qe-graph range="0.8" view-padding="1"></qe-graph> <!-- view spans ±0.8 -->
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Pixel-based sizes (`label-font-size`, the plot title, `fixed-size` marks) are
|
|
291
|
+
converted against the range, so they come out at `size ÷ view-padding` CSS
|
|
292
|
+
pixels: exact with `view-padding="1"`, 1/1.2 of the size at the default.
|
|
293
|
+
|
|
230
294
|
Child element presence controls layer visibility — add `<qe-points>` to show unit dots, omit it to hide them. A `MutationObserver` watches for child additions, removals, and attribute changes, so interactive controls can manipulate the DOM directly:
|
|
231
295
|
|
|
232
296
|
```js
|
|
@@ -236,6 +300,67 @@ edges.setAttribute("compare", "SecondGame");
|
|
|
236
300
|
edges.removeAttribute("also");
|
|
237
301
|
```
|
|
238
302
|
|
|
303
|
+
Each render is rebuilt from the model, so calling `setModelData` again (new
|
|
304
|
+
coordinates, other units, different weights) updates the plot in place: labels
|
|
305
|
+
follow their marks, and marks, edges or labels that are no longer in the model
|
|
306
|
+
or no longer drawn are removed.
|
|
307
|
+
|
|
308
|
+
#### Explicit networks
|
|
309
|
+
|
|
310
|
+
`<qe-edges network="name">` draws the row `name` of the model's `networks`
|
|
311
|
+
frame (signed weights; one column per edge, e.g. `"Data.Design"`). Its edge
|
|
312
|
+
columns are read from the `networks` frame itself, so a model with just `nodes`
|
|
313
|
+
and `networks` is enough:
|
|
314
|
+
|
|
315
|
+
```js
|
|
316
|
+
vis.setModelData({
|
|
317
|
+
nodes: { data: [{ code: "A", x: 0.9, y: 0.3 }, { code: "B", x: -0.6, y: 0.8 }],
|
|
318
|
+
types: { code: "character" } },
|
|
319
|
+
networks: { data: [{ name: "n1", "A.B": 0.8 }], types: { name: "character" } },
|
|
320
|
+
});
|
|
321
|
+
// <qe-graph><qe-nodes></qe-nodes><qe-edges network="n1"></qe-edges></qe-graph>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
With the default `color-scale="model"`, the colour range comes from the `edges`
|
|
325
|
+
frame when the model has one, and otherwise from every row of `networks`.
|
|
326
|
+
|
|
327
|
+
#### Per-row labels and node sizes
|
|
328
|
+
|
|
329
|
+
Rows of the `nodes`, `pointsets` and `groups` frames can carry these optional
|
|
330
|
+
columns, applied on every render:
|
|
331
|
+
|
|
332
|
+
| Column | Type | Meaning |
|
|
333
|
+
|---|---|---|
|
|
334
|
+
| `label` | character | Label text. `""` draws no label for that row; missing or `NA` uses the id (the group name for means). |
|
|
335
|
+
| `label.dx`, `label.dy` | numeric | Offset of the label from its computed spot, in graph units with y down: the units of `qe-label-move`'s `detail.transform`, so a host can write a drag back. `NA` = 0, and 0 clears an earlier offset. When the frame has neither column, a dragged label keeps its own offset. |
|
|
336
|
+
| `label.pinned` | logical | `TRUE` always shows the label, whatever the layer's label mode (even `"off"`), across re-renders. |
|
|
337
|
+
| `size` (`nodes` only) | numeric | The code node's diameter in CSS px at zoom 1, in place of the Σ-edge-width size. It zooms with the plot like the computed size. Unconnected nodes stay a tiny dot (or hidden). |
|
|
338
|
+
|
|
339
|
+
Frames are rectangular: give every row every column (`null` where unset).
|
|
340
|
+
|
|
341
|
+
Labels in `"auto"` and `"click"` modes keep the state hover or a click left
|
|
342
|
+
them in when the plot re-renders, so a host may re-render on hover.
|
|
343
|
+
|
|
344
|
+
Point sets (`<qe-points set="…">`) are labelled too: the text comes from the
|
|
345
|
+
`label` column, else the point id, and the mode from the element's own `label`
|
|
346
|
+
attribute, else `<qe-graph label-points>` (default `"off"`). Their labels, and
|
|
347
|
+
`qe-label-move`, use the point id `<set>::<id>`.
|
|
348
|
+
|
|
349
|
+
Label weight and ONA self-connections:
|
|
350
|
+
|
|
351
|
+
```html
|
|
352
|
+
<qe-nodes label-font-weight="bold"></qe-nodes> <!-- also on <qe-means>, <qe-points>; default 500 -->
|
|
353
|
+
<qe-edges network="n1" self-size="node"></qe-edges>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
`self-size="node"` draws each self-connection dot at half its code node's
|
|
357
|
+
radius (as webENA's sigma plots do), so the self weight only sets its colour;
|
|
358
|
+
a number is that fraction of the node radius. Without it the dot is sized by
|
|
359
|
+
its weight.
|
|
360
|
+
|
|
361
|
+
Pixel sizes (`size`, like `label-font-size`) are converted against the range,
|
|
362
|
+
so with the default `view-padding` they come out at size ÷ 1.2.
|
|
363
|
+
|
|
239
364
|
### Events
|
|
240
365
|
|
|
241
366
|
`<qe-graph>` dispatches interaction events on the public element with
|
|
@@ -250,7 +375,17 @@ DOM. Each event's `detail` also carries the `originalEvent`.
|
|
|
250
375
|
|
|
251
376
|
Labels are **draggable** (drag to reposition; the label pins open and stays
|
|
252
377
|
visible), emitting `qe-label-move` on drop so the host can persist the position
|
|
253
|
-
or mirror it across coordinated plots.
|
|
378
|
+
or mirror it across coordinated plots, e.g. by sending it back in the
|
|
379
|
+
`label.dx` / `label.dy` columns. The drag follows the pointer at any zoom, and
|
|
380
|
+
`detail.transform` is in graph units whatever the zoom.
|
|
381
|
+
|
|
382
|
+
Marks that emit these events (nodes, means, points, edges) show a pointer
|
|
383
|
+
cursor. The plot lives in `<qe-graph>`'s shadow root, so to change it set the
|
|
384
|
+
`--qe-mark-cursor` custom property on the element:
|
|
385
|
+
|
|
386
|
+
```css
|
|
387
|
+
qe-graph { --qe-mark-cursor: crosshair; }
|
|
388
|
+
```
|
|
254
389
|
|
|
255
390
|
For a quick built-in tooltip on hover — `source – target (weight)` over edges,
|
|
256
391
|
the mark name over nodes — add the `tooltip` attribute to `<qe-graph>`. It is
|
|
@@ -292,6 +427,36 @@ graph.getPoints(); // [{ id, group, x, y }, …] (unit points)
|
|
|
292
427
|
graph.pointsInRect({ x, y, w, h }); // ids of unit points in a graph-space rect
|
|
293
428
|
```
|
|
294
429
|
|
|
430
|
+
The user zooms and pans as on webENA's sigma plots:
|
|
431
|
+
|
|
432
|
+
- **Wheel:** zooms toward the pointer, so the point under it stays put, by
|
|
433
|
+
`zoom-step` per 100 px of scroll (default `1.1`; a mouse notch is about
|
|
434
|
+
100 px). A trackpad pinch (ctrl + wheel) follows the pinch.
|
|
435
|
+
- **Double-click:** zooms in 2.2× toward the pointer, eased over 200 ms. Both
|
|
436
|
+
clicks still emit their `qe-*-click`; a double-click on a label doesn't zoom.
|
|
437
|
+
- **Drag:** pans, keeping the grabbed point under the mouse or finger at any
|
|
438
|
+
zoom; two fingers pinch-zoom about their midpoint and pan as it moves. A tap clicks like a mouse click,
|
|
439
|
+
and a finger drags labels as the mouse does.
|
|
440
|
+
|
|
441
|
+
| `<qe-graph>` attribute | Meaning |
|
|
442
|
+
|---|---|
|
|
443
|
+
| `zoom-step="1.5"` | Wheel zoom factor per 100 px of scroll (webENA's sigma: 1.5). |
|
|
444
|
+
| `zoom-min`, `zoom-max` | Zoom levels (1 = the fitted view) that every zoom stays within: wheel, double-click, pinch, `zoomBy`, `zoomTo`, `resetView`. Unbounded by default. |
|
|
445
|
+
| `view-locked` | While present, the user can't zoom or pan (wheel, double-click, drag, touch); the wheel scrolls the page instead. Clicks, hovers, label drags and the methods below still work. |
|
|
446
|
+
|
|
447
|
+
Drive the view from host controls (zoom buttons, a "recentre" action). These
|
|
448
|
+
zoom about the centre of the view, so a panned view keeps what it is showing
|
|
449
|
+
in the middle:
|
|
450
|
+
|
|
451
|
+
```js
|
|
452
|
+
graph.zoomBy(1.25); // zoom in by a factor (< 1 zooms out)
|
|
453
|
+
graph.zoomTo(2); // absolute level; 1 = the fitted view
|
|
454
|
+
graph.resetView(); // zoom 1, no pan
|
|
455
|
+
graph.zoom_level; // current level
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Levels or factors that are not finite and > 0 are ignored.
|
|
459
|
+
|
|
295
460
|
### Transitions & export
|
|
296
461
|
|
|
297
462
|
Opt into animated transitions with the `animate` attribute — on the next
|
|
@@ -302,6 +467,22 @@ snapping (default 300 ms; `animate="500"` sets the duration):
|
|
|
302
467
|
<qe-graph animate>…</qe-graph>
|
|
303
468
|
```
|
|
304
469
|
|
|
470
|
+
Everything travels together: points, point-set points and means, code nodes,
|
|
471
|
+
edges (their ends stay on their nodes, ONA triangles and self-connection dots
|
|
472
|
+
included), the interval and outlier boxes around the means, labels (with their
|
|
473
|
+
offsets) and the highlight. When the view changes too (a new `range`, or an
|
|
474
|
+
extent that follows the data), the view eases to the new one instead of
|
|
475
|
+
jumping. The first frame drawn is the old plot, so nothing flashes at its new
|
|
476
|
+
place first. Marks that appear or disappear do so at once; sizes and colours
|
|
477
|
+
change at the start.
|
|
478
|
+
|
|
479
|
+
A render while a transition runs starts from where the marks are at that
|
|
480
|
+
moment: the same update again carries on smoothly, and a new one turns them
|
|
481
|
+
towards their new places. Attribute and child-element changes made in the
|
|
482
|
+
same task as `setModelData` (before it) are drawn by that call's render;
|
|
483
|
+
changes made after it in the same task take one more render, which carries on
|
|
484
|
+
the same transition.
|
|
485
|
+
|
|
305
486
|
Snapshot the current plot for download or embedding:
|
|
306
487
|
|
|
307
488
|
```js
|
|
@@ -312,7 +493,7 @@ await graph.toPNG(2); // PNG data URL (2× resolution)
|
|
|
312
493
|
### Selection / highlight
|
|
313
494
|
|
|
314
495
|
Drive selection styling from the host without touching qeviz's internal DOM. The
|
|
315
|
-
highlight is an overlay that survives model updates:
|
|
496
|
+
highlight is an overlay that survives model updates and follows zoom and pan:
|
|
316
497
|
|
|
317
498
|
```js
|
|
318
499
|
graph.setHighlight({ edges: [{ source: "Data", target: "Design" }], nodes: ["Data"] });
|