pythonmatplotlibpie-chartsunburst-diagram

Sunburst/Fan chart


I'm interested in developing a custom sunburst plot in for binary search trees (such as those used in genealogy). I'm trying to achieve the following:

enter image description here

As you can see, it is a sunburst chart (such as offered by Plotly) with a removed wedge.


Solution

  • Here's something to at least get you started. You can use matplotlib's pie chart to make nested pie charts. You can also remove specific wedges as shown in https://stackoverflow.com/a/63881380/1862861. Using this information you could do:

    from matplotlib import pyplot as plt
    
    ninner = 2  # number of inner wedge
    width = 0.15  # width of inner wedges
    radius = 0.5  # radius of inner wedges
    gap = 100  # size of missing wedge
    
    ngap = 300 - gap  # total size of filled wedges (missing gap will be 1/3 of total)
    
    fig, ax = plt.subplots()
    
    for i in range(8):
        if i > 0:
            # expand pie chart radius and shrink wedge width
            width *= 0.85
            radius += width
        
        # create data
        data = [gap]
        data.extend([ngap / 2**(i+1)] * ninner)
        colors = ["lightgrey"] * len(data)  # for now they are all grey!
        ninner *= 2
        
        # create pie chart
        wedges, _ = ax.pie(
            data,
            radius=radius,
            colors=colors,
            wedgeprops={"width": width, "edgecolor": "w", "linewidth": 0.25},
            startangle=-150,  # shift start angle
        )
        wedges[0].set_visible(False)  # make gap invisible
    
    fig.tight_layout()
    fig.show()
    

    which produces:

    enter image description here

    Obviously this doesn't give the colours, but it's a start.

    Update

    Here's a version with some added colours:

    from matplotlib import pyplot as plt
    import numpy as np
    
    
    def get_colours(N):
        # use the tab20c colour map and get an array of colours
    
        # Note: the "16" in this is due to the 16 colours in the tab20c colour map
        cmap = plt.colormaps["tab20c"]
        cs = cmap(np.arange(16))
        if N <= 16:
            step = 16 // N
            colours = np.array([cs[i] for i in range(0, 16, step)])
        else:
            s = N // 16
            colours = np.array([cs[int(np.floor(i / s))] for i in range(N)])
    
        return colours
    
    
    ninner = 2  # number of inner wedge
    width = 0.15  # width of inner wedges
    radius = 0.5  # radius of inner wedges
    gap = 100  # size of missing wedge
    
    ngap = 300 - gap  # total size of filled wedges (missing gap will be 1/3 of total)
    
    fig, ax = plt.subplots()
    
    for i in range(8):
        if i > 0:
            # expand pie chart radius and shrink wedge width
            width *= 0.85
            radius += width
        
        # create data
        data = [gap]
        data.extend([ngap / 2**(i+1)] * ninner)
        colours = np.array([[0.8, 0.8, 0.8, 1.0] for _ in range(len(data))])  # initialise as all grey
    
        wcolours = get_colours(ninner)
    
        # this part will depend on your data!
        # let's colour fill all the inner wedges
        if i < 5:
            colours[1:] = wcolours
        else:
            # choose some values to fill in
            nfill = int(np.sqrt(ninner))
            if nfill > 0:
                wfill = np.zeros(ninner)
                wfill[np.random.choice(np.arange(ninner), nfill, replace=False)] = 1.0
                cv = colours[1:]
                cv[wfill.astype(bool)] = wcolours[wfill.astype(bool)]
    
        ninner *= 2
    
        # create pie chart
        wedges, _ = ax.pie(
            data,
            radius=radius,
            colors=colours,
            wedgeprops={"width": width, "edgecolor": "w", "linewidth": 0.25},
            startangle=-150,  # shift start angle
        )
        wedges[0].set_visible(False)  # make gap invisible
    
    fig.tight_layout()
    fig.show()
    

    which produces:

    enter image description here