<commit_before>from six.moves import zip_longest
from six import iterkeys, print_, text_type

import pandas as pd

from .variability import flux_variability_analysis


def format_long_string(string, max_length):
    if len(string) > max_length:
        string = string[:max_length - 3]
        string += '...'
    return string


def metabolite_summary(met, threshold=0.01, fva=False, **solver_args):
    """Print a summary of the reactions which produce and consume this
    metabolite

    threshold: float
    a value below which to ignore reaction fluxes

    fva: float (0->1), or None
    Whether or not to include flux variability analysis in the output.
    If given, fva should be a float between 0 and 1, representing the
    fraction of the optimum objective to be searched.

    """

    def rxn_summary(r):
        return {
            'id': r.id,
            'flux': r.x * r.metabolites[met],
            'reaction': r.reaction,
        }

    flux_summary = pd.DataFrame((rxn_summary(r) for r in met.reactions))
    assert flux_summary.flux.sum() < 1E-6, "Error in flux balance"
    producing = flux_summary[flux_summary.flux > 0].copy()
    consuming = flux_summary[flux_summary.flux < 0].copy()

    for df in [producing, consuming]:
        df['percent'] = df.flux / df.flux.sum()
        df.drop(df[df['percent'] < threshold].index, axis=0,
                inplace=True)

    producing.sort_values('percent', ascending=False, inplace=True)
    consuming.sort_values('percent', ascending=False, inplace=True)

    if not fva:

        producing.flux = producing.flux.apply(
            lambda x: '{:6.2g}'.format(x))
        consuming.flux = consuming.flux.apply(
            lambda x: '{:6.2g}'.format(x))

        flux_len = 6

    else:
        fva_results = pd.DataFrame(
            flux_variability_analysis(met.model, met.reactions,
                                      fraction_of_optimum=fva,
                                      **solver_args)).T
        half_span = (fva_results.maximum - fva_results.minimum) / 2
        median = fva_results.minimum + half_span

        producing.flux = producing.id.apply(
            lambda x, median=median, err=half_span:
            u'{0:0.2f} \u00B1 {1:0.2f}'.format(median[x], err[x]))
        consuming.flux = consuming.id.apply(
            lambda x, median=median, err=half_span:
            u'{0:0.2f} \u00B1 {1:0.2f}'.format(median[x], err[x]))

        flux_len = max(producing.flux.apply(len).max(),
                       consuming.flux.apply(len).max()) + 1

    for df in [producing, consuming]:

        df['reaction'] = df['reaction'].map(
            lambda x: format_long_string(x, 52))
        df['id'] = df['id'].map(
            lambda x: format_long_string(x, 8))

    head = "PRODUCING REACTIONS -- " + format_long_string(met.name, 55)
    print_(head)
    print_("-" * len(head))
    print_(("{0:^6} {1:>" + str(flux_len) + "} {2:>8} {3:^54}").format(
        '%', 'FLUX', 'RXN ID', 'REACTION'))

    for row in producing.iterrows():
        print_((u"{0.percent:6.1%} {0.flux:>" + str(flux_len) +
                "} {0.id:>8} {0.reaction:>54}").format(row[1]))

    print_()
    print_("CONSUMING REACTIONS -- " + format_long_string(met.name, 55))
    print_("-" * len(head))
    print_(("{0:^6} {1:>" + str(flux_len) + "} {2:>8} {3:^54}").format(
        '%', 'FLUX', 'RXN ID', 'REACTION'))

    for row in consuming.iterrows():
        print_((u"{0.percent:6.1%} {0.flux:>" + str(flux_len) +
                "} {0.id:>8} {0.reaction:>54}").format(row[1]))


def model_summary(model, threshold=1E-8, fva=None, digits=2, **solver_args):
    """Print a summary of the input and output fluxes of the model.

    threshold: float
        tolerance for determining if a flux is zero (not printed)

    fva: int or None
        Whether or not to calculate and report flux variability in the
        output summary

    digits: int
        number of digits after the decimal place to print

    """
    obj_fluxes = pd.Series({'{:<15}'.format(r.id): '{:.3f}'.format(r.x)
                            for r in iterkeys(model.objective)})

    if not fva:

        out_rxns = model.reactions.query(
            lambda rxn: rxn.x > threshold, None
        ).query(lambda x: x, 'boundary')

        in_rxns = model.reactions.query(
            lambda rxn: rxn.x < -threshold, None
        ).query(lambda x: x, 'boundary')

        out_fluxes = pd.Series({r.reactants[0]: r.x for r in out_rxns})
        in_fluxes = pd.Series({r.reactants[0]: r.x for r in in_rxns})

        # sort and round
        out_fluxes.sort_values(ascending=False, inplace=True)
        out_fluxes = out_fluxes.round(digits)<commit_msg>Fix to model summary methods (#268)<commit_after>from six.moves import zip_longest
from six import iterkeys, print_, text_type
from warnings import warn

import pandas as pd

from .variability import flux_variability_analysis


def format_long_string(string, max_length):
    if len(string) > max_length:
        string = string[:max_length - 3]
        string += '...'
    return string


def metabolite_summary(met, threshold=0.01, fva=False, **solver_args):
    """Print a summary of the reactions which produce and consume this
    metabolite

    threshold: float
    a value below which to ignore reaction fluxes

    fva: float (0->1), or None
    Whether or not to include flux variability analysis in the output.
    If given, fva should be a float between 0 and 1, representing the
    fraction of the optimum objective to be searched.

    """

    def rxn_summary(r):
        return {
            'id': r.id,
            'flux': r.x * r.metabolites[met],
            'reaction': r.reaction,
        }

    flux_summary = pd.DataFrame((rxn_summary(r) for r in met.reactions))
    assert flux_summary.flux.sum() < 1E-6, "Error in flux balance"
    producing = flux_summary[flux_summary.flux > 0].copy()
    consuming = flux_summary[flux_summary.flux < 0].copy()

    for df in [producing, consuming]:
        df['percent'] = df.flux / df.flux.sum()
        df.drop(df[df['percent'] < threshold].index, axis=0,
                inplace=True)

    producing.sort_values('percent', ascending=False, inplace=True)
    consuming.sort_values('percent', ascending=False, inplace=True)

    if not fva:

        producing.flux = producing.flux.apply(
            lambda x: '{:6.2g}'.format(x))
        consuming.flux = consuming.flux.apply(
            lambda x: '{:6.2g}'.format(x))

        flux_len = 6

    else:
        fva_results = pd.DataFrame(
            flux_variability_analysis(met.model, met.reactions,
                                      fraction_of_optimum=fva,
                                      **solver_args)).T
        half_span = (fva_results.maximum - fva_results.minimum) / 2
        median = fva_results.minimum + half_span

        producing.flux = producing.id.apply(
            lambda x, median=median, err=half_span:
            u'{0:0.2f} \u00B1 {1:0.2f}'.format(median[x], err[x]))
        consuming.flux = consuming.id.apply(
            lambda x, median=median, err=half_span:
            u'{0:0.2f} \u00B1 {1:0.2f}'.format(median[x], err[x]))

        flux_len = max(producing.flux.apply(len).max(),
                       consuming.flux.apply(len).max()) + 1

    for df in [producing, consuming]:

        df['reaction'] = df['reaction'].map(
            lambda x: format_long_string(x, 52))
        df['id'] = df['id'].map(
            lambda x: format_long_string(x, 8))

    head = "PRODUCING REACTIONS -- " + format_long_string(met.name, 55)
    print_(head)
    print_("-" * len(head))
    print_(("{0:^6} {1:>" + str(flux_len) + "} {2:>8} {3:^54}").format(
        '%', 'FLUX', 'RXN ID', 'REACTION'))

    for row in producing.iterrows():
        print_((u"{0.percent:6.1%} {0.flux:>" + str(flux_len) +
                "} {0.id:>8} {0.reaction:>54}").format(row[1]))

    print_()
    print_("CONSUMING REACTIONS -- " + format_long_string(met.name, 55))
    print_("-" * len(head))
    print_(("{0:^6} {1:>" + str(flux_len) + "} {2:>8} {3:^54}").format(
        '%', 'FLUX', 'RXN ID', 'REACTION'))

    for row in consuming.iterrows():
        print_((u"{0.percent:6.1%} {0.flux:>" + str(flux_len) +
                "} {0.id:>8} {0.reaction:>54}").format(row[1]))


def model_summary(model, threshold=1E-8, fva=None, digits=2, **solver_args):
    """Print a summary of the input and output fluxes of the model.

    threshold: float
        tolerance for determining if a flux is zero (not printed)

    fva: int or None
        Whether or not to calculate and report flux variability in the
        output summary

    digits: int
        number of digits after the decimal place to print

    """
    obj_fluxes = pd.Series({'{:<15}'.format(r.id): '{:.3f}'.format(r.x)
                            for r in iterkeys(model.objective)})

    if not fva:

        out_rxns = model.reactions.query(
            lambda rxn: rxn.x > threshold, None
        ).query(lambda x: x, 'boundary')

        in_rxns = model.reactions.query(
            lambda rxn: rxn.x < -threshold, None
        ).query(lambda x: x, 'boundary')

        def get_boundary_species(cobra_reaction):
            """For a given cobra_reaction, find out which species is being
            produced """
            mets = list(iterkeys(cobra_reaction.metabolites))
            if len(mets) != 1:
                warn('The boundary reaction {} exhanges more than one '
                     'metabolite'.format(cobra_reaction.id))

            return mets[0]

        out_fluxes = pd.Series({
            get_boundary_species(r): r.x for r in out_rxns})
        in_fluxes = pd.Series({
            get_boundary_species(r): r.x for r in in_rxns})

        # sort and round
        out_fluxes.sort_values(ascending=False, inplace=True)
        out_fluxes = out_fluxes.round(digits)
{'fraction_non_alphanumeric': 0.1390266113528281, 'fraction_numerical': 0.018314277041384195, 'mean_word_length': 2.3953967708691173, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '901643', 'n_tokens_mistral': 3459, 'n_tokens_neox': 3176, 'n_words': 784}