Skip to content
Astronomy

Potato for astronomy

Vet ZTF and Rubin candidates as real or bogus on FITS cutout triplets, or classify galaxy morphology, with each team member's labels exported separately.

Potato shows FITS images in the browser, where annotators vet transient candidates from surveys such as ZTF and Rubin as real or bogus on the science, reference, and difference cutouts and the light curve, or classify galaxy morphology with a Galaxy-Zoo-style question tree. Potato is free and open source, runs on your own server, and exports each annotator's labels separately for training a real-bogus classifier.

A difference image is a calibrated science exposure minus a reference (template) image of the same field, and a real transient appears in the difference image as a new point source. In real-bogus vetting, annotators label each detection as an astrophysical source or an artifact such as a cosmic ray. The Braai classifier for ZTF was trained on 32,640 labeled science, reference, and difference triplets, and the labels came from Zwickyverse, a simple web-based open-source tool (Duev et al., 2019). In the same paper, about 30% of the Zooniverse volunteers' bogus labels on candidates with low scores from an earlier random-forest classifier turned out to be real. Most of the mislabeled candidates were variable stars, and the volunteers had seen no light curves. In a Pan-STARRS1 supernova search, combining volunteer and neural-network classifications outperformed either one alone (Wright et al., 2017). Potato shows the light curve under the cutouts and sends each candidate to the number of annotators you set.

Astronomy tasks in Potato

Each row uses the fits_cutout display, new in Potato 2.13, with radio and multiselect schemes for the questions.

TaskHow Potato handles the taskDocs
Vet transient candidatesScience, reference, and difference cutouts side by side, with Real, Bogus, and Unsure on the R, B, and U keysAstronomy
Record why a candidate is bogusA multiselect question on the cause, shown only after an annotator picks BogusAstronomy
Check the light curveThe candidate's light curve under the cutouts, with upper limits as open trianglesAstronomy
Classify galaxy morphologyOne image per item and one radio question per node of the tree, with display_logic naming the path to each follow-upAstronomy
Move a Zooniverse workflow in-housepotato import -f zooniverse turns the workflow's tasks into schemes and can keep the volunteers' classificationsDigital humanities
Agreement on vetting labelsPercent agreement, Cohen's and Fleiss' kappa, and Krippendorff's alpha on the vetting questionInter-annotator agreement

A ZTF vetting study with three annotators

The config below has three annotators vet every ZTF candidate, reads the light curve in ZTF's column names, and asks for the cause of each bogus detection. The astronomy page has the item format.

yaml
annotation_task_name: "ZTF candidate vetting"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
data_files: [data/candidates.json]   # each item names three cutouts and a light curve
item_properties: {id_key: id, text_key: summary}
user_config:
  allow_all_users: true
 
num_annotators_per_item: 3
 
instance_display:
  fields:
    - key: candidate
      type: fits_cutout
      label: "Cutouts"
      display_options:
        panels:
          - {key: science, label: Science}
          - {key: reference, label: Reference}
          - {key: difference, label: Difference, stretch: asinh}
        light_curve_columns: {time: jd, band: fid, mag: magpsf, err: sigmapsf, limit: diffmaglim}
        time_label: JD
 
annotation_schemes:
  - annotation_type: radio
    name: vetting
    description: "Is this a real astrophysical transient?"
    humanize_labels: false
    labels:
      - {name: "Real", key_value: "r"}
      - {name: "Bogus", key_value: "b"}
      - {name: "Unsure", key_value: "u"}
    label_requirement: {required: true}
 
  - annotation_type: multiselect
    name: bogus_reason
    description: "What makes the candidate bogus?"
    humanize_labels: false
    labels: ["Subtraction residual (dipole)", "Cosmic ray or hot pixel", "Satellite or asteroid trail", "Bad column or image edge", "Other"]
    display_logic:
      show_when:
        - {schema: vetting, operator: equals, value: "Bogus"}

num_annotators_per_item: 3 sends each candidate to three annotators. Potato's light curve reader looks for column names such as mag and magerr, and light_curve_columns maps ZTF's magpsf and sigmapsf onto the mag and err roles. Without the mapping, every row with a diffmaglim value is drawn as an upper limit. With humanize_labels: false, "Bogus" on screen matches the value in the display_logic condition.

Getting cutouts in and labels out

Potato reads FITS files on the server with astropy, and the astro extra installs astropy (pip install 'potato-annotation[astro]'). Each item names FITS files and light curves relative to the media directory:

  • Cutouts. .fits, .fit, .fts, and gzipped .fits.gz files.
  • Positions. An item may give a center in RA and Dec or in FITS pixels, with a size in pixels or as an angle such as "40 arcsec", and an item with no position shows the whole image.
  • Light curves. A CSV, TSV, or JSON file, or a list of points written into the item.

The display reads every file from the media directory and refuses URLs. The consensus export writes each candidate's top answer, vote fractions, and a retired or needs_review status to consensus_questions.csv:

bash
python -m potato.export -c config.yaml -f consensus -o exports/consensus

With the default agreement_threshold of 0.8 and three annotators, a candidate retires only when all three annotators agree, and the rest go to needs_review. An answer to the cause question stays in the stored annotation after an annotator changes Bogus to Real, and neither the export nor the agreement metrics marks the answer as hidden. Filter bogus_reason on the vetting answer before training on the labels.

Working alongside Zooniverse, SkyPortal, and the alert brokers

Zooniverse hosts free citizen-science projects that launch publicly after a review and suits a public volunteer crowd, as in Galaxy Zoo and Zwicky's Quirky Transients. SkyPortal is a web application that displays astronomical datasets for annotation, analysis, and discovery, with a candidate scanning page for sources from a filtered alert stream. Fritz is the science data platform of ZTF, builds on SkyPortal, and suits a survey collaboration's daily scanning and follow-up. Alert brokers such as ALeRCE and Lasair filter and classify the full alert stream, and Lasair's SQL filters can run on the live stream. Potato fits a private team or a class labeling a fixed set of candidates or galaxies, because Potato assigns each item to a set number of annotators, trains annotators on practice items before the real ones, and exports each annotator's labels separately. One route is to save the cutouts of candidates from a broker as .fits.gz files, vet the candidates in Potato, and train on the retired labels.

Setting up the study with a coding agent

potato-skill 1.2.0 knows the fits_cutout display by name and guides Claude Code, Codex, or Cursor through the study-design side, such as what to ask annotators, how many annotators vet each candidate, training and attention checks, and export. The skill does not yet document the FITS item format, the display options, or the astro extra. Point the agent at the astronomy page and the page's Markdown copy, https://www.potatoannotator.com/docs/annotation-types/astronomy.md, for the formats and options.

Frequently asked questions

Can annotators see the science, template, and difference cutouts of an alert side by side?

Yes. The fits_cutout display shows the science, reference (template), and difference cutouts of each candidate in one row, with shared zoom and pan and one crosshair across the three panels. A ZTF alert cutout saved to disk with a .fits.gz name opens without decompression, and each panel can set a different stretch, such as asinh on the difference image.

Are cutouts that vary in orientation across visits rotated north up?

No. Potato shows each cutout in the orientation the FITS file stores and draws north and east arrows on each panel from the panel's WCS. When the panels are not on one pixel grid, a note under the panels says so, and the crosshair is placed on each panel by sky position.

Can annotators read RA and Dec from the WCS of a FITS image?

Yes. The readout under the panels shows the RA and Dec under the pointer, in sexagesimal and in degrees, with the FITS pixel of the original image. The readout interpolates a grid of sky positions that astropy computes on the server and follows any projection astropy reads, SIP distortion included.

Further reading

References

  1. Duev et al. (2019). Real-bogus classification for the Zwicky Transient Facility using deep learning. Monthly Notices of the Royal Astronomical Society 489(3). https://doi.org/10.1093/mnras/stz2357
  2. Wright et al. (2017). A transient search using combined human and machine classifications. Monthly Notices of the Royal Astronomical Society 472(2). https://doi.org/10.1093/mnras/stx1812

Start here

Other fields

All use cases