Search code examples
pythonmatplotlibscipyheatmapdendrogram

Resizing scipy dendrogram and matplotlib pcolor subplots while keeping alignment


Goal

Make a dendrogram connected to a heatmap like the ones matlab makes;

enter image description here

Or like this plotly example without the fancy javascript using just scipy and matplotlib.

Building off of this question I derived the following code;

INPUT

from scipy.cluster.hierarchy import linkage
from scipy.cluster.hierarchy import dendrogram
from scipy.spatial.distance import pdist
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
from numpy import arange

# Create the figure and set it's size.
fig = plt.figure(figsize=(5,7))

# Create the first subplot in the figure. 
ax1 = plt.subplot(211)

# Set to your favorite colormap.
cm = matplotlib.cm.viridis

# Create array of random numbers.
X = np.random.random([6,300])

# Create a linkage object.
linkmat = linkage(X)

# Make a dendrogram from the linkage object.
dendrogram(linkmat)

# Use the x and y limits to set the aspect.
x0,x1 = ax1.get_xlim()
y0,y1 = ax1.get_ylim()
ax1.set_aspect((x1-x0)/(y1-y0))


# Remove the ticks on the x-axis. 
plt.tick_params(axis='x', which='both', bottom='off', top='off', labelbottom='off')

# Create the second subplot.
ax2 = plt.subplot(212)

labels = ["a", "b", "c", "d", "e"]

plt.xticks(arange(0.5, 7.5, 1))

plt.gca().set_xticklabels(labels)

plt.pcolor(X.T)

x0,x1 = ax2.get_xlim()
y0,y1 = ax2.get_ylim()

ax2.set_aspect((x1-x0)/(y1-y0))

# Insert the color scale
plt.colorbar()
cb = plt.colorbar(ax=ax1)
cb.ax.set_visible(False)

# Make the vertical distance between plots equal to zero 
plt.subplots_adjust(hspace=0)

# Show the plot
plt.show()

OUTPUT

enter image description here

Question

How can I reduce the height of dendrogram by 50% and increase the height of the heatmap by 50% while maintaining their current alignment?


Solution

  • You could use subplot2grid({params}) instead of subplot() since you can tell how many grid it will occupy

    from scipy.cluster.hierarchy import linkage
    from scipy.cluster.hierarchy import dendrogram
    from scipy.spatial.distance import pdist
    import matplotlib
    from matplotlib import pyplot as plt
    import numpy as np
    from numpy import arange
    
    # Create the figure and set it's size.
    fig = plt.figure(figsize=(5,7))
    
    # Create the first subplot in the figure. 
    ax1 = plt.subplot2grid((3, 1), (0, 0), rowspan= 1, colspan=1)
    
    # Set to your favorite colormap.
    cm = matplotlib.cm.viridis
    
    # Create array of random numbers.
    X = np.random.random([6,300])
    
    # Create a linkage object.
    linkmat = linkage(X)
    
    # Make a dendrogram from the linkage object.
    dendrogram(linkmat)
    
    # Use the x and y limits to set the aspect.
    x0,x1 = ax1.get_xlim()
    y0,y1 = ax1.get_ylim()
    #ax1.set_aspect((x1-x0)/(y1-y0))
    
    
    # Remove the ticks on the x-axis. 
    plt.tick_params(axis='x', which='both', bottom='off', top='off', labelbottom='off')
    
    # Create the second subplot.
    ax2 = plt.subplot2grid((3, 1), (1, 0), rowspan= 2, colspan=1)
    
    labels = ["a", "b", "c", "d", "e"]
    
    plt.xticks(arange(0.5, 7.5, 1))
    
    plt.gca().set_xticklabels(labels)
    
    plt.pcolor(X.T)
    
    x0,x1 = ax2.get_xlim()
    y0,y1 = ax2.get_ylim()
    
    #ax2.set_aspect((x1-x0)/(y1-y0))
    
    # Insert the color scale
    plt.colorbar()
    cb = plt.colorbar(ax=ax1)
    cb.ax.set_visible(False)
    
    # Make the vertical distance between plots equal to zero 
    plt.subplots_adjust(hspace=0)
    
    # Show the plot
    plt.show()
    

    enter image description here