':return: A multi-line string representation of this confusion matrix.
:type truncate: int
:param truncate: If specified, then only show the specified
number of values.  Any sorting (e.g., sort_by_count)
will be performed before truncation.
:param sort_by_count: If true, then sort by the count of each
label in the reference data.  I.e., labels that occur more
frequently in the reference label will be towards the left
edge of the matrix, and labels that occur less frequently
will be towards the right edge.
@todo: add marginals?'

def pretty_format(self, show_percents=False, values_in_chart=True, truncate=None, sort_by_count=False):

    confusion = self._confusion
    values = self._values
    if sort_by_count:
        values = sorted(values, key=(lambda v: (- sum(self._confusion[self._indices[v]]))))
    if truncate:
        values = values[:truncate]
    if values_in_chart:
        value_strings = [(u'%s' % val) for val in values]
    else:
        value_strings = [str((n + 1)) for n in range(len(values))]
    valuelen = max((len(val) for val in value_strings))
    value_format = ((u'%' + repr(valuelen)) + u's    |    ')
    if show_percents:
        entrylen = 6
        entry_format = u'%5.1f%%'
        zerostr = u'                    .'
    else:
        entrylen = len(repr(self._max_conf))
        entry_format = ((u'%' + repr(entrylen)) + u'd')
        zerostr = ((u'    ' * (entrylen - 1)) + u'.')
    s = u''
    for i in range(valuelen):
        s += ((u'    ' * valuelen) + u'    |')
        for val in value_strings:
            if (i >= (valuelen - len(val))):
                s += val[((i - valuelen) + len(val))].rjust((entrylen + 1))
            else:
                s += (u'    ' * (entrylen + 1))
        s += u'    |\n'
    s += (u'%s-+-%s+\n' % ((u'-' * valuelen), (u'-' * ((entrylen + 1) * len(values)))))
    for (val, li) in zip(value_strings, values):
        i = self._indices[li]
        s += (value_format % val)
        for lj in values:
            j = self._indices[lj]
            if (confusion[i][j] == 0):
                s += zerostr
            elif show_percents:
                s += (entry_format % ((100.0 * confusion[i][j]) / self._total))
            else:
                s += (entry_format % confusion[i][j])
            if (i == j):
                prevspace = s.rfind(u'    ')
                s = (((s[:prevspace] + u'<') + s[(prevspace + 1):]) + u'>')
            else:
                s += u'    '
        s += u'|\n'
    s += (u'%s-+-%s+\n' % ((u'-' * valuelen), (u'-' * ((entrylen + 1) * len(values)))))
    s += u'(row    =    reference;    col    =    test)\n'
    if (not values_in_chart):
        s += u'Value    key:\n'
        for (i, value) in enumerate(values):
            s += (u'%6d:    %s\n' % ((i + 1), value))
    return s
