Coverage for /home/deng/Projects/metatree_drawer/treeprofiler_algo/pastml/pastml/visualisation/colour_generator.py: 23%
39 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-03-21 09:19 +0100
« prev ^ index » next coverage.py v7.2.7, created at 2024-03-21 09:19 +0100
1import colorsys
2import os
3import re
5import pandas as pd
7NUM2COLOURS = {
8 1: ['#1b9e77'],
9 2: ['#d95f02', '#1b9e77'],
10 3: ['#a6cee3', '#1f78b4', '#b2df8a'],
11 4: ['#66c2a5', '#fc8d62', '#8da0cb', '#e78ac3'],
12 5: ['#e41a1c', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00'],
13 6: ['#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f'],
14 7: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f'],
15 8: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00'],
16 9: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6'],
17 10: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a'],
18 11: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a',
19 '#ffff99'],
20 12: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a',
21 '#ffff99', '#b15928'],
22 13: ['#cc9566', '#ccc466', '#a4cc66', '#75cc66', '#66cc85', '#66ccb4', '#66b4cc',
23 '#6685cc', '#7566cc', '#a466cc', '#cc66c4', '#cc6695', '#cc6666']
24}
26WHITE = '#ffffff'
29def get_enough_colours(num_unique_values):
30 """
31 Generates and returns an array of `num_unique_values` HEX colours.
32 :param num_unique_values: int, number of colours to be generated.
33 :return: array of str, containing colours in HEX format.
34 """
35 if num_unique_values in NUM2COLOURS:
36 return NUM2COLOURS[num_unique_values]
37 vs = ['#%02x%02x%02x' % tuple(rgb) for rgb in
38 (map(lambda x: int(x * 255), colorsys.hsv_to_rgb(*hsv)) for hsv in
39 ((_ / num_unique_values, 0.25 * (1 + (_ % 3)), .8) for _ in range(1, num_unique_values + 1)))]
40 if num_unique_values < 20:
41 return vs[::5] + vs[1::5] + vs[2::5] + vs[3::5] + vs[4::5]
42 return vs[::10] + vs[1::10] + vs[2::10] + vs[3::10] + vs[4::10] \
43 + vs[5::10] + vs[6::10] + vs[7::10] + vs[8::10] + vs[9::10]
46def hex_to_rgb(value):
47 value = value.lstrip('#')
48 return tuple(int(value[i:i + 2], 16) for i in (0, 2, 4))
51def parse_colours(colours, states):
52 if not isinstance(colours, str) and not isinstance(colours, dict):
53 raise ValueError('Colours must be specified either as a dict or as a path to a csv file, not as {}!'
54 .format(type(colours)))
55 if isinstance(colours, str):
56 if not os.path.exists(colours):
57 raise ValueError('The specified colour file ({}) does not exist.'
58 .format(colours))
59 try:
60 colour_dict = pd.read_csv(colours, header=0, index_col=0, sep='\t')
61 if 'colour' not in colour_dict.columns:
62 raise ValueError('Could not find the "colour" column in the parameter file {}. '
63 'It should be a tab-delimited file with two columns, '
64 'the first one containing character states, '
65 'and the second, named "colour", containing colours if HEX format, e.g. #7566cc.')
66 colour_dict = colour_dict.to_dict()['colour']
67 colours = colour_dict
68 except:
69 raise ValueError('The specified colour file {} is malformatted, '
70 'should be a tab-delimited file with two columns, '
71 'the first one containing character states, '
72 'and the second, named "colour", containing colours if HEX format, e.g. #7566cc.'
73 .format(colours))
74 colours = {str(k.encode('ASCII', 'replace').decode()).strip(): v for (k, v) in colours.items()}
75 colours_specified = set(states) & set(colours.keys())
76 if len(colours_specified) < len(states):
77 raise ValueError('Some colour parameters are specified, but missing the following states: {}'
78 .format(', '.join(set(states) - colours_specified)))
79 else:
80 for state in colours_specified:
81 colour = colours[state]
82 if not re.findall('^[#]([a-zA-Z0-9]{6}|[a-zA-Z0-9]{8})$', colour):
83 raise ValueError('The colour {} specified for {} is not in HEX format (e.g. #7566cc).'.format(colour, state))
84 return [colours[s] for s in states]