Skip to content

Commit

Permalink
Merge branch 'develop' into nrs-ta-bokeh-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
mfixstsci authored Jul 22, 2024
2 parents 5c055fc + b93667f commit 94f05b7
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 15 deletions.
41 changes: 34 additions & 7 deletions jwql/jwql_monitors/generate_preview_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ def define_options(parser=None, usage=None, conflict_handler='resolve'):
parser = argparse.ArgumentParser(usage=usage, conflict_handler=conflict_handler)

parser.add_argument('--overwrite', action='store_true', default=None, help='If set, existing preview images will be re-created and overwritten.')
parser.add_argument('-p', '--programs', nargs='+', type=int, help='List of program IDs to generate preview images for. If omitted, all programs will be done.')
return parser


Expand Down Expand Up @@ -540,20 +541,46 @@ def get_base_output_name(filename_dict):

@log_fail
@log_info
def generate_preview_images(overwrite):
def generate_preview_images(overwrite, programs=None):
"""The main function of the ``generate_preview_image`` module.
See module docstring for further details.
Parameters
----------
overwrite : bool
If True, any existing preview images and thumbnails are overwritten
programs : list
List of program ID numbers (e.g. 1068, 01220) for which to generate preview
images. If None (the default), preview images are generated for all programs.
"""
# Get a list of programs to create preview images for. First, generate a list of all
# possible programs. We can compare any user inputs to this list, and if there are no
# user inputs, then use this entire list.
all_programs = [os.path.basename(item) for item in glob.glob(os.path.join(SETTINGS['filesystem'], 'public', 'jw*'))]
all_programs.extend([os.path.basename(item) for item in glob.glob(os.path.join(SETTINGS['filesystem'], 'proprietary', 'jw*'))])

if programs is None:
program_list = all_programs
else:
if not isinstance(programs, list):
raise ValueError(f'program_list must be a list. In this call, it is {type(program_list)}')
program_list = []
for prog in programs:
jwprog = f'jw{str(prog).zfill(5)}'
if jwprog in all_programs:
program_list.append(jwprog)
else:
logging.info(f'Program {prog} not present in filesystem. Excluding.')

if len(program_list) > 0:
program_list = sorted(program_list, reverse=True)
else:
no_prog_message = f'Empty list of programs. No preview images to be made.'
logging.info(no_prog_message)
raise ValueError(no_prog_message)

# Process programs in parallel
program_list = [os.path.basename(item) for item in glob.glob(os.path.join(SETTINGS['filesystem'], 'public', 'jw*'))]
program_list.extend([os.path.basename(item) for item in glob.glob(os.path.join(SETTINGS['filesystem'], 'proprietary', 'jw*'))])
program_list = list(set(program_list))
pool = multiprocessing.Pool(processes=int(SETTINGS['cores']))
program_list = [(element, overwrite) for element in program_list]
results = pool.starmap(process_program, program_list)
Expand Down Expand Up @@ -819,7 +846,7 @@ def update_listfile(filename, file_list, filetype):


@lock_module
def protected_code(overwrite):
def protected_code(overwrite, programs):
"""Protected code ensures only 1 instance of module will run at any given time
Parameters
Expand All @@ -830,11 +857,11 @@ def protected_code(overwrite):
module = os.path.basename(__file__).strip('.py')
start_time, log_file = initialize_instrument_monitor(module)

generate_preview_images(overwrite)
generate_preview_images(overwrite, programs=programs)
update_monitor_table(module, start_time, log_file)


if __name__ == '__main__':
parser = define_options()
args = parser.parse_args()
protected_code(args.overwrite)
protected_code(args.overwrite, args.programs)
48 changes: 43 additions & 5 deletions jwql/utils/preview_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,16 +490,54 @@ def make_figure(self, image, integration_number, min_value, max_value,
dig = 2
format_string = "%.{}f".format(dig)
tlabelstr = [format_string % number for number in tlabelflt]
cbar = self.fig.colorbar(cax, ticks=tickvals)

# This seems to correctly remove the ticks and labels we want to remove. It gives a warning that
# it doesn't work on log scales, which we don't care about. So let's ignore that warning.
warnings.filterwarnings("ignore", message="AutoMinorLocator does not work with logarithmic scale")
cbar.ax.yaxis.set_minor_locator(AutoMinorLocator(n=0))

cbar.ax.set_yticklabels(tlabelstr)
cbar.ax.tick_params(labelsize=maxsize * 5. / 4)
cbar.ax.set_ylabel(self.units, labelpad=10, rotation=270)
xyratio = xsize / ysize
if xyratio < 1.6:
# For apertures that are taller than they are wide, square, or that are wider than
# they are tall but still reasonably close to square, put the colorbar on the right
# side of the image.

# Some magic numbers arrived at through testing aspect ratios for all apertures
if xyratio > 0.4:
cb_width = 0.05
else:
cb_width = 0.05 * 0.4 / xyratio

upper_x_anchor = 0.02
if xyratio < 0.1:
upper_x_anchor = 0.12

cbax = self.fig.add_axes([ax.get_position().x1 + upper_x_anchor,
ax.get_position().y0,
cb_width,
ax.get_position().height
])
cbar = self.fig.colorbar(cax, cax=cbax, ticks=tickvals, orientation='vertical')
cbar.ax.yaxis.set_minor_locator(AutoMinorLocator(n=0))
cbar.ax.set_yticklabels(tlabelstr)
cbar.ax.set_ylabel(self.units, labelpad=7, rotation=270)
else:
# For apertures that are significantly wider than they are tall, put the colorbar
# under the image.

# Again, some magic numbers controlling the positioning and height of the
# colorbar, based on testing.
lower_y_anchor = 0. - (xyratio / 14.5)
cb_height = 0.07 * (np.log2(xyratio) - 1)

cbax = self.fig.add_axes([ax.get_position().x0,
ax.get_position().y0 + lower_y_anchor,
ax.get_position().width,
cb_height])
cbar = self.fig.colorbar(cax, cax=cbax, ticks=tickvals, orientation='horizontal')
cbar.ax.xaxis.set_minor_locator(AutoMinorLocator(n=0))
cbar.ax.set_xticklabels(tlabelstr)
cbar.ax.set_xlabel(self.units, labelpad=7, rotation=0)

ax.set_xlabel('Pixels', fontsize=maxsize * 5. / 4)
ax.set_ylabel('Pixels', fontsize=maxsize * 5. / 4)
ax.tick_params(labelsize=maxsize)
Expand Down
5 changes: 5 additions & 0 deletions jwql/website/apps/jwql/static/css/jwql.css
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,11 @@
display: inline-block;
}

.image_views {
margin-left: 2%;
margin-right: 2%;
}

#loading {
text-align:center;
margin: 0 auto;
Expand Down
2 changes: 1 addition & 1 deletion jwql/website/apps/jwql/templates/view_exposure.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

{% block content %}

<main role="main" class="container">
<main role="main" class="image_views">
<!-- Show exposure group name -->
<h3>Exposure {{ group_root }}</h3>

Expand Down
4 changes: 2 additions & 2 deletions jwql/website/apps/jwql/templates/view_image.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

{% block content %}

<main role="main" class="container">
<main role="main" class="image_views">
<!-- Show image group name -->
<h3>{{ file_root }}</h3>

Expand Down Expand Up @@ -85,7 +85,7 @@ <h3>{{ file_root }}</h3>
<span class="image_preview">
<img class="image_preview_viewer" id="image_viewer"
onerror="image_error(this, true);"
title="Preview image for {{ file_root }}">
title="Preview image for {{ file_root }}" width=1000rem height=auto>
</span>

<div class="int_changer">
Expand Down

0 comments on commit 94f05b7

Please sign in to comment.