Skip to content

Commit 64c3f10

Browse files
Fix python3 dendrogram display bug (#25)
1 parent b0a0356 commit 64c3f10

File tree

4 files changed

+90
-79
lines changed

4 files changed

+90
-79
lines changed

henchman/plotting.py

Lines changed: 62 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -512,71 +512,69 @@ def dendrogram(D, figargs=None):
512512
'''
513513
if figargs is None:
514514
return lambda figargs: dendrogram(D, figargs=figargs)
515+
G = nx.Graph()
516+
517+
vertices_source = ColumnDataSource(
518+
pd.DataFrame({'index': D.columns.keys(),
519+
'desc': list(D.columns.values())}))
520+
edges_source = ColumnDataSource(
521+
pd.DataFrame(D.edges[0]).rename(
522+
columns={1: 'end', 0: 'start'}))
523+
step_source = ColumnDataSource(
524+
pd.DataFrame({'step': [0],
525+
'thresh': [D.threshlist[0]],
526+
'components': [len(D.graphs[0])]}))
527+
528+
G.add_nodes_from([str(x) for x in vertices_source.data['index']])
529+
G.add_edges_from(zip(
530+
[str(x) for x in edges_source.data['start']],
531+
[str(x) for x in edges_source.data['end']]))
532+
533+
graph_renderer = from_networkx(G, nx.circular_layout,
534+
scale=1, center=(0, 0))
535+
536+
graph_renderer.node_renderer.data_source = vertices_source
537+
graph_renderer.node_renderer.view = CDSView(source=vertices_source)
538+
graph_renderer.edge_renderer.data_source = edges_source
539+
graph_renderer.edge_renderer.view = CDSView(source=edges_source)
540+
541+
plot = Plot(plot_width=400, plot_height=400,
542+
x_range=Range1d(-1.1, 1.1),
543+
y_range=Range1d(-1.1, 1.1))
544+
plot.title.text = "Feature Connectivity"
545+
graph_renderer.node_renderer.glyph = Circle(
546+
size=5, fill_color=Spectral4[0])
547+
graph_renderer.node_renderer.selection_glyph = Circle(
548+
size=15, fill_color=Spectral4[2])
549+
graph_renderer.edge_renderer.data_source = edges_source
550+
graph_renderer.edge_renderer.glyph = MultiLine(line_color="#CCCCCC",
551+
line_alpha=0.6,
552+
line_width=.5)
553+
graph_renderer.edge_renderer.selection_glyph = MultiLine(
554+
line_color=Spectral4[2],
555+
line_width=3)
556+
graph_renderer.node_renderer.hover_glyph = Circle(
557+
size=5,
558+
fill_color=Spectral4[1])
559+
graph_renderer.selection_policy = NodesAndLinkedEdges()
560+
graph_renderer.inspection_policy = NodesAndLinkedEdges()
561+
562+
plot.renderers.append(graph_renderer)
563+
564+
plot.add_tools(
565+
HoverTool(tooltips=[("feature", "@desc"),
566+
("index", "@index"), ]),
567+
TapTool(),
568+
BoxZoomTool(),
569+
SaveTool(),
570+
ResetTool())
515571

516-
def modify_doc(doc, D, figargs):
517-
G = nx.Graph()
518-
519-
vertices_source = ColumnDataSource(
520-
pd.DataFrame({'index': D.columns.keys(),
521-
'desc': D.columns.values()}))
522-
edges_source = ColumnDataSource(
523-
pd.DataFrame(D.edges[0]).rename(
524-
columns={1: 'end', 0: 'start'}))
525-
step_source = ColumnDataSource(
526-
pd.DataFrame({'step': [0],
527-
'thresh': [D.threshlist[0]],
528-
'components': [len(D.graphs[0])]}))
529-
530-
G.add_nodes_from(vertices_source.data['index'])
531-
G.add_edges_from(zip(
532-
edges_source.data['start'],
533-
edges_source.data['end']))
534-
535-
graph_renderer = from_networkx(G, nx.circular_layout,
536-
scale=1, center=(0, 0))
537-
538-
graph_renderer.node_renderer.data_source = vertices_source
539-
graph_renderer.node_renderer.view = CDSView(source=vertices_source)
540-
graph_renderer.edge_renderer.data_source = edges_source
541-
graph_renderer.edge_renderer.view = CDSView(source=edges_source)
542-
543-
plot = Plot(plot_width=400, plot_height=400,
544-
x_range=Range1d(-1.1, 1.1),
545-
y_range=Range1d(-1.1, 1.1))
546-
plot.title.text = "Feature Connectivity"
547-
548-
graph_renderer.node_renderer.glyph = Circle(
549-
size=5, fill_color=Spectral4[0])
550-
graph_renderer.node_renderer.selection_glyph = Circle(
551-
size=15, fill_color=Spectral4[2])
552-
553-
graph_renderer.edge_renderer.data_source = edges_source
554-
graph_renderer.edge_renderer.glyph = MultiLine(line_color="#CCCCCC",
555-
line_alpha=0.6,
556-
line_width=.5)
557-
graph_renderer.edge_renderer.selection_glyph = MultiLine(
558-
line_color=Spectral4[2],
559-
line_width=3)
560-
561-
graph_renderer.node_renderer.hover_glyph = Circle(
562-
size=5,
563-
fill_color=Spectral4[1])
564-
565-
graph_renderer.selection_policy = NodesAndLinkedEdges()
566-
graph_renderer.inspection_policy = NodesAndLinkedEdges()
567-
568-
plot.renderers.append(graph_renderer)
569-
570-
plot.add_tools(
571-
HoverTool(tooltips=[("feature", "@desc"),
572-
("index", "@index"), ]),
573-
TapTool(),
574-
BoxZoomTool(),
575-
SaveTool(),
576-
ResetTool())
577-
578-
plot = _modify_plot(plot, figargs)
572+
plot = _modify_plot(plot, figargs)
573+
574+
if figargs['static']:
575+
return plot
579576

577+
def modify_doc(doc, D, figargs):
580578
data_table = DataTable(source=step_source,
581579
columns=[TableColumn(field='step',
582580
title='Step'),
@@ -600,7 +598,7 @@ def callback(attr, old, new):
600598
print(e)
601599

602600
slider = Slider(start=0,
603-
end=len(D.edges),
601+
end=(len(D.edges) - 1),
604602
value=0,
605603
step=1,
606604
title="Step")

henchman/selection.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ def fit(self, X, pairing_func=None, max_threshes=None):
111111
# Make graphs for every thresh
112112
self._build_graphs()
113113

114+
assert len(self.edges) > 0, 'Failed to build edges'
115+
assert len(self.graphs) > 0, 'Failed to build graphs'
116+
114117
def set_params(self, **params):
115118
'''Method to functionally assign parameters.
116119
Expects a dictionary **params as input.
@@ -123,7 +126,7 @@ def _find_all_graphs(self):
123126

124127
self.graphs = []
125128
for edges in tqdm(self.edges):
126-
out = find_connected_components(self.columns.keys(), edges)
129+
out = find_connected_components(list(self.columns.keys()), edges)
127130
self.graphs.append(out)
128131

129132
def _build_graphs(self):
@@ -132,9 +135,6 @@ def _build_graphs(self):
132135
for i, graph in enumerate(self.graphs):
133136
if len(graph) == 1:
134137
break
135-
if len(graph) == len(self.columns) and i > 0:
136-
i += -1
137-
break
138138
self.threshlist = self.threshlist[:i]
139139
self.edges = self.edges[:i]
140140
self.graphs = self.graphs[:i]
@@ -143,14 +143,12 @@ def _build_edges(self, max_threshes):
143143
self.edges = []
144144
self.graphs = []
145145
uniques = list(np.unique(self.adj))
146-
# uniques.reverse()
146+
uniques = [x for x in uniques if not math.isnan(x)]
147147
if max_threshes is None and len(uniques) > 500:
148148
print('Calculating more than 500 graphs')
149149
print('You can pass max_threshes as a kwarg to Dendrogram')
150150
if max_threshes is not None:
151151
if len(uniques) > max_threshes:
152-
# Strip nans
153-
uniques = [x for x in uniques if not math.isnan(x)]
154152
# Take max_threshes evenly spaced thresholds
155153
uniques = uniques[::int(np.floor((len(uniques)/max_threshes)) + 1)]
156154

setup.cfg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ universal = 1
1818
exclude = docs
1919
max-line-length = 100
2020

21-
2221
[aliases]
2322
# Define setup.py command aliases here
2423
test = pytest

tests/test_selection.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33

44
"""Tests for `learning` module"""
5+
import numpy as np
56
import pandas as pd
67
import pytest
78

@@ -87,14 +88,29 @@ def test_dend_transform(Xy, fit_dend, capsys):
8788
assert X_new_2.shape[1] == int(out2[-3:-1])
8889

8990
def test_dend_plot(fit_dend):
91+
show(dendrogram(fit_dend), static=True)
9092
show(dendrogram(fit_dend))
91-
92-
93-
94-
9593

94+
def test_build_edges(capsys):
95+
fake_sel = selection.Dendrogram()
96+
fake_sel.adj = np.asarray(range(501))
97+
fake_sel._build_edges(None)
9698

97-
98-
99-
99+
output, _ = capsys.readouterr()
100+
split_output = output.split('\n')
100101

102+
real_line_1 = 'Calculating more than 500 graphs'
103+
real_line_2 = 'You can pass max_threshes as a kwarg to Dendrogram'
104+
assert split_output[0] == real_line_1
105+
assert split_output[1] == real_line_2
106+
107+
def test_build_graphs_exit():
108+
fake_sel = selection.Dendrogram()
109+
fake_sel.threshlist = [1, 2]
110+
fake_sel.edges = [[(0, 1)], [(1, 2), (0, 1)]]
111+
fake_sel.graphs = [{0: {0, 1}, 2: {2}}, {0: {0, 1, 2}}]
112+
fake_sel._build_graphs()
113+
114+
assert fake_sel.threshlist == [1]
115+
assert fake_sel.edges[0][0][0] == 0
116+
assert fake_sel.graphs[0][2] == {2}

0 commit comments

Comments
 (0)