Beispiel #1
0
def _histogram(xlo, xhi, y, yerr=None, title=None, xlabel=None, ylabel=None,
               overplot=False, clearwindow=True,
               yerrorbars=False,
               errstyle=None,
               errcolor=None,
               errthickness=None,
               fillcolor=None,
               fillopacity=None,
               fillstyle=None,
               xlog=False,
               ylog=False,
               linestyle=chips.chips_solid,
               linecolor=None,
               linethickness=None,
               symbolangle=None,
               symbolcolor=None,
               symbolfill=None,
               symbolsize=None,
               symbolstyle=chips.chips_none):

    if (not overplot) and clearwindow:
        _clear_window()

    if yerrorbars and yerr is not None:
        chips.add_histogram(xlo, xhi, y, yerr)
    else:
        chips.add_histogram(xlo, xhi, y)

    for var in ('errstyle', 'errcolor', 'errthickness',
                'fillcolor', 'fillopacity', 'fillstyle',
                'linestyle', 'linecolor', 'linethickness',
                'symbolangle', 'symbolcolor', 'symbolfill', 'symbolsize',
                'symbolstyle'):
        val = locals()[var]
        if val is not None:
            if 'color' in var:
                val = _check_hex_color(val)
            getattr(chips.advanced, 'set_histogram_' + var)(val)

    if not overplot:
        for log_axis, axis_id in izip((xlog, ylog),
                                      (chips.X_AXIS, chips.Y_AXIS)):
            if log_axis:
                chips.log_scale(axis_id)
            else:
                chips.linear_scale(axis_id)

        if title:
            ttl = title.replace('_', '\\_')
            chips.set_plot_title(ttl)
        if xlabel:
            xlbl = xlabel.replace('_', '\\_')
            chips.set_plot_xlabel(xlbl)
        if ylabel:
            ylbl = ylabel.replace('_', '\\_')
            chips.set_plot_ylabel(ylbl)
Beispiel #2
0
def _histogram(xlo, xhi, y, yerr=None, title=None, xlabel=None, ylabel=None,
               overplot=False, clearwindow=True,
               yerrorbars=False,
               errstyle=None,
               errcolor=None,
               errthickness=None,
               fillcolor=None,
               fillopacity=None,
               fillstyle=None,
               xlog=False,
               ylog=False,
               linestyle=chips.chips_solid,
               linecolor=None,
               linethickness=None,
               symbolangle=None,
               symbolcolor=None,
               symbolfill=None,
               symbolsize=None,
               symbolstyle=chips.chips_none):

    if (not overplot) and clearwindow:
        _clear_window()

    if yerrorbars and yerr is not None:
        chips.add_histogram(xlo, xhi, y, yerr)
    else:
        chips.add_histogram(xlo, xhi, y)

    for var in ('errstyle', 'errcolor', 'errthickness',
                'fillcolor', 'fillopacity', 'fillstyle',
                'linestyle', 'linecolor', 'linethickness',
                'symbolangle', 'symbolcolor', 'symbolfill', 'symbolsize',
                'symbolstyle'):
        val = locals()[var]
        if val is not None:
            if 'color' in var:
                val = _check_hex_color(val)
            getattr(chips.advanced, 'set_histogram_' + var)(val)

    if not overplot:
        for log_axis, axis_id in zip((xlog, ylog),
                                     (chips.X_AXIS, chips.Y_AXIS)):
            if log_axis:
                chips.log_scale(axis_id)
            else:
                chips.linear_scale(axis_id)

        if title:
            ttl = title.replace('_', '\\_')
            chips.set_plot_title(ttl)
        if xlabel:
            xlbl = xlabel.replace('_', '\\_')
            chips.set_plot_xlabel(xlbl)
        if ylabel:
            ylbl = ylabel.replace('_', '\\_')
            chips.set_plot_ylabel(ylbl)
Beispiel #3
0
def _contour(x0, x1, y, levels=None, title=None, xlabel=None, ylabel=None,
             overcontour=False, clearwindow=True,
             xlog=False,
             ylog=False,
             style=None,
             color=None,
             thickness=None,
             axis_pad=0.05):

    if (not overcontour) and clearwindow:
        _clear_window()

    # Catch NANs before sending to ChIPS
    bad = list(numpy.where(numpy.isnan(y)==True)).pop(0)
    bad_vals = numpy.array(y[bad])
    y[bad] = 0.0

    if levels is None:
        chips.add_contour(x0, x1, y)
    else:
        levels = numpy.asarray(levels, numpy.float_)
        chips.add_contour(x0, x1, y, levels)

    y[bad] = bad_vals

    for var in ('style', 'color', 'thickness'):
        val = locals()[var]
        if val is not None:
            if 'color' in var:
                val = _check_hex_color(val)
            getattr(chips.advanced, 'set_contour_' + var)(val)

    chips.advanced.set_axis_pad(axis_pad)

    chips.set_data_aspect_ratio()
    chips.limits(chips.X_AXIS, x0.min(), x0.max())
    chips.limits(chips.Y_AXIS, x1.min(), x1.max())

    if not overcontour:
        for log_axis, axis_id in izip((xlog, ylog),
                                      (chips.X_AXIS, chips.Y_AXIS)):
            if log_axis:
                chips.log_scale(axis_id)
            else:
                chips.linear_scale(axis_id)

        if title:
            ttl = title.replace('_', '\\_')
            chips.set_plot_title(ttl)
        if xlabel:
            xlbl = xlabel.replace('_', '\\_')
            chips.set_plot_xlabel(xlbl)
        if ylabel:
            ylbl = ylabel.replace('_', '\\_')
            chips.set_plot_ylabel(ylbl)
Beispiel #4
0
def _contour(x0, x1, y, levels=None, title=None, xlabel=None, ylabel=None,
             overcontour=False, clearwindow=True,
             xlog=False,
             ylog=False,
             style=None,
             color=None,
             thickness=None,
             axis_pad=0.05):

    if (not overcontour) and clearwindow:
        _clear_window()

    # Catch NANs before sending to ChIPS
    bad = list(numpy.where(numpy.isnan(y)==True)).pop(0)
    bad_vals = numpy.array(y[bad])
    y[bad] = 0.0

    if levels is None:
        chips.add_contour(x0, x1, y)
    else:
        levels = numpy.asarray(levels, numpy.float_)
        chips.add_contour(x0, x1, y, levels)

    y[bad] = bad_vals

    for var in ('style', 'color', 'thickness'):
        val = locals()[var]
        if val is not None:
            if 'color' in var:
                val = _check_hex_color(val)
            getattr(chips.advanced, 'set_contour_' + var)(val)

    chips.advanced.set_axis_pad(axis_pad)

    chips.set_data_aspect_ratio()
    chips.limits(chips.X_AXIS, x0.min(), x0.max())
    chips.limits(chips.Y_AXIS, x1.min(), x1.max())

    if not overcontour:
        for log_axis, axis_id in zip((xlog, ylog),
                                     (chips.X_AXIS, chips.Y_AXIS)):
            if log_axis:
                chips.log_scale(axis_id)
            else:
                chips.linear_scale(axis_id)

        if title:
            ttl = title.replace('_', '\\_')
            chips.set_plot_title(ttl)
        if xlabel:
            xlbl = xlabel.replace('_', '\\_')
            chips.set_plot_xlabel(xlbl)
        if ylabel:
            ylbl = ylabel.replace('_', '\\_')
            chips.set_plot_ylabel(ylbl)
def main(opt):

    # Use verbose option to control sherpa output
    logger = logging.getLogger("sherpa")
    logger.setLevel(LOGLEVELS[opt['verbose']])

    events = extract_events(opt['evtfile'],
                            opt['x'], opt['y'], opt['radius'])

    evt_ra_pnt = events.get_key('RA_PNT').value
    evt_dec_pnt = events.get_key('DEC_PNT').value
    evt_roll_pnt = events.get_key('ROLL_PNT').value

    asol = pycrates.read_file(opt['infile'])
    asol_times = asol.get_column('time').values

    # Sanity check the two input files
    asol_obsid = asol.get_key('OBS_ID').value
    evt_obsid = events.get_key('OBS_ID').value
    if asol_obsid != evt_obsid:
        v1("Error Aspect solution obsid {} != event file obsid {}".format(asol_obsid, evt_obsid))

    # Extract event RA, Dec, and times from event file
    # Do the WCS transformation directly instead of using the pycrates RA/Dec properties to
    # work around intermittent bug https://icxc.harvard.edu/pipe/ascds_help/2013a/0315.html
    wcs = events.get_transform("eqpos")
    evt_x = events.get_column("x").values
    evt_y = events.get_column("y").values
    rd = wcs.apply(np.column_stack([evt_x, evt_y]))
    evt_ra = rd[:, 0]
    evt_dec = rd[:, 1]
    evt_times = events.get_column('Time').values

    # Limit to only using events contained within the range of the aspect solution
    ok_times = (evt_times > asol_times[0]) & (evt_times < asol_times[-1])
    if not np.any(ok_times):
        raise ValueError("No events in region are contained within time range of aspect solution.")
    # Limit this *in place*
    evt_ra = evt_ra[ok_times]
    evt_dec = evt_dec[ok_times]
    evt_times = evt_times[ok_times]

    if len(evt_times) < opt['src_min_counts']:
        v1("Warning only {} counts in src region.  {} minimum suggested 'src_min_counts'".format(
                len(evt_times), opt['src_min_counts']))

    ax_data = {}
    ax_map = {'yag': 'dy',
              'zag': 'dz'}

    ax_data['yag'], ax_data['zag'] = get_event_yag_zag(evt_ra, evt_dec,
                                                       evt_ra_pnt, evt_dec_pnt, evt_roll_pnt)

    # Store comments to print in block after all of the sherpa fit output
    fit_comments = []
    plot_list = []

    for data_id, ax in enumerate(['yag', 'zag']):
        fit_data = ax_data[ax] - np.mean(ax_data[ax])
        mp, model = _fit_poly(fit_data, evt_times, opt['corr_poly_degree'], data_id=data_id)

        bin_centers, bin_mean, bin_std = time_bins(evt_times, fit_data)

        add_window(6, 4, "inches")
        add_curve((bin_centers - evt_times[0]) / 1000., bin_mean, [bin_std, +bin_std],
                  ["line.style", "none", "symbol.style", "none", "err.style", "cap"])
        add_curve(mp.x / 1000., mp.y, ["symbol.style", "none"])
        # set minimum limit on fit plot in arcsecs and set this explicitly as a symmetric limit
        fit_ymax = max(0.3, np.max(np.abs(bin_mean - bin_std)), np.max(np.abs(bin_mean + bin_std)))
        limits(Y_AXIS, -1 * fit_ymax, fit_ymax)
        set_plot_xlabel("Observation elapsed/delta time (ks)")
        set_plot_ylabel("Position offset from mean, {} (arcsec)".format(ax))
        set_plot_title("Fit of {} data (with time-binned event offsets)".format(ax))
        fit_plot = "{}_fit_{}.png".format(opt['corr_plot_root'], ax)
        if os.path.exists(fit_plot) and opt['clobber'] == 'yes':
            os.unlink(fit_plot)
        plot_list.append(fit_plot)
        print_window(fit_plot)

        add_window(6, 4, "inches")
        data_plot = "{}_data_{}.png".format(opt['corr_plot_root'], ax)
        ui.get_data_plot_prefs()['yerrorbars'] = False
        ui.plot_fit(data_id)
        if os.path.exists(data_plot) and opt['clobber'] == 'yes':
            os.unlink(data_plot)
        # set minimum limit on data plot in arcsecs and set this explicitly as a symmetric limit
        data_ymax = max(2.0, np.max(np.abs(fit_data)) + .2)
        limits(Y_AXIS, -1 * data_ymax, data_ymax)
        set_plot_xlabel("Observation elapsed/delta time (s)")
        set_plot_ylabel("Position offset from mean, {} (arcsec)".format(ax))
        set_plot_title("Raw data and fit in {}".format(ax))
        plot_list.append(data_plot)
        print_window(data_plot)

        asol_corr = np.interp(asol_times, mp.x + evt_times[0], mp.y)
        asol_col_to_fix = asol.get_column(ax_map[ax])
        fit_comments.append("Events show drift range of {:.2f} arcsec in {} axis".format(
                np.max(asol_corr) - np.min(asol_corr), ax))
        fit_comments.append("Max absolute correction of {:.2f} arcsec for {} axis".format(
                np.max(np.abs(asol_corr)), ax))

        # Convert the correction from arcsecs to mm (divide by 20) and add the correction
        # to the dy and dz columns in the file.
        asol_col_to_fix.values += (asol_corr / 20)

        # Add header keys saving the axis-specific parts of this correction
        write_key(asol, "ADC{}MN".format(ax.upper()), np.mean(ax_data[ax]),
                  "Aspect Drift Corr. Mean of uncorr {} data".format(ax))
        for deg in range(0, 1 + opt['corr_poly_degree']):
            write_key(asol, "ADC{}C{}".format(ax.upper(), deg),
                      getattr(model, 'c{}'.format(deg)).val,
                      "Aspect Drift Corr. {} model c{}".format(ax, deg))

    # Add header keywords about fit
    write_key(asol, "ADCTIME0", evt_times[0],
              "Aspect Drift Corr. reference time")
    write_key(asol, "ADCSRCX", opt['x'],
              "Aspect Drift Corr. input src x")
    write_key(asol, "ADCSRCY", opt['y'],
              "Aspect Drift Corr. input src y")
    write_key(asol, "ADCSRCR", opt['radius'],
              "Aspect Drift Corr. input src radius", units='pix')
    write_key(asol, "ADCORDR", opt['corr_poly_degree'],
              "Aspect Drift Corr. model poly degree")
    write_key(asol, "ADCVER", VERSION,
              "Aspect Drift Corr. tool version")

    v2("-" * 60)
    v2("Fit results")
    for c in fit_comments:
        v2("\t{}".format(c))
    v2("-" * 60)
    v2("Writing out corrected aspect solution file to {}".format(opt['outfile']))
    v2("\tTo review fit see correction plots in:")
    for p in plot_list:
        v2("\t\t{}".format(p))

    # Actually write out the new aspect solution file
    asol.write(opt['outfile'], clobber=opt['clobber'])

    # Add history
    add_tool_history(opt['outfile'], TOOLNAME, params=opt, toolversion=VERSION)
Beispiel #6
0
def main(opt):

    # Use verbose option to control sherpa output
    logger = logging.getLogger("sherpa")
    logger.setLevel(LOGLEVELS[opt['verbose']])

    events = extract_events(opt['evtfile'], opt['x'], opt['y'], opt['radius'])

    evt_ra_pnt = events.get_key('RA_PNT').value
    evt_dec_pnt = events.get_key('DEC_PNT').value
    evt_roll_pnt = events.get_key('ROLL_PNT').value

    asol = pycrates.read_file(opt['infile'])
    asol_times = asol.get_column('time').values

    # Sanity check the two input files
    asol_obsid = asol.get_key('OBS_ID').value
    evt_obsid = events.get_key('OBS_ID').value
    if asol_obsid != evt_obsid:
        v1("Error Aspect solution obsid {} != event file obsid {}".format(
            asol_obsid, evt_obsid))

    # Extract event RA, Dec, and times from event file
    # Do the WCS transformation directly instead of using the pycrates RA/Dec properties to
    # work around intermittent bug https://icxc.harvard.edu/pipe/ascds_help/2013a/0315.html
    wcs = events.get_transform("eqpos")
    evt_x = events.get_column("x").values
    evt_y = events.get_column("y").values
    rd = wcs.apply(np.column_stack([evt_x, evt_y]))
    evt_ra = rd[:, 0]
    evt_dec = rd[:, 1]
    evt_times = events.get_column('Time').values

    # Limit to only using events contained within the range of the aspect solution
    ok_times = (evt_times > asol_times[0]) & (evt_times < asol_times[-1])
    if not np.any(ok_times):
        raise ValueError(
            "No events in region are contained within time range of aspect solution."
        )
    # Limit this *in place*
    evt_ra = evt_ra[ok_times]
    evt_dec = evt_dec[ok_times]
    evt_times = evt_times[ok_times]

    if len(evt_times) < opt['src_min_counts']:
        v1("Warning only {} counts in src region.  {} minimum suggested 'src_min_counts'"
           .format(len(evt_times), opt['src_min_counts']))

    ax_data = {}
    ax_map = {'yag': 'dy', 'zag': 'dz'}

    ax_data['yag'], ax_data['zag'] = get_event_yag_zag(evt_ra, evt_dec,
                                                       evt_ra_pnt, evt_dec_pnt,
                                                       evt_roll_pnt)

    # Store comments to print in block after all of the sherpa fit output
    fit_comments = []
    plot_list = []

    for data_id, ax in enumerate(['yag', 'zag']):
        fit_data = ax_data[ax] - np.mean(ax_data[ax])
        mp, model = _fit_poly(fit_data,
                              evt_times,
                              opt['corr_poly_degree'],
                              data_id=data_id)

        bin_centers, bin_mean, bin_std = time_bins(evt_times, fit_data)

        add_window(6, 4, "inches")
        add_curve(
            (bin_centers - evt_times[0]) / 1000., bin_mean,
            [bin_std, +bin_std],
            ["line.style", "none", "symbol.style", "none", "err.style", "cap"])
        add_curve(mp.x / 1000., mp.y, ["symbol.style", "none"])
        # set minimum limit on fit plot in arcsecs and set this explicitly as a symmetric limit
        fit_ymax = max(0.3, np.max(np.abs(bin_mean - bin_std)),
                       np.max(np.abs(bin_mean + bin_std)))
        #limits(Y_AXIS, -1 * fit_ymax, fit_ymax)
        set_plot_xlabel("Observation elapsed/delta time (ks)")
        set_plot_ylabel("Position offset from mean, {} (arcsec)".format(ax))
        set_plot_title(
            "Fit of {} data (with time-binned event offsets)".format(ax))
        fit_plot = "{}_fit_{}.png".format(opt['corr_plot_root'], ax)
        if os.path.exists(fit_plot) and opt['clobber']:
            os.unlink(fit_plot)
        plot_list.append(fit_plot)
        print_window(fit_plot)

        add_window(6, 4, "inches")
        data_plot = "{}_data_{}.png".format(opt['corr_plot_root'], ax)
        ui.get_data_plot_prefs()['yerrorbars'] = False
        ui.plot_fit(data_id)
        if os.path.exists(data_plot) and opt['clobber']:
            os.unlink(data_plot)
        # set minimum limit on data plot in arcsecs and set this explicitly as a symmetric limit
        data_ymax = max(2.0, np.max(np.abs(fit_data)) + .2)
        #limits(Y_AXIS, -1 * data_ymax, data_ymax)
        set_plot_xlabel("Observation elapsed/delta time (s)")
        set_plot_ylabel("Position offset from mean, {} (arcsec)".format(ax))
        set_plot_title("Raw data and fit in {}".format(ax))
        plot_list.append(data_plot)
        print_window(data_plot)

        asol_corr = np.interp(asol_times, mp.x + evt_times[0], mp.y)
        asol_col_to_fix = asol.get_column(ax_map[ax])
        fit_comments.append(
            "Events show drift range of {:.2f} arcsec in {} axis".format(
                np.max(asol_corr) - np.min(asol_corr), ax))
        fit_comments.append(
            "Max absolute correction of {:.2f} arcsec for {} axis".format(
                np.max(np.abs(asol_corr)), ax))

        # Convert the correction from arcsecs to mm (divide by 20) and add the correction
        # to the dy and dz columns in the file.
        asol_col_to_fix.values += (asol_corr / 20)

        # Add header keys saving the axis-specific parts of this correction
        write_key(asol, "ADC{}MN".format(ax.upper()), np.mean(ax_data[ax]),
                  "Aspect Drift Corr. Mean of uncorr {} data".format(ax))
        for deg in range(0, 1 + opt['corr_poly_degree']):
            write_key(asol, "ADC{}C{}".format(ax.upper(), deg),
                      getattr(model, 'c{}'.format(deg)).val,
                      "Aspect Drift Corr. {} model c{}".format(ax, deg))

    # Add header keywords about fit
    write_key(asol, "ADCTIME0", evt_times[0],
              "Aspect Drift Corr. reference time")
    write_key(asol, "ADCSRCX", opt['x'], "Aspect Drift Corr. input src x")
    write_key(asol, "ADCSRCY", opt['y'], "Aspect Drift Corr. input src y")
    write_key(asol,
              "ADCSRCR",
              opt['radius'],
              "Aspect Drift Corr. input src radius",
              units='pix')
    write_key(asol, "ADCORDR", opt['corr_poly_degree'],
              "Aspect Drift Corr. model poly degree")
    write_key(asol, "ADCVER", VERSION, "Aspect Drift Corr. tool version")

    v2("-" * 60)
    v2("Fit results")
    for c in fit_comments:
        v2("\t{}".format(c))
    v2("-" * 60)
    v2("Writing out corrected aspect solution file to {}".format(
        opt['outfile']))
    v2("\tTo review fit see correction plots in:")
    for p in plot_list:
        v2("\t\t{}".format(p))

    # Actually write out the new aspect solution file
    asol.write(opt['outfile'], clobber=opt['clobber'])
Beispiel #7
0
def _plot(x, y, yerr=None, xerr=None, title=None, xlabel=None, ylabel=None,
         overplot=False, clearwindow=True,
         xerrorbars=False,
         yerrorbars=False,
         errstyle=None,
         errcolor=None,
         errthickness=None,
         xlog=False,
         ylog=False,
         linestyle=chips.chips_solid,
         linecolor=None,
         symbolstyle=chips.chips_none,
         symbolcolor=None,
         symbolsize=None,
         symbolfill=True,
         linethickness=None,
         xaxis=False,
         ratioline=False):


    if (not overplot) and clearwindow:
        _clear_window()

    if yerrorbars and (yerr is not None) and xerrorbars and (xerr is not None):
        xerr = xerr / 2.
        chips.add_curve(x, y, (yerr, yerr, xerr, xerr) )
    elif yerrorbars and (yerr is not None):
        chips.add_curve(x, y, yerr)
    else:
        chips.add_curve(x, y)

    for var in ('errstyle', 'errcolor', 'errthickness', 'linestyle',
                'linecolor', 'symbolstyle', 'symbolcolor', 'symbolsize',
                'symbolfill', 'linethickness'):
        val = locals()[var]
        if val is not None:
            if 'color' in var:
                val = _check_hex_color(val)
            getattr(chips.advanced, 'set_curve_' + var)(val)

    if not overplot:
        for log_axis, axis_id in izip((xlog, ylog),
                                      (chips.X_AXIS, chips.Y_AXIS)):
            if log_axis:
                chips.log_scale(axis_id)
            else:
                chips.linear_scale(axis_id)

        if title:
            ttl = title.replace('_', '\\_')
            chips.set_plot_title(ttl)
        if xlabel:
            xlbl = xlabel.replace('_', '\\_')
            chips.set_plot_xlabel(xlbl)
        if ylabel:
            ylbl = ylabel.replace('_', '\\_')
            chips.set_plot_ylabel(ylbl)

    if xaxis:
        chips.add_hline(0);

    if ratioline:
        chips.add_hline(1);
Beispiel #8
0
def _plot(x,
          y,
          yerr=None,
          xerr=None,
          title=None,
          xlabel=None,
          ylabel=None,
          overplot=False,
          clearwindow=True,
          xerrorbars=False,
          yerrorbars=False,
          errstyle=None,
          errcolor=None,
          errthickness=None,
          xlog=False,
          ylog=False,
          linestyle=chips.chips_solid,
          linecolor=None,
          symbolstyle=chips.chips_none,
          symbolcolor=None,
          symbolsize=None,
          symbolfill=True,
          linethickness=None,
          xaxis=False,
          ratioline=False):

    if (not overplot) and clearwindow:
        _clear_window()

    if yerrorbars and (yerr is not None) and xerrorbars and (xerr is not None):
        xerr = xerr / 2.
        chips.add_curve(x, y, (yerr, yerr, xerr, xerr))
    elif yerrorbars and (yerr is not None):
        chips.add_curve(x, y, yerr)
    else:
        chips.add_curve(x, y)

    for var in ('errstyle', 'errcolor', 'errthickness', 'linestyle',
                'linecolor', 'symbolstyle', 'symbolcolor', 'symbolsize',
                'symbolfill', 'linethickness'):
        val = locals()[var]
        if val is not None:
            if 'color' in var:
                val = _check_hex_color(val)
            getattr(chips.advanced, 'set_curve_' + var)(val)

    if not overplot:
        for log_axis, axis_id in izip((xlog, ylog),
                                      (chips.X_AXIS, chips.Y_AXIS)):
            if log_axis:
                chips.log_scale(axis_id)
            else:
                chips.linear_scale(axis_id)

        if title:
            ttl = title.replace('_', '\\_')
            chips.set_plot_title(ttl)
        if xlabel:
            xlbl = xlabel.replace('_', '\\_')
            chips.set_plot_xlabel(xlbl)
        if ylabel:
            ylbl = ylabel.replace('_', '\\_')
            chips.set_plot_ylabel(ylbl)

    if xaxis:
        chips.add_hline(0)

    if ratioline:
        chips.add_hline(1)