Search

Creating an image mask

Calibration cannot compensate for every defect in a CCD. Some examples (a non-exhaustive list):

  • Some hot pixels are not actually linear with exposure time.
  • Some pixels in the CCD may respond less to light than others in a way that flat frames cannot compensate for.
  • There may be defects in all or part of a row or column of the chip.
  • Cosmic rays strike the CCD during every exposure. While those are eliminated in the combined calibrated frames with the proper choice of combination parameters, they are not removed from science images.

The first three are discussed in this notebook. Removal of cosmic rays from science images is discussed in the cosmic ray notebook

from pathlib import Path

import numpy as np
import matplotlib.pyplot as plt

from astropy import units as u
from astropy.nddata import CCDData

import ccdproc as ccdp
from photutils import detect_sources
from astrowidgets import ImageWidget

from convenience_functions import show_image, image_snippet
# Use custom style for larger fonts and figures
plt.style.use('guide.mplstyle')

Detecting bad pixels with ccdmask

The ccdproc function ccdmask uses an method that is based on the IRAF task ccdmask. The method works best when the input image used to detect flaws in the CCD is the ratio of two flat frames with different counts. That may or may not be available depending on what images are collected.

In the example below, which uses images from Example 2 in the reduction notebooks, the two extreme exposure times are 1 sec and 1.2 sec, but the average counts in the images differ by 10,000. These were twilight flats taken just after sunset.

Even with dome flats where the illumination is supposed to be constant the counts may actually vary. If they do not, use a single flat for identifying bad pixels instead of a ratio.

We begin by creating an image collection and then the information for all of the calibrated, uncombined, flat images.

ex2_path = Path('example2-reduced')

ifc = ccdp.ImageFileCollection(ex2_path)

for long_values in ['history', 'comment']:
    try:
        ifc.summary.remove_column(long_values)
    except KeyError:
        # These two columns were not present, so removing them failed.
        # Just keep going.
        pass
flats = (ifc.summary['imagetyp'] == 'FLAT') & (ifc.summary['combined'] != True)
ifc.summary[flats]
Table masked=True length=10
filesimplebitpixnaxisnaxis1naxis2date-obsexptimeexposureset-tempccd-tempxpixszypixszxbinningybinningxorgsubfyorgsubfreadoutmfilterimagetypfocallenaptdiaaptareaswcreateswserialsitelatsitelongtelescopinstrumenotesflipstatswownerdatetime-obsuttimesysradecsyspurgedlatitudelongitudaltitudelstjd-obsmjd-obsbiassectrimsecbunittrim_imagetrimimsubtract_darksubdarkcstretchcblackcwhitepedestalbscalebzerosubtract_biassubbiascombinedhjd-obsbjd-obsazimuthhareadmodestlat-obslong-obsalt-obsobservatraobjctradecobjctdecfwhmzmag_quinoxepochpa_type1_rval1_rpix1_delt1_rota1_type2_rval2_rpix2_delt2_rota2_d1_1_d1_2_d2_1_d2_2tr1_0tr1_1tr1_2tr1_3tr1_4tr1_5tr1_6tr1_7tr1_8tr1_9tr1_10tr1_11tr1_12tr1_13tr1_14tr2_0tr2_1tr2_2tr2_3tr2_4tr2_5tr2_6tr2_7tr2_8tr2_9tr2_10tr2_11tr2_12tr2_13tr2_14pltsolvdairmassseczalt-objaz-objobjectcd1_1cd1_2cd2_1cd2_2a_0_0a_0_1a_1_0b_0_0b_0_1b_1_0_ateflat_correctflatcorwcsaxescrpix1crpix2pc1_1pc1_2pc2_1pc2_2cdelt1cdelt2cunit1cunit2ctype1ctype2crval1crval2lonpolelatpoleradesysequinoxa_ordera_0_2a_1_1a_2_0b_orderb_0_2b_1_1b_2_0ap_orderap_0_0ap_0_1ap_0_2ap_1_0ap_1_1ap_2_0bp_orderbp_0_0bp_0_1bp_0_2bp_1_0bp_1_1bp_2_0
str35boolint64int64int64int64objectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectstr9objectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobject
AutoFlat-PANoRot-r-Bin1-001.fitTrue-642409640962018-08-23T01:25:171.01.0-20.0-20.02250259.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:25:1701:25:17UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:04:39.25072458353.55922453758353.05922453704[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-002.fitTrue-642409640962018-08-23T01:25:431.01.0-20.0-20.0413620000000039.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:25:4301:25:43UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:05:05.32192458353.55952546358353.05952546297[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-003.fitTrue-642409640962018-08-23T01:26:081.01.0-20.0-20.0413620000000039.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:26:0801:26:08UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:05:30.39032458353.55981481558353.05981481481[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-004.fitTrue-642409640962018-08-23T01:26:341.01.0-20.0-20.069651259.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:26:3401:26:34UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:05:56.46152458353.56011574158353.06011574074[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-005.fitTrue-642409640962018-08-23T01:27:001.01.0-20.0-20.06022159.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:27:0001:27:00UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:06:22.53272458353.56041666758353.06041666667[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-006.fitTrue-642409640962018-08-23T01:27:251.021.02-20.0-20.0665080000000029.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:27:2501:27:25UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:06:47.60122458353.56070601858353.06070601852[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-007.fitTrue-642409640962018-08-23T01:27:511.061.06-20.0-20.0539350000000039.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:27:5101:27:51UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:07:13.67232458353.56100694558353.06100694444[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-008.fitTrue-642409640962018-08-23T01:28:171.111.11-20.0-20.0507917500000029.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:28:1701:28:17UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:07:39.74352458353.5613078758353.06130787037[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-009.fitTrue-642409640962018-08-23T01:28:421.161.16-20.0-20.02250259.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:28:4201:28:42UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:08:04.81202458353.56159722258353.06159722222[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AutoFlat-PANoRot-r-Bin1-010.fitTrue-642409640962018-08-23T01:29:081.211.21-20.0-20.0130727500000039.09.01100MonochromerFLAT3200.0400.0125663.70964050293MaxIm DL Version 6.18 190601 00KPP00KPP-F3HN8-9JMTJ-1CE5W-A4AX5-F3+46:52:00.408-96:27:11.8008AspenCG16Matt Craig23/08/1801:29:0801:29:08UTCFK5True+46:52:00.408-96:27:11.8008311.799999999566817:08:30.88322458353.56189814858353.06189814815[4096:4109][1:4096, :]adutrimimccd=<CCDData>subdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s, scale=True------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The best we can do here is the ratio of the first and last of the flat images listed above.

first = ifc.summary['file'][flats][0]
last = ifc.summary['file'][flats][-1]
ccd1 = CCDData.read(ex2_path / first)
ccd2 = CCDData.read(ex2_path / last)
WARNING: FITSFixedWarning: RADECSYS= 'FK5 ' / Equatorial coordinate system 
the RADECSYS keyword is deprecated, use RADESYSa. [astropy.wcs.wcs]
WARNING:astropy:FITSFixedWarning: RADECSYS= 'FK5 ' / Equatorial coordinate system 
the RADECSYS keyword is deprecated, use RADESYSa.
ratio = ccd2.divide(ccd1)

The ratio is roughly 0.85:

ratio.data.mean()
0.8424684815539478

Running ccdmask takes a little time but only needs to be done once, not once for each image.

%%time
maskr = ccdp.ccdmask(ratio)
CPU times: user 1min 27s, sys: 295 ms, total: 1min 27s
Wall time: 1min 27s

The result of ccdmask is one where there is a defect and zero where the chip is good, which matches the format of the mask numpy expects.

The input image and derived mask are shown below

fig, axes = plt.subplots(1, 2, figsize=(40, 20))

show_image(ratio, cmap='gray', fig=fig, ax=axes[0], show_colorbar=False)
axes[0].set_title('Ratio of two flats')

show_image(maskr, cmap='gray', fig=fig, ax=axes[1], show_colorbar=False)
axes[1].set_title('Derived mask')
WARNING: The following attributes were set on the data object, but will be ignored by the function: unit [astropy.nddata.decorators]
WARNING:astropy:The following attributes were set on the data object, but will be ignored by the function: unit
Text(0.5, 1.0, 'Derived mask')
/Users/mcraig/conda-main/envs/ccd-guide/lib/python3.6/site-packages/astropy/visualization/mpl_normalize.py:113: RuntimeWarning: invalid value encountered in true_divide
  np.true_divide(values, self.vmax - self.vmin, out=values)
/Users/mcraig/conda-main/envs/ccd-guide/lib/python3.6/site-packages/matplotlib/colors.py:479: RuntimeWarning: invalid value encountered in less
  xa[xa < 0] = -1

Two comments are in order:

  • The "starfish" pattern in the first image is an artifact of the camera shutter. Ideally, a longer exposure time would be used for the flats to avoid this.
  • It appear at first glance that there were no pixels masked. The problem is that the masked regions are very small and, at the scale shown, happen to not be visible.

Two defects in this CCD are shown below. The first is a small patch of pixels that are vastly less sensitive than the rest. The second is a column on the left edge of the CCD. It turns out this column is not actually exposed to light. ccdmask correctly identifies both patches as bad.

fig, axes = plt.subplots(2, 2, figsize=(10, 10))

width = 100
center = (3823, 2446)
plot_row = 0

image_snippet(ccd1, center, width=width, fig=fig, axis=axes[plot_row, 0])
axes[plot_row, 0].set_title('Flat, camera defect')

image_snippet(maskr, center, width=width, fig=fig, axis=axes[plot_row, 1], is_mask=True)
axes[plot_row, 1].set_title('Mask, same center')

center = (0, 2048)
plot_row = 1

image_snippet(ccd1, center, width=width, fig=fig, axis=axes[plot_row, 0], percu=99.9, percl=70)
axes[plot_row, 0].set_title('Flat, bad column')

image_snippet(maskr, center, width=width, fig=fig, axis=axes[plot_row, 1], is_mask=True)
axes[plot_row, 1].set_title('Mask, same center')
Text(0.5, 1.0, 'Mask, same center')

Saving the mask

Click here to comment on this section on GitHub (opens in new tab).

The mask can be saved in a FITS file as an image. We will see in the summary notebook on masking how to combine the mask generated here with a mask generated from the dark current and with a cosmic ray mask for each science image.

mask_as_ccd = CCDData(data=maskr.astype('uint8'), unit=u.dimensionless_unscaled)
mask_as_ccd.header['imagetyp'] = 'flat mask'
mask_as_ccd.write(ex2_path / 'mask_from_ccdmask.fits')

Making the mask with a single flat

The flats we used in Example 1, taken with the Large Format Camera at Palomar, are dome flats taken with nearly constant illumination. In that case the best we can do is run ccdmask on a single flat image. As we will see, this still allows the identification of several clearly bad areas of the chip.

First, a look at the calibratted, but not combined, flat images.

ex1_path = Path('example1-reduced')

ifc1 = ccdp.ImageFileCollection(ex1_path)

flats = (ifc1.summary['imagetyp'] == 'FLATFIELD') & (ifc1.summary['combined'] != True)
ifc1.summary[flats]
Table masked=True length=6
filesimplebitpixnaxisnaxis1naxis2dateoriginlatitudelongitudtelescopfratioinstrumedetectorframeccdpicnoobjectimagetypexptimedarktimedate-obsutjdradecequinoxepochhastairmassfiltergainsecpix1secpix2ccdbin1ccdbin2rotangledatasecccdsecbiassecloginfochipidsubtract_overscansuboscantrim_imagetrimimbunitsubtract_darksubdarkflat_correctflatcorcombined
str27boolint64int64int64int64str10str34float64float64str17float64str3str14int64int64str7str9float64float64str10str12float64str12str12float64float64str12str12float64str2float64float64float64int64int64float64str15str15str18str18int64str8str46str6str13str3objectobjectobjectobjectobject
flat-ccd.014.0.fitsTrue-642204841282016-01-16California Institute of Technology33.4-116.9Hale 5m Telescope7.5LFCSITe SI002 x 61414flat_gFLATFIELD70.00170.6732016-01-1604:17:28.002457403.67879604:08:58.5033:25:12.692000.02000.000:00:04.0004:10:04.461.0g'1.10.1820.182110.0[1:2048,1:4128][1:2048,1:4128][2049:2080,1:4127]Status=0x000000000suboscanccd=<CCDData>, overscan=<CCDData>, median=Truetrimimccd=<CCDData>adusubdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s------
flat-ccd.015.0.fitsTrue-642204841282016-01-16California Institute of Technology33.4-116.9Hale 5m Telescope7.5LFCSITe SI002 x 61515flat_gFLATFIELD70.01170.6832016-01-1604:20:35.002457403.68096104:12:05.1933:25:16.792000.02000.000:00:04.0004:13:11.981.0g'1.10.1820.182110.0[1:2048,1:4128][1:2048,1:4128][2049:2080,1:4127]Status=0x000000000suboscanccd=<CCDData>, overscan=<CCDData>, median=Truetrimimccd=<CCDData>adusubdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s------
flat-ccd.016.0.fitsTrue-642204841282016-01-16California Institute of Technology33.4-116.9Hale 5m Telescope7.5LFCSITe SI002 x 61616flat_gFLATFIELD70.00170.6842016-01-1604:23:41.002457403.68311304:15:12.0033:25:20.792000.02000.000:00:04.0004:16:18.491.0g'1.10.1820.182110.0[1:2048,1:4128][1:2048,1:4128][2049:2080,1:4127]Status=0x000000000suboscanccd=<CCDData>, overscan=<CCDData>, median=Truetrimimccd=<CCDData>adusubdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s------
flat-ccd.017.0.fitsTrue-642204841282016-01-16California Institute of Technology33.4-116.9Hale 5m Telescope7.5LFCSITe SI002 x 61717flat_iFLATFIELD7.07.6832016-01-1604:27:23.002457403.68568304:18:54.5833:25:25.702000.02000.000:00:04.0004:20:01.091.0i'1.10.1820.182110.0[1:2048,1:4128][1:2048,1:4128][2049:2080,1:4127]Status=0x000000000suboscanccd=<CCDData>, overscan=<CCDData>, median=Truetrimimccd=<CCDData>adusubdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s------
flat-ccd.018.0.fitsTrue-642204841282016-01-16California Institute of Technology33.4-116.9Hale 5m Telescope7.5LFCSITe SI002 x 61818flat_iFLATFIELD7.07.6722016-01-1604:29:26.002457403.68710604:20:58.1533:25:28.392000.02000.000:00:04.0004:22:04.431.0i'1.10.1820.182110.0[1:2048,1:4128][1:2048,1:4128][2049:2080,1:4127]Status=0x000000000suboscanccd=<CCDData>, overscan=<CCDData>, median=Truetrimimccd=<CCDData>adusubdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s------
flat-ccd.019.0.fitsTrue-642204841282016-01-16California Institute of Technology33.4-116.9Hale 5m Telescope7.5LFCSITe SI002 x 61919flat_iFLATFIELD7.07.6732016-01-1604:31:30.002457403.68854204:23:01.6533:25:31.202000.02000.000:00:04.0004:24:08.771.0i'1.10.1820.182110.0[1:2048,1:4128][1:2048,1:4128][2049:2080,1:4127]Status=0x000000000suboscanccd=<CCDData>, overscan=<CCDData>, median=Truetrimimccd=<CCDData>adusubdarkccd=<CCDData>, master=<CCDData>, exposure_time=exptime, exposure_unit=s------

We can double check that a ratio of flats will not be useful by calculating the mean counts in each flat image:

ccs = []

for c in ifc1.ccds(imagetyp='flatfield', filter="g'"):
    if 'combined' in c.header:
        continue
    print(c.data.mean())
    ccs.append(c)
19906.38951623411
19902.514437929316
19890.652615963663

The variation in counts is so small that the ratio of two flats will not be useful.

Instead, we run ccdmask on the first flat. There is nothing special about that one. The kind of defects that ccdmask tries to identify are in the CCD sensor itself and should be the same for all filters.

%%time
ccs1_mask = ccdp.ccdmask(ccs[0])
CPU times: user 43.8 s, sys: 199 ms, total: 44 s
Wall time: 44 s

Displaying the flat we used and the mask side-by-side demonstrates that the defects which are clear in the flat are picked up in the mask.

fig, axes = plt.subplots(1, 2, figsize=(15, 10))

show_image(ccs[0], cmap='gray', fig=fig, ax=axes[0])
axes[0].set_title('Single calibrated flat')

show_image(ccs1_mask, cmap='gray', fig=fig, ax=axes[1], is_mask=False)
axes[1].set_title('Derived mask');
WARNING: The following attributes were set on the data object, but will be ignored by the function: meta, unit [astropy.nddata.decorators]
WARNING:astropy:The following attributes were set on the data object, but will be ignored by the function: meta, unit

A couple of cutouts are shown below illustrating some of the individual defects identified.

fig, axes = plt.subplots(2, 2, figsize=(10, 10))

width = 300
center = (512, 3976)
plot_row = 0

image_snippet(ccs[0], center, width=width, fig=fig, axis=axes[plot_row, 0])
axes[plot_row, 0].set_title('Flat, partial bad column')

image_snippet(ccs1_mask, center, width=width, fig=fig, axis=axes[plot_row, 1], is_mask=True)
axes[plot_row, 1].set_title('Mask, same center')

center = (420, 3250)
width = 100
plot_row = 1

image_snippet(ccs[0], center, width=width, fig=fig, axis=axes[plot_row, 0])
axes[plot_row, 0].set_title('Flat, bad patch')

image_snippet(ccs1_mask, center, width=width, fig=fig, axis=axes[plot_row, 1], is_mask=True)
axes[plot_row, 1].set_title('Mask, same center')
Text(0.5, 1.0, 'Mask, same center')