Add quantity API#2
Conversation
There was a problem hiding this comment.
Just to clarify, these produces a new Quantity, not a scalar or something, right?
There was a problem hiding this comment.
That's right, it would create a new Quantity object. I guess we could do something like "take the units from the object on the left" but that seemed kind of arbitrary to me.
There was a problem hiding this comment.
Yep, this makes sense. (you might want to just add that as a comment, that it produces a new Quantity to distinguish from in_ or whatever below.)
|
Using
|
|
Also, I think once this has been implemented, it would be great to add a basically identical |
|
My argument for I definitely think the or something like that. |
|
I see your point, but my concern is that the (somewhat subtle) distinction between "in" and "to" in English does not make it clear what you mean in code-world. That is "What is that in gallons?" could get an english answer of either "five and a half" or "five and a half gallons". The former (in my mind) would be a float of value |
|
Ah, good point -- I think I like is a) plain english and b) clear that it's returning just the value in those units. I'll update the API to reflect this and try to solicit for more opinions! |
There was a problem hiding this comment.
Why bother having unit as a keyword argument if it's going to throw an exception if it's not provided? Seems like it would be better to use a positional argument instead—that's how I would probably use it anyways!
There was a problem hiding this comment.
Fair point, but of course programmatically it doesn't matter. Ultimately I think you're arguing for documentation to not use it as a keyword argument, right?
There was a problem hiding this comment.
I think @adrn was just showing that the second keyword is a unit. In actual code this would still be required right? e.g. def __init__(self, value, unit):....
There was a problem hiding this comment.
If you created a Quantity from a value that contains a unit (like an Angle or another Quantity you wouldn't need to specify unit.
There was a problem hiding this comment.
I see what you're saying, but the problem is that the most convinient API for coordinate-related tasks that we outlined before is not compatible with forcing units into the coordinates. We could do it using some sort of clever wcs-like thing, but then we'd have to throw out all the work we've done on coordinates. And I think, practically speaking, that would delay all of that for ~1 yr.
Put another way, Coordinates are focused on how you represent a point or points in spherical coordinates, while NDData and Quantity are about representing arbitrary numbers that may or may not have specific physical meaning (and it's the context that really determines that).
We may want to later change the internals of Angle to use an NDData object if that turns out to be the most convinient way of getting arrays in there... But the API as seen by the user still can't include units, so it can't directly subclass from Quantity or NDData
There was a problem hiding this comment.
Wait, I'm not convinced that this requires a massive rewrite...
I'm looking at the API now and at least at quick glance, there doesn't seem to be anything that would be inconsistent with switching to a Quantity or NDData subclass. I think the switch would take an afternoon's time.
I also object to naming something Coordinates when you in fact mean a point or points in spherical coordinates, but you can see my comments on the other pull request about this :)
There was a problem hiding this comment.
The main problem is that a Quantity or NDData are essentially wrappers around a scalar or an array, and the class itself has no specific physical interpretation. Hence, unit is necessary, because a raw number needs a unit to have meaning.
Coordinate (or SphericalPoint, or whatever - i can see your point on the wording, but it can be discussed there) is a point in space, essentially. It intentionally hides any details of how its stored. So then unit is not necessary, because a point in space is a concept that requires no specific units to have meaning.
That said, one could subclass from NDData, I suppose, and just force unit to always be radians... but then the coord.radian and coord.degree and so on end up rather confusing, because they then get confused with the NDData representation. I can see the merit of this being used internally (maybe), but to actually be part of the public API as an NDData is more restrictive. Oh, and also Coordinates is (intentionally) a mix of a Quantity and NDData (it can be a scalar or array) because most of the operations you want to do on coordinates are the same either way. That's different from things like constants or spectra, where a scalar spectrum or an array-constant just don't make sense.
There was a problem hiding this comment.
I still don't think the distinction is very clear. While the class Quantity may not have a physical interpretation, an object quantity surely does. I'm not sure I understand your argument, because a raw number doesn't need a unit to have meaning -- a raw number is a raw number! I also don't understand the notion of a 'point in space' not having units. If a point in space has no units or uncertainty, as you say, why not just use raw numbers or arrays?
The Coordinate object can hide the details of how data is stored, but still be built on the same framework (NDData). The API can in fact be exactly the same -- angle.degrees could just call angle.value_in(degrees), etc. In fact, you don't even have to internally store everything as radians anymore -- it actually seems like a nicer solution to me.
My main point is that it now seems weird to have this special Angle class that operates as a scalar or an array, when for any other quantities with units and uncertainties we say "scalar = Quantity, array = NDData". Let me give you a specific example. Let's say I have three arrays representing Galactic X,Y,Z distances. Those are valid coordinates, and most certainly have units and uncertainties associated with them. Why do I have to use NDData to represent those, but when I transform them to RA and Dec I now have this new Angle-like class to deal with rather than an NDData-like class? (when I say Angle-like I mean subclass of Angle)
There was a problem hiding this comment.
I think we may be talking past each other because of an internal vs. external distinction. I definitely see your point that it may be wise to use Quantity or NDData internally in Angle. I just don't want to do it right now because it would further delay the coordinate work (which works as-is right now).
From the users' perspective, though, we don't want unit on Angle because angle has radian degree and hour properties that each give different units. So Angle having unit/value attributes would be confusing (two ways to do the same thing). Furthermore, we would have to change the public API so that Coordinate is either a scalar or array (because the public API for NDData and Quantity will include that requirement), which we don't want to do for Coordinate for a variety of reasons.
I do see your point that this classes do conceptually overlap - I'm just saying we should continue with coordinates until we have the originally laid-out API ready, and then consider how it should connect with Quantity and NDData.
(Maybe we should move further discussion on this to astropy-dev? it's in an outdated diff here, so probably no one else will see it...)
|
@eteq I'm not quite sure what you're recommending. I think we should have it very similar in |
|
I added some example code for uncertainties. There are a few points I slipped in there:
|
|
@wkerzendorf - my comment above about the Or were you referring to just the |
|
An additional question: what does
I think #3. That's the behavior we have right now for |
|
Oh, and I mentioned this in an inline comment somewhat tangentially, but you probably want to update this document to make it expressly clear that |
|
@eteq's comment: I think it should be number 1. For it's similar to having a unit less number added to a normal number - which doesn't make sense. |
|
@eteq's previous comment about |
|
@wkerzendorf - so you think we should have the behavior of auto-casting to floats that's in |
|
Let's take a step back as this has wide ranging applications:
I think both of those things need to work similarly to provide a logical, consistent and easy to learn framework. I'm going to outline a couple of inconsitencies, for nowIn the first example both
|
There was a problem hiding this comment.
Uncertainty should be a class like NDStandardDeviationError in the NDError framework (discussion of renaming, after we make things consistent).
|
+1 for Consider this (this is not code): You didn't add 2 miles to 5 miles, the statement is "2 plus '5 miles'", and that's meaningless. Further, what does this do? 51.1 meters? 10.5 meters? Addition is commutative. This is an error. @wkerzendorf re: "result should not depend on the side" As I said above, the result is the same whether the resulting units are x or y - the quantity is the same. Regardless of the unit in the object, if you were to use the right or left unit, the two objects would evaluate to being equal. It's clearly an ambiguous situation, but not mathematically so, so whether we default to SI if the units are all SI, CGS if the units are all CGS, SI if there is a mixture, the left unit, the right unit, it's all the same. Any decision is ok. The tutorial would point out that if you want a specific unit, then you This is slightly trickier with NDData. This is valid: One option is to say that if NDData has a unit, only Quantities with compatible units may be added. If they don't, then we can do the operation as above. Also, why does |
There was a problem hiding this comment.
very good (str/repr). It should be unit as it's one unit (it should be unit in NDData as well - will change this in NDData once this is all consistent.
we should also be able to access the quantities unit/value: I suggest q1.value and q1.unit , similar to nddata.data and nddata.unit.
|
@demitri: I don't know how to quote things yet in the markup - but let me address the different points:
as for the last comment: |
|
I think constants should behave the same: |
|
If an NDData object is unitless, adding a scalar to it is mathematically valid... |
|
Just a couple of comments:
|
|
Another way to put this - I had originally thought that and then we would we leave uncertainties, WCS, masks, and flags for the more complex This shouldn't affect the coding of the 0.2 API for |
|
Agreed that no one should create a This is just really great. That said, I think that the above line should work with only You can use the Second, to get totally pedantic here, can we stop using |
|
@demitri - small correction, it will work with just i..e there's no need to import the top-level |
|
@astrofrog Even better. Works for me. |
|
Let me put forward the following suggestion - we implement the current proposed to the astropy.units docs, and have all that code be self-contained inside |
|
What @astrofrog is saying sounds good. @adrn are you ok with this scheme? Particularly the aspect where (oh, and @astrofrog, your example should be |
|
And I agree that with this limited scope it makes sense in |
|
👍 will do. |
|
@astrofrog: I've been wondering about the |
|
@wkerzendorf - I don't understand what you're suggesting here. As @astrofrog outlined, |
|
@eteq: He suggested that Anyways, this can be done later and we should get |
|
@eteq - the to also give a |
|
@astrofrog: I like that. |
|
ok, we can table the discussion of if/how to connect this to |
|
👍 |
|
Who's making the |
|
I assume that was the plan, given that he's doing this. But lets first make sure this document is merged before starting on the implementation. |
|
OK, I've updated the document to (hopefully) include the most recent suggestions. If this looks good, merge it, and we'll defer any more discussion until I have a pull request for the actual code (soon). Nice work -- 125 comments on this one! |
|
That's > 1.2 comments per line! ;-) Looks good to me, though as I said above, I'm pretty sure the uncertainty stuff shouldn't go in the base |
There was a problem hiding this comment.
can you add a q1.unit as well which just returns the unit (or is the unit).
There was a problem hiding this comment.
right, q1.unit should return the unit object
|
I agree with @astrofrog that it would make sense to move the uncertainty stuff to the end and add a note like "Quantity may end up not even having uncertainties, depending on what we decide in 0.3 for how to divide NDData and Quantity functionality". Other than that, looks great, @adrn! |
|
Alrighty! |
|
@eteq @astrofrog I think we've come to an agreement -- can we merge this pull request? I've started working on the code, so I'd like to discourage people from adding any more discussion here, and rather comment on the code pull request when that happens. Thanks! |
|
Looks good to me! |
|
Looks good to me as well, and it looks like everyone else too as best as I can tell. So I'll go ahead and merge it. Thanks for working on this, @adrn - for the implementation you're doing now, you're not going to include uncertainties, right? |
In this pull request is a rough sketch of what we want the Quantity class to be able to do. It may not be complete, and there are a few thing we need to discuss: