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'