简体   繁体   中英

python plotly - rotating secondary X axis labels

Let's say I create a plotly figure like this:

x = [['A','A','B','B'], ['X','Y','X','Y']]
y = [1,2,3,2]
fig = go.Figure()
fig.add_bar(x=x, y=y)
fig.show()

I get this: 在此处输入图像描述 I want to rotate the secondary X labels ('A' and 'B'). I tried:

fig.update_xaxes(tickangle=45)

but this only rotates the 'X' and 'Y' labels. How can I do it?

Based on this discussion by the plotly team, it doesn't appear that the capability to rotate both labels for a multicategorical axis was implemented, because it would be difficult to control overlapping labels if the secondary label was long.

In your case, the best you could probably do is add the secondary labels as annotations. I replaced the each unique label with different numbers of spaces so they don't show up, but are still interpreted as another category by Plotly (eg 'A' is replaced by ' ' , 'B' is replaced by ' ' , and so on...).

Then instead of just placing down the labels where we know they should go, it's better to make a scalable function that determines where the secondary labels should be placed based on the number of secondary x-labels you have. I wrote a function that does that below (and to demonstrate, I modified the number of secondary labels):

import plotly.graph_objects as go

## use placeholders so labels don't show up
## map each unique label to a different number of spaces
## extend the labels to show that the solution can be generalized
secondary_labels = ['A','A','A','B','B','C']

label_set = sorted(set(secondary_labels), key=secondary_labels.index)
label_mapping = {label:' '*i for i, label in enumerate(label_set)}
secondary_labels_mapped = [label_mapping[label] for label in secondary_labels]

x = [secondary_labels_mapped, ['X','Y','Z','X','Y','X']]
y = [1,2,3,4,2,4]

## source: https://www.geeksforgeeks.org/python-program-to-find-cumulative-sum-of-a-list/
def cumsum(lists):
    cu_list = []
    length = len(lists)
    cu_list = [sum(lists[0:x:1]) for x in range(0, length+1)]
    return cu_list[1:]

relative_lengths = {}
start_loc = []
for label in label_set:
    relative_lengths[label] = secondary_labels.count(label) / len(secondary_labels)

## get the length of each interval
end_lens = list(relative_lengths.values())
start_lens = [0] + end_lens[:-1]

end_locs = cumsum(end_lens)
start_locs = cumsum(start_lens)

annotation_locs = [(start + end) / 2 for start, end in zip(start_locs, end_locs)]

fig = go.Figure()
fig.add_bar(x=x, y=y)

for label, loc in zip(label_set,annotation_locs):
    fig.add_annotation(
        x=loc,
        y=0,
        xref="paper",
        yref="paper",
        text=label,
        showarrow=False,
    )

## shift annotations down so they display on the axes
fig.update_annotations(yshift=-40)
fig.show()

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM