diff --git a/pes_to_spec/bnn.py b/pes_to_spec/bnn.py
index 887512e093e555bb65bef8442585eb0c84801146..32461c28a8c9313fe8adea470240d397f12e5627 100644
--- a/pes_to_spec/bnn.py
+++ b/pes_to_spec/bnn.py
@@ -222,7 +222,7 @@ class BNNModel(RegressorMixin, BaseEstimator):
 
         # train
         self.model.train()
-        epochs = 500
+        epochs = 1000
         for epoch in range(epochs):
             meter = {k: AverageMeter(k, ':6.3f')
                     for k in ('loss', '-log(lkl)', '-log(prior)', '-log(hyper)', 'sigma', 'w.prec.')}
diff --git a/pes_to_spec/test/offline_analysis.py b/pes_to_spec/test/offline_analysis.py
index a9ba79450dffcacbcc0b93b19eec85337c741174..871670e92e0c8b13091b1fa6cbf5128656a592d2 100755
--- a/pes_to_spec/test/offline_analysis.py
+++ b/pes_to_spec/test/offline_analysis.py
@@ -11,6 +11,10 @@ import numpy as np
 from extra_data import open_run, by_id, RunDirectory
 from pes_to_spec.model import Model, matching_ids
 
+# for helper plots
+from pes_to_spec.model import SelectRelevantLowResolution
+from sklearn.decomposition import PCA
+
 from itertools import product
 
 import matplotlib
@@ -71,11 +75,46 @@ def plot_pes(filename: str, pes_raw_int: np.ndarray, first: int, last: int):
     fig = plt.figure(figsize=(16, 8))
     gs = GridSpec(1, 1)
     ax = fig.add_subplot(gs[0, 0])
-    ax.plot(np.arange(first, last), pes_raw_int, c='b', lw=3, label="Low-resolution measurement")
-    ax.legend()
+    ax.plot(np.arange(first, last), pes_raw_int, c='b', lw=3)
+    #ax.legend()
     ax.set(title=f"",
-           xlabel="ToF index",
-           ylabel="Intensity")
+           xlabel="Time-of-flight index",
+           ylabel="Counts [a.u.]")
+    ax.spines['top'].set_visible(False)
+    ax.spines['right'].set_visible(False)
+    fig.savefig(filename)
+    plt.close(fig)
+
+def pca_variance_plot(filename: str, variance_ratio: np.ndarray, n_comp: int):
+    """
+    Plot variance contribution.
+
+    Args:
+      filename: Output file name.
+      variance_ratio: Contribution of each component's variance.
+
+    """
+    fig = plt.figure(figsize=(8, 8))
+    gs = GridSpec(1, 1)
+    ax = fig.add_subplot(gs[0, 0])
+    c = np.cumsum(variance_ratio)
+    ax.bar(1+np.arange(len(variance_ratio)), variance_ratio*100, color='tab:red', alpha=0.3, label="Per component")
+    ax.plot(1+np.arange(len(variance_ratio)), c*100, c='tab:blue', lw=5, label="Cumulative")
+    ax.plot([n_comp, n_comp], [0, c[n_comp]*100], lw=3, ls='--', c='m', label="Components kept")
+    ax.plot([0, n_comp], [c[n_comp]*100, c[n_comp]*100], lw=3, ls='--', c='m')
+    ax.legend(frameon=False)
+    print(f"PCA plot: total n. components: {len(variance_ratio)}")
+    x_max = np.where(c > 0.99)[0][0]
+    print(f"Fraction of variance: {c[n_comp]}")
+    ax.set_yscale('log')
+    ax.set(title=f"",
+           xlabel="Component",
+           ylabel="Variance [%]",
+           xlim=(1, x_max),
+           ylim=(0.1, 100))
+    ax.spines['top'].set_visible(False)
+    ax.spines['right'].set_visible(False)
+    plt.tight_layout()
     fig.savefig(filename)
     plt.close(fig)
 
@@ -113,11 +152,12 @@ def plot_result(filename: str,
                            unc=unc,
                            beam_intensity=intensity*1e-3*np.ones_like(spec_raw_pe)
                            ))
-    df.to_csv(filename.replace('.png', '.csv'))
-    pes_data = deepcopy(pes)
-    pes_data['bin'] = np.arange(len(pes['channel_1_D']))
-    df = pd.DataFrame(pes_data)
-    df.to_csv(filename.replace('.png', '_pes.csv'))
+    df.to_csv(filename.replace('.pdf', '.csv'))
+    if pes is not None:
+        pes_data = deepcopy(pes)
+        pes_data['bin'] = np.arange(len(pes['channel_1_D']))
+        df = pd.DataFrame(pes_data)
+        df.to_csv(filename.replace('.pdf', '_pes.csv'))
 
     fig = plt.figure(figsize=(12, 8))
     gs = GridSpec(1, 1)
@@ -140,9 +180,9 @@ def plot_result(filename: str,
     ax.spines['right'].set_visible(False)
     ax.set(
            xlabel="Photon energy [eV]",
-           ylabel="Intensity",
+           ylabel="Intensity [a.u.]",
            ylim=(0, 1.3*Y))
-    if pes is not None:
+    if (pes is not None) and (pes_to_show != ""):
         ax2 = plt.axes([0,0,1,1])
         # Manually set the position and relative size of the inset axes within ax1
         #ip = InsetPosition(ax, [0.65,0.6,0.35,0.4])
@@ -180,7 +220,7 @@ def main():
     parser.add_argument('-t', '--test-run', type=int, metavar='INT', help='Run to test', default=None)
     parser.add_argument('-m', '--model', type=str, metavar='FILENAME', default="", help='Model to load. If given, do not train a model and just do inference with this one.')
     parser.add_argument('-d', '--directory', type=str, metavar='DIRECTORY', default=".", help='Where to save the results.')
-    parser.add_argument('-S', '--spec', type=str, metavar='NAME', default="SA3_XTD10_SPECT/MDL/SPECTROMETER_SQS_NAVITAR:output", help='SPEC name')
+    parser.add_argument('-S', '--spec', type=str, metavar='NAME', default="SA3_XTD10_SPECT/MDL/SPECTROMETER_SCS_NAVITAR:output", help='SPEC name')
     parser.add_argument('-P', '--pes', type=str, metavar='NAME', default="SA3_XTD10_PES/ADC/1:network", help='PES name')
     parser.add_argument('-X', '--xgm', type=str, metavar='NAME', default="SA3_XTD10_XGM/XGM/DOOCS:output", help='XGM name')
     parser.add_argument('-o', '--offset', type=int, metavar='INT', default=0, help='Train ID offset')
@@ -253,8 +293,10 @@ def main():
     print(f"Number of test IDs: {len(test_tids)}")
 
     # read the PES data for each channel
+    #channels = [f"channel_{i}_{l}"
+    #            for i, l in product(range(1, 5), ["A", "B", "C", "D"])]
     channels = [f"channel_{i}_{l}"
-                for i, l in product(range(1, 5), ["A", "B", "C", "D"])]
+                for i, l in product([1,3,4], ["A", "B", "C", "D"])]
     pes_raw = {ch: run[pes_name, f"digitizers.{ch}.raw.samples"].select_trains(by_id[tids]).ndarray()
                for ch in channels}
     pes_raw_t = {ch: run_test[pes_name, f"digitizers.{ch}.raw.samples"].select_trains(by_id[test_tids]).ndarray()
@@ -296,14 +338,42 @@ def main():
     t = list()
     t_names = list()
 
-    model = Model(model_type=args.model_type)
+    model = Model(channels=channels, model_type=args.model_type)
 
     train_idx = np.isin(tids, train_tids) & (xgm_flux[:,0] > args.xgm_cut)
     # we just need this for training and we need to avoid copying it, which blows up the memoray usage
     for k in pes_raw.keys():
         pes_raw[k] = pes_raw[k][train_idx]
 
-    model.debug_peak_finding(pes_raw, os.path.join(args.directory, "test_peak_finding.png"))
+    # apply only PES selection for plotting
+    x_select = SelectRelevantLowResolution(channels, tof_start=None, delta_tof=300, poly=True)
+    x_select.fit(pes_raw)
+    pes_raw_select = x_select.transform(pes_raw, pulse_energy=xgm_flux[train_idx])
+    ch = channels[0]
+    idx = 0
+    first = x_select.tof_start - x_select.delta_tof
+    last = x_select.tof_start + x_select.delta_tof
+    plot_pes(os.path.join(args.directory, f"pes_example_{ch}.pdf"),
+             -pes_raw[ch][idx, first:last],
+             first=first,
+             last=last)
+
+    # apply PCA for plotting
+    B, P, _ = pes_raw_select.shape
+    pes_raw_select = pes_raw_select.reshape((B*P, -1))
+    pca = PCA(None, whiten=True)
+    pca.fit(pes_raw_select)
+    pca_variance_plot(os.path.join(args.directory, f"pca_pes.pdf"),
+                      pca.explained_variance_ratio_,
+                      600)
+
+    pca_spec = PCA(None, whiten=True)
+    pca_spec.fit(spec_raw_int[train_idx])
+    pca_variance_plot(os.path.join(args.directory, f"pca_spec.pdf"),
+                      pca_spec.explained_variance_ratio_,
+                      20)
+
+    model.debug_peak_finding(pes_raw, os.path.join(args.directory, "test_peak_finding.pdf"))
     if len(args.model) == 0:
         print("Fitting")
         start = time_ns()
@@ -344,7 +414,7 @@ def main():
            ylabel="Response [a.u.]",
            yscale='log',
            )
-    fig.savefig(os.path.join(args.directory, "impulse.png"))
+    fig.savefig(os.path.join(args.directory, "impulse.pdf"))
     plt.close(fig)
     print(f"Resolution: {model.resolution:.2f} eV")
 
@@ -358,7 +428,7 @@ def main():
            ylabel="Filter intensity [a.u.]",
            yscale='log',
            )
-    fig.savefig(os.path.join(args.directory, "wiener_ft.png"))
+    fig.savefig(os.path.join(args.directory, "wiener_ft.pdf"))
     plt.close(fig)
 
     fig = plt.figure(figsize=(12, 8))
@@ -370,7 +440,7 @@ def main():
            ylabel="Filter value [a.u.]",
            yscale='log',
            )
-    fig.savefig(os.path.join(args.directory, "wiener.png"))
+    fig.savefig(os.path.join(args.directory, "wiener.pdf"))
     plt.close(fig)
 
     print("Check consistency")
@@ -434,7 +504,7 @@ def main():
         ax2.xaxis.label.set_size(SMALL_SIZE)
         ax2.yaxis.label.set_size(SMALL_SIZE)
         ax2.tick_params(axis='both', which='major', labelsize=SMALL_SIZE)
-        fig.savefig(os.path.join(args.directory, "intensity_vs_chi2.png"))
+        fig.savefig(os.path.join(args.directory, "intensity_vs_chi2.pdf"))
         plt.close(fig)
 
         fig = plt.figure(figsize=(12, 8))
@@ -454,7 +524,7 @@ def main():
         #        verticalalignment='top', horizontalalignment='right',
         #        transform=ax.transAxes,
         #        color='black', fontsize=15)
-        fig.savefig(os.path.join(args.directory, "chi2.png"))
+        fig.savefig(os.path.join(args.directory, "chi2.pdf"))
         plt.close(fig)
 
         spec_smooth_pca = model.y_model['pca'].transform(spec_smooth)
@@ -478,7 +548,7 @@ def main():
         #        verticalalignment='top', horizontalalignment='right',
         #        transform=ax.transAxes,
         #        color='black', fontsize=15)
-        fig.savefig(os.path.join(args.directory, "chi2_prepca.png"))
+        fig.savefig(os.path.join(args.directory, "chi2_prepca.pdf"))
         plt.close(fig)
 
         fig = plt.figure(figsize=(12, 8))
@@ -491,7 +561,7 @@ def main():
                xlim=(0, 5),
                ylim=(0, np.mean(xgm_flux_t) + 3*np.std(xgm_flux_t))
                )
-        fig.savefig(os.path.join(args.directory, "intensity_vs_chi2_prepca.png"))
+        fig.savefig(os.path.join(args.directory, "intensity_vs_chi2_prepca.pdf"))
         plt.close(fig)
 
         res_prepca = np.sum((spec_smooth_pca[:, np.newaxis, :] - spec_pred["expected_pca"])/spec_pred["expected_pca_unc"], axis=1)
@@ -508,7 +578,7 @@ def main():
                xlim=(-3, 3),
                )
             ax.legend(frameon=False)
-        fig.savefig(os.path.join(args.directory, "res_prepca.png"))
+        fig.savefig(os.path.join(args.directory, "res_prepca.pdf"))
         plt.close(fig)
 
         fig = plt.figure(figsize=(12, 8))
@@ -528,7 +598,7 @@ def main():
         #        transform=ax.transAxes,
         #        color='black', fontsize=15)
         plt.tight_layout()
-        fig.savefig(os.path.join(args.directory, "intensity.png"))
+        fig.savefig(os.path.join(args.directory, "intensity.pdf"))
         plt.close(fig)
 
         # rmse
@@ -542,7 +612,7 @@ def main():
                xlabel=r"Root-mean-squared error",
                ylabel="XGM intensity [uJ]",
                )
-        fig.savefig(os.path.join(args.directory, "intensity_vs_rmse.png"))
+        fig.savefig(os.path.join(args.directory, "intensity_vs_rmse.pdf"))
         plt.close(fig)
 
         fig = plt.figure(figsize=(12, 8))
@@ -561,7 +631,7 @@ def main():
         #        verticalalignment='top', horizontalalignment='right',
         #        transform=ax.transAxes,
         #        color='black', fontsize=15)
-        fig.savefig(os.path.join(args.directory, "rmse.png"))
+        fig.savefig(os.path.join(args.directory, "rmse.pdf"))
         plt.close(fig)
 
         ## SPEC integral w.r.t XGM intensity
@@ -600,16 +670,16 @@ def main():
         #plt.close(fig)
 
     first, last = model.get_low_resolution_range()
-    first = max(0, first+250)
-    last = min(last, pes_raw_t["channel_1_D"].shape[1]-1)
-    pes_to_show = 'sum'
+    first = max(0, first+200)
+    last = min(last-200, pes_raw_t["channel_1_D"].shape[1]-1)
+    pes_to_show = "" #'channel_1_D'
     # plot
     high_int_idx = np.argsort(xgm_flux_t[:,0])
     for q in [10, 25, 50, 75, 100]:
         qi = int(len(high_int_idx)*(q/100.0))
         for idx in high_int_idx[qi-10:qi]:
             tid = test_tids[idx]
-            plot_result(os.path.join(args.directory, f"test_q{q}_{tid}.png"),
+            plot_result(os.path.join(args.directory, f"test_q{q}_{tid}.pdf"),
                        {k: item[idx, 0, ...] if k != "pca"
                            else item[0, ...]
                            for k, item in spec_pred.items()},
@@ -622,9 +692,9 @@ def main():
                         pes_to_show=pes_to_show,
                         pes_bin=np.arange(first, last),
                         )
-            #for ch in channels:
-            #    plot_pes(os.path.join(args.directory, f"test_pes_{tid}_{ch}.png"),
-            #             pes_raw_t[ch][idx, first:last], first, last)
+            for ch in channels:
+                plot_pes(os.path.join(args.directory, f"test_pes_{tid}_{ch}.pdf"),
+                         -pes_raw_t[ch][idx, first:last], first, last)
 
 if __name__ == '__main__':
     main()