Search code examples
pythonpandasmatplotlibranking

How do I plot an energy ranking figure using Python?


This is a typical energy ranking that is used in a few published papers and I am struggling to reproduce one for my data using Python (anything matplotlib, sns etc.). I have my data constructed in Pandas dataframe like below:

System  Color_id  Data1  Data2
Form I     1      0.0    0.6
Form II    2      0.8    0.0
Form III   3      2.1    2.7
Form IV    4      2.2    0.3
Form V     5      1.7    1.2

I added "Color_id" column to enable specific_column_values coloring as in matplotlib and I think I am half-way using simply plt.scatter. What I am struggling mostly is plotting elongated lines instead of typical markers, and how to automatically connect those dash lines between similar systems across different data? Any help or suggestions is much appreciated.

Energy Ranking Plots


Solution

  • I implemented an example of what I suggested in the comments. This doesn't automatically scale the axes (I hardcoded it), or add the tick labels, but those are all things you should be able to find on other questions.

    import matplotlib.pyplot as plt
    import numpy as np
    
    def energy_rank(data, marker_width=.5, color='blue'):
        y_data = np.repeat(data, 2)
        x_data = np.empty_like(y_data)
        x_data[0::2] = np.arange(1, len(data)+1) - (marker_width/2)
        x_data[1::2] = np.arange(1, len(data)+1) + (marker_width/2)
        lines = []
        lines.append(plt.Line2D(x_data, y_data, lw=1, linestyle='dashed', color=color))
        for x in range(0,len(data)*2, 2):
            lines.append(plt.Line2D(x_data[x:x+2], y_data[x:x+2], lw=2, linestyle='solid', color=color))
        return lines
    
    data = np.random.rand(4,8) * 4 # 4 lines with 8 datapoints from 0 - 4
    
    artists = []
    for row, color in zip(data, ('red','blue','green','magenta')):
        artists.extend(energy_rank(row, color=color))
    
    fig, ax = plt.subplots()
    
    for artist in artists:
        ax.add_artist(artist)
    ax.set_ybound([0,4])
    ax.set_xbound([.5,8.5])