pythonmatplotlibgraphcharts

Building gauge chart in Python with matplotlib


I am attempting to follow this tutorial to create a roughly semi-circle gauge chart with matplotlib. However, my figure contains several different charts - it is being created via a line like:

fig, ax = plt.subplots(2, 4, figsize=(11,6))

With each chart being created similar to this:

ax[0,0].bar(categories, values)

The issue I am running into is if I try to alter the tutorial code to something like

ax[0,0].bar(x=[0, 0.44, 0.88,1.32,1.76,2.2,2.64], width=0.5, height=0.5, bottom=2, linewidth=3, edgecolor="white", color=colors, align="edge");

It seems to not be contained within the grid of charts, and is much larger than anticipated. I assume this is an issue with the line ax = fig.add_subplot(projection="polar");, since none of the other charts I have created use anything like this, but I am not sure how to specify that the chart needs to use polar coordinates otherwise. Any suggestions are appreciated.Image of oversized gauge chart

Edit: Here is a full reproducible example with random data

fig, ax = plt.subplots(2, 2, figsize=(11,6))

gauge_colors = ["#FF2C2C", "#FFF34F", "#39FF14", "#FFF34F", "#FF2C2C"]
ax[0, 0] = plt.subplot(projection="polar")
ax[0, 0].bar(x=[0, 0.44, 0.88, 1.32, 1.76, 2.2, 2.64], width=0.5, height=0.5, bottom=2,
             linewidth=3, edgecolor="white",
             color=gauge_colors, align="edge");
ax[0, 0].annotate("50", xytext=(0, 0), xy=(1.1, 2.0),
                  arrowprops=dict(arrowstyle="wedge, tail_width=0.5", color="black", shrinkA=0),
                  bbox=dict(boxstyle="circle", facecolor="black", linewidth=2.0, ),
                  fontsize=45, color="white", ha="center"
                  );

for i in range(2):
    for j in range(2):
        if i > 0 or j > 0:
            ax[i, j].plot(np.random.rand(10))

plt.show()

Solution

  • The issue is that you cannot change the projection of an existing Axes instance. And plt.subplots does not allow you to set the projection of each Axes instance individually.

    @rehaqds's answer is one way to do what you want. However, if you want to continue using plt.subplots to create your grid of subplots, you can, with a small modification.

    First, you create the grid of subplots. Then you remove the one you want to change to polar projection, and then add it again, using, for example, fig.add_subplot().

    For your minimal example, that would look like:

    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots(2, 2, figsize=(11,6))
    
    ax[0, 0].remove()
    ax[0, 0] = fig.add_subplot(2, 2, 1, projection="polar")
    
    gauge_colors = ["#FF2C2C", "#FFF34F", "#39FF14", "#FFF34F", "#FF2C2C"]
    
    ax[0, 0].bar(x=[0, 0.44, 0.88, 1.32, 1.76, 2.2, 2.64], width=0.5, height=0.5, bottom=2,
                 linewidth=3, edgecolor="white",
                 color=gauge_colors, align="edge");
    ax[0, 0].annotate("50", xytext=(0, 0), xy=(1.1, 2.0),
                      arrowprops=dict(arrowstyle="wedge, tail_width=0.5", color="black", shrinkA=0),
                      bbox=dict(boxstyle="circle", facecolor="black", linewidth=2.0, ),
                      fontsize=15, color="white", ha="center"
                      );
    
    for i in range(2):
        for j in range(2):
            if i > 0 or j > 0:
                ax[i, j].plot(np.random.rand(10))
    
    plt.show()
    

    enter image description here