8000 Alphabetically sort the legend in px.pie / vm.Graph while keeping slice order by value · Issue #1146 · mckinsey/vizro · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Alphabetically sort the legend in px.pie / vm.Graph while keeping slice order by value #1146

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

Open
3 of 4 tasks
fpeucelle opened this issue May 5, 2025 · 5 comments
8000
Open
3 of 4 tasks
Assignees
Labels
General Question ❓ Issue contains a general question Needs triage 🔍 Issue needs triaging

Comments

@fpeucelle
Copy link
fpeucelle commented May 5, 2025

Have you already looked into this topic?

  • I've reviewed the Vizro documentation for any relevant information
  • I've searched through existing issues for similar questions
  • I've already searched online (e.g., Dash documentation) but couldn’t find anything helpful

Question

Hi Vizro team 👋,

First of all, thanks for the great work—Vizro is powering our judicial analytics dashboards and it’s been a pleasure to use. I have a question (and maybe a feature request) regarding pie‑chart legends.

When users switch filters or jump between tabs, the slice order (by value) can change from one state to another. Because the legend always mirrors that slice order, its entries shuffle around and users lose their visual bearings. An alphabetically fixed legend would reduce that cognitive load.

What I’ve tried

  1. category_orders controls both slice order and legend order, so decoupling them isn’t possible there.
  2. layout.legend.traceorder only accepts "normal" | "reversed" | "grouped"—no custom alphabetical order.
  3. A workaround with invisible traces (go.Scatter(x=[None], y=[None])) creates a fake legend, but it breaks the native interactivity (click‑to‑hide) and bloats the figure for large category counts.

Question / Feature Request
Is there any built‑in way in Vizro or Plotly to break the coupling and:

keep the slice order driven by values, but supply an independent alphabetical order for the legend (so it stays stable across filter and tab changes)?

If not, would you consider adding something like legend_category_orders (analogous to category_orders but applied only to the legend)?

Thanks a lot for your time and for maintaining Vizro!
Greetings from Chubut, Argentina 🇦🇷
Francisco

Code/Examples

import pandas as pd
import vizro.plotly.express as px
import vizro.models as vm
from vizro import Vizro

df = pd.DataFrame({
    "descItem": ["Rawson", "Comodoro", "Trelew", "Esquel"],
    "Valor":    [20, 12, 7, 15]
})

pie_df   = df.sort_values("Valor", ascending=False)   # slice order by value
legend_alphabetic = sorted(df["descItem"])            # desired legend order

color_map = {
    "Comodoro": "#1f77b4",
    "Esquel":   "#ff7f0e",
    "Rawson":   "#2ca02c",
    "Trelew":   "#d62728",
}

fig = px.pie(
    pie_df,
    names="descItem",
    values="Valor",
    category_orders={"descItem": pie_df["descItem"].tolist()},
    color="descItem",
    color_discrete_map=color_map,
)
fig.update_traces(sort=False)  # keep slice order as supplied

page = vm.Page(components=[vm.Graph(figure=fig)])
Vizro().build(vm.Dashboard(pages=[page])).run()

Which package?

vizro

Code of Conduct

@fpeucelle fpeucelle added Needs triage 🔍 Issue needs triaging General Question ❓ Issue contains a general question labels May 5, 2025
@nadijagraca nadijagraca self-assigned this May 7, 2025
@nadijagraca
Copy link
Contributor

Hi @fpeucelle 👋

Thank you—we’re thrilled to hear that Vizro is supporting your work and that you enjoy using it.

Vizro rebuilds the fig whenever the page is loaded or a filter is applied. Because the figure gets rebuilt each time, any settings like fig.update_traces(sort=False) will be lost during the rebuild.
The 8000 solution is to use a custom chart. So, whatever is included in the custom chart function will persist and be shown correctly whenever the page loads or filter is applied. You can find more about custom charts in our docs.

So something like below will hopefully resolve the issue.

@capture("graph")
def custom_pie(data_frame):
    fig = px.pie(
        data_frame,
        names="descItem",
        values="Valor",
        color="descItem",
        color_discrete_map=color_map,
    )
    fig.update_traces(sort=False)  # keep slice order as supplied
    return fig

If the problem persists, let us know and we will try to find other solution.

Greetings to Argentina,
Nadija,

@nadijagraca
Copy link
Contributor

I will close this issue now. If you have any further questions or if the issue persists, feel free to comment here and we’ll be happy to reopen it.

@fpeucelle
Copy link
Author
fpeucelle commented May 8, 2025

Thank you, @nadijagraca 🙌.
I appreciate your time and explanation.

To clarify what I’m aiming for:

Sort the pie‑chart slices in descending order by their value.

Sort the legend alphabetically (A → Z), independent of the slice order.

From your comment, I understand that this currently requires a custom figure function, and I admit my previous example wasn’t the best. 🤦‍♂️

What I’m attaching in this comment

a self‑contained script with two captured functions (custom_pie and standard_pie) and a minimal dashboard that displays both charts side‑by‑side.

obtained_charts.png – a screenshot of the results I get with that code (they don’t meet the desired ordering).
Image

desired_chart.png – a mock‑up of the final chart I’m trying to achieve (slices sorted ↓ by value, legend sorted ↑ alphabetically).
Image

I hope this makes the expected behavior clearer. I’m happy to adjust anything—thanks again for your help!

# sample_two_pies_vizro.py
# ------------------------------------------------------------
# 1. Custom pie chart function (keeps slice order)
# ------------------------------------------------------------
import pandas as pd
import vizro.plotly.express as px
import vizro.models as vm
from vizro import Vizro
from vizro.models.types import capture


@capture("graph")
def custom_pie(
        data_frame,
        names,
        values,
        color,
        color_discrete_map,
        category_orders=None):
    """Pie chart that preserves the row order given in *data_frame*."""
    fig = px.pie(
        data_frame=data_frame,
        names=names,
        values=values,
        color=color,
        color_discrete_map=color_discrete_map,
        category_orders=category_orders,
    )
    fig.update_traces(
        sort=False,   # keep supplied order
        direction='clockwise'
    )
    fig.update_layout(title_text="Sorted Pie Chart by Legend")  # chart title
    return fig


@capture("graph")
def standard_pie(
        data_frame,
        names,
        values,
        color,
        color_discrete_map,
        category_orders=None):
    """Default Plotly pie chart without extra adjustments."""
    fig = px.pie(
        data_frame=data_frame,
        names=names,
        values=values,
        color=color,
        color_discrete_map=color_discrete_map,
        category_orders=category_orders,
    )
    fig.update_traces(
        direction='clockwise'
    )
    fig.update_layout(title_text="Sorted Pie Chart by Values clockwise")
    return fig


color_map = {
    "Comodoro": "#1f77b4",
    "Esquel":   "#ff7f0e",
    "Rawson":   "#2ca02c",
    "Trelew":   "#d62728",
}


# ------------------------------------------------------------
# 2. Data preparation
# ------------------------------------------------------------
df = pd.DataFrame({
    "descItem": ["Rawson", "Comodoro", "Trelew", "Esquel"],
    "Value":    [20, 12, 7, 15]
})

# Slices sorted by value; legend alphabetically
pie_df = df.sort_values("Value", ascending=False)
legend_alphabetic = sorted(df["descItem"])

# ------------------------------------------------------------
# 3. Figure generation
# ------------------------------------------------------------
fig_sorted = custom_pie(
    data_frame=pie_df,
    names="descItem",
    values="Value",
    color="descItem",
    color_discrete_map=color_map,
    category_orders={"descItem": legend_alphabetic},
)

fig_default = standard_pie(
    data_frame=df,
    names="descItem",
    values="Value",
    color="descItem",
    color_discrete_map=color_map,
)

# ------------------------------------------------------------
# 4. Build Vizro dashboard (horizontal layout)
# ------------------------------------------------------------
page = vm.Page(
    title="Distribution by District",
    layout=vm.Grid(grid=[[0, 1]]),
    components=[
        vm.Graph(
            id="pie_sorted",
            figure=fig_sorted,
            footer="Legend OK"
        ),
        vm.Graph(
            id="pie_default",
            figure=fig_default,
            footer="Graph OK"
        ),
    ],
)

dashboard = vm.Dashboard(
    pages=[page],
)

Vizro().build(dashboard).run()

@nadijagraca nadijagraca reopened this May 9, 2025
@nadijagraca
Copy link
Contributor

Hi @fpeucelle,

Thank you for clarifying.

The below custom_chart function appears to give me the correct version of the graph.

@capture("graph")
def custom_pie(data_frame, names, values, color, color_discrete_map, category_orders=None):
    """Pie chart that preserves the row order given in *data_frame*."""
    fig = px.pie(
        data_frame=data_frame,
        names=names,
        values=values,
        color=color,
        color_discrete_map=color_discrete_map,
    )
    fig.update_traces(
        sort=False,  # keep supplied order
        direction="clockwise",
    )
    fig.update_traces(
        labels=category_orders["descItem"],
        sort=False,  # prevents auto-sorting of slices
    )
    fig.update_layout(title_text="Sorted Pie Chart by Legend")  # chart title
    return fig

I've added the code below to prevent auto-sorting of the slices.

    fig.update_traces(
        labels=category_orders["descItem"],
        sort=False,  # prevents auto-sorting of slices
    )

The below is the graph I get with the above adjustments.
Image

Let me know if this fixes the issue for you.

Nadija,

@fpeucelle
Copy link
Author

Hi again @nadijagraca ,

I’ve just retested with the current patch but, unfortunately, the slice values are now incorrect. In my dataset “Comodoro” should be 22 %, yet the updated chart shows 37 %. It looks like the fix re‑orders the slices correctly but recalculates the percentages based on the new order, so the visualization no longer reflects the real data.

Could we explore another approach that keeps the descending slice order without altering the original values?

Thanks anyway for your quick response and assistance!

Cheers,
Francisco

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
General Question ❓ Issue contains a general question Needs triage 🔍 Issue needs triaging
Projects
None yet
Development

No branches or pull requests

2 participants
0