Skip to content

Commit fcbb831

Browse files
authored
Merge pull request #4522 from plotly/fix4499-handle-empty-bars
Fix - hide empty bars in interactive mode
2 parents 453e70e + b3ee369 commit fcbb831

File tree

4 files changed

+256
-4
lines changed

4 files changed

+256
-4
lines changed

src/traces/bar/plot.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
147147
!isNumeric(y0) ||
148148
!isNumeric(y1)
149149
);
150+
150151
// display zeros if line.width > 0
151152
if(isBlank && shouldDisplayZeros && helpers.getLineWidth(trace, di) && (isHorizontal ? x1 - x0 === 0 : y1 - y0 === 0)) {
152153
isBlank = false;
@@ -156,6 +157,9 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
156157
if(isBlank && isHorizontal) x1 = x0;
157158
if(isBlank && !isHorizontal) y1 = y0;
158159

160+
var spansHorizontal = isHorizontal && (x0 !== x1);
161+
var spansVertical = !isHorizontal && (y0 !== y1);
162+
159163
// in waterfall mode `between` we need to adjust bar end points to match the connector width
160164
if(adjustPixel && !isBlank) {
161165
if(isHorizontal) {
@@ -210,10 +214,15 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
210214

211215
var op = Color.opacity(mc);
212216
var fixpx = (op < 1 || lw > 0.01) ? roundWithLine : expandToVisible;
213-
x0 = fixpx(x0, x1);
214-
x1 = fixpx(x1, x0);
215-
y0 = fixpx(y0, y1);
216-
y1 = fixpx(y1, y0);
217+
218+
if(spansHorizontal) {
219+
x0 = fixpx(x0, x1);
220+
x1 = fixpx(x1, x0);
221+
}
222+
if(spansVertical) {
223+
y0 = fixpx(y0, y1);
224+
y1 = fixpx(y1, y0);
225+
}
217226
}
218227

219228
var sel = transition(Lib.ensureSingle(bar, 'path'), fullLayout, opts, makeOnCompleteCallback);
31.6 KB
Loading

test/image/mocks/bar_hide_nulls.json

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
{
2+
"data": [
3+
{
4+
"type": "bar",
5+
"x": [
6+
"A",
7+
"B",
8+
"C",
9+
"D"
10+
],
11+
"y": [
12+
0,
13+
null,
14+
0.001,
15+
1
16+
],
17+
"text": [
18+
0,
19+
null,
20+
0.001,
21+
1
22+
],
23+
"textposition": "auto",
24+
"insidetextanchor": "middle",
25+
"cliponaxis": false
26+
},
27+
{
28+
"type": "bar",
29+
"x": [
30+
"A",
31+
"B",
32+
"C",
33+
"D"
34+
],
35+
"y": [
36+
0,
37+
null,
38+
0.001,
39+
1
40+
],
41+
"text": [
42+
0,
43+
null,
44+
0.001,
45+
1
46+
],
47+
"textposition": "auto",
48+
"insidetextanchor": "middle",
49+
"cliponaxis": false,
50+
"xaxis": "x2",
51+
"yaxis": "y2"
52+
},
53+
{
54+
"type": "bar",
55+
"orientation": "h",
56+
"x": [
57+
0,
58+
null,
59+
0.001,
60+
1
61+
],
62+
"y": [
63+
"A",
64+
"B",
65+
"C",
66+
"D"
67+
],
68+
"text": [
69+
0,
70+
null,
71+
0.001,
72+
1
73+
],
74+
"textposition": "auto",
75+
"insidetextanchor": "middle",
76+
"cliponaxis": false,
77+
"xaxis": "x3",
78+
"yaxis": "y3"
79+
},
80+
{
81+
"type": "bar",
82+
"orientation": "h",
83+
"x": [
84+
0,
85+
null,
86+
0.001,
87+
1
88+
],
89+
"y": [
90+
"A",
91+
"B",
92+
"C",
93+
"D"
94+
],
95+
"text": [
96+
0,
97+
null,
98+
0.001,
99+
1
100+
],
101+
"textposition": "auto",
102+
"insidetextanchor": "middle",
103+
"cliponaxis": false,
104+
"xaxis": "x4",
105+
"yaxis": "y4"
106+
}
107+
],
108+
"layout": {
109+
"showlegend": false,
110+
"width": 800,
111+
"height": 800,
112+
"dragmode": "pan",
113+
"xaxis": {
114+
"domain": [
115+
0,
116+
0.48
117+
]
118+
},
119+
"xaxis2": {
120+
"autorange": "reversed",
121+
"anchor": "y2",
122+
"domain": [
123+
0.52,
124+
1
125+
]
126+
},
127+
"xaxis3": {
128+
"range": [
129+
-0.01,
130+
1
131+
],
132+
"zeroline": false,
133+
"anchor": "y3",
134+
"domain": [
135+
0,
136+
0.48
137+
]
138+
},
139+
"xaxis4": {
140+
"range": [
141+
-0.01,
142+
1
143+
],
144+
"zeroline": false,
145+
"autorange": "reversed",
146+
"anchor": "y4",
147+
"domain": [
148+
0.52,
149+
1
150+
]
151+
},
152+
"yaxis": {
153+
"range": [
154+
-0.01,
155+
1
156+
],
157+
"zeroline": false,
158+
"domain": [
159+
0,
160+
0.48
161+
]
162+
},
163+
"yaxis2": {
164+
"range": [
165+
-0.01,
166+
1
167+
],
168+
"zeroline": false,
169+
"autorange": "reversed",
170+
"anchor": "x2",
171+
"domain": [
172+
0.52,
173+
1
174+
]
175+
},
176+
"yaxis3": {
177+
"anchor": "x3",
178+
"domain": [
179+
0.52,
180+
1
181+
]
182+
},
183+
"yaxis4": {
184+
"autorange": "reversed",
185+
"anchor": "x4",
186+
"domain": [
187+
0,
188+
0.48
189+
]
190+
}
191+
}
192+
}

test/jasmine/tests/bar_test.js

+51
Original file line numberDiff line numberDiff line change
@@ -2025,6 +2025,57 @@ describe('A bar plot', function() {
20252025
.catch(failTest)
20262026
.then(done);
20272027
});
2028+
2029+
it('should not show up null and zero bars as thin bars', function(done) {
2030+
var mock = Lib.extendDeep({}, require('@mocks/bar_hide_nulls.json'));
2031+
2032+
function getArea(path) {
2033+
var pos = path
2034+
.substr(1, path.length - 2)
2035+
.replace('V', ',')
2036+
.replace('H', ',')
2037+
.replace('V', ',')
2038+
.split(',');
2039+
var dx = +pos[0];
2040+
var dy = +pos[1];
2041+
dy -= +pos[2];
2042+
dx -= +pos[3];
2043+
2044+
return Math.abs(dx * dy);
2045+
}
2046+
2047+
Plotly.plot(gd, mock)
2048+
.then(function() {
2049+
var nodes = gd.querySelectorAll('g.point > path');
2050+
expect(nodes.length).toBe(16, '# of bars');
2051+
2052+
[
2053+
[0, false],
2054+
[1, false],
2055+
[2, true],
2056+
[3, true],
2057+
[4, false],
2058+
[5, false],
2059+
[6, true],
2060+
[7, true],
2061+
[8, false],
2062+
[9, false],
2063+
[10, true],
2064+
[11, true],
2065+
[12, false],
2066+
[13, false],
2067+
[14, true],
2068+
[15, true]
2069+
].forEach(function(e) {
2070+
var i = e[0];
2071+
var d = nodes[i].getAttribute('d');
2072+
var visible = e[1];
2073+
expect(getArea(d) > 0).toBe(visible, 'item:' + i);
2074+
});
2075+
})
2076+
.catch(failTest)
2077+
.then(done);
2078+
});
20282079
});
20292080

20302081
describe('bar visibility toggling:', function() {

0 commit comments

Comments
 (0)