Skip to content

mef.get_transform_fxn() outputs should be OrderedDict instead of lists to carry around channel ID #232

Description

@JS3xton

mef.get_transform_fxn() loops through specified MEF channels and builds a functools.partial function which transforms RFI values to MEF values based on specified bead data. If you ask for full_output, this function accumulates useful intermediate data structures and information for each specified MEF channel (specified via mef_channels input) in a series of lists and returns these lists to the user. E.g. from the mef.get_transform_fxn() documentation -

    fitting : dict, only if ``full_output==True``
        Results of the model fitting step, containing the following fields:
        std_crv : list
            Functions encoding the standard curves, for each channel in
            `mef_channels`.
        beads_model : list
            Functions encoding the fluorescence model of the
            calibration beads, for each channel in `mef_channels`.
        beads_params : list
            Fitted parameters of the bead fluorescence model, for each
            channel in `mef_chanels`.
        beads_model_str : list
            String representation of the bead models used, for each channel
            in `mef_channels`.
        beads_params_names : list
            Names of the parameters given in `beads_params`, for each
            channel in `mef_channels`.

I think it would be more useful if these accumulation data structures were OrderedDicts keyed on the mef_channels values. This seems like a natural way to carry around the channel ID for use in subsequent computations, and I believe the original list can be recovered easily via OrderedDict.values().

My use case is that I'm using the excel_ui.process_beads_table() function from the Python API, and I want to print the detector voltages of the channels I've chosen to MEF.

excel_ui.process_beads_table() returns:

    beads_samples : list of FCSData objects
        A list of processed, gated, and transformed samples, as specified
        in `beads_table`, in the order of ``beads_table.index``.
    mef_transform_fxns : OrderedDict
        A dictionary of MEF transformation functions, indexed by
        ``beads_table.index``.
    mef_outputs : list
        A list with intermediate results of the generation of the MEF
        transformation functions, indexed by ``beads_table.index``. Only
        included if `full_output` is True.

so I can extract useful information (e.g. the bead fitting parameters) by accessing mef_outputs via the numerical list index which corresponds to the Beads table entry I am interested in. (I will note here that mef_outputs and beads_samples should also maybe be an OrderedDict to be consistent with mef_transform_fxns. In general, I've found it very useful to loop through the Beads Table UIDs (DataFrame index) and access these structures via the UID instead of having to additionally carry around the list index (e.g. via enumerate) to access a bunch of lists).

From this context, though, I don't have access to the mef_channels that excel_ui.process_beads_table() called mef.get_transform_fxn() with without going back to the Excel file and re-parsing/extracting them myself, which seems woefully inelegant. I don't think it's possible in the general case with the current implementation to determine the channel ID without consulting the Excel file because the user can specify any combination of valid channels to MEF.

Problematic example code:

beads_samples, mef_transform_fxns, mef_outputs = fc.excel_ui.process_beads_table(
    beads_table=beads_table,
    instruments_table=instruments_table,
    full_output=True)

print('Bead Fluorescence Model Parameters:')
for idx,uid in enumerate(beads_table.index):        # <-- idx feels unnecessary
    print('-Bead Table ID: {}'.format(uid))
    for ch_idx, ch_params in enumerate(mef_outputs[idx].fitting['beads_params']):
        print('--Channel Index: {} (voltage={}), Params: {}'.format(
            ch_idx,
            beads_samples[idx].detector_voltage(channels=???),
            ch_params))

I would prefer:

beads_samples, mef_transform_fxns, mef_outputs = fc.excel_ui.process_beads_table(
    beads_table=beads_table,
    instruments_table=instruments_table,
    full_output=True)

print('Bead Fluorescence Model Parameters:')
for uid in beads_table.index:
    print('-Bead Table ID: {}'.format(uid))
    for ch, ch_params in mef_outputs[uid].fitting['beads_params']:
        print('--Channel: {} (voltage={}), Params: {}'.format(
            ch,
            beads_samples[uid].detector_voltage(channels=ch),
            ch_params))

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions