-
Notifications
You must be signed in to change notification settings - Fork 3
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
Add magic functions #19
Conversation
included flow.cpp as showcase of future classes
Gen grid obj
I should add, right now |
This is an element-wise operation in Matlab's TT, too. And I think this is fine. One could just implement an isequal-function to compare objects. This would require checking the equality of the array of elevations, coordinates, etc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all seems to work. I left a few questions and very minor changes in comments on specific lines.
Is there a better way to make GridObject
behave like a NumPy ndarray
with some extra metadata -- the cellsize -- that follows it around? I have looked at Subclassing ndarray. I haven't completely understood it yet, but it seems like it might be better in the long run to get something like that working than to have to implement our own wrappers around whatever NumPy functionality we need.
def __eq__(self, other): | ||
dem = copy.deepcopy(self) | ||
|
||
if not isinstance(other, self.__class__): | ||
raise TypeError("Can only compare two GridObjects.") | ||
|
||
if self.columns != other.columns or self.rows != other.rows: | ||
raise ValueError("Both GridObjects have to be the same size.") | ||
|
||
for x in range(0, self.columns): | ||
for y in range(0, self.rows): | ||
|
||
dem.z[x][y] = self.z[x][y] == other.z[x][y] | ||
|
||
return dem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting for myself: You need the deepcopy here because a shallow copy copies the pointer to self.z into dem.z, and then when you write to it in the loop, the pointers are the same and they get overwritten. This doesn't happen with the functions for add, etc., because we use the builtin numpy addition of the two arrays, which allocates a new destination array and assigns a pointer to that new array into dem.z.
Why do we not do something like:
dem.z = self.z == other.z
or something similar for the other boolean operations?
I played around with subclassing a bit, it generally seems to work for our use case. I will create a new branch in my fork to try to implement it. Then we can decide if we want to go this route and merge it. We will have to see if we run into any issues when overwriting functions such as |
I think I would be against subclassing ndarray. Since def __array__(self):
return self.z ensures that you don't need to use In my opinion the issue with subclassing is, that we also inherit functions like: I think we should go through the ndarray functions and choose which we want to keep. Writing a wrapper for each will probably be no big task. Otherwise, I fear we would add a lot of functions that see no use. When overwriting a function in a subclass, we could remove the functionality, but not the existence of the function. So for example in an IDE the autocomplete would have many "empty" functions, which could prove annoying. If you think we should still go the subclass route, I'm open to it. But as of right now, I don't see the immediate advantage. |
That’s how I do in MATLAB. And it allows you to set extra options.
Von Gmail Mobile gesendet
Theo ***@***.***> schrieb am Mo. 13. Mai 2024 um 21:39:
… I think I would be against subclassing ndarray.
Since
def __array__(self):
return self.z
ensures that you don't need to use dem.z when passing an instance to
Matplotlib, for example (just dem works). There is no need to subclass
for plotting.
In my opinion the issue with subclassing is, that we also inherit
functions like: astype, sort, byteswap, dump or tofile. It's not like
these functions should not exist for the GridObject, I think giving the
user access to them will do more harm than good. We could just overwrite
them. If the user really wants to use them, they can still do
dem.z.some_function.
I think we should go through the ndarray functions
<https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html> and
choose which we want to keep. Writing a wrapper for each will probably be
no big task.
—
Reply to this email directly, view it on GitHub
<#19 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB4RU3CYP52TD5KJGVOJM63ZCEJF3AVCNFSM6AAAAABHCMJIMCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMBYGY3DAMJXHE>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
I think that makes sense for now. @Teschl: Is there anything left to do here or should I go ahead and merge this PR? |
I added the str magic function so |
In this version, I implemented the previously discussed "magic" functions. Turns out the
r
andi
versions (as noted in #17 ) are not needed, but instead of__cmp__
all the functions for comparing had to be implemented on their own.I am using a
copy.deepcopy()
when returning the new dem (after computingand
, for example) since only doing a shallow copy resulted in overwritingdem1
when doing this, for example:dem3 = dem1 & dem2
__len__
we need to decide, if we want to return the number of elements in the first dimension (like it works for the np.array). or i we want to return the shape of the dem (rows, cols).__delitem__
I am questioning if we need it at all. I can't think of a situation, where the user would want to delete a specific row of their dem.I included the notebook
examples/example_magic_funcs.ipynb
which provides simple examples that showcase functionality. Feel free to play around with those a bit.