Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
47ca1a2
Add scatterquiver trace type
degzhaus Oct 21, 2025
b147fce
Ensure no-gl-jasmine tests pass
degzhaus Oct 22, 2025
ac0c611
Name plot type quiver not scatterquiver
degzhaus Nov 2, 2025
4c63785
Model quiver api closer to 3d cone trace
degzhaus Nov 3, 2025
db525aa
Match arrowhead attributes for annotations
degzhaus Nov 11, 2025
e75e55c
Derive scaling from axes
degzhaus Nov 11, 2025
2c4e7d5
Remove angle attribute
degzhaus Nov 11, 2025
9e91a1e
Include colorscale attributes in quiver
degzhaus Nov 11, 2025
23f2019
Add support for coloring by an independent scalar array
degzhaus Nov 11, 2025
7a96cc5
Run npm run schema
degzhaus Nov 11, 2025
e4806e1
Use isArrayOrTypedArray
degzhaus Nov 19, 2025
47498de
Add quiver jasmine and image tests
degzhaus Nov 17, 2025
110618a
Generate baseline images for quiver tests
degzhaus Nov 17, 2025
4d24647
Run npm run schema
degzhaus Nov 30, 2025
7d5c348
Improve code readability
degzhaus Dec 18, 2025
8258a46
Reuse scatter selectPoints for quiver instead of duplicating selectio…
degzhaus Feb 16, 2026
a370d0a
Use hasColorscale() to conditionally enable colorscale instead of har…
degzhaus Feb 16, 2026
79ad59f
Reuse scatter handleXYDefaults() for quiver x/y coercion, validation,…
degzhaus Feb 16, 2026
4cae5ac
Move colorscale attrs under marker and replace custom c attribute wit…
degzhaus Feb 16, 2026
f1a664f
Fix axis autorange to include arrow tips, not just base positions; re…
degzhaus Feb 16, 2026
41fd8b1
Add legend line icon for quiver traces by including quiver in getStyl…
degzhaus Feb 16, 2026
713fce1
Add marker_colorbar config to quiver module so colorbars render corre…
degzhaus Feb 16, 2026
9bd89c9
Implement visual text label rendering for quiver using shared Drawing…
degzhaus Feb 16, 2026
1ef51d7
Implement per-arrow selected/unselected styling with opacity dimming …
degzhaus Feb 16, 2026
885b0b4
Run npm run schema
degzhaus Feb 16, 2026
259d03e
Fix colorbar crash by ensuring traceOut.marker exists before colorsca…
degzhaus Feb 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/index-strict.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Plotly.register([
require('../src/traces/scatterpolargl/strict'),
require('./barpolar'),
require('./scattersmith'),
require('./quiver'),

// components
require('./calendars'),
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Plotly.register([
require('./scatterpolargl'),
require('./barpolar'),
require('./scattersmith'),
require('./quiver'),

// components
require('./calendars'),
Expand Down
3 changes: 3 additions & 0 deletions lib/quiver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';

module.exports = require('../src/traces/quiver');
2 changes: 1 addition & 1 deletion src/components/legend/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ function getGradientDirection(reversescale, isRadial) {
function getStyleGuide(d) {
var trace = d[0].trace;
var contours = trace.contours;
var showLine = subTypes.hasLines(trace);
var showLine = subTypes.hasLines(trace) || (trace.visible && trace.type === 'quiver');
var showMarker = subTypes.hasMarkers(trace);

var showFill = trace.visible && trace.fill && trace.fill !== 'none';
Expand Down
256 changes: 256 additions & 0 deletions src/traces/quiver/attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
'use strict';

var baseAttrs = require('../../plots/attributes');
var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var fontAttrs = require('../../plots/font_attributes');
var axisHoverFormat = require('../../plots/cartesian/axis_format_attributes').axisHoverFormat;
var dash = require('../../components/drawing/attributes').dash;

var extendFlat = require('../../lib/extend').extendFlat;
var colorScaleAttrs = require('../../components/colorscale/attributes');

var attrs = {
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
anim: true,
description: 'Sets the x coordinates of the arrow locations.'
},
y: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
anim: true,
description: 'Sets the y coordinates of the arrow locations.'
},
u: {
valType: 'data_array',
editType: 'calc',
anim: true,
description: 'Sets the x components of the arrow vectors.'
},
v: {
valType: 'data_array',
editType: 'calc',
anim: true,
description: 'Sets the y components of the arrow vectors.'
},
sizemode: {
valType: 'enumerated',
values: ['scaled', 'absolute', 'raw'],
editType: 'calc',
dflt: 'scaled',
description: [
'Determines whether `sizeref` is set as a *scaled* (unitless) scalar',
'(normalized by the max u/v norm in the vector field), as an *absolute*',
'value (in the same units as the vector field), or *raw* to use the',
'raw vector lengths.'
].join(' ')
},
sizeref: {
valType: 'number',
min: 0,
editType: 'calc',
description: [
'Adjusts the arrow size scaling.',
'The arrow length is determined by the vector norm multiplied by `sizeref`,',
'optionally normalized when `sizemode` is *scaled*.'
].join(' ')
},
anchor: {
valType: 'enumerated',
values: ['tip', 'tail', 'cm', 'center', 'middle'],
dflt: 'tail',
editType: 'calc',
description: [
'Sets the arrows\' anchor with respect to their (x,y) positions.',
'Use *tail* to place (x,y) at the base, *tip* to place (x,y) at the head,',
'or *cm*/*center*/*middle* to center the arrow on (x,y).'
].join(' ')
},
hoverdistance: {
valType: 'number',
min: -1,
dflt: 20,
editType: 'calc',
description: 'Maximum distance (in pixels) to look for nearby arrows on hover.'
},

xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
uhoverformat: axisHoverFormat('u', 'noDate'),
vhoverformat: axisHoverFormat('v', 'noDate'),

// Arrowhead sizing, consistent with annotations API naming
arrowsize: {
valType: 'number',
min: 0.3,
dflt: 1,
editType: 'calc',
description: [
'Scales the size of the arrow head relative to a base size.',
'Higher values produce larger heads.'
].join(' ')
},
// Back-compat alias
arrow_scale: {
valType: 'number',
min: 0,
max: 1,
editType: 'calc',
description: 'Deprecated alias for `arrowsize`-based sizing. Prefer using `arrowsize`.'
},

// Line styling for arrows
line: {
color: {
valType: 'color',
dflt: '#000',
editType: 'style',
description: 'Sets the color of the arrow lines.'
},
width: {
valType: 'number',
min: 0,
dflt: 1,
editType: 'style',
description: 'Sets the width (in px) of the arrow lines.'
},
dash: dash,
shape: {
valType: 'enumerated',
values: ['linear', 'spline', 'hv', 'vh', 'hvh', 'vhv'],
dflt: 'linear',
editType: 'plot',
description: 'Determines the line shape.'
},
smoothing: {
valType: 'number',
min: 0,
max: 1.3,
dflt: 1,
editType: 'plot',
description: 'Has an effect only if `shape` is set to *spline*. Sets the amount of smoothing.'
},
simplify: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: 'Simplifies lines by removing nearly-overlapping points.'
},
editType: 'style'
},

// Alias consistent with annotations; maps to line.width
arrowwidth: {
valType: 'number',
min: 0.1,
editType: 'style',
description: 'Sets the width (in px) of the arrow line (alias of `line.width`).'
},

// Text and labels
text: {
valType: 'data_array',
editType: 'calc',
anim: true,
description: 'Sets text elements associated with each (x,y) pair.'
},
textposition: {
valType: 'enumerated',
values: [
'top left', 'top center', 'top right',
'middle left', 'middle center', 'middle right',
'bottom left', 'bottom center', 'bottom right'
],
dflt: 'middle center',
editType: 'calc',
description: 'Sets the positions of the `text` elements with respects to the (x,y) coordinates.'
},
// Text font
textfont: fontAttrs({
editType: 'calc',
colorEditType: 'style',
arrayOk: true,
description: 'Sets the text font.'
}),

// Marker (for colorscale-based coloring of arrows)
marker: extendFlat(
{
editType: 'calc'
},
colorScaleAttrs('marker', {
showScaleDflt: true,
editTypeOverride: 'calc'
})
),

// Selection and styling
selected: {
line: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the line color of selected points.'
},
width: {
valType: 'number',
min: 0,
editType: 'style',
description: 'Sets the line width of selected points.'
},
editType: 'style'
},
textfont: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the text font color of selected points, applied only when a selection exists.'
},
editType: 'style'
},
editType: 'style'
},
unselected: {
line: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the line color of unselected points.'
},
width: {
valType: 'number',
min: 0,
editType: 'style',
description: 'Sets the line width of unselected points.'
},
editType: 'style'
},
textfont: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the text font color of unselected points, applied only when a selection exists.'
},
editType: 'style'
},
editType: 'style'
}
};

// Extend with base attributes (includes hoverinfo, etc.)
extendFlat(attrs, baseAttrs);

// Add hoverinfo with proper flags for quiver
// We need to create a new object to avoid mutating the shared base attributes
attrs.hoverinfo = extendFlat({}, baseAttrs.hoverinfo, {
flags: ['x', 'y', 'u', 'v', 'text', 'name'],
dflt: 'all'
});

// Add hovertemplate
attrs.hovertemplate = extendFlat({}, hovertemplateAttrs({}, {
keys: ['x', 'y', 'u', 'v', 'text', 'name']
}));

module.exports = attrs;
Loading