diff --git a/cal_tools/cal_tools/plotting.py b/cal_tools/cal_tools/plotting.py index 2eda7286b05cc55c192b2ee6339bcd5de526f28d..2134f80d08897757d8f18b2e060a8a35091daa71 100644 --- a/cal_tools/cal_tools/plotting.py +++ b/cal_tools/cal_tools/plotting.py @@ -1,11 +1,15 @@ +from pathlib import Path from typing import Any, Dict, Optional -from extra_geom import AGIPD_500K2GGeometry import matplotlib.pyplot as plt +import numpy as np from matplotlib import colors -from matplotlib.patches import Patch, Rectangle +from matplotlib.patches import Patch from mpl_toolkits.axes_grid1 import AxesGrid -import numpy as np + +from extra_geom import (AGIPD_1MGeometry, AGIPD_500K2GGeometry, + DSSC_1MGeometry, LPD_1MGeometry) +from extra_geom import tests as eg_tests def show_overview(d, cell_to_preview, gain_to_preview, out_folder=None, infix=None): @@ -215,258 +219,95 @@ def show_processed_modules(dinstance: str, constants: Optional[Dict[str, Any]], "processed": To show the modules successfully processed. :return """ - fig, ax = plt.subplots(1, figsize=(10, 10)) - ax.set_axis_off() - counter = 0 # Used as index within the `Noise` matrix, found in constants - if dinstance in ('AGIPD1M1', 'AGIPD1M2'): + # Create the geometry figure for each detector - ax.set_xlim(0, 90) - ax.set_ylim(0, 75) - asic_pos = 5 - q_st = 8 - # quad_pos = [Q1[x, y], Q2[x, y], Q3[x, y], Q4[x, y]] - quad_pos = [[43, 66], [45, 34], [4, 32], [2, 64]] - l_y = 6 - l_x = 5 - for iq, q_x in enumerate(quad_pos): - for im in range(4): - if mode == "processed": - color = 'gray' - ecolor = 'darkgreen' - if f'Q{iq+1}M{im+1}' in mnames: - color = 'green' - if 'Noise' not in constants.keys() or \ - np.nanmean(constants['Noise'][counter, :, :, :, 0]) == 0: # noqa - color = 'red' - counter += 1 - else: - color = 'lightblue' - ecolor = 'c' - x = q_x[0] - for _ in range(8): - # adding modules patches - ax.add_patch(Rectangle((x, q_x[1] - q_st * im), 5, 6, - linewidth=2, edgecolor=ecolor, - facecolor=color, fill=True)) - if mode == "position": - if f"Q{iq+1}M{im+1}" in mnames: - ax.add_patch( - Rectangle((x, q_x[1] - q_st * im), - l_x, l_y / 2, linewidth=2, - edgecolor='c', - facecolor='sandybrown', - fill=True)) - ax.add_patch( - Rectangle((x, (q_x[1] - q_st * im + 3)), - l_x, l_y / 2, linewidth=2, - edgecolor='c', - facecolor='sandybrown', - fill=True)) - x += asic_pos - if mode == "position": - if f"Q{iq+1}M{im+1}" in mnames: - # Change Text for current processed module. - ax.text(q_x[0] + 13, q_x[1] - q_st * im + 1.5, - f'Q{iq+1}M{im+1}', fontsize=28, - color='mediumblue', weight='bold') - else: - ax.text(q_x[0] + 14, q_x[1] - q_st * im + 1.5, - f'Q{iq+1}M{im+1}', fontsize=25, color='k') - elif mode == "processed": - ax.text(q_x[0] + 14.5, q_x[1] - q_st * im + 1.5, - f'Q{iq+1}M{im+1}', fontsize=24, color='gold') + if dinstance in ('AGIPD1M1', 'AGIPD1M2'): + quadrants = 4 + modules = 4 + tiles = 8 + quad_pos = [(-525, 625), (-550, -10), (520, -160), (542.5, 475)] + geom = AGIPD_1MGeometry.from_quad_positions(quad_pos) elif dinstance == 'AGIPD500K': - # Create a dict that contains the range of tiles, in the figure, - # that belong to a module. - ranges = dict() - count = 0 - for quadrant in range(1, 3): - for module in range(1, 5): - ranges[f'Q{quadrant}M{module}'] = [count, count + 8] - count += 8 - + quadrants = 2 + modules = 4 + tiles = 8 geom = AGIPD_500K2GGeometry.from_origin() - ax = geom.inspect() - ax.set_title('') # Cannot remove title - ax.set_axis_off() - ax.get_legend().set_visible(False) - ax.figure.set_dpi(100) + elif 'LPD' in dinstance: + quadrants = 4 + modules = 4 + tiles = 16 + quad_pos = [(11.4, 299), (-11.5, 8), (254.5, -16), (278.5, 275)] + geom = LPD_1MGeometry.from_quad_positions(quad_pos) - # Remove non-tiles markings from figure - tiles, = ax.collections = ax.collections[:1] + elif 'DSSC' in dinstance: + quadrants = 4 + modules = 4 + tiles = 2 + quad_pos = [(-130, 5), (-130, -125), (5, -125), (5, 5)] + + geom = DSSC_1MGeometry.from_h5_file_and_quad_positions( + Path(eg_tests.__file__).parent / 'dssc_geo_june19.h5', + quad_pos) + + else: + raise ValueError(f'{dinstance} is not a real detector') + + # Create a dict that contains the range of tiles, in the figure, + # that belong to a module. + ranges = dict() + tile_count = 0 + for quadrant in range(1, quadrants+1): + for module in range(1, modules+1): + ranges[f'Q{quadrant}M{module}'] = [tile_count, tile_count + tiles] + tile_count += tiles + + # Create the figure + ax = geom.inspect() + ax.set_title('') # Cannot remove title + ax.set_axis_off() + ax.get_legend().set_visible(False) - # Set each tile colour individually - facecolors = tiles.get_facecolors().tolist() * 64 + # Remove non-tiles markings from figure + tiles, = ax.collections = ax.collections[:1] - # Set module name fonts - for text in ax.texts: - text.set_fontweight('regular') + # Set each tile colour individually, extra_geom provides a single color + # for all tiles. + facecolors = tiles.get_facecolor() * tile_count - texts = [t for t in ax.texts if t.get_text() in mnames] - for text in texts: - text.set_fontweight('extra bold') - text.set_fontsize(14) + # Set module name fonts + for text in ax.texts: + text.set_fontweight('regular') - if mode == 'position': # Highlight selected modules - for module in mnames: - start, stop = ranges[module] - for idx in range(start, stop): - facecolors[idx] = colors.to_rgba('pink') + texts = [t for t in ax.texts if t.get_text() in mnames] + for text in texts: + text.set_fontweight('extra bold') + text.set_fontsize(14) - if mode == 'processed': # Highlight processed modules - for module, (start, stop) in ranges.items(): - color = 'grey' # Unprocessed modules are grey + if mode == 'position': # Highlight selected modules + for module in mnames: + start, stop = ranges[module] + facecolors[start:stop] = colors.to_rgba('pink') - if module in mnames: - color = 'green' - if ('Noise' not in constants.keys() or - np.nanmean(constants['Noise'][counter, :, :, :, 0]) == 0): # noqa - color = 'red' - counter += 1 + else: # mode == 'processed': Highlight processed modules + counter = 0 # Used as index within the `Noise` matrix + for module, (start, stop) in ranges.items(): + color = 'grey' # Unprocessed modules are grey - for idx in range(start, stop): # Set the colours - facecolors[idx] = colors.to_rgba(color) + if module in mnames: + color = 'green' + if ('Noise' not in constants.keys() or + np.nanmean(constants['Noise'][counter, :, :, :, 0]) == 0): # noqa + color = 'red' + counter += 1 - tiles.set_facecolors(facecolors) # Update colours in figure + for idx in range(start, stop): # Set the colours + facecolors[idx] = colors.to_rgba(color) - elif 'LPD' in dinstance: + tiles.set_facecolors(facecolors) # Update colours in figure - ax.set_xlim(0, 97) - ax.set_ylim(0, 97) - q_poses = np.array([[51, 47], [47, 1], [1, 5], [5, 51]]) - m_poses = np.array([[22.5, 20.5], [22.5, 0.5], - [0.5, 0.5], [0.5, 20.5]]) - - for iq, q_pos in enumerate(q_poses): - ax.add_patch(Rectangle(q_pos, 45, 45, linewidth=2, - edgecolor='darkgreen', - facecolor='cornsilk', fill=True)) - ax.text(q_pos[0] + 20, q_pos[1] + 41.5, f'Q{iq+1}', fontsize=22) - - for im, m_pos in enumerate(m_poses): - if mode == "processed": - color = 'gray' - ecolor = 'darkgreen' - if f'Q{iq+1}M{im+1}' in mnames: - color = 'green' - if 'Noise' not in constants.keys() or \ - np.nanmean(constants['Noise'][counter, :, :, :, 0]) == 0: # noqa - color = 'red' - counter += 1 - pos = q_pos + m_pos + np.array([5, 8]) - ax.text(pos[0], pos[1], f'Q{iq+1}M{im+1}', - fontsize=24, color='gold') - elif mode == "position": - color = 'lightblue' - ecolor = 'c' - # adding modules patches - ax.add_patch(Rectangle(q_pos + m_pos, 22, 20, linewidth=3, - edgecolor=ecolor, facecolor=color, - fill=True)) - if mode == "position": - if f"Q{iq+1}M{im+1}" in mnames: - for a_posx in range(2): - for a_posy in range(8): - a_pos = np.array([a_posx*11., a_posy*20/8.]) - pos = q_pos + m_pos + a_pos - # Top Asics patches - ax.add_patch(Rectangle(q_pos+m_pos+a_pos, 11, - 20/8., linewidth=1, - edgecolor='k', - facecolor='sandybrown', - fill=True)) - if a_posx == 0: - label = str(a_posy + 9) - else: - label = str(-a_posy + (a_posx * 8)) - ax.text(pos[0] + 4, pos[1] + 0.3, label, - fontsize=14) - else: - pos = q_pos + m_pos + np.array([5, 8]) - ax.text(pos[0], pos[1], f'Q{iq+1}M{im+1}', - fontsize=22, color='k') - - if mode == "position": - ax.add_patch(Rectangle([65, 93], 30, 4, linewidth=1, - edgecolor='k', facecolor='sandybrown', - fill=True)) - ax.text(52, 94, 'ASICs:', fontsize=22, color='k') - - for i_pos in range(8): - pos = np.array([65, 93]) + np.array([i_pos*30/8.+0.3, 0.3]) # noqa - - ax.add_patch(Rectangle(pos, 24/8., 3.4, linewidth=1, - edgecolor='k', - facecolor='sandybrown', - fill=True)) - - ax.text(pos[0]+0.5, pos[1]+0.5, f'{i_pos+1}', - fontsize=18, color='k') - - elif 'DSSC' in dinstance: - ax.set_xlim(0, 85) - ax.set_ylim(0, 79) - asic_pos = 20 - q_st = 8 - - # quad_pos = [Q1[x, y], Q2[x, y], Q3[x, y], Q4[x, y]] - quad_pos = [[45, 64], [43, 24], [0, 28], [0, 66]] - mod_ind = [[4, 3, 2, 1], [4, 3, 2, 1], [1, 2, 3, 4], [1, 2, 3, 4]] - - for iq, q_x in enumerate(quad_pos): - for im in range(4): - if mode == "processed": - color = 'gray' - ecolor = 'darkgreen' - if f'Q{iq+1}M{mod_ind[iq][im]}' in mnames: - color = 'green' - if 'Noise' not in constants.keys() or \ - np.nanmean(constants['Noise'][counter, :, :, :]) == 0: # noqa - color = 'red' - counter += 1 - else: - color = 'lightblue' - ecolor = 'c' - x = q_x[0] - for _ in range(2): - # adding modules patches - ax.add_patch(Rectangle((x, q_x[1] - q_st * im), 19, 10, - linewidth=2, edgecolor=ecolor, - facecolor=color, fill=True)) - if mode == "position": - # Check if it is the processed module to highlight. - if f"Q{iq+1}M{mod_ind[iq][im]}" in mnames: - ax.add_patch(Rectangle((x, q_x[1] - q_st * im), - 19, 10, linewidth=2, - edgecolor='c', - facecolor="sandybrown", - fill=True)) - - ax.text(q_x[0] + 2, q_x[1] - q_st * im + 4.5, - 'T1 T2', fontsize=18, # noqa - color='grey') - x += asic_pos - if mode == "position": - # Check if it is the processed module to highlight. - if f'Q{iq+1}M{mod_ind[iq][im]}' in mnames: - # Change Text for current processed module. - ax.text(q_x[0] + 12.7, q_x[1] - q_st * im + 4.5, - f'Q{iq + 1} M{mod_ind[iq][im]}', fontsize=26, - color='mediumblue', weight='bold') - else: - ax.text(q_x[0] + 13.5, q_x[1] - q_st * im + 4.5, - f'Q{iq+1} M{mod_ind[iq][im]}', - fontsize=25, color='k') - elif mode == "processed": - ax.text(q_x[0] + 13.5, q_x[1] - q_st * im + 4.5, - f'Q{iq+1} M{mod_ind[iq][im]}', fontsize=24, - color='gold') - ax.text(q_x[0] + 2, q_x[1] - q_st * im + 4.5, - 'T1 T2', fontsize=18, - color='y') if mode == "processed": _ = ax.legend(handles=[Patch(facecolor='red', label='No data'), Patch(facecolor='gray', label='Not processed'), diff --git a/tests/test_cal_tools.py b/tests/test_cal_tools.py index 865eb90c46705d8cd858eb5530a999cbda2b24e7..803eba3b12f85f80bb3d1603f47c51c9959ea297 100644 --- a/tests/test_cal_tools.py +++ b/tests/test_cal_tools.py @@ -2,9 +2,19 @@ from datetime import datetime from pathlib import Path import pytest +from cal_tools.plotting import show_processed_modules from cal_tools.tools import get_dir_creation_date +def test_show_processed_modules(): + mnames = ['Q1M1'] + + with pytest.raises(ValueError) as err: + show_processed_modules('LDP', mnames=mnames, + constants={}, mode='processed') + assert 'LDP' in err.value() + + def test_dir_creation_date(): folder = '/gpfs/exfel/exp/DETLAB/202031/p900172/raw'