Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3aa9559

Browse filesBrowse files
authored
Merge pull request plotly#6101 from s417-lama/pattern_fill_scatter
Add pattern fill for scatter filled area
2 parents d5f03f9 + 8ca0955 commit 3aa9559
Copy full SHA for 3aa9559

File tree

Expand file treeCollapse file tree

11 files changed

+224
-60
lines changed
Filter options
Expand file treeCollapse file tree

11 files changed

+224
-60
lines changed

‎draftlogs/6101_add.md

Copy file name to clipboard
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add pattern fill for scatter filled area

‎src/components/drawing/index.js

Copy file name to clipboardExpand all lines: src/components/drawing/index.js
+28-24Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -177,24 +177,42 @@ drawing.dashStyle = function(dash, lineWidth) {
177177
return dash;
178178
};
179179

180+
function setFillStyle(sel, trace, gd) {
181+
var markerPattern = trace.fillpattern;
182+
var patternShape = markerPattern && drawing.getPatternAttr(markerPattern.shape, 0, '');
183+
if(patternShape) {
184+
var patternBGColor = drawing.getPatternAttr(markerPattern.bgcolor, 0, null);
185+
var patternFGColor = drawing.getPatternAttr(markerPattern.fgcolor, 0, null);
186+
var patternFGOpacity = markerPattern.fgopacity;
187+
var patternSize = drawing.getPatternAttr(markerPattern.size, 0, 8);
188+
var patternSolidity = drawing.getPatternAttr(markerPattern.solidity, 0, 0.3);
189+
var patternID = trace.uid;
190+
drawing.pattern(sel, 'point', gd, patternID,
191+
patternShape, patternSize, patternSolidity,
192+
undefined, markerPattern.fillmode,
193+
patternBGColor, patternFGColor, patternFGOpacity
194+
);
195+
} else if(trace.fillcolor) {
196+
sel.call(Color.fill, trace.fillcolor);
197+
}
198+
}
199+
180200
// Same as fillGroupStyle, except in this case the selection may be a transition
181-
drawing.singleFillStyle = function(sel) {
201+
drawing.singleFillStyle = function(sel, gd) {
182202
var node = d3.select(sel.node());
183203
var data = node.data();
184-
var fillcolor = (((data[0] || [])[0] || {}).trace || {}).fillcolor;
185-
if(fillcolor) {
186-
sel.call(Color.fill, fillcolor);
187-
}
204+
var trace = ((data[0] || [])[0] || {}).trace || {};
205+
setFillStyle(sel, trace, gd);
188206
};
189207

190-
drawing.fillGroupStyle = function(s) {
208+
drawing.fillGroupStyle = function(s, gd) {
191209
s.style('stroke-width', 0)
192210
.each(function(d) {
193211
var shape = d3.select(this);
194212
// N.B. 'd' won't be a calcdata item when
195213
// fill !== 'none' on a segment-less and marker-less trace
196214
if(d[0].trace) {
197-
shape.call(Color.fill, d[0].trace.fillcolor);
215+
setFillStyle(shape, d[0].trace, gd);
198216
}
199217
});
200218
};
@@ -347,12 +365,7 @@ drawing.gradient = function(sel, gd, gradientID, type, colorscale, prop) {
347365
sel.style(prop, getFullUrl(fullID, gd))
348366
.style(prop + '-opacity', null);
349367

350-
var className2query = function(s) {
351-
return '.' + s.attr('class').replace(/\s/g, '.');
352-
};
353-
var k = className2query(d3.select(sel.node().parentNode)) +
354-
'>' + className2query(sel);
355-
fullLayout._gradientUrlQueryParts[k] = 1;
368+
sel.classed('gradient_filled', true);
356369
};
357370

358371
/**
@@ -559,11 +572,6 @@ drawing.pattern = function(sel, calledBy, gd, patternID, shape, size, solidity,
559572
.style('fill-opacity', null);
560573

561574
sel.classed('pattern_filled', true);
562-
var className2query = function(s) {
563-
return '.' + s.attr('class').replace(/\s/g, '.');
564-
};
565-
var k = className2query(d3.select(sel.node().parentNode)) + '>.pattern_filled';
566-
fullLayout._patternUrlQueryParts[k] = 1;
567575
};
568576

569577
/*
@@ -579,9 +587,7 @@ drawing.initGradients = function(gd) {
579587
var gradientsGroup = Lib.ensureSingle(fullLayout._defs, 'g', 'gradients');
580588
gradientsGroup.selectAll('linearGradient,radialGradient').remove();
581589

582-
// initialize stash of query parts filled in Drawing.gradient,
583-
// used to fix URL strings during image exports
584-
fullLayout._gradientUrlQueryParts = {};
590+
d3.select(gd).selectAll('.gradient_filled').classed('gradient_filled', false);
585591
};
586592

587593
drawing.initPatterns = function(gd) {
@@ -590,9 +596,7 @@ drawing.initPatterns = function(gd) {
590596
var patternsGroup = Lib.ensureSingle(fullLayout._defs, 'g', 'patterns');
591597
patternsGroup.selectAll('pattern').remove();
592598

593-
// initialize stash of query parts filled in Drawing.pattern,
594-
// used to fix URL strings during image exports
595-
fullLayout._patternUrlQueryParts = {};
599+
d3.select(gd).selectAll('.pattern_filled').classed('pattern_filled', false);
596600
};
597601

598602
drawing.getPatternAttr = function(mp, i, dflt) {

‎src/components/legend/style.js

Copy file name to clipboardExpand all lines: src/components/legend/style.js
+10-6Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,16 @@ module.exports = function style(s, gd, legend) {
111111
var colorscale = cOpts.colorscale;
112112
var reversescale = cOpts.reversescale;
113113

114-
var fillGradient = function(s) {
114+
var fillStyle = function(s) {
115115
if(s.size()) {
116-
var gradientID = 'legendfill-' + trace.uid;
117-
Drawing.gradient(s, gd, gradientID,
118-
getGradientDirection(reversescale),
119-
colorscale, 'fill');
116+
if(showFill) {
117+
Drawing.fillGroupStyle(s, gd);
118+
} else {
119+
var gradientID = 'legendfill-' + trace.uid;
120+
Drawing.gradient(s, gd, gradientID,
121+
getGradientDirection(reversescale),
122+
colorscale, 'fill');
123+
}
120124
}
121125
};
122126

@@ -145,7 +149,7 @@ module.exports = function style(s, gd, legend) {
145149
fill.enter().append('path').classed('js-fill', true);
146150
fill.exit().remove();
147151
fill.attr('d', pathStart + 'h' + itemWidth + 'v6h-' + itemWidth + 'z')
148-
.call(showFill ? Drawing.fillGroupStyle : fillGradient);
152+
.call(fillStyle);
149153

150154
if(showLine || showGradientLine) {
151155
var lw = boundLineWidth(undefined, trace.line, MAX_LINE_WIDTH, CST_LINE_WIDTH);

‎src/snapshot/tosvg.js

Copy file name to clipboardExpand all lines: src/snapshot/tosvg.js
+14-25Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ module.exports = function toSVG(gd, format, scale) {
3333
var toppaper = fullLayout._toppaper;
3434
var width = fullLayout.width;
3535
var height = fullLayout.height;
36-
var i, k;
36+
var i;
3737

3838
// make background color a rect in the svg, then revert after scraping
3939
// all other alterations have been dealt with by properly preparing the svg
@@ -106,32 +106,21 @@ module.exports = function toSVG(gd, format, scale) {
106106
}
107107
});
108108

109-
var queryParts = [];
110-
if(fullLayout._gradientUrlQueryParts) {
111-
for(k in fullLayout._gradientUrlQueryParts) queryParts.push(k);
112-
}
113-
114-
if(fullLayout._patternUrlQueryParts) {
115-
for(k in fullLayout._patternUrlQueryParts) queryParts.push(k);
116-
}
109+
svg.selectAll('.gradient_filled,.pattern_filled').each(function() {
110+
var pt = d3.select(this);
117111

118-
if(queryParts.length) {
119-
svg.selectAll(queryParts.join(',')).each(function() {
120-
var pt = d3.select(this);
121-
122-
// similar to font family styles above,
123-
// we must remove " after the SVG DOM has been serialized
124-
var fill = this.style.fill;
125-
if(fill && fill.indexOf('url(') !== -1) {
126-
pt.style('fill', fill.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
127-
}
112+
// similar to font family styles above,
113+
// we must remove " after the SVG DOM has been serialized
114+
var fill = this.style.fill;
115+
if(fill && fill.indexOf('url(') !== -1) {
116+
pt.style('fill', fill.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
117+
}
128118

129-
var stroke = this.style.stroke;
130-
if(stroke && stroke.indexOf('url(') !== -1) {
131-
pt.style('stroke', stroke.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
132-
}
133-
});
134-
}
119+
var stroke = this.style.stroke;
120+
if(stroke && stroke.indexOf('url(') !== -1) {
121+
pt.style('stroke', stroke.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
122+
}
123+
});
135124

136125
if(format === 'pdf' || format === 'eps') {
137126
// these formats make the extra line MathJax adds around symbols look super thick in some cases

‎src/traces/scatter/attributes.js

Copy file name to clipboardExpand all lines: src/traces/scatter/attributes.js
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplat
66
var colorScaleAttrs = require('../../components/colorscale/attributes');
77
var fontAttrs = require('../../plots/font_attributes');
88
var dash = require('../../components/drawing/attributes').dash;
9+
var pattern = require('../../components/drawing/attributes').pattern;
910

1011
var Drawing = require('../../components/drawing');
1112
var constants = require('./constants');
@@ -363,6 +364,7 @@ module.exports = {
363364
'marker color, or marker line color, whichever is available.'
364365
].join(' ')
365366
},
367+
fillpattern: pattern,
366368
marker: extendFlat({
367369
symbol: {
368370
valType: 'enumerated',

‎src/traces/scatter/defaults.js

Copy file name to clipboardExpand all lines: src/traces/scatter/defaults.js
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var handleLineDefaults = require('./line_defaults');
1414
var handleLineShapeDefaults = require('./line_shape_defaults');
1515
var handleTextDefaults = require('./text_defaults');
1616
var handleFillColorDefaults = require('./fillcolor_defaults');
17+
var coercePattern = require('../../lib').coercePattern;
1718

1819
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
1920
function coerce(attr, dflt) {
@@ -67,6 +68,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
6768
if(traceOut.fill !== 'none') {
6869
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
6970
if(!subTypes.hasLines(traceOut)) handleLineShapeDefaults(traceIn, traceOut, coerce);
71+
coercePattern(coerce, 'fillpattern', traceOut.fillcolor, false);
7072
}
7173

7274
var lineColor = (traceOut.line || {}).color;

‎src/traces/scatter/plot.js

Copy file name to clipboardExpand all lines: src/traces/scatter/plot.js
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,11 +304,11 @@ function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transition
304304
// the points on the axes are the first two points. Otherwise
305305
// animations get a little crazy if the number of points changes.
306306
transition(ownFillEl3).attr('d', 'M' + pt1 + 'L' + pt0 + 'L' + fullpath.substr(1))
307-
.call(Drawing.singleFillStyle);
307+
.call(Drawing.singleFillStyle, gd);
308308
} else {
309309
// fill to self: just join the path to itself
310310
transition(ownFillEl3).attr('d', fullpath + 'Z')
311-
.call(Drawing.singleFillStyle);
311+
.call(Drawing.singleFillStyle, gd);
312312
}
313313
}
314314
} else if(tonext) {
@@ -320,15 +320,15 @@ function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transition
320320
// This makes strange results if one path is *not* entirely
321321
// inside the other, but then that is a strange usage.
322322
transition(tonext).attr('d', fullpath + 'Z' + prevRevpath + 'Z')
323-
.call(Drawing.singleFillStyle);
323+
.call(Drawing.singleFillStyle, gd);
324324
} else {
325325
// tonextx/y: for now just connect endpoints with lines. This is
326326
// the correct behavior if the endpoints are at the same value of
327327
// y/x, but if they *aren't*, we should ideally do more complicated
328328
// things depending on whether the new endpoint projects onto the
329329
// existing curve or off the end of it
330330
transition(tonext).attr('d', fullpath + 'L' + prevRevpath.substr(1) + 'Z')
331-
.call(Drawing.singleFillStyle);
331+
.call(Drawing.singleFillStyle, gd);
332332
}
333333
trace._polygons = trace._polygons.concat(prevPolygons);
334334
} else {

‎src/traces/scatter/style.js

Copy file name to clipboardExpand all lines: src/traces/scatter/style.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function style(gd) {
2727
.call(Drawing.lineGroupStyle);
2828

2929
s.selectAll('g.trace path.js-fill')
30-
.call(Drawing.fillGroupStyle);
30+
.call(Drawing.fillGroupStyle, gd);
3131

3232
Registry.getComponentMethod('errorbars', 'style')(s);
3333
}
72.3 KB
Loading
+69Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"data": [
3+
{
4+
"x": [1, 2, 3, 4, 5],
5+
"y": [0.1, 0.3, 0.2, 0.8, 0.7],
6+
"stackgroup": "one",
7+
"fillpattern": {
8+
"fillmode": "overlay",
9+
"shape": "/"
10+
}
11+
},
12+
{
13+
"x": [1, 2, 3, 4, 5],
14+
"y": [0.3, 0.2, 0.1, 0.1, 0.2],
15+
"stackgroup": "one",
16+
"fillpattern": {
17+
"fillmode": "overlay",
18+
"shape": "\\"
19+
}
20+
},
21+
{
22+
"x": [1, 2, 3, 4, 5],
23+
"y": [0.8, 0.8, 0.6, 0.7, 0.4],
24+
"stackgroup": "one",
25+
"fillpattern": {
26+
"fillmode": "overlay",
27+
"shape": "."
28+
}
29+
},
30+
31+
{
32+
"xaxis": "x2",
33+
"yaxis": "y2",
34+
"x": [1, 2, 3, 4, 5, 6],
35+
"y": [0.1, 0.3, 0.4, 1.1, 0.8, 0.3],
36+
"fill": "tozeroy",
37+
"fillpattern": {
38+
"fillmode": "replace",
39+
"solidity": 0.4,
40+
"size": 12,
41+
"shape": "-"
42+
}
43+
},
44+
{
45+
"xaxis": "x2",
46+
"yaxis": "y2",
47+
"x": [1, 2, 3, 4, 5, 6],
48+
"y": [0.8, 0.7, 0.1, 0.6, 0.7, 0.8],
49+
"fill": "tonexty",
50+
"fillpattern": {
51+
"fillmode": "replace",
52+
"solidity": 0.4,
53+
"size": 12,
54+
"shape": "|"
55+
}
56+
}
57+
],
58+
"layout": {
59+
"title": {"text": "Pattern fill for scatter"},
60+
"width": 800,
61+
"height": 400,
62+
63+
"grid": {
64+
"rows": 1,
65+
"columns": 2,
66+
"pattern": "independent"
67+
}
68+
}
69+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.