Skip to content

Commit 21da158

Browse files
authored
Merge pull request #7908 from zeehio/claude/plotly-issue-6499-repro-6k2s7e
fix: Clamp colorbar axis domain to prevent inversion errors
2 parents b074563 + ec65958 commit 21da158

3 files changed

Lines changed: 82 additions & 10 deletions

File tree

draftlogs/7908_fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fix crash ("Something went wrong with axis scaling") when a colorbar's title or padding leaves it with a negative domain length [[#7908](https://github.com/plotly/plotly.js/pull/7908)], with thanks to @zeehio for the contribution!

src/components/colorbar/draw.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ function makeColorBarData(gd) {
167167
return out;
168168
}
169169

170+
// Move domain[0] toward domain[1] by delta, without crossing it
171+
const insetDomainStart = (domain, delta) => [Math.min(domain[0] + delta, domain[1]), domain[1]];
172+
173+
// Move domain[1] toward domain[0] by delta, without crossing it
174+
const insetDomainEnd = (domain, delta) => [domain[0], Math.max(domain[1] - delta, domain[0])];
175+
170176
function drawColorBar(g, opts, gd) {
171177
var isVertical = opts.orientation === 'v';
172178
var len = opts.len;
@@ -300,13 +306,8 @@ function drawColorBar(g, opts, gd) {
300306

301307
// set domain after init, because we may want to
302308
// allow it outside [0,1]
303-
ax.domain = isVertical ? [
304-
vFrac + ypad / gs.h,
305-
vFrac + lenFrac - ypad / gs.h
306-
] : [
307-
vFrac + xpad / gs.w,
308-
vFrac + lenFrac - xpad / gs.w
309-
];
309+
var padFrac = isVertical ? ypad / gs.h : xpad / gs.w;
310+
ax.domain = insetDomainEnd(insetDomainStart([vFrac, vFrac + lenFrac], padFrac), padFrac);
310311

311312
ax.setScale();
312313

@@ -473,10 +474,10 @@ function drawColorBar(g, opts, gd) {
473474
titleHeight += 5;
474475

475476
if(titleSide === 'top') {
476-
ax.domain[1] -= titleHeight / gs.h;
477+
ax.domain = insetDomainEnd(ax.domain, titleHeight / gs.h);
477478
titleTrans[1] *= -1;
478479
} else {
479-
ax.domain[0] += titleHeight / gs.h;
480+
ax.domain = insetDomainStart(ax.domain, titleHeight / gs.h);
480481
var nlines = svgTextUtils.lineCount(titleText);
481482
titleTrans[1] += (1 - nlines) * lineSize;
482483
}
@@ -487,7 +488,7 @@ function drawColorBar(g, opts, gd) {
487488
} else { // horizontal colorbars
488489
if(titleWidth) {
489490
if(titleSide === 'right') {
490-
ax.domain[0] += (titleWidth + titleFontSize / 2) / gs.w;
491+
ax.domain = insetDomainStart(ax.domain, (titleWidth + titleFontSize / 2) / gs.w);
491492
}
492493

493494
titleGroup.attr('transform', strTranslate(titleTrans[0], titleTrans[1]));

test/jasmine/tests/colorbar_test.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,76 @@ describe('Test colorbar:', function() {
9595
.then(done, done.fail);
9696
});
9797

98+
// see https://github.com/plotly/plotly.js/issues/6499
99+
it('does not throw when the colorbar is too short for its own length/padding', function(done) {
100+
Plotly.newPlot(gd, [{
101+
type: 'scatter',
102+
mode: 'markers',
103+
x: [1, 2, 3],
104+
y: [1, 2, 3],
105+
marker: {
106+
color: [1, 2, 3],
107+
colorbar: {len: 0.01, thickness: 30}
108+
}
109+
}], {width: 300, height: 120})
110+
.then(done, done.fail);
111+
});
112+
113+
it('does not throw when a top-side colorbar title is taller than the colorbar', function(done) {
114+
Plotly.newPlot(gd, [{
115+
type: 'scatter',
116+
mode: 'markers',
117+
x: [1, 2, 3],
118+
y: [1, 2, 3],
119+
marker: {
120+
color: [1, 2, 3],
121+
colorbar: {
122+
title: {text: 'Long title', side: 'top', font: {size: 60}},
123+
len: 0.3,
124+
thickness: 30
125+
}
126+
}
127+
}], {width: 300, height: 120})
128+
.then(done, done.fail);
129+
});
130+
131+
it('does not throw when a bottom-side colorbar title is taller than the colorbar', function(done) {
132+
Plotly.newPlot(gd, [{
133+
type: 'scatter',
134+
mode: 'markers',
135+
x: [1, 2, 3],
136+
y: [1, 2, 3],
137+
marker: {
138+
color: [1, 2, 3],
139+
colorbar: {
140+
title: {text: 'Long title', side: 'bottom', font: {size: 60}},
141+
len: 0.3,
142+
thickness: 30
143+
}
144+
}
145+
}], {width: 300, height: 120})
146+
.then(done, done.fail);
147+
});
148+
149+
it('does not throw when a right-side horizontal colorbar title is wider than the colorbar', function(done) {
150+
Plotly.newPlot(gd, [{
151+
type: 'scatter',
152+
mode: 'markers',
153+
x: [1, 2, 3],
154+
y: [1, 2, 3],
155+
marker: {
156+
color: [1, 2, 3],
157+
colorbar: {
158+
orientation: 'h',
159+
title: {text: 'Long title', side: 'right', font: {size: 60}},
160+
len: 0.3,
161+
thickness: 30
162+
}
163+
}
164+
}], {width: 300, height: 120})
165+
.then(done, done.fail);
166+
});
167+
98168
function assertCB(msg, present, opts) {
99169
var expandedMarginR = opts.expandedMarginR;
100170
var expandedMarginT = opts.expandedMarginT;

0 commit comments

Comments
 (0)