Polars
K-Dense-AI/scientific-agent-skills
High-performance DataFrame library for Python ETL, analytics, and pandas migration.
Core Python library for astronomy/astrophysics: units with dimensional analysis, celestial coordinate transforms (ICRS/Galactic/AltAz/FK5), FITS I/O, tables (FITS/HDF5/VOTable/CSV), cosmology…
$ npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install jaechang-hits/SciAgent-Skills astropy-astronomy --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/jaechang-hits/SciAgent-Skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/scientific-computing/astropy-astronomy .claude/skills/astropy-astronomy && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "astropy-astronomy" agent skill from https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/scientific-computing/astropy-astronomy into .claude/skills/astropy-astronomy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "astropy-astronomy", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/scientific-computing/astropy-astronomyType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install jaechang-hits/SciAgent-Skills astropy-astronomy --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jaechang-hits/SciAgent-Skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/scientific-computing/astropy-astronomy .agents/skills/astropy-astronomy && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "astropy-astronomy" agent skill from https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/scientific-computing/astropy-astronomy into .agents/skills/astropy-astronomy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "astropy-astronomy", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install jaechang-hits/SciAgent-Skills astropy-astronomy --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jaechang-hits/SciAgent-Skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/scientific-computing/astropy-astronomy .cursor/skills/astropy-astronomy && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "astropy-astronomy" agent skill from https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/scientific-computing/astropy-astronomy into .cursor/skills/astropy-astronomy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "astropy-astronomy", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/jaechang-hits/SciAgent-Skills.git --path skills/scientific-computing/astropy-astronomy--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install jaechang-hits/SciAgent-Skills astropy-astronomy --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jaechang-hits/SciAgent-Skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/scientific-computing/astropy-astronomy .gemini/skills/astropy-astronomy && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "astropy-astronomy" agent skill from https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/scientific-computing/astropy-astronomy into .gemini/skills/astropy-astronomy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "astropy-astronomy", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install jaechang-hits/SciAgent-Skills astropy-astronomyInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/jaechang-hits/SciAgent-Skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/scientific-computing/astropy-astronomy .github/skills/astropy-astronomy && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "astropy-astronomy" agent skill from https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/scientific-computing/astropy-astronomy into .github/skills/astropy-astronomy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "astropy-astronomy", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install jaechang-hits/SciAgent-Skills astropy-astronomy --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jaechang-hits/SciAgent-Skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/scientific-computing/astropy-astronomy .opencode/skills/astropy-astronomy && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "astropy-astronomy" agent skill from https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/scientific-computing/astropy-astronomy into .opencode/skills/astropy-astronomy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "astropy-astronomy", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
astropy-astronomyCore Python library for astronomy/astrophysics: units with dimensional analysis, celestial coordinate transforms (ICRS/Galactic/AltAz/FK5), FITS I/O, tables (FITS/HDF5/VOTable/CSV), cosmology…
Astropy Astronomy is an agent skill from jaechang-hits/SciAgent-Skills. Core Python library for astronomy/astrophysics: units with dimensional analysis, celestial coordinate transforms (ICRS/Galactic/AltAz/FK5), FITS I/O, tables (FITS/HDF5/VOTable/CSV), cosmology (Planck18, distance/age), precise time (UTC/TAI/TT/TDB, Julian, barycentric), WCS pixel-world mapping, model fitting. For general tables use pandas/polars; for radio interferometry use CASA.
Its SKILL.md is about 5.5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 4 other files, including reference files (for example `references/auxiliary_modules.md`, `references/coordinates_time_cosmology.md` and `references/data_io_guide.md`).
It sits in Research & Science, covering Physical and earth sciences and DataFrames. It works with Python, pandas and Polars. The repository describes itself as: 197 bioinformatics & life science skills for Claude Code and AI agents — BixBench 92.0% accuracy. RNA-seq, single-cell, drug discovery, proteomics, and more. Powers OmicsHorizon. The licence is BSD-3-Clause.
7 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 82c862c. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pipFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
docs.astropy.orglearn.astropy.orggithub.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Astropy Astronomy loads about 5.5k tokens when it runs, and up to ~12k if it reads all its reference files. Until then it costs about 100 tokens; SKILL.md has 892 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from jaechang-hits/SciAgent-Skills at commit 82c862c, republished under its BSD-3-Clause licence (© jaechang-hits). 892 words, ~5,541 tokens.
.claude/skills/astropy-astronomy/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.Astropy is the core Python package for astronomy, providing essential functionality for astronomical research: unit-aware calculations, celestial coordinate transformations, FITS file I/O, cosmological calculations, precise time handling, tabular data operations, and WCS image coordinate mapping.
pip install astropy # Core package
pip install astropy[all] # With optional dependencies (regions, photutils, etc.)
pip install pytz # For timezone conversionsimport astropy.units as u
from astropy.coordinates import SkyCoord
from astropy.time import Time
from astropy.io import fits
from astropy.table import Table
from astropy.cosmology import Planck18
# Units and quantities
distance = 100 * u.pc
print(f"{distance.to(u.km):.3e}") # 3.086e+15 km
# Coordinates
coord = SkyCoord(ra=10.5*u.degree, dec=41.2*u.degree, frame='icrs')
print(f"Galactic: l={coord.galactic.l:.2f}, b={coord.galactic.b:.2f}")
# Cosmology
d_L = Planck18.luminosity_distance(z=1.0)
print(f"Luminosity distance at z=1: {d_L:.1f}") # ~6780 Mpc
# Time
t = Time('2023-01-15 12:30:00')
print(f"JD: {t.jd:.6f}, MJD: {t.mjd:.6f}")astropy.units)import astropy.units as u
import numpy as np
# Create quantities
distance = 10 * u.kpc
flux = 3.5e-15 * u.erg / u.s / u.cm**2
wavelength = 6563 * u.Angstrom
# Unit conversions
distance_ly = distance.to(u.lyr)
flux_jy = flux.to(u.Jy, equivalencies=u.spectral_density(wavelength))
print(f"Distance: {distance_ly:.2f}")
# Arithmetic with automatic unit tracking
velocity = 300 * u.km / u.s
time = 1 * u.Gyr
distance_traveled = (velocity * time).to(u.Mpc)
print(f"Distance traveled: {distance_traveled:.2f}")
# Equivalencies for domain-specific conversions
freq = wavelength.to(u.Hz, equivalencies=u.spectral())
energy = wavelength.to(u.eV, equivalencies=u.spectral())
parallax_dist = (0.1 * u.arcsec).to(u.pc, equivalencies=u.parallax())
print(f"Frequency: {freq:.3e}, Parallax distance: {parallax_dist:.1f}")# Logarithmic units (magnitudes)
mag = -2.5 * u.mag
flux_ratio = mag.to(u.dimensionless_unscaled)
# Performance: pre-compute composite units
flux_unit = u.erg / u.s / u.cm**2 / u.Angstrom
fluxes = np.array([1e-15, 2e-15, 3e-15]) * flux_unit
# Custom units
bbl = u.def_unit('bbl', 158.987 * u.liter)astropy.coordinates)from astropy.coordinates import SkyCoord, EarthLocation, AltAz
from astropy.time import Time
import astropy.units as u
# Create coordinates (multiple formats)
c = SkyCoord(ra='05h23m34.5s', dec='-69d45m22s', frame='icrs')
c = SkyCoord(ra=10.5*u.degree, dec=41.2*u.degree)
c = SkyCoord(l=280*u.degree, b=-30*u.degree, frame='galactic')
# Transform between frames
c_gal = c.galactic
c_fk5 = c.fk5
print(f"Galactic: l={c_gal.l:.4f}, b={c_gal.b:.4f}")
# Observer-dependent AltAz (requires time + location)
location = EarthLocation(lat=40*u.deg, lon=-120*u.deg, height=1000*u.m)
obstime = Time('2023-06-15 23:00:00')
altaz = c.transform_to(AltAz(obstime=obstime, location=location))
print(f"Alt={altaz.alt:.2f}, Az={altaz.az:.2f}")# Angular separation and matching
c1 = SkyCoord(ra=10*u.deg, dec=20*u.deg)
c2 = SkyCoord(ra=10.1*u.deg, dec=20.05*u.deg)
sep = c1.separation(c2)
print(f"Separation: {sep.arcsec:.2f} arcsec")
# Catalog matching
from astropy.coordinates import match_coordinates_sky
idx, sep, _ = coords1.match_to_catalog_sky(coords2)
matches = sep < 1 * u.arcsec
# Named object lookup
m31 = SkyCoord.from_name('M31')
# 3D coordinates with distance
c3d = SkyCoord(ra=10*u.deg, dec=20*u.deg, distance=50*u.kpc)
print(f"Cartesian: {c3d.cartesian}")
# Velocity information
c_vel = SkyCoord(ra=10*u.deg, dec=20*u.deg,
pm_ra_cosdec=5*u.mas/u.yr, pm_dec=-3*u.mas/u.yr,
radial_velocity=100*u.km/u.s)astropy.io.fits)from astropy.io import fits
import numpy as np
# Read FITS file
with fits.open('observation.fits') as hdul:
hdul.info() # Show HDU structure
data = hdul[0].data # Image data as NumPy array
header = hdul[0].header # Header as dict-like object
# Access header values
exptime = header['EXPTIME']
header['OBSERVER'] = 'Smith' # Modify
header.add_history('Processed with astropy')
# Convenience functions
data = fits.getdata('image.fits')
header = fits.getheader('image.fits')
value = fits.getval('image.fits', 'EXPTIME')# Create new FITS file
hdu_primary = fits.PrimaryHDU(data=np.zeros((100, 100)))
hdu_primary.header['OBJECT'] = 'M31'
# Multi-extension file
hdu_image = fits.ImageHDU(data=np.random.random((256, 256)), name='SCI')
hdu_table = fits.BinTableHDU.from_columns([
fits.Column(name='ID', format='J', array=np.arange(100)),
fits.Column(name='FLUX', format='E', array=np.random.random(100)),
fits.Column(name='NAME', format='20A', array=['star']*100)
])
hdul = fits.HDUList([hdu_primary, hdu_image, hdu_table])
hdul.writeto('output.fits', overwrite=True)
# Large file handling with memory mapping
hdul = fits.open('huge.fits', memmap=True)
cutout = hdul[0].section[100:200, 100:200] # Read only a sliceastropy.table)from astropy.table import Table, QTable
import astropy.units as u
import numpy as np
# Create tables
t = Table({'ra': [10.0, 20.0, 30.0], 'dec': [41.0, 42.0, 43.0],
'mag': [15.2, 16.1, 14.8]})
# Read from file (auto-detect format)
t = Table.read('catalog.fits')
t = Table.read('data.csv', format='csv')
t = Table.read('catalog.vot', format='votable')
# Unit-aware QTable
qt = QTable({'distance': [10, 20, 30] * u.kpc,
'flux': [1e-15, 2e-15, 3e-15] * u.erg / u.s / u.cm**2})
# Filter, sort, column operations
bright = t[t['mag'] < 15.5]
t.sort('mag')
t['abs_mag'] = t['mag'] - 5 * np.log10(100)
print(f"Rows: {len(t)}, Columns: {t.colnames}")# Joins and grouping
from astropy.table import join, vstack, hstack
# Database-style join
merged = join(t1, t2, keys='id', join_type='inner')
# Stack tables
combined = vstack([t1, t2, t3]) # Vertical (row-append)
combined = hstack([t_coords, t_phot]) # Horizontal (column-append)
# Group and aggregate
grouped = t.group_by('field')
stats = grouped.groups.aggregate(np.mean)
# Write
t.write('output.fits', format='fits', overwrite=True)
t.write('output.ecsv', format='ascii.ecsv') # Preserves units + metadataastropy.time)from astropy.time import Time, TimeDelta
import astropy.units as u
import numpy as np
# Create from various formats
t = Time('2023-01-15 12:30:45', format='iso', scale='utc')
t = Time(2460000.0, format='jd')
t = Time(59945.0, format='mjd')
t = Time(1673785845.0, format='unix')
# Convert between formats and scales
print(f"ISO: {t.iso}")
print(f"JD: {t.jd}, MJD: {t.mjd}")
print(f"TAI: {t.tai.iso}") # UTC → TAI (includes leap seconds)
print(f"TDB: {t.tdb.iso}") # UTC → Barycentric Dynamical Time
# Time arithmetic
dt = TimeDelta(7, format='jd')
t_future = t + dt
t_future = t + 1 * u.hour
duration = Time('2024-01-01') - Time('2023-01-01')
print(f"Duration: {duration.jd:.1f} days")
# Array of times
times = Time('2023-01-01') + np.arange(365) * u.day# Observing features
from astropy.coordinates import SkyCoord, EarthLocation
location = EarthLocation.of_site('Keck Observatory')
t = Time('2023-06-15 23:00:00', location=location)
# Sidereal time
lst = t.sidereal_time('apparent')
print(f"LST: {lst}")
# Barycentric correction
target = SkyCoord(ra='23h23m08.55s', dec='+18d24m59.3s')
ltt = t.light_travel_time(target, kind='barycentric')
t_bary = t.tdb + ltt
print(f"Barycentric correction: {ltt.sec:.3f} seconds")astropy.cosmology)from astropy.cosmology import Planck18, FlatLambdaCDM
import astropy.units as u
import numpy as np
# Built-in cosmologies: Planck18, Planck15, Planck13, WMAP9, WMAP7
z = 1.5
# Distance calculations
d_L = Planck18.luminosity_distance(z)
d_A = Planck18.angular_diameter_distance(z)
d_C = Planck18.comoving_distance(z)
dm = Planck18.distmod(z) # Distance modulus
print(f"d_L={d_L:.1f}, d_A={d_A:.1f}, d_C={d_C:.1f}")
# Time calculations
age = Planck18.age(z)
lookback = Planck18.lookback_time(z)
print(f"Age at z={z}: {age.to(u.Gyr):.2f}")
print(f"Lookback time: {lookback.to(u.Gyr):.2f}")
# Scale and volume
scale = Planck18.kpc_proper_per_arcmin(z)
vol = Planck18.comoving_volume(z)
print(f"Scale: {scale:.2f}")# Inverse calculations — find z for given property
from astropy.cosmology import z_at_value
z_10gyr = z_at_value(Planck18.lookback_time, 10 * u.Gyr)
z_1gpc = z_at_value(Planck18.comoving_distance, 1 * u.Gpc)
print(f"z at lookback 10 Gyr: {z_10gyr:.4f}")
# Custom cosmology
cosmo = FlatLambdaCDM(H0=70, Om0=0.3, Tcmb0=2.725)
d_L_custom = cosmo.luminosity_distance(z=1.0)
# Array operations (all methods accept arrays)
z_array = np.linspace(0.1, 3.0, 100)
distances = Planck18.luminosity_distance(z_array)
print(f"Distance array shape: {distances.shape}") # (100,)from astropy.wcs import WCS
from astropy.io import fits
import astropy.units as u
# Read WCS from FITS
with fits.open('image.fits') as hdul:
wcs = WCS(hdul[0].header)
# Pixel ↔ world transformations
world = wcs.pixel_to_world(100, 200) # Returns SkyCoord
print(f"RA: {world.ra:.6f}, Dec: {world.dec:.6f}")
from astropy.coordinates import SkyCoord
coord = SkyCoord(ra=10.5*u.degree, dec=41.2*u.degree)
x, y = wcs.world_to_pixel(coord)
# WCS properties
print(f"Ref pixel: {wcs.wcs.crpix}")
print(f"Ref value: {wcs.wcs.crval}")
print(f"Pixel scale: {wcs.proj_plane_pixel_scales()}")
footprint = wcs.calc_footprint() # Corner coordinates# Image visualization
from astropy.visualization import simple_norm, ZScaleInterval, AsinhStretch, ImageNormalize
import matplotlib.pyplot as plt
data = fits.getdata('image.fits')
norm = simple_norm(data, 'sqrt', percent=99)
plt.imshow(data, norm=norm, cmap='gray', origin='lower')
plt.colorbar()
# Advanced normalization
interval = ZScaleInterval()
stretch = AsinhStretch()
norm = ImageNormalize(data, interval=interval, stretch=stretch)
# Sigma clipping for robust statistics
from astropy.stats import sigma_clipped_stats
mean, median, std = sigma_clipped_stats(data, sigma=3.0)
print(f"Background: {median:.2f} ± {std:.2f}")Astropy's equivalencies parameter enables domain-specific conversions that are not dimensionally equivalent:
| Equivalency | Converts Between | Example |
|---|---|---|
u.spectral() | Wavelength ↔ frequency ↔ energy | (500*u.nm).to(u.THz, u.spectral()) |
u.spectral_density(wav) | Flux density (Fλ ↔ Fν ↔ Jy) | flux.to(u.Jy, u.spectral_density(wav)) |
u.parallax() | Parallax angle ↔ distance | (10*u.mas).to(u.pc, u.parallax()) |
u.doppler_optical(rest) | Velocity ↔ wavelength (optical) | vel.to(u.Angstrom, u.doppler_optical(rest)) |
u.brightness_temperature(freq) | Flux ↔ temperature | For radio astronomy |
| Scale | Description | Use When |
|---|---|---|
| UTC | Coordinated Universal Time (with leap seconds) | Default; civil time |
| TAI | International Atomic Time (UTC + leap seconds) | Continuous timekeeping |
| TT | Terrestrial Time (TAI + 32.184s) | Geocentric calculations |
| TDB | Barycentric Dynamical Time | Solar system dynamics, ephemerides |
| UT1 | Earth rotation angle | Sidereal time, AltAz transforms |
Access via: t.utc, t.tai, t.tt, t.tdb, t.ut1
obstime + location)from astropy.coordinates import SkyCoord, EarthLocation, AltAz
from astropy.time import Time
import astropy.units as u
# Load catalog of sources
from astropy.table import Table
cat = Table.read('sources.fits')
coords = SkyCoord(ra=cat['RA']*u.degree, dec=cat['DEC']*u.degree)
# Transform to galactic
gal = coords.galactic
print(f"Galactic l range: {gal.l.min():.1f} to {gal.l.max():.1f}")
# Check observability (AltAz)
location = EarthLocation.of_site('Paranal Observatory')
obstime = Time('2023-06-15 23:00:00')
altaz = coords.transform_to(AltAz(obstime=obstime, location=location))
observable = altaz.alt > 30 * u.deg
print(f"Observable (alt>30°): {observable.sum()} of {len(coords)}")from astropy.io import fits
from astropy.wcs import WCS
from astropy.stats import sigma_clipped_stats
from astropy.visualization import simple_norm
import numpy as np
# Load image and WCS
with fits.open('science_image.fits') as hdul:
data = hdul[0].data.astype(float)
wcs = WCS(hdul[0].header)
# Background statistics
mean, median, std = sigma_clipped_stats(data, sigma=3.0)
print(f"Background: {median:.2f} ± {std:.2f}")
# Find bright pixels (simple threshold detection)
threshold = median + 5 * std
sources = np.where(data > threshold)
print(f"Pixels above 5σ: {len(sources[0])}")
# Convert pixel positions to sky coordinates
sky_coords = wcs.pixel_to_world(sources[1], sources[0])
print(f"RA range: {sky_coords.ra.min():.4f} to {sky_coords.ra.max():.4f}")from astropy.table import Table
from astropy.coordinates import SkyCoord
import astropy.units as u
# Read two catalogs
cat1 = Table.read('catalog1.fits')
cat2 = Table.read('catalog2.fits')
coords1 = SkyCoord(ra=cat1['RA']*u.degree, dec=cat1['DEC']*u.degree)
coords2 = SkyCoord(ra=cat2['RA']*u.degree, dec=cat2['DEC']*u.degree)
# Match
idx, sep, _ = coords1.match_to_catalog_sky(coords2)
max_sep = 1 * u.arcsec
matches = sep < max_sep
cat1_matched = cat1[matches]
cat2_matched = cat2[idx[matches]]
print(f"Matched: {matches.sum()} of {len(cat1)} (within {max_sep})")| Parameter | Module | Default | Description |
|---|---|---|---|
frame | SkyCoord | 'icrs' | Coordinate reference frame |
scale | Time | 'utc' | Time scale (utc, tai, tt, tdb, ut1) |
format | Time | auto | Time format (iso, jd, mjd, unix, etc.) |
equivalencies | .to() | None | Domain-specific unit conversion rules |
memmap | fits.open | True | Memory-map large files |
join_type | join() | 'inner' | Join type (inner, outer, left, right) |
sigma | sigma_clip | 3.0 | Clipping threshold in standard deviations |
stretch | simple_norm | 'linear' | Image stretch (linear, sqrt, log, asinh) |
percent | simple_norm | 100 | Percentile for normalization limits |
Always attach units — Use Quantity objects (e.g., 10 * u.kpc) to prevent dimensional errors. Bare numbers silently produce wrong results.
Use context managers for FITS — with fits.open(...) as hdul: ensures proper file closing and memory map cleanup.
Process arrays, not loops — All astropy operations accept arrays. Process 10,000 coordinates at once instead of looping.
Be explicit about time scales — Time('2023-01-15', scale='utc') prevents ambiguity. UTC↔TDB differences matter for precision timing.
Use QTable for unit-aware columns — QTable preserves units through I/O; plain Table stores units as metadata only.
Use ECSV for round-trip fidelity — t.write('file.ecsv') preserves units, dtypes, and metadata. CSV/FITS lose some metadata.
Anti-pattern — Wrong cosmology model: Always specify which cosmology you're using. Different models give different distances at the same redshift. Planck18 is current standard.
Anti-pattern — Ignoring WCS origin convention: astropy uses 0-based pixel coordinates. FITS standard uses 1-based. Use wcs.pixel_to_world() (handles this automatically) instead of manual calculations.
from astropy.cosmology import FlatLambdaCDM
import astropy.units as u
cosmo = FlatLambdaCDM(
H0=67.66, Om0=0.3111, Tcmb0=2.7255,
Neff=3.046, m_nu=[0, 0, 0.06] * u.eV
)
print(f"Age of universe: {cosmo.age(0).to(u.Gyr):.3f}")from astropy.modeling import models, fitting
import numpy as np
# Generate noisy Gaussian data
x = np.linspace(0, 10, 100)
y = 10 * np.exp(-0.5 * ((x - 5) / 1.0)**2) + np.random.normal(0, 0.5, 100)
# Fit
fitter = fitting.LevMarLSQFitter()
model = models.Gaussian1D(amplitude=8, mean=4, stddev=1.5)
fitted = fitter(model, x, y)
print(f"Amplitude: {fitted.amplitude.value:.2f}")
print(f"Mean: {fitted.mean.value:.2f}")
print(f"Stddev: {fitted.stddev.value:.2f}")from astropy.nddata import CCDData, StdDevUncertainty
import astropy.units as u
import numpy as np
# Create CCDData with uncertainty
data = np.random.random((256, 256))
uncertainty = StdDevUncertainty(np.sqrt(np.abs(data)))
ccd = CCDData(data, unit=u.adu, uncertainty=uncertainty,
meta={'OBJECT': 'M31', 'EXPTIME': 300.0})
# Read/write
ccd.write('processed.fits', overwrite=True)
ccd2 = CCDData.read('processed.fits', unit=u.adu)| Problem | Cause | Solution |
|---|---|---|
UnitConversionError | Incompatible units without equivalency | Add equivalencies=u.spectral() or appropriate equivalency |
| Wrong coordinate frame after transform | Missing obstime/location for AltAz | Provide both: AltAz(obstime=t, location=loc) |
ErfaWarning: dubious year | Time outside 1960–2040 range for UT1 | Use scale='tt' or scale='tdb' for extreme dates |
FileNotFoundError for IERS data | Leap second table not downloaded | Run from astropy.utils.iers import IERS_Auto; IERS_Auto.open() |
FITS header VerifyError | Non-standard FITS keywords | Use fits.open(f, ignore_missing_end=True) or hdul.verify('fix') |
| Slow coordinate transforms | Looping over single coordinates | Use array SkyCoord: SkyCoord(ra=ra_array, dec=dec_array) |
QTable loses units on write | Using CSV format | Use ECSV format: qt.write('file.ecsv') |
KeyError accessing FITS extension | Wrong extension index | Use hdul.info() to see structure; access by name: hdul['SCI'] |
| Inaccurate barycentric correction | Wrong time scale or missing location | Use scale='utc', set location on Time object |
ModelFit doesn't converge | Bad initial parameters | Provide closer initial guesses; try SimplexLSQFitter |
references/data_io_guide.md — Detailed FITS operations (headers, multi-extension, binary tables, column format codes, memory mapping, remote access), Table operations (creation, I/O formats, joins, grouping, indexing, QTable, masked data, display, performance), and collection conversion patterns. Consolidated from original fits.md and tables.md.references/coordinates_time_cosmology.md — Complete coordinate system reference (all frames, 3D coordinates, proper motions, representations, catalog matching), time handling (all formats, all scales, TimeDelta, sidereal time, light travel time, barycentric corrections, precision), and cosmological models (all built-ins, custom models, distances, volumes, inverse calculations, neutrino effects). Consolidated from original coordinates.md, time.md, and cosmology.md.references/auxiliary_modules.md — WCS detailed operations, NDData/CCDData, modeling framework (1D/2D models, fitting, compound models), image visualization (stretches, intervals, normalization), constants catalog, convolution, robust statistics, SAMP interoperability, data download utilities. Consolidated from original wcs_and_other_modules.md and units.md (equivalency details).Not migrated as separate files: Original had 7 reference files. Consolidated into 3 topical reference files covering all capabilities. units.md equivalency content split between SKILL.md Key Concepts (summary table) and auxiliary_modules.md (detailed code).
© jaechang-hits, BSD-3-Clause. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 3 other files (references) in skills/scientific-computing/astropy-astronomy of jaechang-hits/SciAgent-Skills.
Open the folder on GitHubat commit 82c862c
We found 1 copy of this SKILL.md (exact, near-identical or edited) in other folders, from 1 other GitHub owner. This page covers the copy in jaechang-hits/SciAgent-Skills, which our catalogue first saw on October 7, 2026.
Astropy Astronomy next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Astropy Astronomy this skilljaechang-hits/SciAgent-Skills | 374 | 1 repos | ~5.5k | Automated safety check: Pass | BSD-3-Clause | |
| PolarsK-Dense-AI/scientific-agent-skills | 48k | 1 repos | ~3.3k | Automated safety check: Pass | MIT | |
| Transforming Dataancoleman/ai-design-components | 525 | — | ~3k | Automated safety check: Pass | MIT | |
| Plot ML Figureprobabl-ai/skills | 138 | — | ~796 | Automated safety check: Pass | BSD-3-Clause | |
| Python Pipelinejamditis/claude-skills-journalism | 416 | — | ~4.8k | Automated safety check: Pass | MIT | |
| Bio Proteomics Data ImportGPTomics/bioSkills | 1.2k | 1 repos | ~4.5k | Automated safety check: Pass | MIT |
K-Dense-AI/scientific-agent-skills
High-performance DataFrame library for Python ETL, analytics, and pandas migration.
ancoleman/ai-design-components
Transform raw data into analytical assets using ETL/ELT patterns, SQL (dbt), Python (pandas/polars/PySpark), and orchestration (Airflow).
probabl-ai/skills
Pick how to write a figure before custom plot code. An agent skill from probabl-ai/skills.
jamditis/claude-skills-journalism
Python data pipelines with modular architecture. An agent skill from jamditis/claude-skills-journalism.
GPTomics/bioSkills
Loads mass-spectrometry data into Python/R and strips the search engine's bookkeeping before any number is trusted -- removes decoys (REV/Reverse), contaminants (CON/Potential contaminant)…
vemetric/vemetric
A skill your agent uses when the user has tabular data (pandas DataFrame, parquet, csv, Arrow, json) and wants to filter, group, aggregate, join, or speed up slow pandas.
jaechang-hits/SciAgent-Skills
NEB-IRC activation energy pipeline for reaction barriers using GFN2-xTB and pysisyphus.
jaechang-hits/SciAgent-Skills
3Dmol.js WebGL molecular visualization emitted as self-contained HTML.
jaechang-hits/SciAgent-Skills
Constraint-based (COBRA) analysis of genome-scale metabolic models: FBA, FVA, knockouts, flux sampling, production envelopes, gapfilling, media optimization.
jaechang-hits/SciAgent-Skills
Read, write, and edit ChemDraw CDX/CDXML files with RDKit's rdkit.Chem.rdChemDraw plus direct XML editing, always paired with a rendered PNG.
jaechang-hits/SciAgent-Skills
Programmatic PubMed access via NCBI E-utilities REST API. An agent skill from jaechang-hits/SciAgent-Skills.
jaechang-hits/SciAgent-Skills
Scaffold a new SciAgent-Skills entry. An agent skill from jaechang-hits/SciAgent-Skills.
Categories
Core Python library for astronomy/astrophysics: units with dimensional analysis, celestial coordinate transforms (ICRS/Galactic/AltAz/FK5), FITS I/O, tables (FITS/HDF5/VOTable/CSV), cosmology…. Astropy Astronomy is an agent skill from jaechang-hits/SciAgent-Skills. Core Python library for astronomy/astrophysics: units with dimensional analysis, celestial coordinate transforms (ICRS/Galactic/AltAz/FK5), FITS I/O, tables (FITS/HDF5/VOTable/CSV), cosmology (Planck18, distance/age), precise time (UTC/TAI/TT/TDB, Julian, barycentric), WCS pixel-world mapping, model fitting.
Astropy Astronomy fits situations like: tasks that involve Physical and earth sciences; tasks that involve DataFrames.
Run `npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a claude-code`. Or copy the skill folder (skills/scientific-computing/astropy-astronomy in jaechang-hits/SciAgent-Skills) into .claude/skills/astropy-astronomy in your project. Claude Code loads it when a task matches its description.
Run `npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a codex`. Or copy the skill folder (skills/scientific-computing/astropy-astronomy in jaechang-hits/SciAgent-Skills) into .agents/skills/astropy-astronomy in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add jaechang-hits/SciAgent-Skills --skill astropy-astronomy -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/astropy-astronomy, .gemini/skills/astropy-astronomy, .github/skills/astropy-astronomy and .opencode/skills/astropy-astronomy in your project.
Going by SKILL.md and its folder, Astropy Astronomy needs the command-line tools its instructions call (pip). Our summary lists: Python 3.
SKILL.md names 3 domains. As links in the text: docs.astropy.org, learn.astropy.org and github.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Astropy Astronomy is published under the BSD-3-Clause licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.5k tokens (SKILL.md is roughly 22k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 6.1k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Astropy Astronomy: Polars (K-Dense-AI/scientific-agent-skills, 48k stars), Transforming Data (ancoleman/ai-design-components, 525 stars), Plot ML Figure (probabl-ai/skills, 138 stars) and Python Pipeline (jamditis/claude-skills-journalism, 416 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
jaechang-hits (a GitHub user) maintains it in jaechang-hits/SciAgent-Skills, which has 374 GitHub stars. The repository holds 169 skills in this directory. The repository was last updated on September 29, 2026.
Source: jaechang-hits/SciAgent-Skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.