Skip to content

Add option for rounded corners on bar charts #6761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 81 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
024f05f
add basic cornerradius for bar charts
emilykl Oct 18, 2023
31c3ac2
update plot-schema
emilykl Oct 18, 2023
b0c6258
add layout.barcornerradius property
emilykl Oct 31, 2023
d71fe49
handle negative bars
emilykl Nov 2, 2023
bb78c78
formatting
emilykl Nov 2, 2023
5dfd686
round corners of legend icon if bar is rounded
emilykl Nov 8, 2023
64912d4
change the way layout.barcornerradius is handled
emilykl Nov 8, 2023
cc1e6ff
rename mock
emilykl Nov 8, 2023
dc2c54c
handle reversed x and y axes
emilykl Nov 9, 2023
3b725fa
cleanup and simplify bar path logic for rounded corners
emilykl Nov 22, 2023
870d4c9
don't round corners of bars which are not top of stack
emilykl Nov 22, 2023
aa8ba1e
fix outmost bar logic
emilykl Nov 27, 2023
5845e0e
extend rounding to lower bars
emilykl Dec 15, 2023
85f47c6
remove 0 default for bar.marker.cornerradius
emilykl Dec 30, 2023
578712a
only set helper values for rounded corners if needed
emilykl Dec 30, 2023
8f77cde
better pct string handling
emilykl Dec 30, 2023
45689ae
remove cornerradius attr from barpolar and funnel
emilykl Dec 30, 2023
137e185
fix rounding for grouped barmode
emilykl Dec 30, 2023
795235b
handle stacked traces with different cornerradius
emilykl Jan 2, 2024
dd717b6
handle label text position inside bars
emilykl Jan 5, 2024
35e0c8f
fix function name
emilykl Jan 6, 2024
7aa7496
test label position for cornerradius in mock
emilykl Jan 6, 2024
250bf31
adjust cornerradius standardization for stacked bars
emilykl Jan 6, 2024
495d950
update plot-schema
emilykl Jan 6, 2024
be0ddff
don't coerce marker.cornerradius
emilykl Jan 6, 2024
819e8bf
add draftlog
emilykl Jan 6, 2024
ed69422
syntax
emilykl Jan 6, 2024
4a44291
syntax
emilykl Jan 6, 2024
65d3b55
add image baseline
emilykl Jan 6, 2024
e8cdde1
update draftlog
emilykl Jan 6, 2024
9c4227e
fix rounding for relative barmode
emilykl Jan 6, 2024
dabcaf0
fix NaN bug
emilykl Jan 6, 2024
701fd8c
fix bug with stacking in group mode
emilykl Jan 6, 2024
29589e8
coerce marker.cornerradius for histograms
emilykl Jan 8, 2024
d0b9a90
fix histogram2d
emilykl Jan 8, 2024
3e5a957
fix behavior for negative bars in stacked barmode
emilykl Jan 8, 2024
582ce13
fix behavior for negative bars in stacked barmode (2)
emilykl Jan 8, 2024
a238c87
Cast radius parameter to number
emilykl Jan 9, 2024
ac329f7
validate cornerradius value in supply defaults
emilykl Jan 9, 2024
8a607e6
export validateCornerradius
emilykl Jan 9, 2024
338b4e6
Change cornerradius editType to calc
emilykl Jan 9, 2024
60c918e
Change barcornerradius editType to calc
emilykl Jan 9, 2024
9dd0896
better handling of text placement on rounded horizontal bars
emilykl Jan 9, 2024
1628b5c
avoid using Math.sign
emilykl Jan 10, 2024
bfbd397
lint
emilykl Jan 10, 2024
71e4896
update plot-schema
emilykl Jan 10, 2024
4e794d0
bugfix
emilykl Jan 11, 2024
dedce2a
bugfix
emilykl Jan 11, 2024
b137b25
store cornerradius in t instead of trace; general cleanup
emilykl Jan 11, 2024
fdd6d03
small cleanup and add comments
emilykl Jan 17, 2024
8fcc3a5
Merge branch 'master' into rounded-bars
emilykl Jan 17, 2024
71b53c3
update baseline
emilykl Jan 17, 2024
90cf5c3
add text to zz-bar-rounded-corners
archmoj Jan 19, 2024
510c66b
rounded-bar display_height_zero line_width
archmoj Jan 19, 2024
5599ea6
round bar_gantt-chart
archmoj Jan 19, 2024
8dffbbe
round hist_cum_stacked
archmoj Jan 19, 2024
c165f6a
round histogram_colorscale
archmoj Jan 19, 2024
ee2451a
round histogram-offsetgroups
archmoj Jan 19, 2024
256a87e
round period_positioning9
archmoj Jan 19, 2024
b122521
round bar_stackto100_negative
archmoj Jan 19, 2024
015b881
round bar_attrs_relative
archmoj Jan 19, 2024
8b57fb5
round worldcup
archmoj Jan 19, 2024
ec44d87
bugfix
emilykl Jan 19, 2024
2913c6e
text position DRAFT
emilykl Jan 24, 2024
9e3c249
update baselines
archmoj Jan 24, 2024
f986349
fix text padding for rounded bars
emilykl Jan 26, 2024
99352d0
update baselines
archmoj Jan 26, 2024
6f685c0
fix text scale and pad for rounded bars
emilykl Jan 26, 2024
f093ee7
fix text position for stacked rounded bars
emilykl Jan 30, 2024
e3cd5a5
simplify logic in cross_trace_calc
emilykl Jan 30, 2024
98356b4
update baselines
emilykl Jan 30, 2024
a2befea
fix variable declaration
emilykl Jan 30, 2024
781fbe2
remove lxFunc and lyFunc
emilykl Jan 31, 2024
97f0b0e
use absolute arcs for bar path
emilykl Feb 1, 2024
c52890c
simplify text placement logic
emilykl Feb 1, 2024
10e38f4
Update docstring
emilykl Feb 1, 2024
f7d4b4a
Update docstring
emilykl Feb 1, 2024
4335ba0
more permissive text inside/outside logic for rounded bars
emilykl Feb 1, 2024
e9043e9
Merge branch 'rounded-bars' of https://github.com/plotly/plotly.js in…
emilykl Feb 1, 2024
4624132
updated baselines
archmoj Feb 1, 2024
8c45d15
update schema
archmoj Feb 1, 2024
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
11 changes: 10 additions & 1 deletion src/traces/bar/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ var marker = extendFlat({
editType: 'style',
description: 'Sets the opacity of the bars.'
},
pattern: pattern
pattern: pattern,
cornerradius: {
valType: 'any',
dflt: 0,
editType: 'plot',
description: [
'Sets the rounding of corners. May be an integer number of pixels,',
'or a percentage of bar width(as a string).'
].join(' ')
},
});

module.exports = {
Expand Down
11 changes: 10 additions & 1 deletion src/traces/bar/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,14 @@ module.exports = {
'Sets the gap (in plot fraction) between bars of',
'the same location coordinate.'
].join(' ')
}
},
barcornerradius: {
valType: 'any',
dflt: 0,
editType: 'plot',
description: [
'Sets the rounding of corners. May be an integer number of pixels,',
'or a percentage of bar width(as a string).'
].join(' ')
},
};
1 change: 1 addition & 0 deletions src/traces/bar/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ module.exports = function(layoutIn, layoutOut, fullData) {

coerce('bargap', (shouldBeGapless && !gappedAnyway) ? 0 : 0.2);
coerce('bargroupgap');
coerce('barcornerradius');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use validateCornerradius to validate the inputs here as well .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that necessary? layout.barcornerradius is used only as a default value for trace.marker.cornerradius; it's never referenced again after that.

So the only reason to validate it would be for internal consistency within the plot object, which I guess is a good enough reason if that's consistent with what we do elsewhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. It does not seem necessary.
So we could skip it for now and possibly add a line comment?

};
44 changes: 43 additions & 1 deletion src/traces/bar/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,51 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
y1 = fixpx(y1, y0, !isHorizontal);
}

// Here is where bar is drawn
// TODO: Implement rounded corners here

function calcCornerRadius(radiusParam) {
var barWidth = isHorizontal ? Math.abs(y1 - y0) : Math.abs(x1 - x0);
if(!radiusParam) {
return 0;
} else if(typeof radiusParam === "string") { // if it's a percentage string
var rPercent = parseFloat(radiusParam.replace('%', ''));
return barWidth * (rPercent / 100);
} else { // otherwise, it's a number
return Math.min(
radiusParam,
barWidth/2,
);
}
}
var r = calcCornerRadius(trace.marker.cornerradius || fullLayout.barcornerradius);
var bardir = isHorizontal ? Math.sign(x1 - x0) : Math.sign(y0 - y1);
var cornersweep = bardir >= 0 ? 1 : 0;

var path;
if(r && isHorizontal) {
path = 'M' + x0 + ',' + y0
+ 'V' + y1
+ 'H' + (x1 - r*bardir)
+ 'a ' + r + ',' + r + ' 0 0 '+cornersweep+' ' + r*bardir + ',' + r
+ 'V' + (y0 - r)
+ 'a ' + r + ',' + r + ' 0 0 '+cornersweep+' ' + -r*bardir + ',' + r
+ 'Z';
} else if(r) {
path = 'M' + x0 + ',' + y0
+ 'V' + (y1 + r*bardir)
+ 'a ' + r + ',' + r + ' 0 0 '+cornersweep+' ' + r + ',' + -r*bardir
+ 'H' + (x1 - r)
+ 'a ' + r + ',' + r + ' 0 0 '+cornersweep+' ' + r + ',' + r*bardir
+ 'V' + y0 + 'Z';
} else {
path = 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z';
}

var sel = transition(Lib.ensureSingle(bar, 'path'), fullLayout, opts, makeOnCompleteCallback);
sel
.style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke')
.attr('d', (isNaN((x1 - x0) * (y1 - y0)) || (isBlank && gd._context.staticPlot)) ? 'M0,0Z' : 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z')
.attr('d', (isNaN((x1 - x0) * (y1 - y0)) || (isBlank && gd._context.staticPlot)) ? 'M0,0Z' : path)
.call(Drawing.setClipUrl, plotinfo.layerClipId, gd);

if(!fullLayout.uniformtext.mode && withTransition) {
Expand Down Expand Up @@ -350,6 +391,7 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCom
if(textPosition === 'auto') {
if(isOutmostBar) {
// draw text using insideTextFont and check if it fits inside bar
// TODO: Need to consider `cornerradius` here
textPosition = 'inside';

font = Lib.ensureUniformFontSize(gd, insideTextFont);
Expand Down
1 change: 1 addition & 0 deletions src/traces/bar/style_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module.exports = function handleStyleDefaults(traceIn, traceOut, coerce, default

coerce('marker.line.width');
coerce('marker.opacity');
coerce('marker.cornerradius');
coercePattern(coerce, 'marker.pattern', markerColor, hasMarkerColorscale);
coerce('selected.marker.color');
coerce('unselected.marker.color');
Expand Down
32 changes: 32 additions & 0 deletions test/image/mocks/bar-rounded-corners.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"data": [
{
"x": [
"giraffes",
"orangutans",
"monkeys",
"capybaras"
],
"y": [20, -14, 2, 18
],
"type": "bar",
"marker": {"cornerradius": 10}
},
{
"y": [
"giraffes",
"orangutans",
"monkeys",
"capybaras"
],
"x": [20, -4, -12, 18],
"type": "bar",
"orientation": "h",
"xaxis": "x2",
"yaxis": "y2"
}

],
"layout": {"grid": {"rows": 1, "columns": 2, "pattern": "independent"}, "barcornerradius": "30%"}
}

36 changes: 36 additions & 0 deletions test/plot-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -14083,6 +14083,12 @@
"editType": "none",
"valType": "string"
},
"cornerradius": {
"description": "Sets the rounding of corners. May be an integer number of pixels, or a percentage of bar width(as a string).",
"dflt": 0,
"editType": "plot",
"valType": "any"
},
"editType": "calc",
"line": {
"autocolorscale": {
Expand Down Expand Up @@ -14770,6 +14776,12 @@
"zoomScale"
],
"layoutAttributes": {
"barcornerradius": {
"description": "Sets the rounding of corners. May be an integer number of pixels, or a percentage of bar width(as a string).",
"dflt": 0,
"editType": "plot",
"valType": "any"
},
"bargap": {
"description": "Sets the gap (in plot fraction) between bars of adjacent location coordinates.",
"editType": "calc",
Expand Down Expand Up @@ -15632,6 +15644,12 @@
"editType": "none",
"valType": "string"
},
"cornerradius": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one shouldn't be added to barpolar.

"description": "Sets the rounding of corners. May be an integer number of pixels, or a percentage of bar width(as a string).",
"dflt": 0,
"editType": "plot",
"valType": "any"
},
"editType": "calc",
"line": {
"autocolorscale": {
Expand Down Expand Up @@ -26829,6 +26847,12 @@
"editType": "none",
"valType": "string"
},
"cornerradius": {
"description": "Sets the rounding of corners. May be an integer number of pixels, or a percentage of bar width(as a string).",
"dflt": 0,
"editType": "plot",
"valType": "any"
},
"editType": "calc",
"line": {
"autocolorscale": {
Expand Down Expand Up @@ -31439,6 +31463,12 @@
"editType": "none",
"valType": "string"
},
"cornerradius": {
"description": "Sets the rounding of corners. May be an integer number of pixels, or a percentage of bar width(as a string).",
"dflt": 0,
"editType": "plot",
"valType": "any"
},
"editType": "calc",
"line": {
"autocolorscale": {
Expand Down Expand Up @@ -32044,6 +32074,12 @@
"showLegend"
],
"layoutAttributes": {
"barcornerradius": {
"description": "Sets the rounding of corners. May be an integer number of pixels, or a percentage of bar width(as a string).",
"dflt": 0,
"editType": "plot",
"valType": "any"
},
"bargap": {
"description": "Sets the gap (in plot fraction) between bars of adjacent location coordinates.",
"editType": "calc",
Expand Down