Sort y axis for traces (part of a figure)

Hi, my figure is composed of multiple traces depending on what attributes the user would like to see. So, a figure can consist of multiple traces, for example:

if id:
    id_traces = px.scatter().data
    for trace in id_traces:
        fig.add_trace(trace)

if year:
    year_traces = px.scatter().data
    for trace in year_traces :
        fig.add_trace(trace)

Now, if I want to sort the y-axis showing the year only, is it possible? I don’t want to sort the whole y-axis, because that would just sort the whole figure and interfere with other traces (like the IDs). I tried to update the year plot before adding it to fig:

if year:
    year_plot = px.scatter()
    year_plot .update_yaxes(categoryorder='category ascending')
    year_traces = year_plot .data
    for trace in year_traces :
        fig.add_trace(trace)

But that unfortunately did not work, unless I did something wrong (in that case, please let me know)!

Hi @Peilin ,

I have been reading your questions, but I am so sorry, it rather not clear for me.
Can you reproduce as sample of code, that can be executed.
So I can get more understanding what are you needed.

Thanks.

1 Like

Yes, of course! For example, consider the code below:

data = {
    'start': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01', '2023-06-01'],
    'selection': [1977, 1997, 1990, 2001, 1999, 2008],
    'category': ['A', 'B', 'C', 'A', 'D', 'H']
}
df = pd.DataFrame(data)

fig = px.line(df, x='start', y="category")
selection_traces = px.line(df, x='start', y="selection").data

for trace in selection_traces:
    fig.add_trace(trace)
    
fig.show()

This code produces the following plot, probably due to it converting the year values from int to string (but correct me if I’m wrong)

What I want to achieve is to sort the years before adding them to the figure; after the year is sorted, it does not matter if they are then converted to string or not. So, for the upper part, it would look like this (and combined with the lower half of the first image)

How can I achieve this? Possible to for example sort the selection_traces before adding them to the fig, which seems to be the easiest; but I tried this and that did not work:

fig = px.line(df, x='start', y="category")
selection_fig = px.line(df, x='start', y="selection")
selection_fig.update_yaxes(categoryorder='sum descending')
for trace in selection_fig.data:
    fig.add_trace(trace)

Or do I have to use subplot for this?

Hi @Peilin ,

Sorry, it’s been take a while to response your reply.

I found that I could do your requirement by creating your data into 2 data frames.
By doing thi,s you don’t have to create subplot.

df is the first dataframe.
df1 is the second dataframe, it is a copy df but with sorted selection column .

you can sort selection column values by using sort_values function in pandas.

By doing this way, it will make the ‘year’ plot is displayed little bit different, because it was sorted by value to achieve sorted y axis.

if this meet your requirement, the code shown below.

import pandas as pd
import plotly.express as px

data = {
    'start': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01', '2023-06-01'],
    'selection': [1977, 1997, 1990, 2001, 1999, 2008],
    'category': ['A', 'B', 'C', 'A', 'D', 'H']
}
df = pd.DataFrame(data)

# new dataframe with sorted 'selection' column
df1 = df.sort_values(['selection'])

fig = px.line(df, x='start', y="category")
selection_traces = px.line(df1, x='start', y="selection")
selection_traces = selection_traces.data

for trace in selection_traces:
    fig.add_trace(trace)

fig.show()

Another alternative is update category order after second traces combined.

import pandas as pd
import plotly.express as px

data = {
    'start': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01', '2023-06-01'],
    'selection': [1977, 1997, 1990, 2001, 1999, 2008],
    'category': ['A', 'B', 'C', 'A', 'D', 'H']
}
df = pd.DataFrame(data)

fig = px.line(df, x='start', y="category")
selection_traces = px.line(df, x='start', y="selection")
selection_traces = selection_traces.data

for trace in selection_traces:
	fig.add_trace(trace)

fig.update_layout(yaxis={'categoryorder':'category ascending'})
fig.show()

the result will be well ordered , but put category column above selection column like shown image below.

Hope this help.

1 Like

Thanks @farispriadi for helping out. I also specified the y-axis range, by getting the category and min/max of the year, such as

y_axis_order= []
category_order= df['category'].dropna().unique().tolist()
category_order.sort()
y_axis_order += category_order

min_year = df['selection'].min()
max_year = df['selection'].max()
year_order = [str(year) for year in range(int(min_year), int(max_year))]
y_axis_order += year_order 

and then update the y-axis using this list fig.update_yaxes(categoryorder='array', categoryarray=y_axis_order ), this makes the portion that shows the year ticks (selection) take much of the space and squeeze the A/B/C, etc… (category) portion.

Is it then possible to adjust the height separately, or for example have them take up 2:1 ratio space respectively?

Edit: I guess this follow-up question took on another direction; i have opened up another post here instead. Thanks so far! :smile:

1 Like