code: import os
  
  import matplotlib.pyplot as plt
  import numpy as np
  import strax
  import straxen
  
  
  @straxen.mini_analysis(requires=('raw_records',), warn_beyond_sec=5)
  def plot_pulses_tpc(context, raw_records, run_id, time_range=None,
                      plot_hits=False, plot_median=False,
                      max_plots=20, store_pdf=False, path=''):
      plot_pulses(context, raw_records, run_id, time_range,
                  plot_hits, plot_median,
                  max_plots, store_pdf, path)
  
  
  @straxen.mini_analysis(requires=('raw_records_mv',), warn_beyond_sec=5)
  def plot_pulses_mv(context, raw_records_mv, run_id, time_range=None,
                     plot_hits=False, plot_median=False,
                     max_plots=20, store_pdf=False, path=''):
      plot_pulses(context, raw_records_mv, run_id, time_range,
                  plot_hits, plot_median,
                  max_plots, store_pdf, path, detector_ending='_mv')
  
  
  @straxen.mini_analysis(requires=('raw_records_nv',), warn_beyond_sec=5)
  def plot_pulses_nv(context, raw_records_nv, run_id, time_range=None,
                     plot_hits=False, plot_median=False,
                     max_plots=20, store_pdf=False, path=''):
      plot_pulses(context, raw_records_nv, run_id, time_range,
                  plot_hits, plot_median,
                  max_plots, store_pdf, path, detector_ending='_nv')
  
  
  def plot_pulses(context, raw_records, run_id, time_range,
                  plot_hits=False, plot_median=False,
                  max_plots=20, store_pdf=False, path='',
                  detector_ending=''):
      """
      Plots nveto pulses for a list of records.
      :param context: Context to be used.
      :param plot_hits: If True plot hit boundaries including the left
          and right extension as orange shaded regions.
      :param plot_median: If true plots pulses sample median as dotted
          line.
      :param max_plots: Limits the number of figures. If you would like
          to plot more pulses you should put the plots in a PDF.
      :param store_pdf: If true figures are put to a PDF instead of
          plotting them to your notebook. The file name is automatically
          generated including the time range and run_id.
      :param path: Relative path where the PDF should be stored. By default
          it is the directory of the notebook.
      :param detector_ending: Ending of the corresponding detector. Empty
          string for TPC '_nv' for neutron-veto and '_mv' muon-veto. 
      """
      # Register records plugin to get settings
      p = context.get_single_plugin(run_id, 'records' + detector_ending)
  
      # Compute strax baseline and baseline_rms:
      records = strax.raw_to_records(raw_records)
      records = strax.sort_by_time(records)
      strax.zero_out_of_bounds(records)
  
      baseline_key = [key for key in p.config.keys() if 'baseline_samples' in key][0]
  
      if isinstance(p.config[baseline_key], int):
          baseline_samples = p.config[baseline_key]
      else:
          baseline_samples = straxen.get_correction_from_cmt(
              run_id, p.config[baseline_key])
  
      strax.baseline(records,
                     baseline_samples=baseline_samples,
                     flip=True)
  
      nfigs = 1
      if store_pdf and time_range is None:
          raise ValueError(f'Specify time range!')
      if store_pdf:
          from matplotlib.backends.backend_pdf import PdfPages
          fname = f'pulses_{run_id}_{time_range[0]}_{time_range[1]}.pdf'
          fname = os.path.join(path, fname)
          pdf = PdfPages(fname)
  
      hits = None  # needed for delete if false
  
      for inds in _yield_pulse_indices(raw_records):
          # Grouped our pulse so now plot:
          rr_pulse = raw_records[inds]
          r_pulse = records[inds]
  
          fig, axes = straxen.plot_single_pulse(rr_pulse, run_id)
          if detector_ending == '_nv':
              # We only store for the nv digitizer baseline values:
              axes.axhline(rr_pulse[0]['baseline'], ls='dashed',
                           color='k', label=f'D. Bas.: {rr_pulse[0]["baseline"]} ADC')
  
          baseline = r_pulse[0]['baseline']
          baseline_rms = r_pulse[0]['baseline_rms']
          axes.axhline(baseline, ls='solid',
                       color='k',
                       label=f'Strax Bas. +/-RMS:\n ({baseline:.2f}+/-{baseline_rms:.2f}) ADC')
          xlim = axes.get_xlim()
          axes.fill_between(xlim,
                            [baseline + baseline_rms] * 2,
                            [baseline - baseline_rms] * 2,
                            color='gray', alpha=0.4
                            )
  
          # check type of p.hit_thresholds
          if isinstance(p.hit_thresholds, int):
              thr = p.hit_thresholds
          elif isinstance(p.hit_thresholds, np.ndarray):
              thr = p.hit_thresholds[rr_pulse['channel']][0]
  
          if plot_median:
              # Plot median if asked.
              # Have to make pulse again:
              pulse = straxen.matplotlib_utils._make_pulse(rr_pulse)
              median = np.median(pulse)
              axes.axhline(median,
                           ls='dotted',
                           color='k',
                           label=f'Median Bas.: {median:.0f} ADC')
  
              axes.axhline(median - thr,
                           ls='dotted', color='orange'
                           )
  
          if plot_hits:
              min_amplitude = thr
  
              axes.axhline(baseline - min_amplitude,
                           color='orange', label='Hitfinder threshold')
  
              hits = strax.find_hits(r_pulse,
                                     min_amplitude=min_amplitude
                                     )
              if detector_ending != '_he':
                  # We don't have 'save_outside_hits_he' at all!
                  le, re = p.config['save_outside_hits' + detector_ending]
              else:
                  le, re = p.config['save_outside_hits']
              start = (hits['time'] - r_pulse[0]['time']) / r_pulse[0]['dt'] - le
              end = (strax.endtime(hits) - r_pulse[0]['time']) / r_pulse[0]['dt'] + re
  
              ylim = axes.get_ylim()
              for s, e in zip(start, end):
                  plt.fill_between((s, e), *ylim, alpha=0.2, color='orange')
              axes.set_ylim(*ylim)
  
          plt.legend()
          axes.set_xlim(*xlim)
  
          if store_pdf:
              plt.close()
              pdf.savefig(fig)
  
          nfigs += 1
          if max_plots is not None and nfigs > max_plots:
              break
  
      if store_pdf:
          pdf.close()
      del records, hits
  
  
  def _yield_pulse_indices(records):
      """
      Function which yields indices of records which are within a pulse.
      Note:
          Only finds fragments of the pulse if record_i == 0 is within list
          of records.
      :yields: indices of fragments to make the corresponding pulse.
      """
      # Get record links and find start indicies:
      _, next_ri = strax.record_links(records)
      start_ri = np.where(records['record_i'] == 0)[0]
  
      # Loop over pulse start_ri, group fragments by pulses yield for plot:
      for ri in start_ri:
          # Buffer for indices:
          inds = []
  
          tries = 1
          max_tries = 5000
          while ri != -1:
              inds.append(ri)
              ri = next_ri[ri]
  
              tries += 1
              if tries > max_tries:
                  raise ValueError('Tried more than 5000 times to find subsequent record.'
                                   ' Am I stuck in a loop?')
          yield inds
  
apis: matplotlib.pyplot.legend matplotlib.backends.backend_pdf.PdfPages numpy.median matplotlib.pyplot.close numpy.where matplotlib.pyplot.fill_between