Skip to content

Commit

Permalink
Addition of "pixel-conventions" documentation file (and more explicit…
Browse files Browse the repository at this point in the history
… mention of this in overview file).
  • Loading branch information
perwin committed Apr 11, 2023
1 parent 208df82 commit 2ee9f66
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Documentation for PyImfit
installation
sample_usage
overview
pixel_conventions

.. toctree::
:maxdepth: 2
Expand Down
16 changes: 14 additions & 2 deletions docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ If you've already used the command-line version of **Imfit**, here are the essen
will read a standard **Imfit** configuration file and return an instance of that class with the
model specification. You can also build up a `ModelDescription` instance by programmatically
specifying components from within Python, or via a dict-based description.

* PyImfit uses the same [column-major, 1-based indexing](./pixel_conventions.html) as Imfit; thus, a
function set with (Py)Imfit coordnates x0,y0 = 100,50 would have Python (NumPy) coordinates
`array[49,99]`

* Fitting is done by instantiating an `Imfit` object with a `ModelDescription` object as
input, then adding a 2D NumPy array as the data to be fit (along with, optionally, mask
Expand Down Expand Up @@ -97,6 +101,12 @@ with a PSF, you can also supply the PSF image (in the form of a 2D NumPy array):

#### Creating a model; setting parameter values and limits

**Important Note on Pixel Conventions:** PyImfit uses the same FITS/IRAF/SAOimage convention for pixel
coordinates, where the first coordinate is the column number and the second is the row number and
indexing is 1-based (i.e., the center of the lower-left pixel in an image is at x,y = 1.0,1.0).
This is _different from_ the default Python/NumPy (column-major, 0-based) convention; see
[here](./pixel_conventions.html) for more details.

Each image-function parameter within a model can have a "current" value (e.g., the initial guess for
the fitting process, the result from the fit, etc.) and either: a set of lower and upper limits for
possible values **or** the string "fixed", which means the parameter value should be kept constant during fits.
Expand All @@ -108,8 +118,10 @@ computing model magnitudes; see below.)
A very simple example of programmatically constructing a model:

model_desc = pyimfit.SimpleModelDescription()
# define the limits on the central-coordinate X0 and Y0 as +/-10 pixels relative to initial values
# (note that Imfit treats image coordinates using the IRAF/Fortran numbering scheme: the lower-left
# define the limits on the central-coordinate X0 and Y0
# as +/-10 pixels relative to initial values
# (note that Imfit treats image coordinates using the
# FITS/IRAF/Fortran 1-based numbering scheme: the lower-left
# pixel in the image has coordinates (x,y) = (1,1))
model_desc.x0.setValue(105, [95,115])
model_desc.y0.setValue(62, [52,72])
Expand Down
19 changes: 17 additions & 2 deletions docs/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ the essential things to know:
by programmatically specifying components from within Python, or via
a dict-based description.

- PyImfit uses the same `column-major, 1-based
indexing <./pixel_conventions.html>`__ as Imfit; thus, a function set
with (Py)Imfit coordnates x0,y0 = 100,50 would have Python (NumPy)
coordinates ``array[49,99]``

- Fitting is done by instantiating an ``Imfit`` object with a
``ModelDescription`` object as input, then adding a 2D NumPy array as
the data to be fit (along with, optionally, mask and error images,
Expand Down Expand Up @@ -122,6 +127,14 @@ also supply the PSF image (in the form of a 2D NumPy array):
Creating a model; setting parameter values and limits
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Important Note on Pixel Conventions:** PyImfit uses the same
FITS/IRAF/SAOimage convention for pixel coordinates, where the first
coordinate is the column number and the second is the row number and
indexing is 1-based (i.e., the center of the lower-left pixel in an
image is at x,y = 1.0,1.0). This is *different from* the default
Python/NumPy (column-major, 0-based) convention; see
`here <./pixel_conventions.html>`__ for more details.

Each image-function parameter within a model can have a “current” value
(e.g., the initial guess for the fitting process, the result from the
fit, etc.) and either: a set of lower and upper limits for possible
Expand All @@ -138,8 +151,10 @@ A very simple example of programmatically constructing a model:
::

model_desc = pyimfit.SimpleModelDescription()
# define the limits on the central-coordinate X0 and Y0 as +/-10 pixels relative to initial values
# (note that Imfit treats image coordinates using the IRAF/Fortran numbering scheme: the lower-left
# define the limits on the central-coordinate X0 and Y0
# as +/-10 pixels relative to initial values
# (note that Imfit treats image coordinates using the
# FITS/IRAF/Fortran 1-based numbering scheme: the lower-left
# pixel in the image has coordinates (x,y) = (1,1))
model_desc.x0.setValue(105, [95,115])
model_desc.y0.setValue(62, [52,72])
Expand Down
36 changes: 36 additions & 0 deletions docs/pixel_conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Pixel Coordinate Conventions

### Image Coordinates

Imfit was written to follow the standard 2D array indexing conventions of FITS, IRAF, and (e.g.) SAOimage
DS9, which are 1-based and column-major. This means that the center of the first pixel (in the lower-left
of the image) has coordinates (x,y) = (1.0,1.0); the lower-left _corner_ of that pixel has coordinates (0.5,0.5),
and the upper-right corner of the same pixel is at (1.5,1.5).
The first coordinate ("x") is the column number; the second ("y") is the row number.

To allow one to use Imfit configuration files with PyImfit, PyImfit adopts the same column-major, 1-based
indexing standard. The most obvious way this shows up is in the X0,Y0 coordinates
for the centers of function sets.

Python (and in particular NumPy), on the other hand, is 0-based and row-major. This means that the
first pixel in the image is at (0,0); it also means that the first index is the _row_ number.

To translate coordinate systems, remember that a pixel with Imfit/PyImfit coordinates x,y
would be found in a NumPy array at `array[y0 - 1,x0 - 1]`.


### Specifying Image Subsets for Fitting

The command-line version of Imfit allows you to specify image subsets for fitting
using a pixel-indexing convention similar to that of IRAF, which is 1-based and
inclusive of the limits -- i.e., you can fit a subset of the FITS file `data_image.fits`
using `data_image.fits[100:200,1203:1442]`, which will extract
and work on columns 100 through 200 and rows 1203 through 1442 of the image.

In a Python session (or script file or Jupyter notebook) you would instead simply apply the
image-subset specification via indexing of NumPy arrays,
in which case you would necessarily be using Python indexing. So the previous
example would be done using (assuming you've read the `data_image.fits` file into
a NumPy variable named `data_image`) `data_image[1202:1442,99:200]`, since NumPy
arrays are row-major (y-values listed first) and use 0-based indexing, with the
upper index _excluded_.
46 changes: 46 additions & 0 deletions docs/pixel_conventions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Pixel Coordinate Conventions
============================

Image Coordinates
~~~~~~~~~~~~~~~~~

Imfit was written to follow the standard 2D array indexing conventions
of FITS, IRAF, and (e.g.) SAOimage DS9, which are 1-based and
column-major. This means that the center of the first pixel (in the
lower-left of the image) has coordinates (x,y) = (1.0,1.0); the
lower-left *corner* of that pixel has coordinates (0.5,0.5), and the
upper-right corner of the same pixel is at (1.5,1.5). The first
coordinate (“x”) is the column number; the second (“y”) is the row
number.

To allow one to use Imfit configuration files with PyImfit, PyImfit
adopts the same column-major, 1-based indexing standard. The most
obvious way this shows up is in the X0,Y0 coordinates for the centers of
function sets.

Python (and in particular NumPy), on the other hand, is 0-based and
row-major. This means that the first pixel in the image is at (0,0); it
also means that the first index is the *row* number.

To translate coordinate systems, remember that a pixel with
Imfit/PyImfit coordinates x,y would be found in a NumPy array at
``array[y0 - 1,x0 - 1]``.

Specifying Image Subsets for Fitting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The command-line version of Imfit allows you to specify image subsets
for fitting using a pixel-indexing convention similar to that of IRAF,
which is 1-based and inclusive of the limits – i.e., you can fit a
subset of the FITS file ``data_image.fits`` using
``data_image.fits[100:200,1203:1442]``, which will extract and work on
columns 100 through 200 and rows 1203 through 1442 of the image.

In a Python session (or script file or Jupyter notebook) you would
instead simply apply the image-subset specification via indexing of
NumPy arrays, in which case you would necessarily be using Python
indexing. So the previous example would be done using (assuming you’ve
read the ``data_image.fits`` file into a NumPy variable named
``data_image``) ``data_image[1202:1442,99:200]``, since NumPy arrays are
row-major (y-values listed first) and use 0-based indexing, with the
upper index *excluded*.

0 comments on commit 2ee9f66

Please sign in to comment.