extendable heatmap system axis modifications should be conisistent, documented, and reusably/compositionally customizable

Issue #79 new
Thomas Gilgenast created an issue

currently, ExtendableHeatmap.add_margin_ax() calls ax.axis('off'), which turns off the axis for a cleaner, less boxy aesthetic

however, individual ExtendableHeatmap.add_*() functions can sometimes override this

in particular, add_chipseq_track() also performs all of the following modifications to the axis:

        ax.axis('on')
        ax.set_frame_on(False)
        ...
        if orientation == 'vertical':
            ax.axes.get_yaxis().set_visible(False)
            ax.set_xticks(tick_positions)
            ax.set_xticklabels(tick_labels, rotation=270, fontsize=7)
            ax.xaxis.set_ticks_position('bottom')
            ax.get_xaxis().set_tick_params(direction='out')
        else:
            ax.axes.get_xaxis().set_visible(False)
            ax.set_yticks(tick_positions)
            ax.set_yticklabels(tick_labels, fontsize=7)
            ax.yaxis.set_ticks_position('left')
            ax.get_yaxis().set_tick_params(direction='out')

the intent of this was to provide “nice” defaults for all margin tracks

however, users wanting to modify the added axis further are presented with a highly inconsistent set of axis states when they begin their modifications - it is very hard to tell what set of modifications have been made and this set could be different for each type of margin plot

we propose to

  1. standardize the axis state returned by any add_margin_ax()-based plotter (e.g., ax.axis('off') only with no exceptions)
  2. document what this axis state is and how to undo it (e.g., ax.axis('on')) on the ExtendableHeatmap module-level docstring
  3. provide opt-in styling functions (e.g., in a new module lib5c.plotters.axis_styles) that can be called on the newly-added axes (e.g., my_style(h.add_whatever_track(...)))

Comments (4)

  1. Thomas Gilgenast reporter

    in order for this to work well, there needs to be a way for the add_margin_ax()-based plotters to include information in the axes they return that the axis styling functions can consume

    for example, the chipseq track styling requires knowing the orientation of the axis and also the track_height value - is there a way we can avoid having to pass these two values to the axis styling function?

  2. Thomas Gilgenast reporter

    if we could figure out orientation, then track_height can be obtained by checking ax.get_xlim()[1] or ax.get_ylim()[1] as appropriate for the orientation

  3. Thomas Gilgenast reporter

    related to #55 and its goal of reducing the amount of code in these plotters, we could abstract out a label_track(ax, label) function if we knew the orientation of the track which could be composable with all other margin ax plotters

  4. Thomas Gilgenast reporter

    one “syntactic sugar“ option is to create a MarginAxes class that wraps a pyplot.Axes object plus the orientation, maybe it’s position within the grid, padding, etc. and bound methods for styling and labeling

    this would enable chaining calls like: h.add_chipseq_tracks(...).chipseq_style().label('my label')

  5. Log in to comment