3

Currently I'm trying to plot a graph showing the rank of some equipment in operation, the rank goes from 1 to 300 (1 is the best, 300 is the worst) over a few days (df columns). What I'm trying to do, is a graph similar to this:

enter image description here

And what I got is this: enter image description here

I would like to make the lines inclined as it is on the first graph instead of vertical, but I can't figure it out how. I found the base for the first graph on this question here and I started the code from there, this is what I end up having:

import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
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=0.8, linestyle='dashed', color=color,alpha=1,marker='.'))
    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

head = 8
dfPlot = vazio.sort_values(dia, ascending = True).head(head)
data = dfPlot.to_numpy()

colorsHEX=('#FE5815','#001A70','#2F5C22','#B01338','#00030D','#2DE1FC','#2E020C','#B81D8C')

artists = []
for row, color in zip(data, colorsHEX):
    artists.extend(energy_rank(row, color=color))


eixoXDatas = pd.to_datetime(list(vazio.columns),format='%d/%m/%y').strftime('%d/%b')    

fig, ax = plt.subplots()
plt.xticks(np.arange(len(vazio.columns)),
           eixoXDatas,
           rotation = 35,
           fontsize = 14)
plt.yticks(fontsize = 14)

plt.xlabel('Dias', fontsize=18)
plt.ylabel('Ranking', fontsize=18)

fig = plt.gcf()
fig.set_size_inches(16, 8)

for artist in artists:
    ax.add_artist(artist)
ax.set_ybound([0,15])
ax.set_ylim(ax.get_ylim()[::-1])
ax.set_xbound([-0.1,float(len(vazio.columns))+2.5])
plt.yticks(np.arange(1,16,step=1))
ax.grid(axis='y',alpha=0.5)

lastDay = vazio.sort_values(vazio.iloc[:,-1:].columns.values[0], ascending = True).iloc[:,-1:]
lastDay = lastDay.head(head)

for inverter, pos in lastDay.iterrows():
    ax.annotate(inverter, xy =(plt.gca().get_xlim()[1]-2.4, pos), color=colorsHEX[int(pos)-1])

I tried implementing on energy_rank function, removing the +/- parts on x_data but I only could end up with inclined lines with dots instead of the horizontal lines. Can anyone help me out how can I mantain the horziontal lines and instead of vertical dashed lines, implement inclined lines as the example above?

I imagine that is vertical because the points change on top of the x ticks. If you observe the 1st image, the horizontal bars are centralized on each x tick, so the lines "have some room" to be inclined.

vazio dataframe is as follows (contains the rank of each equipment):

    Equipment         21-03-27  21-03-28    21-03-29    21-03-30    21-03-31    21-04-01    21-04-02 
P01-INV-1-1              1         1           1           1           1           2           2
P01-INV-1-2              2         2           4           4           5           1           1
P01-INV-1-3              4         4           3           5           6           10          10
Pedro de Sá
  • 760
  • 6
  • 19

1 Answers1

1

Here is an adaption of your energy_rank function creating horizontal line segments together with their connections. The line drawing part is inspired by this tutorial example. Optionally the area below the lines can be filled.

import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import numpy as np

def energy_rank(data, marker_width=.5, color='blue', ax=None, fill=False):
    ax = ax or plt.gca()
    y = data
    x = np.arange(1, len(data) + 1)

    segments1 = np.array([x - marker_width / 2, y, x + marker_width / 2, y]).T.reshape(-1, 2, 2)
    lc1 = LineCollection(segments1, color=color)
    lc1.set_linewidth(2)
    lc1.set_linestyle('-')
    lines_hor = ax.add_collection(lc1)

    segments2 = np.array([x[:-1] + marker_width / 2, y[:-1], x[1:] - marker_width / 2, y[1:]]).T.reshape(-1, 2, 2)
    lc2 = LineCollection(segments2, color=color)
    lc2.set_linewidth(0.5)
    lc2.set_linestyle('--')
    lines_connect = ax.add_collection(lc2)

    if fill:
        ax.fill_between(segments1.reshape(-1,2)[:,0], segments1.reshape(-1,2)[:,1],
                        color=color, alpha=0.05)
    return lines_hor, lines_connect

fig, ax = plt.subplots()

M, N = 5, 25
y = np.random.uniform(-2, 2, (M, N)).cumsum(axis=1)
y += np.random.uniform(0.5, 2, (M, 1)) - y.min(axis=1, keepdims=True)
colorsHEX = ('#FE5815', '#001A70', '#2F5C22', '#B01338', '#00030D')
for yi, color in zip(y, colorsHEX):
    energy_rank(yi, ax=ax, color=color)

ax.set_xlim(0, N + 1)
ax.set_ylim(0, y.max() + 1)
plt.show()

horizontal line segments connected with dashed lines

JohanC
  • 71,591
  • 8
  • 33
  • 66