Skip to content

Strip correct excess columns in multiple-coordinates tables and clean up hmsdms format - #12302

Merged
astrofrog merged 6 commits into
astropy:mainfrom
dhomeier:cdswriter-coordinates
Oct 30, 2021
Merged

astrofrog merged 6 commits into
astropy:mainfrom
dhomeier:cdswriter-coordinates

Conversation

@dhomeier

@dhomeier dhomeier commented Oct 26, 2021 •

Copy link
Copy Markdown
Contributor

Description

Fixes #12299

A core problem seems to have been poping the columns in forward order, messing up the indices of the remaining columns in the process, so instead of the extra SkyCoord column e.g. the following RAh column would be stripped.
Also this was only done after the fact of already adding the duplicate RAh RAm... columns to self.cols.
In addition I found a number of problems with the coordinate formatting, so listing the declination sign in the header would depend on perchance having a negative value in the first row or not. An example with positive declination would look like this:

Byte-by-byte Description of file: table.dat
--------------------------------------------------------------------------------
 Bytes Format Units  Label     Explanations
--------------------------------------------------------------------------------
  1-  7  A7     ---    name    Description of name     
  9- 12  F4.1   h      RAh     Right Ascension (hour)  
 14- 17  F4.1   min    RAm     Right Ascension (minute)
 19- 33  F15.12 s      RAs     Right Ascension (second)
 35- 39  F5.1   deg    DEd     Declination (degree)    
 41- 44  F4.1   arcmin DEm     Declination (arcmin)    
 46- 60  F15.12 arcsec DEs     Declination (arcsec)    
 62- 65  F4.1   h      RAh     Right Ascension (hour)  
 67- 70  F4.1   min    RAm     Right Ascension (minute)
 72- 86  F15.12 s      RAs     Right Ascension (second)
 88- 92  F5.1   deg    DEd     Declination (degree)    
 94- 97  F4.1   arcmin DEm     Declination (arcmin)    
 99-113  F15.12 arcsec DEs     Declination (arcsec)    
--------------------------------------------------------------------------------
Notes:
--------------------------------------------------------------------------------
HD4760   0.0 49.0 39.900000000000   6.0 24.0 25.999992000001  0.0 49.0 39.900000000000   6.0 24.0 28.800000000001
HD81809 22.0  2.0 15.450000000007 -61.0 39.0 34.599996000001 22.0  2.0 15.600000000012 -61.0 39.0 35.999999999988

Moreover the hour-deg-minute columns were formatted in floating-point format despite being of integer type.
So in addition to stripping the excess column hopefully correctly, I have changed those formats to fixed I2 width, plus leading zeros in the minutes/seconds for better readability and consistency with examples on http://vizier.u-strasbg.fr/doc/catstd-3.htx or
https://github.com/cds-astro/cds.pyreadme/blob/b84fc8b8b44b12d323eef3446e5084c52b9d7c39/tests/table.ascii#L1-L3

Checklist for package maintainer(s)

This checklist is meant to remind the package maintainer(s) who will review this pull request of some common things to look for. This list is not exhaustive.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see "When to rebase and squash commits".
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the Extra CI label.
  • Is a change log needed? If yes, did the change log check pass? If no, add the no-changelog-entry-needed label. If this is a manual backport, use the skip-changelog-checks label unless special changelog handling is necessary.
  • Is a milestone set? Milestone must be set but astropy-bot check might be missing; do not let the green checkmark fool you.
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate backport-X.Y.x label(s) before merge.

@dhomeier

dhomeier commented Oct 26, 2021 •

Copy link
Copy Markdown
Contributor Author

FutureWarning: Parquet format '2.0' pseudo version is deprecated failure on Windows looks unrelated (#12300),
but I expect major merge conflicts with #12301...

@hamogu

hamogu commented Oct 26, 2021

Copy link
Copy Markdown
Member

This looks good to me - but then I did not catch the various problems with the original PR, so I'm probably not the best person to review this either.

@hamogu hamogu added this to the v5.0 milestone Oct 26, 2021
@dhomeier

Copy link
Copy Markdown
Contributor Author

The docs on Vizier only show an example of

  14- 15  I2     h       RAh      Right Ascension J2000 , Epoch 1989.0 (hours)
  17- 18  I2     min     RAm      Right Ascension J2000 (minutes)
  20- 25  F6.3   s       RAs      Right Ascension J2000 (seconds)
      27  A1     ---     DE-      Declination J2000 (sign)
  28- 29  I2     deg     DEd      Declination J2000 , Epoch 1989.0 (degrees)
  31- 32  I2     arcmin  DEm      Declination J2000 (minutes)
  34- 38  F5.2   arcsec  DEs      Declination J2000 (seconds)

so it's not clear whether formatting RAh etc. as F4.1 is explicitly discouraged or if that part is just cosmetic.

@aaryapatil

aaryapatil commented Oct 27, 2021 •

Copy link
Copy Markdown
Member

This is a great catch! I remember being careful about poping only the first SkyCoord, but did not think about how this would mess up the rest of the indices. I quickly glanced over it, and it looks great to me. I will take a closer look but don't know helpful I will be 👩‍💻

@hamogu hamogu added Affects-dev PRs and issues that do not impact an existing Astropy release no-changelog-entry-needed labels Oct 27, 2021
@hamogu

hamogu commented Oct 27, 2021

Copy link
Copy Markdown
Member

I believe this does not need a changelog-entry because it only "affects-dev", but someone with more knowledge of all those label and milestones should check if my understanding of that is correct.

@nstarman

Copy link
Copy Markdown
Member

FutureWarning: Parquet format '2.0' pseudo version is deprecated failure on Windows looks unrelated (#12300),

I think the tests should now pass if this PR is rebased.

@taldcroft

Copy link
Copy Markdown
Member

Awesome work @dhomeier , thanks!! I will take a look as well.

One thing is that I think life will be easier if we merge #12301 first. Basically what I did from main was:

cd astropy/io/ascii
cp cds.py mrt.py
git checkout v4.3.1 cds.py
# Then start making edits

So I think the changes you made will all go cleanly into my branch, but in mrt.py instead of cds.py. If we merge this PR #12302 first then I think it will be a big problem to rebase. I'm not sure if there will be a clever way in git to cherry pick your changes, but we can figure something out.

I do want to get #12301 into 5.0 because otherwise after that doing the splitting represents an API change and will break existing code that was using cds to write.

@pllim

pllim commented Oct 27, 2021 •

Copy link
Copy Markdown
Member

Please rebase to pick up #12300 that will get rid of the unrelated failure. FYI. (Oh, ops, I just saw #12302 (comment) after posting this.)

@Suyog7130

Copy link
Copy Markdown
Contributor

@dhomeier and others, thank you very much for your work. This makes the code much more robust and neat. It's a pity we didn't catch up the issue during the original writing. Please ping me up if there's something specific I can help with.

@taldcroft taldcroft left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good apart from the comments.

Comment thread astropy/io/ascii/cds.py Outdated
# For all other coordinate types, simply divide into two columns
# for latitude and longitude resp. with the unit used been as it is.
# Galactic coordinates.
elif col.name == 'galactic' and 'GLAT' not in self.colnames:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should you also check for 'GLON' in colnames? Same below for ecliptic and ELON and ELAT.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The primary incentive here was to check if any prior coordinate column of the same kind had already been expanded, in which case there would always been both 'GLAT' and 'GLON' columns; analogously for 'RAh' etc. But of course if the original table perchance already had a column named 'GLON', that would of course be missed and a duplicate column created like

 Bytes Format Units  Label     Explanations
--------------------------------------------------------------------------------
 1- 7  A7     ---    name    Description of name  
 9-15  F7.3   ---    GLON    Description of GLON  
17-32  F16.12 deg    GLON    Galactic Longitude   
34-49  F16.12 deg    GLAT    Galactic Latitude    
51-64  A14    ---    coord2  Description of coord2
--------------------------------------------------------------------------------
Notes:
--------------------------------------------------------------------------------
HD4760    6.402  12.416250000000   6.402222000000 12.4163 6.407 
HD81809 -61.660 330.556444000000 -61.659611110000 330.564 -61.66

Might say that it's up to the user to avoid such ambiguities, but perhaps it's better to check lon and lat in a consistent manner.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rewrote the LON/LAT block in a more general (and hopefully also easier to extend) manner, which checks for all relevant columns.

Comment thread astropy/io/ascii/cds.py Outdated

if col.format is not None:
col.formatted_width = max([len(sval) for sval in col.str_vals])
min_width = re.match(r'^(\+?)(\d+)', col.format)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is this change trying to fix? Doing a regex match on the format is not robust because the format can come in many flavors. Here are legal examples that break this code:

def myfmt(x):
    return '{:.3f}'.format(x)

t = Table()
t['i'] = [100, 2]
t['f'] = [100.2, 3.4]
t['f'].format = myfmt
t['i'].format = '0{:05d}'

Basically the col.str_vals are formatted either by col.format or the default formatting for the data type. So I'm not sure why the if col.format is not None test is being done.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Here is a more minimal change that passes tests. It also removes the unnecessary block that sets col.format from col.info.format. For Column objects those two are the same thing. Honestly the logic in this code is pretty convoluted so I'm not entirely sure what's going on so need to rely on tests.

diff --git a/astropy/io/ascii/cds.py b/astropy/io/ascii/cds.py
index 9181aefbb4..d0b5bc6765 100644
--- a/astropy/io/ascii/cds.py
+++ b/astropy/io/ascii/cds.py
@@ -413,18 +413,8 @@ class CdsHeader(core.BaseHeader):
             # Check if column is MaskedColumn
             col.has_null = isinstance(col, MaskedColumn)
 
-            min_width = None
-            # Check if the column format was set by the passed ``formats`` argument.
-            if col.format is None:
-                if col.info.format is not None:
-                    col.format = col.info.format
-
             if col.format is not None:
-                min_width = re.match(r'^(\+?)(\d+)', col.format)
-                if min_width is None:
-                    col.formatted_width = max([len(sval) for sval in col.str_vals])
-                else:
-                    col.formatted_width = int(min_width.groups()[1])
+                col.formatted_width = max([len(sval) for sval in col.str_vals])
 
             # Set CDSColumn type, size and format.
             if np.issubdtype(col.dtype, np.integer):
@@ -433,7 +423,7 @@ class CdsHeader(core.BaseHeader):
                 if getattr(col, 'formatted_width', None) is None:  # If ``formats`` not passed.
                     col.formatted_width = max(len(str(col.max)), len(str(col.min)))
                 col.fortran_format = "I" + str(col.formatted_width)
-                if min_width is None:
+                if col.format is None:
                     col.format = ">" + col.fortran_format[1:]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, that does work as intended also for the cases I checked!
The regex was only meant to detect the RA* and DE* column formats, which are very specifically set in write, as I was hesitant to remove the default setting from fortran_format in the original.

                col.fortran_format = "I" + str(col.formatted_width)
                col.format = ">" + col.fortran_format[1:]

But at least for the tests there is no other output expected in any other column types.

@taldcroft

Copy link
Copy Markdown
Member

About the changelog entry, this should have a changelog to indicate continued work on #11897. You just copy the 11897.feature.rst exactly to 12302.feature.rst, but in this case only after rebasing on #12301. The identical feature news fragments get turned into one changelog entry with multiple PRs.

@nstarman

Copy link
Copy Markdown
Member

The identical feature news fragments get turned into one changelog entry with multiple PRs.

That's a nice bit of institutional wisdom! I had no clue about that, is it documented?

@dhomeier

Copy link
Copy Markdown
Contributor Author

@dhomeier and others, thank you very much for your work. This makes the code much more robust and neat. It's a pity we didn't catch up the issue during the original writing. Please ping me up if there's something specific I can help with.

Thanks @Suyog7130, this is a very nice contribution to work on! Hopefully we will be getting the rest of the updates in in time; unfortunately I only had time to look at the original PR very intermittently, otherwise I would have joined the discussion much earlier.

@dhomeier

Copy link
Copy Markdown
Contributor Author

One more question @taldcroft - was there a specific reason to convert some of the exp_out in the tests to lists of lines only, or just stylistic grounds?

@dhomeier

Copy link
Copy Markdown
Contributor Author

Oh, @Suyog7130, @hamogu , @taldcroft – having just had the discussion on the right number of digits for 'vounit' strings; I had already been scratching my head over the picoarcsec precision currently printed in the RAs and DEs columns, but also mostly considered it a stylistic issue. However the standard explicitly states

Data dumps provided at the floating-point precision of a computer are inconsistent with these requirements and will be returned to the author for correction, i.e., rounding to significant digits.

So perhaps should reduce that format to a more sensible number of digits as well?

@dhomeier
dhomeier force-pushed the cdswriter-coordinates branch from 6fea1d8 to 2af7cd7 Compare October 30, 2021 00:57
@taldcroft

taldcroft commented Oct 30, 2021 •

Copy link
Copy Markdown
Member

This code does choose a default precision, and think that a default precision of microarcsec is preferable to picoarcsec. A precision of microarcsec may be reasonable in some cases, but picoarcsec is always wrong and requires users to always dig around in the docs.

For that matter we could make the default correspond to a common case of 3 digits, and force the outlier people to find the magic way of fixing it.

I don't think that forcing users to fix the table by hand should be considered an option (since that demands fixing all the column start/stop fields as well). Also remember this format is specifically designed for use in publications and displaying tables, so defaulting to (beyond) machine precision to losslessly serialize data is not really why MRT exists.

Comment thread docs/io/ascii/write.rst Resolved
@taldcroft

Copy link
Copy Markdown
Member

Of course in the interest of time, the changes that @dhomeier put up are at least better in not exceeding actual machine precision. So fine with that.

@dhomeier
dhomeier force-pushed the cdswriter-coordinates branch from 2af7cd7 to d2da8a7 Compare October 30, 2021 01:43
@dhomeier

Copy link
Copy Markdown
Contributor Author

Fine with stripping 3 or 6 more digits as well; the current solution has the advantage of not requiring any changes in the GLON etc. formats and their outputs.

@astrofrog

Copy link
Copy Markdown
Member

Should this be merged for 5.0?

@dhomeier

Copy link
Copy Markdown
Contributor Author

I was just waiting a bit for further discussion, but with the suggested typo fix applied it should be good to go.

@dhomeier

Copy link
Copy Markdown
Contributor Author

Oh well, another break-it-all! Is that a pyerfa failure now?

@taldcroft

Copy link
Copy Markdown
Member

I'm fine with the PR now, but we probably need to get tests passing again, somehow?? How can we restart tests?

@astrofrog - yes please, this should get into 5.0!

@hamogu

hamogu commented Oct 30, 2021

Copy link
Copy Markdown
Member

I've restarted the tests, although this one does not look like it should just be a fluke, but let's see. It's certainly not related to this PR.

@dhomeier

Copy link
Copy Markdown
Contributor Author

Yes, they all passed before a single-character fix in the docs – if the commit button had permitted it, I would have marked it ci skip ;-).

@hamogu

hamogu commented Oct 30, 2021

Copy link
Copy Markdown
Member

If it was just that, we could have made an exception and merged with failing PR. However, d2da8a7 also failed and there is no successful run since the last fource-push, so I'm a little reluctant to do so, unless @astrofrog tell me that it's OK.

@hamogu

hamogu commented Oct 30, 2021

Copy link
Copy Markdown
Member

Fails like before in coordinate stacking for new mix-in columns. Maybe @taldcroft has any ideas?

@hamogu

hamogu commented Oct 30, 2021

Copy link
Copy Markdown
Member

(Or maybe the d2da8a7 only had the allowed failures fail, but I'm too stupid to find the correct run in GH actions. Also entirely possible. Either way, I'm not qualified enough to decide if this is a time to ignore the CI. Today is not the time to casually break main.)

@dhomeier

dhomeier commented Oct 30, 2021 •

Copy link
Copy Markdown
Contributor Author
      table.vstack([t1, t3])

E AssertionError: Regex pattern 'loss of information' does not match 'input representations are inconsistent.'.
../../.tox/py38-test/lib/python3.8/site-packages/astropy/table/tests/test_operations.py:1260: AssertionError

I'd think that's something outside of Astropy.

@astrofrog

Copy link
Copy Markdown
Member

The CI is now fixed in main so worth trying to rebase this - any failures will be real

@dhomeier
dhomeier force-pushed the cdswriter-coordinates branch from 7fa2ecd to 10b8e3c Compare October 30, 2021 12:38
@astrofrog

Copy link
Copy Markdown
Member

Ah I think main is still failing, investigating

@astrofrog

Copy link
Copy Markdown
Member

I'm fixing the CI issue in https://github.com/astropy/astropy/pull/12336/files but in the mean time this looks fine so I'll go ahead and merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Affects-dev PRs and issues that do not impact an existing Astropy release Bug io.ascii

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TST: test_write_extra_SkyCoord_cols fails on Azure Pipelines

8 participants