Skip to content
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

allow to filter and group by property #879

Merged
merged 3 commits into from
Jan 29, 2025
Merged

Conversation

snoyer
Copy link
Contributor

@snoyer snoyer commented Jan 25, 2025

This would allow

shape.edges().filter_by(Edge.is_interior)

as an alternative to

shape.edges().filter_by(lambda e: e.is_interior)

Copy link

codecov bot commented Jan 25, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.65%. Comparing base (edf1dbd) to head (bdd11a9).
Report is 8 commits behind head on dev.

Additional details and impacted files
@@           Coverage Diff           @@
##              dev     #879   +/-   ##
=======================================
  Coverage   96.65%   96.65%           
=======================================
  Files          31       31           
  Lines        9177     9184    +7     
=======================================
+ Hits         8870     8877    +7     
  Misses        307      307           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@gumyr
Copy link
Owner

gumyr commented Jan 27, 2025

@snoyer thank you for sharing your mastery of Python. Was there a reason to not include sort_by in this PR?

Using shape properties directly as sort_by/group_by/filter_by parameters is very elegant and makes me wonder about the whole SortBy enum - should it be replaced entirely? Currently one might group_by(SortBy.AREA) which looks kinda weird. group_by(Face.area) makes more sense to me and is future proof as need properties would be automatically supported. Should the use of SortBy be deprecated?

The GeomType/geom_type enum/property should probably stay though as I don't see how one could use this property without using a lambda.

@snoyer
Copy link
Contributor Author

snoyer commented Jan 27, 2025

Was there a reason to not include sort_by in this PR?

It didn't occur to me at all! I wanted to do filter_by and remembered group_by worked basically the same but I just didn't think of sorting. But you are right it should work there too.

Regarding SortBy I'm not sure, it looks like you've got at least SortBy.DISTANCE that would be a bit involved to replace, but even the other ones do a bit more than just fetching the property because of the rounding in group_by (although I guess you could check the type of the property value and do the rounding if it's a number)

Either way, let me know if I should add sort_by to this PR (property support, that is) or if you want to do it later once you've decided what to do with the enum.

@jdegenstein
Copy link
Collaborator

Should the use of SortBy be deprecated?

If this is possible as described then absolutely yes it should be deprecated. The naming is already confusing since group_by(SortBy.XYZ) has been possible for a long time.

Regarding SortBy I'm not sure, it looks like you've go at least SortBy.DISTANCE that would be a bit involved to replace

Good point.

@gumyr
Copy link
Owner

gumyr commented Jan 28, 2025

Please add sort_by. For now let's leave the SortBy changes as I'd like to look into changing SortBy.DISTANCE so it has the flexibility to work on any point not just the origin.

@snoyer
Copy link
Contributor Author

snoyer commented Jan 28, 2025

Please add sort_by.

done

I'd like to look into changing SortBy.DISTANCE so it has the flexibility to work on any point not just the origin.

Turns out you can already do .sort_by(other_shape.distance) so maybe it can just be dropped?

from itertools import product

from build123d import Box, ShapeList, Solid, Vertex
from ocp_vscode import ColorMap, show

boxes = ShapeList(
    Box(1, 1, 1).scale(0.75 if (i, j) == (1, 2) else 0.25).translate((i, j, 0))
    for i, j in product(range(-5, 6), repeat=2)
)

# sort by distance to origin
boxes = boxes.sort_by(Vertex().distance)
show(*boxes, colors=ColorMap.listed(len(boxes)))

image

# sort by distance to largest box
boxes = boxes.sort_by(boxes.sort_by(Solid.volume).last.distance)
show(*boxes, colors=ColorMap.listed(len(boxes)))

image

@gumyr gumyr merged commit 9268f31 into gumyr:dev Jan 29, 2025
20 checks passed
@gumyr
Copy link
Owner

gumyr commented Jan 29, 2025

Thank you. This is a really nice enhancement. I need to get my head around boxes = boxes.sort_by(boxes.sort_by(Solid.volume).last.distance) - cool that it works though.

@snoyer snoyer deleted the filter_by-property branch January 29, 2025 01:11
@snoyer
Copy link
Contributor Author

snoyer commented Jan 29, 2025

@gumyr

Thank you. This is a really nice enhancement. I need to get my head around boxes = boxes.sort_by(boxes.sort_by(Solid.volume).last.distance) - cool that it works though.

You're welcome :)

This last example was a bit dense on purpose but if we break it down we have

largest_box = boxes.sort_by(Solid.volume).last  # sorting by property as per this PR
boxes = boxes.sort_by(largest_box.distance)     # sorting by callable as was already possible

the key here is that the Shape class has a def distance(self, other: Shape) -> float method so:

  • Shape.distance is a (Shape, Shape) -> float function
  • a_shape.distance is (Shape) -> float function, and it can be used it to sort/filter/group

@gumyr
Copy link
Owner

gumyr commented Jan 29, 2025

Got it, thanks. There will need to be some good documentation around these capabilities as it probably will be a little more difficult for new users to understand as there isn't a simple list of things that can be done now (which is kinda the whole point but still...).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants