mirror of
https://github.com/samba-team/samba.git
synced 2025-08-02 00:22:11 +03:00
python/graph: add full_matrix graph function
This makes an ASCII/ANSI art picture like distance_matrix(), but from a full matrix, not a list of adjacencies as in the distance_matrix case. This will be used to visualise up-to-dateness vectors. Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
committed by
Andrew Bartlett
parent
6813e1b3c2
commit
02bca5590c
@ -658,3 +658,165 @@ def distance_matrix(vertices, edges,
|
|||||||
(c_disconn, missing, c_reset))
|
(c_disconn, missing, c_reset))
|
||||||
|
|
||||||
return '\n'.join(lines)
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def pad_char(char, digits, padding=' '):
|
||||||
|
if digits == 1:
|
||||||
|
padding = ''
|
||||||
|
return ' ' * (digits - 1) + char + padding
|
||||||
|
|
||||||
|
|
||||||
|
def transpose_dict_matrix(m):
|
||||||
|
m2 = {}
|
||||||
|
for k1, row in m.items():
|
||||||
|
for k2, dist in row.items():
|
||||||
|
m2.setdefault(k2, {})[k1] = dist
|
||||||
|
return m2
|
||||||
|
|
||||||
|
def full_matrix(rows,
|
||||||
|
utf8=False,
|
||||||
|
colour=None,
|
||||||
|
shorten_names=False,
|
||||||
|
generate_key=False,
|
||||||
|
grouping_function=None,
|
||||||
|
row_comments=None,
|
||||||
|
colour_scale=None,
|
||||||
|
digits=1,
|
||||||
|
ylabel='source',
|
||||||
|
xlabel='destination',
|
||||||
|
transpose=True):
|
||||||
|
lines = []
|
||||||
|
write = lines.append
|
||||||
|
|
||||||
|
if transpose:
|
||||||
|
rows = transpose_dict_matrix(rows)
|
||||||
|
|
||||||
|
use_padding = digits > 1
|
||||||
|
|
||||||
|
charset = CHARSETS['utf8' if utf8 else 'ascii']
|
||||||
|
vertical = pad_char(charset['vertical'], digits)
|
||||||
|
horizontal = charset['horizontal'] * (digits + use_padding)
|
||||||
|
corner = pad_char(charset['corner'], digits,
|
||||||
|
charset['horizontal'])
|
||||||
|
diagonal = pad_char(charset['diagonal'], digits)
|
||||||
|
missing = pad_char(charset['missing'], digits)
|
||||||
|
toobig = pad_char('>', digits)
|
||||||
|
right_arrow = charset['right_arrow']
|
||||||
|
empty = pad_char(' ', digits)
|
||||||
|
|
||||||
|
colours = COLOUR_SETS[colour]
|
||||||
|
|
||||||
|
colour_cycle = cycle(colours.get('alternate rows', ('',)))
|
||||||
|
vertices = list(rows.keys())
|
||||||
|
if grouping_function is not None:
|
||||||
|
# we sort and colour according to the grouping function
|
||||||
|
# which can be used to e.g. alternate colours by site.
|
||||||
|
vertices.sort(key=grouping_function)
|
||||||
|
colour_list = []
|
||||||
|
for k, v in groupby(vertices, key=grouping_function):
|
||||||
|
c = colour_cycle.next()
|
||||||
|
colour_list.extend(c for x in v)
|
||||||
|
else:
|
||||||
|
colour_list = [colour_cycle.next() for v in vertices]
|
||||||
|
|
||||||
|
if shorten_names:
|
||||||
|
vmap, replacements = shorten_vertex_names(vertices, '+',
|
||||||
|
aggressive=True)
|
||||||
|
rows2 = {}
|
||||||
|
for vert, r in rows.items():
|
||||||
|
rows2[vmap[vert]] = dict((vmap[k], v) for k, v in r.items())
|
||||||
|
|
||||||
|
rows = rows2
|
||||||
|
vertices = list(rows.keys())
|
||||||
|
|
||||||
|
vlen = max(6, len(xlabel), max(len(v) for v in vertices))
|
||||||
|
|
||||||
|
# first, the key for the columns
|
||||||
|
c_header = colours.get('header', '')
|
||||||
|
c_disconn = colours.get('disconnected', '')
|
||||||
|
c_conn = colours.get('connected', '')
|
||||||
|
c_reset = colours.get('reset', '')
|
||||||
|
|
||||||
|
if colour_scale is None:
|
||||||
|
colour_scale = len(rows)
|
||||||
|
colour_transitive = get_transitive_colourer(colours, colour_scale)
|
||||||
|
|
||||||
|
vspace = ' ' * vlen
|
||||||
|
verticals = ''
|
||||||
|
write("%s %s %s%s%s" % (vspace,
|
||||||
|
empty * (len(rows) + 1),
|
||||||
|
c_header,
|
||||||
|
xlabel,
|
||||||
|
c_reset))
|
||||||
|
for i, v in enumerate(vertices):
|
||||||
|
j = len(rows) - i
|
||||||
|
c = colour_list[i]
|
||||||
|
if j == 1:
|
||||||
|
start = '%s%s%s%s' % (vspace[:-len(ylabel)],
|
||||||
|
c_header,
|
||||||
|
ylabel,
|
||||||
|
c_reset)
|
||||||
|
else:
|
||||||
|
start = vspace
|
||||||
|
write('%s %s%s%s%s%s %s%s' % (start,
|
||||||
|
verticals,
|
||||||
|
c_reset,
|
||||||
|
c,
|
||||||
|
corner,
|
||||||
|
horizontal * j,
|
||||||
|
v,
|
||||||
|
c_reset
|
||||||
|
))
|
||||||
|
verticals += '%s%s' % (c, vertical)
|
||||||
|
|
||||||
|
end_cell = '%s%s' % (' ' * use_padding, c_reset)
|
||||||
|
overflow = False
|
||||||
|
for i, v in enumerate(vertices):
|
||||||
|
links = rows[v]
|
||||||
|
c = colour_list[i]
|
||||||
|
row = []
|
||||||
|
for v2 in vertices:
|
||||||
|
if v2 not in links:
|
||||||
|
row.append('%s%s%s' % (c_disconn, missing, c_reset))
|
||||||
|
elif v == v2:
|
||||||
|
row.append('%s%s%s%s' % (c_reset, c, diagonal, c_reset))
|
||||||
|
else:
|
||||||
|
link = links[v2]
|
||||||
|
if link >= 10 ** digits:
|
||||||
|
ct = colour_transitive(link)
|
||||||
|
row.append('%s%s%s' % (ct, toobig, c_reset))
|
||||||
|
overflow = True
|
||||||
|
continue
|
||||||
|
if link == 0:
|
||||||
|
ct = c_conn
|
||||||
|
else:
|
||||||
|
ct = colour_transitive(link)
|
||||||
|
row.append('%s%*s%s' % (ct, digits, link, end_cell))
|
||||||
|
|
||||||
|
if row_comments is not None and row_comments[i]:
|
||||||
|
row.append('%s %s %s' % (c_reset, right_arrow, row_comments[i]))
|
||||||
|
|
||||||
|
write('%s%*s%s %s%s' % (c, vlen, v, c_reset,
|
||||||
|
''.join(row), c_reset))
|
||||||
|
|
||||||
|
if overflow or shorten_names:
|
||||||
|
write('')
|
||||||
|
|
||||||
|
if overflow:
|
||||||
|
write("'%s%s%s' means greater than %d " %
|
||||||
|
(colour_transitive(10 ** digits),
|
||||||
|
toobig,
|
||||||
|
c_reset,
|
||||||
|
10 ** digits - 1))
|
||||||
|
|
||||||
|
if shorten_names:
|
||||||
|
example_c = colour_cycle.next()
|
||||||
|
for substitute, original in reversed(replacements):
|
||||||
|
write("'%s%s%s' stands for '%s%s%s'" % (example_c,
|
||||||
|
substitute,
|
||||||
|
c_reset,
|
||||||
|
example_c,
|
||||||
|
original,
|
||||||
|
c_reset))
|
||||||
|
|
||||||
|
return '\n'.join(lines)
|
||||||
|
Reference in New Issue
Block a user