Repository: plotly/dash-bio

Issue:
Clustergram: Why is complete linkage hard-coded? 
https://github.com/plotly/dash-bio/blob/a471d1d51ac361e04242ae7424af20f32fb26fce/dash_bio/component_factory/_clustergram.py#L29

Shouldn't this also be a kwarg? 

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1229b672..9e5c47f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## Unreleased - ???
+
+### Changed
+* [#589](https://github.com/plotly/dash-bio/pull/589) Removed hardcoded clustergram linkage method, added parameter `link_method` instead. 
+
 ## [0.8.0] - 2021-09-27
 
 ### Fixed
diff --git a/dash_bio/component_factory/_clustergram.py b/dash_bio/component_factory/_clustergram.py
index 8ac4258f..33a143b4 100644
--- a/dash_bio/component_factory/_clustergram.py
+++ b/dash_bio/component_factory/_clustergram.py
@@ -26,7 +26,8 @@ def Clustergram(
     row_dist="euclidean",
     col_dist="euclidean",
     dist_fun=scs.distance.pdist,
-    link_fun=lambda x, **kwargs: sch.linkage(x, "complete", **kwargs),
+    link_fun=None,
+    link_method=None,
     color_threshold=None,
     optimal_leaf_order=False,
     color_map=None,
@@ -87,6 +88,11 @@ Keyword arguments:
 - link_fun (function; default scipy.cluster.hierarchy.linkage): Function to
     compute the linkage matrix from the pairwise distances (see docs for
     scipy.cluster.hierarchy.linkage).
+- link_method (string; default 'complete'): The linkage algorithm to use
+    if link_fun not set. For method 'single', an optimized algorithm based
+    on minimum spanning, for methods 'complete', 'average', 'weighted' and
+    'ward', an algorithm called nearest-neighbors chain is implemented
+    (see docs for scipy.cluster.hierarchy.linkage).
 - color_threshold (dict; default {'row': 0, 'col': 0}): Maximum
     linkage value for which unique colors are assigned to clusters;
     'row' for rows, and 'col' for columns.
@@ -162,6 +168,7 @@ Keyword arguments:
 - width (number; default 500): The width of the graph, in px.
 
     """
+
     if color_threshold is None:
         color_threshold = dict(row=0, col=0)
 
@@ -209,7 +216,8 @@ Methods:
         row_dist="euclidean",
         col_dist="euclidean",
         dist_fun=scs.distance.pdist,
-        link_fun=lambda x, **kwargs: sch.linkage(x, "complete", **kwargs),
+        link_fun=None,
+        link_method=None,
         color_threshold=None,
         optimal_leaf_order=False,
         color_map=None,
@@ -246,6 +254,15 @@ Methods:
         # Always keep unique identifiers for columns
         column_ids = list(range(data.shape[1]))
 
+        if link_method is None:
+            link_method = "complete"
+
+        if link_fun is None:
+            def linkage(x, **kwargs):
+                return sch.linkage(x, link_method, **kwargs)
+
+            link_fun = linkage
+
         self._data = data
         self._row_labels = row_labels
         self._row_ids = row_ids


Test patch:
diff --git a/tests/unit/test_clustergram.py b/tests/unit/test_clustergram.py
index 4bb130f2..b03643cc 100644
--- a/tests/unit/test_clustergram.py
+++ b/tests/unit/test_clustergram.py
@@ -83,3 +83,18 @@ def test_column_labels():
     clustered_data = CLUSTERED_DATA.T
 
     assert np.array_equal(curves_dict['heatmap']['z'], clustered_data)
+
+
+def test_link_method():
+    """Test that specifying linkage method."""
+
+    data = DATA
+    _, _, curves_dict = Clustergram(
+        data,
+        generate_curves_dict=True,
+        return_computed_traces=True,
+        center_values=False,
+        link_method='centroid'
+    )
+    clustered_data = CLUSTERED_DATA
+    assert not np.array_equal(curves_dict['heatmap']['z'], clustered_data)