-
-
Couldn't load subscription status.
- Fork 1.9k
Treemap new trace type #4185
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
Treemap new trace type #4185
Changes from 1 commit
ec6a9de
52ded31
320f81a
06d93ae
6cc8590
6a595b6
671e864
648167d
6dad958
cceee49
f3d38b8
088b0e0
e23a577
eb54f24
0e3185f
fdd69e7
a7b6074
4c85360
65c0e02
ca4b385
0012fa1
544977e
13e0449
57dec38
65f0213
ad24987
36fb510
284bf6d
4e2c328
0cf5bf6
2405ba4
19c7a61
4e3b7f3
e5181ac
e9c0202
e4bc91e
a54ca9c
d7b06a1
c91f9db
ceb13f7
1270d67
35ea4b3
1de80d9
e7e22c6
6130f96
e3a8e91
14674d6
01c5f68
4c7a092
1860826
d2b07b5
1fdf574
3004a9a
4d790a1
1c6e47b
e339bf5
1309bfd
217c0f4
8416883
c918da9
7d67c7a
f8cef49
3c12bf6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,324 @@ | ||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * Copyright 2012-2019, Plotly, Inc. | ||||||||||||||||||||||||||||||||||||||
| * All rights reserved. | ||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||
| * This source code is licensed under the MIT license found in the | ||||||||||||||||||||||||||||||||||||||
| * LICENSE file in the root directory of this source tree. | ||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| 'use strict'; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; | ||||||||||||||||||||||||||||||||||||||
| var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| var colorScaleAttrs = require('../../components/colorscale/attributes'); | ||||||||||||||||||||||||||||||||||||||
| var domainAttrs = require('../../plots/domain').attributes; | ||||||||||||||||||||||||||||||||||||||
| var pieAttrs = require('../pie/attributes'); | ||||||||||||||||||||||||||||||||||||||
| var sunburstAttrs = require('../sunburst/attributes'); | ||||||||||||||||||||||||||||||||||||||
| var constants = require('./constants'); | ||||||||||||||||||||||||||||||||||||||
| var extendFlat = require('../../lib/extend').extendFlat; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| module.exports = { | ||||||||||||||||||||||||||||||||||||||
| labels: sunburstAttrs.labels, | ||||||||||||||||||||||||||||||||||||||
| parents: sunburstAttrs.parents, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| values: sunburstAttrs.values, | ||||||||||||||||||||||||||||||||||||||
| branchvalues: sunburstAttrs.branchvalues, | ||||||||||||||||||||||||||||||||||||||
| count: sunburstAttrs.count, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| level: sunburstAttrs.level, | ||||||||||||||||||||||||||||||||||||||
| maxdepth: sunburstAttrs.maxdepth, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| tiling: { | ||||||||||||||||||||||||||||||||||||||
| packing: { | ||||||||||||||||||||||||||||||||||||||
archmoj marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
| valType: 'enumerated', | ||||||||||||||||||||||||||||||||||||||
| values: [ | ||||||||||||||||||||||||||||||||||||||
| 'squarify', | ||||||||||||||||||||||||||||||||||||||
| 'binary', | ||||||||||||||||||||||||||||||||||||||
| 'dice', | ||||||||||||||||||||||||||||||||||||||
| 'slice', | ||||||||||||||||||||||||||||||||||||||
| 'slice-dice', | ||||||||||||||||||||||||||||||||||||||
| 'dice-slice' | ||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||
| dflt: 'squarify', | ||||||||||||||||||||||||||||||||||||||
| role: 'info', | ||||||||||||||||||||||||||||||||||||||
| editType: 'plot', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'Determines d3 treemap solver.', | ||||||||||||||||||||||||||||||||||||||
| 'For more info please refer to https://github.com/d3/d3-hierarchy#treemap-tiling' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| squarifyratio: { | ||||||||||||||||||||||||||||||||||||||
| valType: 'number', | ||||||||||||||||||||||||||||||||||||||
| role: 'info', | ||||||||||||||||||||||||||||||||||||||
| min: 1, | ||||||||||||||||||||||||||||||||||||||
| dflt: 1, | ||||||||||||||||||||||||||||||||||||||
| editType: 'plot', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'When using *squarify* `packing` algorithm, according to https://github.com/d3/d3-hierarchy/blob/master/README.md#squarify_ratio', | ||||||||||||||||||||||||||||||||||||||
| 'this option specifies the desired aspect ratio of the generated rectangles.', | ||||||||||||||||||||||||||||||||||||||
| 'The ratio must be specified as a number greater than or equal to one.', | ||||||||||||||||||||||||||||||||||||||
| 'Note that the orientation of the generated rectangles (tall or wide)', | ||||||||||||||||||||||||||||||||||||||
| 'is not implied by the ratio; for example, a ratio of two will attempt', | ||||||||||||||||||||||||||||||||||||||
| 'to produce a mixture of rectangles whose width:height ratio is either 2:1 or 1:2.', | ||||||||||||||||||||||||||||||||||||||
| 'When using *squarify*, unlike d3 which uses the Golden Ratio i.e. 1.618034,', | ||||||||||||||||||||||||||||||||||||||
| 'Plotly applies 1 to increase squares in treemap layouts.' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| mirror: { | ||||||||||||||||||||||||||||||||||||||
etpinard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
| valType: 'flaglist', | ||||||||||||||||||||||||||||||||||||||
| role: 'info', | ||||||||||||||||||||||||||||||||||||||
| flags: [ | ||||||||||||||||||||||||||||||||||||||
| 'x', | ||||||||||||||||||||||||||||||||||||||
| 'y' | ||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||
| dflt: '', | ||||||||||||||||||||||||||||||||||||||
| editType: 'plot', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'Determines if the positions obtained from solver are mirrored on each axis.' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| pad: { | ||||||||||||||||||||||||||||||||||||||
| valType: 'number', | ||||||||||||||||||||||||||||||||||||||
| role: 'style', | ||||||||||||||||||||||||||||||||||||||
| min: 0, | ||||||||||||||||||||||||||||||||||||||
| dflt: 3, | ||||||||||||||||||||||||||||||||||||||
| editType: 'plot', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'Sets the inner padding (in px).' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| editType: 'calc', | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| marker: extendFlat({ | ||||||||||||||||||||||||||||||||||||||
| pad: { | ||||||||||||||||||||||||||||||||||||||
| top: { | ||||||||||||||||||||||||||||||||||||||
etpinard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
| valType: 'number', | ||||||||||||||||||||||||||||||||||||||
| role: 'style', | ||||||||||||||||||||||||||||||||||||||
| min: 0, | ||||||||||||||||||||||||||||||||||||||
| dflt: 'auto', | ||||||||||||||||||||||||||||||||||||||
| editType: 'plot', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'Sets the padding form the top (in px).' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| left: { | ||||||||||||||||||||||||||||||||||||||
| valType: 'number', | ||||||||||||||||||||||||||||||||||||||
| role: 'style', | ||||||||||||||||||||||||||||||||||||||
| min: 0, | ||||||||||||||||||||||||||||||||||||||
| dflt: 'auto', | ||||||||||||||||||||||||||||||||||||||
| editType: 'plot', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'Sets the padding form the left (in px).' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| right: { | ||||||||||||||||||||||||||||||||||||||
| valType: 'number', | ||||||||||||||||||||||||||||||||||||||
| role: 'style', | ||||||||||||||||||||||||||||||||||||||
| min: 0, | ||||||||||||||||||||||||||||||||||||||
| dflt: 'auto', | ||||||||||||||||||||||||||||||||||||||
| editType: 'plot', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'Sets the padding form the right (in px).' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| bottom: { | ||||||||||||||||||||||||||||||||||||||
| valType: 'number', | ||||||||||||||||||||||||||||||||||||||
| role: 'style', | ||||||||||||||||||||||||||||||||||||||
| min: 0, | ||||||||||||||||||||||||||||||||||||||
| dflt: 'auto', | ||||||||||||||||||||||||||||||||||||||
| editType: 'plot', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'Sets the padding form the bottom (in px).' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| editType: 'calc' | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| colors: { | ||||||||||||||||||||||||||||||||||||||
| valType: 'data_array', | ||||||||||||||||||||||||||||||||||||||
| editType: 'calc', | ||||||||||||||||||||||||||||||||||||||
| description: [ | ||||||||||||||||||||||||||||||||||||||
| 'Sets the color of each sector of this treemap chart.', | ||||||||||||||||||||||||||||||||||||||
| 'If not specified, the default trace color set is used', | ||||||||||||||||||||||||||||||||||||||
| 'to pick the sector colors.' | ||||||||||||||||||||||||||||||||||||||
| ].join(' ') | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| opacity: { | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| opacity = trace.marker.opacity * Math.pow(trace.branch.opacity, pt.height); |
That's interesting, but wouldn't having marker.opacity (when set) override branch.opacity be more user friendly in your mind? In particular, if we allow marker.opacity to be arrayOk, this could allow users to set the opacity of a sector pretty easily.
What do you think @archmoj ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A very good call!
It helped me rethink a couple of things in 0012fa1.
Now the API is more similar to sunburst where both have a leaf.opacity option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
marker.depthfade?
It also occurs to me that opacity might not actually be quite the effect we want - perhaps it would be better to use the opaque color that would result from blending the marker color with the background color in the same proportion? For the bottom-most layer the effect is equivalent, but anything stacked above it currently effectively is more opaque (if the two colors are the same) or blended to a different color (if using a colorscale or explicit colors). Both of these I think are problematic:
- if the color has meaning, a faded version of that color is probably still easy to mentally connect with the original, keeping its interpretation the same, but a version blended with a different color could shift the implied meaning of that color.
- making stacked layers more opaque kind of defeats the purpose - it means that the final effective opacity drops off too slowly at first, then more quickly toward the back of the stack.
Anyway if we extend the analogy I mentioned this morning of "looking at layers of hills in the distance" - those hills are not transparent, they are faded by the air in front of them - which is exactly the same effect as blending with the background color.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexcjohnson Thanks very much for the feedback. Is there a place in plotly.js code that a similar colour blending is applied?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
look for color.combine
plotly.js/src/components/color/index.js
Lines 46 to 62 in 56f6983
| color.combine = function(front, back) { | |
| var fc = tinycolor(front).toRgb(); | |
| if(fc.a === 1) return tinycolor(front).toRgbString(); | |
| var bc = tinycolor(back || background).toRgb(); | |
| var bcflat = bc.a === 1 ? bc : { | |
| r: 255 * (1 - bc.a) + bc.r * bc.a, | |
| g: 255 * (1 - bc.a) + bc.g * bc.a, | |
| b: 255 * (1 - bc.a) + bc.b * bc.a | |
| }; | |
| var fcflat = { | |
| r: bcflat.r * (1 - fc.a) + fc.r * fc.a, | |
| g: bcflat.g * (1 - fc.a) + fc.g * fc.a, | |
| b: bcflat.b * (1 - fc.a) + fc.b * fc.a | |
| }; | |
| return tinycolor(fcflat).toRgbString(); | |
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New attempt in 4c7a092 - which I'm a fan of 👌
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this solution, especially this part:
plotly.js/src/traces/treemap/style.js
Line 43 in 648167d
| opacity = trace.marker.opacity * Math.pow(trace.branch.opacity, pt.height); |
which I think gives a nice visual effect while keeping all sectors opaque enough.
As this implementation is a little different than the one proposed in #1038 (comment) and I don't remember us talking about this in a meeting, I'll cc @nicolaskruchten @alexcjohnson @antoinerg
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plus here is one image test related to that:
https://github.com/plotly/plotly.js/blob/treemap-finalist/test/image/baselines/treemap_pad_mirror.png
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a small number of levels I think it looks good. For a large number like treemap_pad_mirror has, seems like the bottom layer is too transparent. Maybe limit the power to something like 4 max? If that looks weird as you cross the max-height threshold, we could smoothly asymptote with something like:
hEffective = (h^(-p) + max^(-p))^(-1/p)
(and insert hEffective as the power instead of pt.height)
p=3, max=4 would be the first one I'd try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latest implementation is in #4185 (comment)
etpinard marked this conversation as resolved.
Show resolved
Hide resolved
etpinard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
etpinard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
etpinard marked this conversation as resolved.
Show resolved
Hide resolved
etpinard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
etpinard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
etpinard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
etpinard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /** | ||
| * Copyright 2012-2019, Plotly, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| 'use strict'; | ||
|
|
||
| var plots = require('../../plots/plots'); | ||
|
|
||
| exports.name = 'treemap'; | ||
|
|
||
| exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) { | ||
| plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback); | ||
| }; | ||
|
|
||
| exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { | ||
| plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| /** | ||
| * Copyright 2012-2019, Plotly, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| 'use strict'; | ||
|
|
||
| var sunburstCalc = require('../sunburst/calc'); | ||
|
|
||
| exports.calc = function(gd, trace) { | ||
| return sunburstCalc.calc(gd, trace); | ||
| }; | ||
|
|
||
| exports.crossTraceCalc = function(gd) { | ||
| return sunburstCalc._runCrossTraceCalc('treemap', gd); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /** | ||
| * Copyright 2012-2019, Plotly, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| 'use strict'; | ||
|
|
||
| module.exports = { | ||
| CLICK_TRANSITION_TIME: 750, | ||
| CLICK_TRANSITION_EASING: 'cubic', | ||
| eventDataKeys: [ | ||
| 'currentPath', | ||
| 'percentRoot', | ||
| 'percentVisible', | ||
| 'percentParent', | ||
| 'rootLabel', | ||
| 'visibleLabel', | ||
| 'parentLabel' | ||
| ] | ||
| }; |
Uh oh!
There was an error while loading. Please reload this page.