Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 draftlogs/7986_fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fix the `node.pad` clamp warning in Sankey traces: it never fired after the `@plotly/d3-sankey` v0.12 upgrade because the layout getter now returns the configured padding rather than the effective (post-clamp) value; the warning now measures the laid-out node gaps and fires with the effective padding [[#7986](https://github.com/plotly/plotly.js/pull/7986)]
1 change: 1 addition & 0 deletions draftlogs/7991_fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Correct the `colorbar.dtick` (and `coloraxis.colorbar.dtick`) description: the special *log*/*date* string forms (*L<f>*, *D1*, *D2*, *M<n>*) are not supported on color bars - the internal color-bar axis is always linear, so such strings are silently ignored. The attribute now documents that only positive numbers are honored [[#7376](https://github.com/plotly/plotly.js/issues/7376)]
14 changes: 13 additions & 1 deletion src/components/colorbar/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,22 @@ module.exports = overrideAll(
description: 'Sets the color of padded area.'
},
// tick and title properties named and function exactly as in axes
// (except dtick: the colorbar axis is mocked as type *linear*, so the
// special *log*/*date* string forms documented on `dtick` - *L<f>*,
// *D1*, *D2*, *M<n>* - are silently discarded, see #7376)
tickmode: axesAttrs.minor.tickmode,
nticks: axesAttrs.nticks,
tick0: axesAttrs.tick0,
dtick: axesAttrs.dtick,
dtick: extendFlat({}, axesAttrs.dtick, {
description: [
'Sets the step in-between ticks on this color bar. Use with `tick0`.',
'Must be a positive number.',
'Unlike on x/y axes, the special *log* and *date* string forms',
'(*L<f>*, *D1*, *D2*, *M<n>*) are NOT supported here: this axis is',
'always linear, so such strings are silently ignored and the step',
'falls back to its default.'
].join(' ')
}),
tickvals: axesAttrs.tickvals,
ticktext: axesAttrs.ticktext,
ticks: extendFlat({}, axesAttrs.ticks, { dflt: '' }),
Expand Down
37 changes: 35 additions & 2 deletions src/traces/sankey/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,41 @@ function sankeyModel(layout, d, traceIndex) {

var graph = sankey();

if(sankey.nodePadding() < nodePad) {
Lib.warn('node.pad was reduced to ', sankey.nodePadding(), ' to fit within the figure.');
/*
* Detect a clamped node.pad from the laid-out node positions rather than
* from `sankey.nodePadding()`: since @plotly/d3-sankey v0.12 the getter
* returns the *configured* value (the post-clamp padding is kept in an
* internal variable), so comparing against it never fires. Measuring the
* smallest gap between consecutive nodes sharing a column works for both
* @plotly/d3-sankey and @plotly/d3-sankey-circular.
*/
var effectiveNodePad = null;
if(graph.nodes.length > 1) {
var colAttr = horizontal ? 'x0' : 'y0';
var posAttr = horizontal ? 'y0' : 'x0';
var columns = {};
graph.nodes.forEach(function(n) {
var ck = n[colAttr];
if(!columns[ck]) columns[ck] = [];
columns[ck].push(n);
});
Object.keys(columns).forEach(function(ck) {
var col = columns[ck].sort(function(a, b) { return a[posAttr] - b[posAttr]; });
for(var i = 1; i < col.length; i++) {
var gap = col[i][posAttr] - col[i - 1][posAttr];
if(effectiveNodePad === null || gap < effectiveNodePad) {
effectiveNodePad = gap;
}
}
});
}

if(effectiveNodePad !== null && effectiveNodePad < nodePad) {
Lib.warn(
'node.pad was reduced to ',
Math.round(effectiveNodePad * 100) / 100,
' to fit within the figure.'
);
}

// Counters for nested loops
Expand Down
2 changes: 1 addition & 1 deletion src/types/generated/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export interface ColorBar {
*/
borderwidth?: number;
/**
* Sets the step in-between ticks on this axis. Use with `tick0`. Must be a positive number, or special strings available to *log* and *date* axes. If the axis `type` is *log*, then ticks are set every 10^(n*dtick) where n is the tick number. For example, to set a tick mark at 1, 10, 100, 1000, ... set dtick to 1. To set tick marks at 1, 100, 10000, ... set dtick to 2. To set tick marks at 1, 5, 25, 125, 625, 3125, ... set dtick to log_10(5), or 0.69897000433. *log* has several special values; *L<f>*, where `f` is a positive number, gives ticks linearly spaced in value (but not position). For example `tick0` = 0.1, `dtick` = *L0.5* will put ticks at 0.1, 0.6, 1.1, 1.6 etc. To show powers of 10 plus small digits between, use *D1* (all digits) or *D2* (only 2 and 5). `tick0` is ignored for *D1* and *D2*. If the axis `type` is *date*, then you must convert the time to milliseconds. For example, to set the interval between ticks to one day, set `dtick` to 86400000.0. *date* also has special values *M<n>* gives ticks spaced by a number of months. `n` must be a positive integer. To set ticks on the 15th of every third month, set `tick0` to *2000-01-15* and `dtick` to *M3*. To set ticks every 4 years, set `dtick` to *M48*
* Sets the step in-between ticks on this color bar. Use with `tick0`. Must be a positive number. Unlike on x/y axes, the special *log* and *date* string forms (*L<f>*, *D1*, *D2*, *M<n>*) are NOT supported here: this axis is always linear, so such strings are silently ignored and the step falls back to its default.
* Setting this also sets: tickmode = "linear"
*/
dtick?: any;
Expand Down
65 changes: 65 additions & 0 deletions test/jasmine/tests/sankey_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,71 @@ describe('sankey tests', function () {
});
});

describe('node.pad clamp warning (issue 7832)', function() {
var gd;
beforeEach(function() {
gd = createGraphDiv();
});
afterEach(destroyGraphDiv);

function padWarnings() {
var warnings = [];
spyOn(Lib, 'warn').and.callFake(function(msg) {
warnings.push(msg);
});
return warnings;
}

it('fires when node.pad is clamped to fit the figure', function(done) {
var warnings = padWarnings();
var labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
// 8 sibling nodes cannot fit in a ~300px-high domain with
// node.pad: 40 -> d3-sankey clamps the padding
Plotly.newPlot(gd, [{
type: 'sankey',
domain: { x: [0, 1], y: [0, 0.5] },
node: {
label: labels,
pad: 40,
thickness: 15
},
link: {
source: [0, 0, 0, 0, 0, 0, 0, 0],
target: [1, 2, 3, 4, 5, 6, 7, 8],
value: [1, 1, 1, 1, 1, 1, 1, 1]
}
}])
.then(function() {
expect(warnings.length).toBe(1);
expect(warnings[0]).toContain('node.pad was reduced');
})
.then(done, done.fail);
});

it('does not fire when node.pad fits', function(done) {
var warnings = padWarnings();

Plotly.newPlot(gd, [{
type: 'sankey',
domain: { x: [0, 1], y: [0, 1] },
node: {
label: ['a', 'b', 'c', 'd'],
pad: 20,
thickness: 10
},
link: {
source: [0, 0, 0],
target: [1, 2, 3],
value: [1, 1, 1]
}
}])
.then(function() {
expect(warnings.length).toBe(0);
})
.then(done, done.fail);
});
});

describe('lifecycle methods', function () {
var gd;
beforeEach(function () {
Expand Down
Loading
Loading