Repository: spacetelescope/jwql

Issue:
Creation of unnecessary thumbnails
The only thumbnails used by the web app are a single representative thumbnail, which is used on the Archive page, and the thumbnail for the SCI extension for each exposure, used on the program page. 

But our thumbnail generation code currently creates thumbnails for every filetype associated with each exposure (e.g. uncal, rate, cal). This is leading to the creation of lots of thumbnails that are never actually used. We should restrict the thumbnail generation code to create only one thumbnail for each exposure. I think using the rate file is probably the best choice, since some observations never go through later stages of the pipeline and will never have e.g. cal.fits versions made, or for modes like WFSS, the stage 2 output contains cutouts of each source. I *think* all files go through stage1 and produce rate files though.


Discussion:

Resolving patch:
diff --git a/jwql/jwql_monitors/generate_preview_images.py b/jwql/jwql_monitors/generate_preview_images.py
--- a/jwql/jwql_monitors/generate_preview_images.py
+++ b/jwql/jwql_monitors/generate_preview_images.py
@@ -660,6 +660,13 @@ def process_program(program):
     ----------
     program : str
         The program identifier (e.g. ``88600``)
+
+    Returns
+    -------
+    preview_image_files : list
+        List of preview image filenames
+    thumbnail_files : list
+        List of thumbnail image filenames
     """
 
     logging.info('')
@@ -679,6 +686,8 @@ def process_program(program):
     preview_image_files = []
     for filename in filenames:
 
+        logging.info(f'Working on {filename}')
+
         # Determine the save location
         try:
             identifier = 'jw{}'.format(filename_parser(filename)['program_id'])
@@ -712,10 +721,19 @@ def process_program(program):
             im.output_format = 'jpg'
             im.preview_output_directory = preview_output_directory
             im.thumbnail_output_directory = thumbnail_output_directory
-            im.make_image(max_img_size=8)
-            thumbnail_files.extend(im.thumbnail_images)
+
+            # Create a thumbnail for rate or dark files only. Create preview
+            # images for all filetypes
+            if 'rate.fits' in filename or 'dark.fits' in filename:
+                im.make_image(max_img_size=8, create_thumbnail=True)
+                thumbnail_files.extend(im.thumbnail_images)
+                logging.info('\tCreated preview image and thumbnail for: {}'.format(filename))
+            else:
+                im.make_image(max_img_size=8, create_thumbnail=False)
+                logging.info('\tCreated preview image for: {}'.format(filename))
+
             preview_image_files.extend(im.preview_images)
-            logging.info('\tCreated preview image and thumbnail for: {}'.format(filename))
+
         except (ValueError, AttributeError) as error:
             logging.warning(error)
 
diff --git a/jwql/utils/preview_image.py b/jwql/utils/preview_image.py
--- a/jwql/utils/preview_image.py
+++ b/jwql/utils/preview_image.py
@@ -368,8 +368,17 @@ def make_figure(self, image, integration_number, min_value, max_value,
             filename = os.path.split(self.file)[-1]
             ax.set_title(filename + ' Int: {}'.format(np.int(integration_number)))
 
-    def make_image(self, max_img_size=8.0):
-        """The main function of the ``PreviewImage`` class."""
+    def make_image(self, max_img_size=8.0, create_thumbnail=False):
+        """The main function of the ``PreviewImage`` class.
+
+        Parameters
+        ----------
+        max_img_size : float
+            Image size in the largest dimension
+
+        create_thumbnail : bool
+            If True, a thumbnail image is created and saved.
+        """
 
         shape = self.data.shape
 
@@ -419,7 +428,7 @@ def make_image(self, max_img_size=8.0):
 
             # Create thumbnail image matplotlib object, only for the
             # first integration
-            if i == 0:
+            if i == 0 and create_thumbnail:
                 if self.thumbnail_output_directory is None:
                     outdir = indir
                 else:
@@ -429,7 +438,7 @@ def make_image(self, max_img_size=8.0):
                                  maxsize=max_img_size, thumbnail=True)
                 self.save_image(outfile, thumbnail=True)
                 plt.close()
-                self.thumbnail_images.append(outfile)
+                self.thumbnail_images.append(self.thumbnail_filename)
 
     def save_image(self, fname, thumbnail=False):
         """
@@ -454,8 +463,9 @@ def save_image(self, fname, thumbnail=False):
 
         # If the image is a thumbnail, rename to '.thumb'
         if thumbnail:
-            thumb_fname = fname.replace('.jpg', '.thumb')
-            os.rename(fname, thumb_fname)
-            logging.info('\tSaved image to {}'.format(thumb_fname))
+            self.thumbnail_filename = fname.replace('.jpg', '.thumb')
+            os.rename(fname, self.thumbnail_filename)
+            logging.info('\tSaved image to {}'.format(self.thumbnail_filename))
         else:
             logging.info('\tSaved image to {}'.format(fname))
+            self.thumbnail_filename = None
diff --git a/jwql/website/apps/jwql/data_containers.py b/jwql/website/apps/jwql/data_containers.py
--- a/jwql/website/apps/jwql/data_containers.py
+++ b/jwql/website/apps/jwql/data_containers.py
@@ -1479,7 +1479,24 @@ def thumbnails_ajax(inst, proposal, obs_num=None):
         data_dict['file_data'][rootname] = {}
         data_dict['file_data'][rootname]['filename_dict'] = filename_dict
         data_dict['file_data'][rootname]['available_files'] = available_files
-        data_dict['file_data'][rootname]['suffixes'] = [filename_parser(filename)['suffix'] for filename in available_files]
+
+        # We generate thumbnails only for rate and dark files. Check if these files
+        # exist in the thumbnail filesystem. In the case where neither rate nor
+        # dark thumbnails are present, revert to 'none', which will then cause the
+        # "thumbnail not available" fallback image to be used.
+        available_thumbnails = get_thumbnails_by_rootname(rootname)
+
+        if len(available_thumbnails) > 0:
+            preferred = [thumb for thumb in available_thumbnails if 'rate' in thumb]
+            if len(preferred) == 0:
+                preferred = [thumb for thumb in available_thumbnails if 'dark' in thumb]
+            if len(preferred) > 0:
+                data_dict['file_data'][rootname]['thumbnail'] = os.path.basename(preferred[0])
+            else:
+                data_dict['file_data'][rootname]['thumbnail'] = 'none'
+        else:
+            data_dict['file_data'][rootname]['thumbnail'] = 'none'
+
         try:
             data_dict['file_data'][rootname]['expstart'] = exp_start
             data_dict['file_data'][rootname]['expstart_iso'] = Time(exp_start, format='mjd').iso.split('.')[0]


Test patch: