Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1191 lines (1073 sloc) 47.5 KB
#!/usr/bin/env python
"""
Colormap-related functions
Authors:
- Arno Klein, 2016 (arno@mindboggle.info) http://binarybottle.com
Copyright 2016, Mindboggle team (http://mindboggle.info), Apache v2.0 License
"""
def distinguishable_colors(ncolors, backgrounds=[[0,0,0],[1,1,1]],
save_csv=True, plot_colormap=True, verbose=True):
"""
Create a colormap of perceptually distinguishable colors.
This program is a Python program based on Tim Holy's 2010-2011
BSD-licensed Matlab program "distinguishable_colors.m"
(https://www.mathworks.com/matlabcentral/fileexchange/
29702-generate-maximally-perceptually-distinct-colors):
"This function generates a set of colors which are distinguishable
by reference to the "Lab" color space, which more closely matches
human color perception than RGB. Given an initial large list of possible
RGB colors, it iteratively chooses the entry in the list that is farthest
(in Lab space) from all previously-chosen entries. While this "greedy"
algorithm does not yield a global maximum, it is simple and efficient.
Moreover, the sequence of colors is consistent no matter how many you
request, which facilitates the users' ability to learn the color order
and avoids major changes in the appearance of plots when adding or
removing lines."
Parameters
----------
ncolors : integer
number of colors for the colormap
backgrounds : list of list(s) of 3 elements between 0 and 1
rgb background colors to initialize and distinguish from
save_csv : Boolean
save colormap as csv file?
plot_colormap : Boolean
plot colormap as horizontal bar chart?
verbose : Boolean
print to stdout?
Returns
-------
colors : numpy ndarray of ndarrays of 3 floats between 0 and 1
rgb colormap
Examples
--------
>>> from mindboggle.mio.colors import distinguishable_colors
>>> ncolors = 31
>>> backgrounds = [[0,0,0],[1,1,1]]
>>> save_csv = False
>>> plot_colormap = False
>>> verbose = False
>>> colors = distinguishable_colors(ncolors, backgrounds,
... save_csv, plot_colormap, verbose)
>>> colors[0]
array([ 0.62068966, 0.06896552, 1. ])
>>> colors[1]
array([ 0. , 0.5862069, 0. ])
>>> colors[2]
array([ 0.75862069, 0.20689655, 0. ])
"""
import numpy as np
import matplotlib.pyplot as plt
from colormath.color_objects import LabColor, AdobeRGBColor
from colormath.color_conversions import convert_color
from colormath.color_diff import delta_e_cie2000
filename = "colormap_of_{0}_distinguishable_colors".format(ncolors)
# ------------------------------------------------------------------------
# Generate a sizable number of RGB triples. This represents our space of
# possible choices. By starting in RGB space, we ensure that all of the
# colors can be generated by the monitor:
# ------------------------------------------------------------------------
n_grid = 30 # number of grid divisions along each axis in RGB space
x = np.linspace(0, 1, num=n_grid, endpoint=True)
R, G, B = np.meshgrid(x, x, x)
ncolors_total = np.size(R)
RGB = np.vstack([np.ravel(R), np.ravel(G), np.ravel(B)])
RGB = [[RGB[0][icolor], RGB[1][icolor], RGB[2][icolor]]
for icolor in range(ncolors_total)]
if ncolors > ncolors_total:
raise IOError("You can't readily distinguish that many colors")
# ------------------------------------------------------------------------
# Convert to Lab color space which better represents human perception:
# ------------------------------------------------------------------------
# https://python-colormath.readthedocs.io/en/latest/illuminants.html
lab_colors = []
for rgb in RGB:
lab = convert_color(AdobeRGBColor(rgb[0],
rgb[1],
rgb[2]), LabColor)
lab_colors.append(lab)
bg_lab_colors = []
for bg_rgb in backgrounds:
bg_lab = convert_color(AdobeRGBColor(bg_rgb[0],
bg_rgb[1],
bg_rgb[2]), LabColor)
bg_lab_colors.append(bg_lab)
# ------------------------------------------------------------------------
# If the user specified multiple background colors, compute differences
# between the candidate colors and the background colors:
# ------------------------------------------------------------------------
min_dx = np.inf * np.ones(ncolors_total)
if backgrounds:
for bg_lab_color in bg_lab_colors:
# Store difference from closest previously-chosen color:
for icolor_total, lab_color in enumerate(lab_colors):
dx = delta_e_cie2000(lab_color, bg_lab_color)
min_dx[icolor_total] = min(dx, min_dx[icolor_total])
# ------------------------------------------------------------------------
# Iteratively pick the color that maximizes the difference
# with the nearest already-picked color:
# ------------------------------------------------------------------------
# Initialize by making the "previous" color equal to the last background:
last_lab_color = bg_lab_colors[-1]
colors = np.zeros((ncolors, 3))
for icolor in range(ncolors):
# Find the difference of the last color from all colors on the list:
for icolor_total, lab_color in enumerate(lab_colors):
dx = delta_e_cie2000(lab_color, last_lab_color)
min_dx[icolor_total] = min(dx, min_dx[icolor_total])
# Find the entry farthest from all previously chosen colors:
imax_dx = np.argmax(min_dx)
# Store distant color:
colors[icolor] = RGB[imax_dx]
# Prepare for next iteration:
last_lab_color = lab_colors[imax_dx]
# ------------------------------------------------------------------------
# Plot the colormap as a horizontal bar chart:
# ------------------------------------------------------------------------
if plot_colormap:
if verbose:
print("RGB values:")
plt.figure(ncolors, figsize=(5, 10))
for icolor in range(ncolors):
ax = plt.subplot(ncolors, 1, icolor + 1)
plt.axis("off")
rgb = colors[icolor]
#rgb = [[rgb.rgb_r, rgb.rgb_g, rgb.rgb_b]]
if verbose:
print(rgb)
plt.barh(0, 50, 1, 0, color=rgb)
plt.savefig(filename + ".png")
if verbose:
print("Colormap image saved to {0}".format(filename + ".png"))
# ------------------------------------------------------------------------
# Save the colormap as a csv file:
# ------------------------------------------------------------------------
if save_csv:
np.savetxt(filename + ".csv", colors, fmt='%.18e', delimiter=',',
newline='\n', header='')
if verbose:
print("Colormap saved to {0}".format(filename + ".csv"))
return colors
def label_adjacency_matrix(label_file, ignore_values=[-1, 999], add_value=0,
save_table=True, output_format='csv',
verbose=True):
"""
Extract surface or volume label boundaries, find unique label pairs,
and write adjacency matrix (useful for constructing a colormap).
Each row of the (upper triangular) adjacency matrix corresponds to an
index to a unique label, where each column has a 1 if the label indexed
by that column is adjacent to the label indexed by the row.
Parameters
----------
label_file : string
path to VTK surface file or nibabel-readable volume file with labels
ignore_values : list of integers
labels to ignore
add_value : integer
value to add to labels
matrix : pandas dataframe
adjacency matrix
save_table : Boolean
output table file?
output_format : string
format of adjacency table file name (currently only 'csv')
verbose : Boolean
print to stdout?
Returns
-------
labels : list
label numbers
matrix : pandas DataFrame
adjacency matrix
output_table : string
adjacency table file name
Examples
--------
>>> from mindboggle.mio.colors import label_adjacency_matrix
>>> from mindboggle.mio.fetch_data import prep_tests
>>> urls, fetch_data = prep_tests()
>>> ignore_values = [-1, 0]
>>> add_value = 0
>>> save_table = False
>>> output_format = 'csv'
>>> verbose = False
>>> label_file = fetch_data(urls['left_manual_labels'], '', '.vtk')
>>> labels, matrix, output_table = label_adjacency_matrix(label_file,
... ignore_values, add_value, save_table, output_format, verbose)
>>> matrix.lookup([20,21,22,23,24,25,26,27,28,29],
... [35,35,35,35,35,35,35,35,35,35])
array([ 0., 1., 0., 0., 0., 0., 0., 1., 1., 1.])
>>> label_file = fetch_data(urls['freesurfer_labels'], '', '.nii.gz')
>>> labels, matrix, output_table = label_adjacency_matrix(label_file,
... ignore_values, add_value, save_table, output_format, verbose)
>>> matrix.lookup([4,5,7,8,10,11,12,13,14,15], [4,4,4,4,4,4,4,4,4,4])
array([ 1., 1., 0., 0., 0., 1., 0., 0., 1., 0.])
"""
import numpy as np
import pandas as pd
from nibabel import load
from scipy import ndimage
from mindboggle.guts.mesh import find_neighbors
from mindboggle.guts.segment import extract_borders
from mindboggle.mio.vtks import read_vtk
# Use Mindboggle's extract_borders() function for surface VTK files:
if label_file.endswith('.vtk'):
f1,f2,f3, faces, labels, f4, npoints, f5 = read_vtk(label_file,
True, True)
neighbor_lists = find_neighbors(faces, npoints)
return_label_pairs = True
indices_borders, label_pairs, f1 = extract_borders(list(range(npoints)),
labels, neighbor_lists, ignore_values, return_label_pairs)
output_table = 'adjacent_surface_labels.' + output_format
# Use scipy to dilate volume files to find neighboring labels:
elif label_file.endswith('.nii.gz'):
L = load(label_file).get_data()
unique_volume_labels = np.unique(L)
label_pairs = []
for label in unique_volume_labels:
if label not in ignore_values:
B = L * np.logical_xor(ndimage.binary_dilation(L==int(label)),
(L==int(label)))
neighbor_labels = np.unique(np.ravel(B))
for neigh in neighbor_labels:
if neigh > 0 and neigh in unique_volume_labels:
# and neigh%2==(int(label)%2):
label_pairs.append([int(label), int(neigh)])
output_table = 'adjacent_volume_labels.' + output_format
else:
raise IOError("Use appropriate input file type.")
# Find unique pairs (or first two of each list):
pairs = []
for pair in label_pairs:
new_pair = [int(pair[0]) + add_value,
int(pair[1]) + add_value]
if new_pair not in pairs:
pairs.append(new_pair)
# Write adjacency matrix:
unique_labels = np.unique(pairs)
nlabels = np.size(unique_labels)
matrix = np.zeros((nlabels, nlabels))
for pair in pairs:
index1 = [i for i, x in enumerate(unique_labels) if x == pair[0]]
index2 = [i for i, x in enumerate(unique_labels) if x == pair[1]]
matrix[index1, index2] = 1
df1 = pd.DataFrame({'ID': unique_labels}, index=None)
df2 = pd.DataFrame(matrix, index=None)
df2.columns = unique_labels
matrix = pd.concat([df1, df2], axis=1)
if save_table:
if output_format == 'csv':
matrix.to_csv(output_table, index=False)
if verbose:
print("Adjacency matrix saved to {0}".format(output_table))
else:
raise IOError("Set appropriate output file format.")
else:
output_table = None
labels = list(unique_labels)
return labels, matrix, output_table
def group_colors(colormap, colormap_name, description='', adjacency_matrix=[],
IDs=[], names=[], groups=[],
save_text_files=True, plot_colors=True,
plot_graphs=True, out_dir='.', verbose=True):
"""
This greedy algoritm reorders a colormap so that labels assigned to
the same group have more similar colors, but within a group (usually
of adjacent labels), the colors are reordered so that adjacent labels
have dissimilar colors:
1. Convert colormap to Lab color space
which better represents human perception.
2. Load a binary (or weighted) adjacency matrix, where each row or column
represents a label, and each value signifies whether (or the degree
to which) a given pair of labels are adjacent.
If a string (file) is provided instead of a numpy ndarray:
column 0 = label "ID" number
column 1 = label "name"
column 2 = "group" number (each label is assigned to a group)
columns 3... = label adjacency matrix
3. Sort labels by decreasing number of adjacent labels (adjacency sum).
4. Order label groups by decreasing maximum adjacency sum.
5. Create a similarity matrix for pairs of colors.
6. Sort colors by decreasing perceptual difference from all other colors.
7. For each label group:
7.1. Select unpicked colors for group that are similar to the first
unpicked color (unpicked colors were sorted above by decreasing
perceptual difference from all other colors).
7.2. Reorder subgraph colors according to label adjacency sum
(decreasing number of adjacent labels).
8. Assign new colors.
For plotting graphs and colormap:
1. Convert the matrix to a graph, where each node represents a label
and each edge represents the adjacency value between connected nodes.
2. Break up the graph into subgraphs, where each subgraph contains labels
assigned the same group number (which usually means they are adjacent).
3. Plot the colormap and colored sub/graphs.
NOTE: Requires pydotplus
Parameters
----------
colormap : string or numpy ndarray of ndarrays of 3 floats between 0 and 1
csv file containing rgb colormap, or colormap array
colormap_name : string
name of colormap
description : string
description of colormap
adjacency_matrix : string or NxN numpy ndarray (N = number of labels)
csv file containing label adjacency matrix or matrix itself
IDs : list of integers
label ID numbers
names : list of strings
label names
groups : list of integers
label group numbers (one per label)
save_text_files : Boolean
save colormap as csv and json files?
plot_colors : Boolean
plot colormap as horizontal bar chart?
plot_graphs : Boolean
plot colormap as graphs?
out_dir : string
output directory path
verbose : Boolean
print to stdout?
Returns
-------
colors : numpy ndarray of ndarrays of 3 floats between 0 and 1
rgb colormap
Examples
--------
>>> # Get colormap:
>>> from mindboggle.mio.colors import distinguishable_colors
>>> colormap = distinguishable_colors(ncolors=31,
... backgrounds=[[0,0,0],[1,1,1]],
... save_csv=False, plot_colormap=False, verbose=False)
>>> # Get adjacency matrix:
>>> from mindboggle.mio.colors import label_adjacency_matrix
>>> from mindboggle.mio.fetch_data import prep_tests
>>> urls, fetch_data = prep_tests()
>>> label_file = fetch_data(urls['left_manual_labels'], '', '.vtk')
>>> IDs, adjacency_matrix, output_table = label_adjacency_matrix(label_file,
... ignore_values=[-1, 0], add_value=0, save_table=False,
... output_format='', verbose=False)
>>> adjacency_matrix = adjacency_matrix.values
>>> adjacency_matrix = adjacency_matrix[:, 1::]
>>> # Reorganize colormap:
>>> from mindboggle.mio.colors import group_colors
>>> from mindboggle.mio.labels import DKTprotocol
>>> dkt = DKTprotocol()
>>> colormap_name = "DKT31colormap"
>>> description = "Colormap for DKT31 human brain cortical labels"
>>> save_text_files = True
>>> plot_colors = False
>>> plot_graphs = False
>>> out_dir = '.'
>>> verbose = False
>>> #IDs = dkt.DKT31_numbers
>>> names = dkt.DKT31_names #dkt.left_cerebrum_cortex_DKT31_names
>>> groups = dkt.DKT31_groups
>>> colors = group_colors(colormap, colormap_name, description,
... adjacency_matrix, IDs, names, groups,
... save_text_files, plot_colors, plot_graphs, out_dir, verbose)
>>> colors[0]
[0.7586206896551724, 0.20689655172413793, 0.0]
>>> colors[1]
[0.48275862068965514, 0.4482758620689655, 0.48275862068965514]
>>> colors[2]
[0.3448275862068966, 0.3103448275862069, 0.034482758620689655]
>>> colors[-1]
[0.7931034482758621, 0.9655172413793103, 0.7931034482758621]
No groups / subgraphs:
>>> groups = []
>>> colors = group_colors(colormap, colormap_name, description,
... adjacency_matrix, IDs, names, groups,
... save_text_files, plot_colors, plot_graphs, out_dir, verbose)
>>> colors[0]
[0.5172413793103449, 0.8275862068965517, 1.0]
>>> colors[1]
[0.13793103448275862, 0.0, 0.24137931034482757]
>>> colors[2]
[0.3793103448275862, 0.27586206896551724, 0.48275862068965514]
>>> colors[-1]
[0.6206896551724138, 0.48275862068965514, 0.3448275862068966]
"""
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from colormath.color_diff import delta_e_cie2000
from colormath.color_objects import LabColor, AdobeRGBColor
from colormath.color_conversions import convert_color
import itertools
from mindboggle.mio.colors import write_json_colormap, write_xml_colormap
# ------------------------------------------------------------------------
# Set parameters for graph layout and output files:
# ------------------------------------------------------------------------
if plot_graphs:
graph_node_size = 1000
graph_edge_width = 2
graph_font_size = 10
subgraph_node_size = 3000
subgraph_edge_width = 5
subgraph_font_size = 18
axis_buffer = 10
graph_image_file = os.path.join(out_dir, "label_graph.png")
subgraph_image_file_pre = os.path.join(out_dir, "label_subgraph")
subgraph_image_file_post = ".png"
if plot_colors:
colormap_image_file = os.path.join(out_dir, 'label_colormap.png')
if save_text_files:
colormap_csv_file = os.path.join(out_dir, 'label_colormap.csv')
colormap_json_file = os.path.join(out_dir, 'label_colormap.json')
colormap_xml_file = os.path.join(out_dir, 'label_colormap.xml')
run_permutations = False
# ------------------------------------------------------------------------
# Load colormap:
# ------------------------------------------------------------------------
if verbose:
print("Load colormap and convert to CIELAB color space.")
if isinstance(colormap, np.ndarray):
colors = colormap
elif isinstance(colormap, str):
colors = pd.read_csv(colormap, sep=',', header=None)
colors = colors.values
else:
raise IOError("Please use correct format for colormap.")
nlabels = np.shape(colors)[0]
new_colors = np.copy(colors)
if not IDs:
IDs = range(nlabels)
if not names:
names = [str(x) for x in range(nlabels)]
if not groups:
groups = [1 for x in range(nlabels)]
# ------------------------------------------------------------------------
# Convert to Lab color space which better represents human perception:
# ------------------------------------------------------------------------
# https://python-colormath.readthedocs.io/en/latest/illuminants.html
lab_colors = []
for rgb in colors:
lab_colors.append(convert_color(AdobeRGBColor(rgb[0], rgb[1], rgb[2]),
LabColor))
# ------------------------------------------------------------------------
# Load label adjacency matrix:
# ------------------------------------------------------------------------
if np.size(adjacency_matrix):
if verbose:
print("Load label adjacency matrix.")
if isinstance(adjacency_matrix, np.ndarray):
adjacency_values = adjacency_matrix
# If a string (file) is provided instead of a numpy ndarray:
# column 0 = label "ID" number
# column 1 = label "name"
# column 2 = "group" number (each label is assigned to a group)
# columns 3... = label adjacency matrix
elif isinstance(adjacency_matrix, str):
matrix = pd.read_csv(adjacency_matrix, sep=',', header=None)
matrix = matrix.values
IDs = matrix.ID
names = matrix.name
groups = matrix.group
adjacency_values = matrix[[str(x) for x in IDs]].values
else:
raise IOError("Please use correct format for adjacency matrix.")
if np.shape(adjacency_values)[0] != nlabels:
raise IOError("The colormap and label adjacency matrix don't "
"have the same number of labels.")
# Normalize adjacency values:
adjacency_values = adjacency_values / np.max(adjacency_values)
else:
plot_graphs = False
# ------------------------------------------------------------------------
# Sort labels by decreasing number of adjacent labels (adjacency sum):
# ------------------------------------------------------------------------
if np.size(adjacency_matrix):
adjacency_sums = np.sum(adjacency_values, axis = 1) # sum rows
isort_labels = np.argsort(adjacency_sums)[::-1]
else:
isort_labels = range(nlabels)
# ------------------------------------------------------------------------
# Order label groups by decreasing maximum adjacency sum:
# ------------------------------------------------------------------------
label_groups = np.unique(groups)
if np.size(adjacency_matrix):
max_adjacency_sums = []
for label_group in label_groups:
igroup = [i for i,x in enumerate(groups) if x == label_group]
max_adjacency_sums.append(max(adjacency_sums[igroup]))
label_groups = label_groups[np.argsort(max_adjacency_sums)[::-1]]
# ------------------------------------------------------------------------
# Convert adjacency matrix to graph for plotting:
# ------------------------------------------------------------------------
if plot_graphs:
adjacency_graph = nx.from_numpy_matrix(adjacency_values)
for inode in range(nlabels):
adjacency_graph.node[inode]['ID'] = IDs[inode]
adjacency_graph.node[inode]['label'] = names[inode]
adjacency_graph.node[inode]['group'] = groups[inode]
# ------------------------------------------------------------------------
# Create a similarity matrix for pairs of colors:
# ------------------------------------------------------------------------
if verbose:
print("Create a similarity matrix for pairs of colors.")
dx_matrix = np.zeros((nlabels, nlabels))
for icolor1 in range(nlabels):
for icolor2 in range(nlabels):
dx_matrix[icolor1,icolor2] = delta_e_cie2000(lab_colors[icolor1],
lab_colors[icolor2])
# ------------------------------------------------------------------------
# Sort colors by decreasing perceptual difference from all other colors:
# ------------------------------------------------------------------------
icolors_to_pick = list(np.argsort(np.sum(dx_matrix, axis = 1))[::-1])
# ------------------------------------------------------------------------
# Loop through label groups:
# ------------------------------------------------------------------------
for label_group in label_groups:
if verbose:
print("Labels in group {0}...".format(label_group))
igroup = [i for i,x in enumerate(groups) if x == label_group]
N = len(igroup)
# --------------------------------------------------------------------
# Select unpicked colors for group that are similar to the first
# unpicked color (unpicked colors were sorted above by decreasing
# perceptual difference from all other colors):
# --------------------------------------------------------------------
isimilar = np.argsort(dx_matrix[icolors_to_pick[0],
icolors_to_pick])[0:N]
icolors_to_pick_copy = icolors_to_pick.copy()
group_colors = [list(colors[icolors_to_pick[i]]) for i in isimilar]
if run_permutations:
group_lab_colors = [lab_colors[icolors_to_pick[i]]
for i in isimilar]
for iremove in isimilar:
icolors_to_pick.remove(icolors_to_pick_copy[iremove])
# --------------------------------------------------------------------
# Reorder group colors according to label adjacency sum
# (decreasing number of adjacent labels):
# --------------------------------------------------------------------
isort_group_labels = np.argsort(isort_labels[igroup])
group_colors = [group_colors[i] for i in isort_group_labels]
# --------------------------------------------------------------------
# Compute differences between every pair of colors within group:
# --------------------------------------------------------------------
weights = False
if run_permutations:
permutation_max = np.zeros(N)
NxN_matrix = np.zeros((N, N))
# ----------------------------------------------------------------
# Extract group adjacency submatrix:
# ----------------------------------------------------------------
neighbor_matrix = adjacency_values[igroup, :][:, igroup]
if not weights:
neighbor_matrix = (neighbor_matrix > 0).astype(np.uint8)
# ----------------------------------------------------------------
# Permute colors and color pair differences:
# ----------------------------------------------------------------
DEmax = 0
permutations = [np.array(s) for s
in itertools.permutations(range(0, N), N)]
if verbose:
print(" ".join([str(N),'labels,',
str(len(permutations)),
'permutations:']))
for permutation in permutations:
delta_matrix = NxN_matrix.copy()
for i1 in range(N):
for i2 in range(N):
if (i2 > i1) and (neighbor_matrix[i1, i2] > 0):
delta_matrix[i1,i2] = delta_e_cie2000(group_lab_colors[i1],
group_lab_colors[i2])
if weights:
DE = np.sum((delta_matrix * neighbor_matrix))
else:
DE = np.sum(delta_matrix)
# ------------------------------------------------------------
# Store color permutation with maximum adjacency cost:
# ------------------------------------------------------------
if DE > DEmax:
DEmax = DE
permutation_max = permutation
# ------------------------------------------------------------
# Reorder group colors by the maximum adjacency cost:
# ------------------------------------------------------------
group_colors = [group_colors[x] for x in permutation_max]
new_colors[isimilar] = group_colors
# --------------------------------------------------------------------
# Assign new colors:
# --------------------------------------------------------------------
else:
new_colors[isimilar] = group_colors
# --------------------------------------------------------------------
# Draw a figure of the colored subgraph:
# --------------------------------------------------------------------
if plot_graphs:
plt.figure(label_group)
subgraph = adjacency_graph.subgraph(igroup)
# Layout:
pos = nx.nx_pydot.graphviz_layout(subgraph,
prog="neato")
nx.draw(subgraph, pos, node_size=subgraph_node_size,
width=subgraph_edge_width, alpha=0.5,
with_labels=False)
# Labels:
labels={}
for iN in range(N):
labels[subgraph.nodes()[iN]] = \
subgraph.node[subgraph.nodes()[iN]]['label']
nx.draw_networkx_labels(subgraph, pos, labels,
font_size=subgraph_font_size,
font_color='black')
# Nodes:
nodelist = list(subgraph.node.keys())
for iN in range(N):
nx.draw_networkx_nodes(subgraph, pos,
node_size=subgraph_node_size,
nodelist=[nodelist[iN]],
node_color=group_colors[iN])
# Figure:
ax = plt.gca().axis()
plt.gca().axis([ax[0]-axis_buffer, ax[1]+axis_buffer,
ax[2]-axis_buffer, ax[3]+axis_buffer])
plt.savefig(subgraph_image_file_pre + str(int(label_group)) +
subgraph_image_file_post)
#plt.show()
# ------------------------------------------------------------------------
# Plot the entire graph (without colors):
# ------------------------------------------------------------------------
if plot_graphs:
plt.figure(nlabels)
# Graph:
pos = nx.nx_pydot.graphviz_layout(adjacency_graph, prog="neato")
nx.draw(adjacency_graph, pos,
node_color='yellow',
node_size=graph_node_size,
width=graph_edge_width,
with_labels=False)
# Labels:
labels={}
for ilabel in range(nlabels):
labels[ilabel] = adjacency_graph.node[ilabel]['label']
nx.draw_networkx_labels(adjacency_graph, pos, labels,
font_size=graph_font_size,
font_color='black')
# # Nodes:
# nodelist = list(adjacency_graph.node.keys())
# for icolor, new_color in enumerate(new_colors):
# nx.draw_networkx_nodes(subgraph, pos,
# node_size=graph_node_size,
# nodelist=[nodelist[icolor]],
# node_color=new_color)
plt.savefig(graph_image_file)
plt.show()
# ------------------------------------------------------------------------
# Plot the subgraphs (colors):
# ------------------------------------------------------------------------
if plot_graphs:
for label_group in label_groups:
plt.figure(label_group)
plt.show()
# ------------------------------------------------------------------------
# Plot the colormap as a horizontal bar chart:
# ------------------------------------------------------------------------
if plot_colors:
plt.figure(nlabels, figsize=(5, 10))
for ilabel in range(nlabels):
ax = plt.subplot(nlabels, 1, ilabel + 1)
plt.axis("off")
rgb = new_colors[ilabel]
plt.barh(0, 50, 1, 0, color=rgb)
plt.savefig(colormap_image_file)
plt.show()
# ------------------------------------------------------------------------
# Save new colormap as text files:
# ------------------------------------------------------------------------
if save_text_files:
# ------------------------------------------------------------------------
# Save new colormap as a csv file:
# ------------------------------------------------------------------------
np.savetxt(colormap_csv_file, new_colors, fmt='%.18e', delimiter=',',
newline='\n', header='')
# ------------------------------------------------------------------------
# Save new colormap as a json file:
# ------------------------------------------------------------------------
write_json_colormap(colormap=new_colors, label_numbers=IDs,
label_names=names,
colormap_file=colormap_json_file,
colormap_name=colormap_name,
description=description)
# ------------------------------------------------------------------------
# Save new colormap as an xml file:
# ------------------------------------------------------------------------
write_xml_colormap(colormap=new_colors, label_numbers=IDs,
colormap_file=colormap_xml_file,
colormap_name=colormap_name)
# ------------------------------------------------------------------------
# Return new colors:
# ------------------------------------------------------------------------
colors = new_colors.tolist()
return colors
def write_json_colormap(colormap, label_numbers, label_names=[],
colormap_file='', colormap_name='', description=''):
"""
Write colormap to json format.
Parameters
----------
colormap : numpy ndarray or list of lists of string and floats
label, 1, red, green, blue
label_names : list of strings
label names
label_numbers : list of integers
label numbers
colormap_file : string
output json file name
colormap_name : string
name of colormap
description : string
description of colormap
Examples
--------
>>> from mindboggle.mio.colors import write_xml_colormap
>>> from mindboggle.mio.labels import DKTprotocol
>>> dkt = DKTprotocol()
>>> colormap = dkt.colormap_normalized
>>> colormap = [[x[2], x[3], x[4]] for x in colormap]
>>> label_numbers = dkt.label_numbers
>>> label_names = dkt.label_names
>>> colormap_file = ''
>>> colormap_name = "DKT31colormap"
>>> description = "Colormap for DKT31 human brain cortical labels"
>>> colormap[0]
[0.803921568627451, 0.24313725490196078, 0.3058823529411765]
>>> write_json_colormap(colormap, label_numbers, label_names,
... colormap_file, colormap_name, description)
"""
if not colormap_file:
colormap_file = 'label_colormap.json'
if not colormap_name:
colormap_name = 'Colormap'
f = open(colormap_file, 'w')
f.write("{\n")
f.write(' "name": "{0}",\n'.format(colormap_name))
f.write(' "description": "{0}",\n'.format(description))
f.write(' "colormap": [\n')
for icolor, color in enumerate(colormap):
if icolor == len(colormap) - 1:
end_comma = ''
else:
end_comma = ','
f.write(' {0}"ID": "{1}", "name": "{2}", '
'"red": "{3}", "green": "{4}", "blue": "{5}"{6}{7}\n'.
format("{", label_numbers[icolor], label_names[icolor],
color[0], color[1], color[2], "}", end_comma))
f.write(']}')
f.close()
def write_xml_colormap(colormap, label_numbers, colormap_file='',
colormap_name=''):
"""
Write colormap to xml format.
Parameters
----------
colormap : numpy ndarray or list of lists of string and floats
label, 1, red, green, blue
label_numbers : list of integers
label numbers
colormap_file : string
output xml file name
colormap_name : string
name of colormap
Examples
--------
>>> from mindboggle.mio.colors import write_xml_colormap
>>> from mindboggle.mio.labels import DKTprotocol
>>> dkt = DKTprotocol()
>>> colormap = dkt.colormap_normalized
>>> colormap = [[x[2], x[3], x[4]] for x in colormap]
>>> label_numbers = dkt.label_numbers
>>> colormap_file = ''
>>> colormap_name = 'DKT31colormap'
>>> colormap[0]
[0.803921568627451, 0.24313725490196078, 0.3058823529411765]
>>> write_xml_colormap(colormap, label_numbers, colormap_file,
... colormap_name)
"""
if not colormap_file:
colormap_file = 'label_colormap.xml'
if not colormap_name:
colormap_name = 'Colormap'
f = open(colormap_file,'w')
f.write('''
<ColorMap name="{0}" space="RGB">
<NaN r="0" g="0" b="0"/>
<Point x="-1" o="0" r="0" g="0" b="0"/>
'''.format(colormap_name))
for icolor, color in enumerate(colormap):
f.write(''' <Point x="{0}" o="1" r="{1}" g="{2}" b="{3}"/>
'''.format(label_numbers[icolor], color[0], color[1], color[2]))
f.write('''
</ColorMap>
''')
f.close()
def viridis_colormap():
"""
https://github.com/BIDS/colormap/blob/master/colormaps.py
Returns
-------
viridis : list of lists of three floats
viridis colormap
"""
viridis = [[0.267004, 0.004874, 0.329415],
[0.268510, 0.009605, 0.335427],
[0.269944, 0.014625, 0.341379],
[0.271305, 0.019942, 0.347269],
[0.272594, 0.025563, 0.353093],
[0.273809, 0.031497, 0.358853],
[0.274952, 0.037752, 0.364543],
[0.276022, 0.044167, 0.370164],
[0.277018, 0.050344, 0.375715],
[0.277941, 0.056324, 0.381191],
[0.278791, 0.062145, 0.386592],
[0.279566, 0.067836, 0.391917],
[0.280267, 0.073417, 0.397163],
[0.280894, 0.078907, 0.402329],
[0.281446, 0.084320, 0.407414],
[0.281924, 0.089666, 0.412415],
[0.282327, 0.094955, 0.417331],
[0.282656, 0.100196, 0.422160],
[0.282910, 0.105393, 0.426902],
[0.283091, 0.110553, 0.431554],
[0.283197, 0.115680, 0.436115],
[0.283229, 0.120777, 0.440584],
[0.283187, 0.125848, 0.444960],
[0.283072, 0.130895, 0.449241],
[0.282884, 0.135920, 0.453427],
[0.282623, 0.140926, 0.457517],
[0.282290, 0.145912, 0.461510],
[0.281887, 0.150881, 0.465405],
[0.281412, 0.155834, 0.469201],
[0.280868, 0.160771, 0.472899],
[0.280255, 0.165693, 0.476498],
[0.279574, 0.170599, 0.479997],
[0.278826, 0.175490, 0.483397],
[0.278012, 0.180367, 0.486697],
[0.277134, 0.185228, 0.489898],
[0.276194, 0.190074, 0.493001],
[0.275191, 0.194905, 0.496005],
[0.274128, 0.199721, 0.498911],
[0.273006, 0.204520, 0.501721],
[0.271828, 0.209303, 0.504434],
[0.270595, 0.214069, 0.507052],
[0.269308, 0.218818, 0.509577],
[0.267968, 0.223549, 0.512008],
[0.266580, 0.228262, 0.514349],
[0.265145, 0.232956, 0.516599],
[0.263663, 0.237631, 0.518762],
[0.262138, 0.242286, 0.520837],
[0.260571, 0.246922, 0.522828],
[0.258965, 0.251537, 0.524736],
[0.257322, 0.256130, 0.526563],
[0.255645, 0.260703, 0.528312],
[0.253935, 0.265254, 0.529983],
[0.252194, 0.269783, 0.531579],
[0.250425, 0.274290, 0.533103],
[0.248629, 0.278775, 0.534556],
[0.246811, 0.283237, 0.535941],
[0.244972, 0.287675, 0.537260],
[0.243113, 0.292092, 0.538516],
[0.241237, 0.296485, 0.539709],
[0.239346, 0.300855, 0.540844],
[0.237441, 0.305202, 0.541921],
[0.235526, 0.309527, 0.542944],
[0.233603, 0.313828, 0.543914],
[0.231674, 0.318106, 0.544834],
[0.229739, 0.322361, 0.545706],
[0.227802, 0.326594, 0.546532],
[0.225863, 0.330805, 0.547314],
[0.223925, 0.334994, 0.548053],
[0.221989, 0.339161, 0.548752],
[0.220057, 0.343307, 0.549413],
[0.218130, 0.347432, 0.550038],
[0.216210, 0.351535, 0.550627],
[0.214298, 0.355619, 0.551184],
[0.212395, 0.359683, 0.551710],
[0.210503, 0.363727, 0.552206],
[0.208623, 0.367752, 0.552675],
[0.206756, 0.371758, 0.553117],
[0.204903, 0.375746, 0.553533],
[0.203063, 0.379716, 0.553925],
[0.201239, 0.383670, 0.554294],
[0.199430, 0.387607, 0.554642],
[0.197636, 0.391528, 0.554969],
[0.195860, 0.395433, 0.555276],
[0.194100, 0.399323, 0.555565],
[0.192357, 0.403199, 0.555836],
[0.190631, 0.407061, 0.556089],
[0.188923, 0.410910, 0.556326],
[0.187231, 0.414746, 0.556547],
[0.185556, 0.418570, 0.556753],
[0.183898, 0.422383, 0.556944],
[0.182256, 0.426184, 0.557120],
[0.180629, 0.429975, 0.557282],
[0.179019, 0.433756, 0.557430],
[0.177423, 0.437527, 0.557565],
[0.175841, 0.441290, 0.557685],
[0.174274, 0.445044, 0.557792],
[0.172719, 0.448791, 0.557885],
[0.171176, 0.452530, 0.557965],
[0.169646, 0.456262, 0.558030],
[0.168126, 0.459988, 0.558082],
[0.166617, 0.463708, 0.558119],
[0.165117, 0.467423, 0.558141],
[0.163625, 0.471133, 0.558148],
[0.162142, 0.474838, 0.558140],
[0.160665, 0.478540, 0.558115],
[0.159194, 0.482237, 0.558073],
[0.157729, 0.485932, 0.558013],
[0.156270, 0.489624, 0.557936],
[0.154815, 0.493313, 0.557840],
[0.153364, 0.497000, 0.557724],
[0.151918, 0.500685, 0.557587],
[0.150476, 0.504369, 0.557430],
[0.149039, 0.508051, 0.557250],
[0.147607, 0.511733, 0.557049],
[0.146180, 0.515413, 0.556823],
[0.144759, 0.519093, 0.556572],
[0.143343, 0.522773, 0.556295],
[0.141935, 0.526453, 0.555991],
[0.140536, 0.530132, 0.555659],
[0.139147, 0.533812, 0.555298],
[0.137770, 0.537492, 0.554906],
[0.136408, 0.541173, 0.554483],
[0.135066, 0.544853, 0.554029],
[0.133743, 0.548535, 0.553541],
[0.132444, 0.552216, 0.553018],
[0.131172, 0.555899, 0.552459],
[0.129933, 0.559582, 0.551864],
[0.128729, 0.563265, 0.551229],
[0.127568, 0.566949, 0.550556],
[0.126453, 0.570633, 0.549841],
[0.125394, 0.574318, 0.549086],
[0.124395, 0.578002, 0.548287],
[0.123463, 0.581687, 0.547445],
[0.122606, 0.585371, 0.546557],
[0.121831, 0.589055, 0.545623],
[0.121148, 0.592739, 0.544641],
[0.120565, 0.596422, 0.543611],
[0.120092, 0.600104, 0.542530],
[0.119738, 0.603785, 0.541400],
[0.119512, 0.607464, 0.540218],
[0.119423, 0.611141, 0.538982],
[0.119483, 0.614817, 0.537692],
[0.119699, 0.618490, 0.536347],
[0.120081, 0.622161, 0.534946],
[0.120638, 0.625828, 0.533488],
[0.121380, 0.629492, 0.531973],
[0.122312, 0.633153, 0.530398],
[0.123444, 0.636809, 0.528763],
[0.124780, 0.640461, 0.527068],
[0.126326, 0.644107, 0.525311],
[0.128087, 0.647749, 0.523491],
[0.130067, 0.651384, 0.521608],
[0.132268, 0.655014, 0.519661],
[0.134692, 0.658636, 0.517649],
[0.137339, 0.662252, 0.515571],
[0.140210, 0.665859, 0.513427],
[0.143303, 0.669459, 0.511215],
[0.146616, 0.673050, 0.508936],
[0.150148, 0.676631, 0.506589],
[0.153894, 0.680203, 0.504172],
[0.157851, 0.683765, 0.501686],
[0.162016, 0.687316, 0.499129],
[0.166383, 0.690856, 0.496502],
[0.170948, 0.694384, 0.493803],
[0.175707, 0.697900, 0.491033],
[0.180653, 0.701402, 0.488189],
[0.185783, 0.704891, 0.485273],
[0.191090, 0.708366, 0.482284],
[0.196571, 0.711827, 0.479221],
[0.202219, 0.715272, 0.476084],
[0.208030, 0.718701, 0.472873],
[0.214000, 0.722114, 0.469588],
[0.220124, 0.725509, 0.466226],
[0.226397, 0.728888, 0.462789],
[0.232815, 0.732247, 0.459277],
[0.239374, 0.735588, 0.455688],
[0.246070, 0.738910, 0.452024],
[0.252899, 0.742211, 0.448284],
[0.259857, 0.745492, 0.444467],
[0.266941, 0.748751, 0.440573],
[0.274149, 0.751988, 0.436601],
[0.281477, 0.755203, 0.432552],
[0.288921, 0.758394, 0.428426],
[0.296479, 0.761561, 0.424223],
[0.304148, 0.764704, 0.419943],
[0.311925, 0.767822, 0.415586],
[0.319809, 0.770914, 0.411152],
[0.327796, 0.773980, 0.406640],
[0.335885, 0.777018, 0.402049],
[0.344074, 0.780029, 0.397381],
[0.352360, 0.783011, 0.392636],
[0.360741, 0.785964, 0.387814],
[0.369214, 0.788888, 0.382914],
[0.377779, 0.791781, 0.377939],
[0.386433, 0.794644, 0.372886],
[0.395174, 0.797475, 0.367757],
[0.404001, 0.800275, 0.362552],
[0.412913, 0.803041, 0.357269],
[0.421908, 0.805774, 0.351910],
[0.430983, 0.808473, 0.346476],
[0.440137, 0.811138, 0.340967],
[0.449368, 0.813768, 0.335384],
[0.458674, 0.816363, 0.329727],
[0.468053, 0.818921, 0.323998],
[0.477504, 0.821444, 0.318195],
[0.487026, 0.823929, 0.312321],
[0.496615, 0.826376, 0.306377],
[0.506271, 0.828786, 0.300362],
[0.515992, 0.831158, 0.294279],
[0.525776, 0.833491, 0.288127],
[0.535621, 0.835785, 0.281908],
[0.545524, 0.838039, 0.275626],
[0.555484, 0.840254, 0.269281],
[0.565498, 0.842430, 0.262877],
[0.575563, 0.844566, 0.256415],
[0.585678, 0.846661, 0.249897],
[0.595839, 0.848717, 0.243329],
[0.606045, 0.850733, 0.236712],
[0.616293, 0.852709, 0.230052],
[0.626579, 0.854645, 0.223353],
[0.636902, 0.856542, 0.216620],
[0.647257, 0.858400, 0.209861],
[0.657642, 0.860219, 0.203082],
[0.668054, 0.861999, 0.196293],
[0.678489, 0.863742, 0.189503],
[0.688944, 0.865448, 0.182725],
[0.699415, 0.867117, 0.175971],
[0.709898, 0.868751, 0.169257],
[0.720391, 0.870350, 0.162603],
[0.730889, 0.871916, 0.156029],
[0.741388, 0.873449, 0.149561],
[0.751884, 0.874951, 0.143228],
[0.762373, 0.876424, 0.137064],
[0.772852, 0.877868, 0.131109],
[0.783315, 0.879285, 0.125405],
[0.793760, 0.880678, 0.120005],
[0.804182, 0.882046, 0.114965],
[0.814576, 0.883393, 0.110347],
[0.824940, 0.884720, 0.106217],
[0.835270, 0.886029, 0.102646],
[0.845561, 0.887322, 0.099702],
[0.855810, 0.888601, 0.097452],
[0.866013, 0.889868, 0.095953],
[0.876168, 0.891125, 0.095250],
[0.886271, 0.892374, 0.095374],
[0.896320, 0.893616, 0.096335],
[0.906311, 0.894855, 0.098125],
[0.916242, 0.896091, 0.100717],
[0.926106, 0.897330, 0.104071],
[0.935904, 0.898570, 0.108131],
[0.945636, 0.899815, 0.112838],
[0.955300, 0.901065, 0.118128],
[0.964894, 0.902323, 0.123941],
[0.974417, 0.903590, 0.130215],
[0.983868, 0.904867, 0.136897],
[0.993248, 0.906157, 0.143936]]
return viridis