-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Extend multicategory axes to more than 2 levels #2175
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
Comments
If your team is used to JMP, this axis style is definitely a must-have. I think using annotations with subplots for the lower axes labels (like in the example you linked) is fairly robust though. This plot for example would be 3 subplots with 3 annotation labels: The popcorn example would be 4 subplots with 6 annotations: There isn't another issue for this ASFAIK. To make JMP-style labels part of the JSON schema, a company would probably have to sponsor this feature to get it on the roadmap: https://plot.ly/products/consulting-and-oem/ |
I've been trying to figure out if there's a way to generate similar plots using the current plotly capabilities. One option is to just concatenate the keys and use that for a categorical axis, but that's hard to read. I also tried to set this up using multiple axes (along the lines of this demo) but I haven't had much success, mostly because the I also saw a demo that used a normal categorical axis for the first level and annotations for the 2nd, but it was not clear if it could be extended to more than two levels. Was there some automated process that generated the annotations shown here or was that all done by hand? |
Some fondation work has been done in: #3300 Extending |
Hi @etpinard , import plotly.graph_objects as go I imagine just change x for Thanks a lot, |
Mentioned in the community forum https://community.plotly.com/t/multicategory-axis-how-many-categories-are-allowed/39563/2 |
+1 |
Can someone please comment on the status of this feature or at least tell us where in the source code we need to look to try and add this capability ourselves? @etpinard, can you give a high level overview of what we would need to change to extend multicategory axis capability? Any help is greatly appreciated. Thanks |
I'm extremly expecting this feature (multil categories over 2) being available or the official team can provide an extend approach for developers to use in short term. |
Did anybody find at least where the slicing occurs? As no error is thrown when 3 columns are inserted as x argument, and only the first 2 get their labels plotted, I tried at least to find the slicing, without success. Any help on this matter is appreciated. |
I’ve decided to take a closer look at this. Initially I was trying to find out where plotly.py was slicing the dataframe, as I was trying to do this in Python.
If I understood it correctly, here it also tries to sort the columns, after it collects the combinations.
The sorting does not account for all the levels, as per #3723 and #3908. I solved the sorting problem, implemented it inside
Original sorting changes only the second level, and not all of them. Edited sorting algorithm: Slightly editing the x data, and increasing the dimension:
After solving the dimension and sorting issues, I tried to implement some foundation for the multicategory with n-levels, in formatMultiCategory and getSecondaryLabelVals. function formatMultiCategory(ax, out, hover) {
var v = Math.round(out.x);
// copy categories to prevent hover instability
- var cats = ax._categories[v] || [];
+ var cats = ax._categories[v].map(function(cat) {return cat;}) || [];
+ var texts = cats.reverse().map(function(cat) {
+ return cat === undefined ? '' : String(cat);
+ });
+ ax.levels = cats.length;
if(hover) {
// TODO is this what we want?
- out.text = tt2 + ' - ' + tt;
+ out.text = texts.at(-1) + ' - ' + texts.at(-2);
} else {
// setup for secondary labels
- out.text = tt;
- out.text2 = tt2;
+ out.texts = texts
}
}
-function getSecondaryLabelVals(ax, vals) {
+function getSecondaryLabelVals(ax, vals, level) {
var out = [];
var lookup = {};
for(var i = 0; i < vals.length; i++) {
var d = vals[i];
- if(lookup[d.text2]) {
- lookup[d.text2].push(d.x);
+ var text = d.texts[level];
+ if(lookup[text]) {
+ lookup[text].push(d.x);
} else {
- lookup[text2] = [d.x];
+ lookup[text] = [d.x];
}
}
for(var k in lookup) {
out.push(tickTextObj(ax, Lib.interp(lookup[k], 0.5), k));
}
return out;
}
At this point, the rough data is ready for the multicategory, but I could not advance in the actual formatting and plotting of the relabeled data. Instead, as I can sort this before plotting, I removed the x axis and rendered a simple html table. Using the popcorn example commented above and the boxplot, the result is enough to get the base layout. This hack is pretty much useless on Python, and far from ideal regarding component widths, but with a frontend and dynamic width tables I guess I can get close enough with the current functionality. Maybe with a little help I could try to further improve on the code and get the expected results. |
I've decided to try and implement this in Plotly.js, and the result turned up pretty good. Available in https://codepen.io/richardnm-2/pen/RwyjMrB I also replaced the minified version inside plotly.py, and the results were also pretty promising. JMP like styles applied. and the popcorn example from before, connecting cell means also available. Couple of things I saw that went wrong:
Other than the Other then these problems, I would be happy to receive a code review, maybe work for a PR. https://github.com/richardnm-2/plotly.js. If anyone finds another bug except those already mentioned, feel free to post it, I can try and work on them. |
@richardnm-2 fantastic, nice work! Perhaps the easiest would be to create a PR into the main repo, that would be the easiest way for us to look at what you have and see if we can help resolve those two issues, as well as figure out what else might be needed to get it merged. |
Ok, just opened a draft PR. This is my first contribution, so please let me know if I have to do anything differently. I hope this is integrated, please keep me posted on the development and next steps! |
Apologies if I'm not using this properly - first time to comment. Is it possible to use this for a heatmap in plotly.js? I have doing it with the same sequence for the trace but it doesnt appear to work I just get y1 labels e.g. |
plotly#2175: Chromatogram: Refactor component for painting chromatogram
This is a request to add nested categorical axes. These are often used in "variability charts", examples of which can be seen here.
There's a few ways this could be implemented in practice. Rather than passing an array of values for
y
the user could pass an object like:or simply pass a category name / number (
1
or"gourmet-large-little"
) and pass the nesting information for the axis in the layout section.(I was surprised not to find an open issue for this -- it's possible that there is one but I didn't search using the right terms).
Edit: There is some limited support for this as shown here but it involves hacking the axis together by hand and would be difficult to use in an automated manner.
The text was updated successfully, but these errors were encountered: