Skip to content

fix: Setting category_orders was leading to missing data #4877

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

Merged
merged 6 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions packages/python/plotly/plotly/express/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2422,7 +2422,6 @@ def get_groups_and_orders(args, grouper):
# figure out orders and what the single group name would be if there were one
single_group_name = []
unique_cache = dict()
grp_to_idx = dict()

for i, col in enumerate(grouper):
if col == one_group:
Expand All @@ -2440,27 +2439,31 @@ def get_groups_and_orders(args, grouper):
else:
orders[col] = list(OrderedDict.fromkeys(list(orders[col]) + uniques))

grp_to_idx = {k: i for i, k in enumerate(orders)}

if len(single_group_name) == len(grouper):
# we have a single group, so we can skip all group-by operations!
groups = {tuple(single_group_name): df}
else:
required_grouper = list(orders.keys())
required_grouper = [
key for key in orders if key in grouper and key != one_group
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe one_group will never be in orders so this can be simplified to

Suggested change
key for key in orders if key in grouper and key != one_group
key for key in orders if key in grouper

]
order_mapping = {key: orders[key] for key in required_grouper}
grouped = dict(df.group_by(required_grouper, drop_null_keys=True).__iter__())
sorted_group_names = list(grouped.keys())

for i, col in reversed(list(enumerate(required_grouper))):
sorted_group_names = sorted(
sorted_group_names,
key=lambda g: orders[col].index(g[i]) if g[i] in orders[col] else -1,
)
sorted_group_names = sorted(
grouped.keys(),
key=lambda group: [
order_mapping[key].index(value) if value in order_mapping[key] else -1
for key, value in zip(required_grouper, group)
],
)

# calculate the full group_names by inserting "" in the tuple index for one_group groups
full_sorted_group_names = [
tuple(
[
"" if col == one_group else sub_group_names[grp_to_idx[col]]
""
if col == one_group
else sub_group_names[required_grouper.index(col)]
for col in grouper
]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,27 @@ def test_orthogonal_orderings(backend, days, times):
assert_orderings(backend, days, days, times, times)


def test_category_order_with_category_as_x(backend):
# https://github.com/plotly/plotly.py/issues/4875
tips = nw.from_native(px.data.tips(return_type=backend))
fig = px.bar(
tips,
x="day",
y="total_bill",
color="smoker",
barmode="group",
facet_col="sex",
category_orders={
"day": ["Thur", "Fri", "Sat", "Sun"],
"smoker": ["Yes", "No"],
"sex": ["Male", "Female"],
},
)
assert fig["layout"]["xaxis"]["categoryarray"] == ("Thur", "Fri", "Sat", "Sun")
for trace in fig["data"]:
assert sorted(set(trace["x"])) == ["Fri", "Sat", "Sun", "Thur"]


def test_permissive_defaults():
msg = "'PxDefaults' object has no attribute 'should_not_work'"
with pytest.raises(AttributeError, match=msg):
Expand Down