'Get the height of the rectangles in a plot

I have the following graph 1 obtained with the following code [2]. As you can see from the first line inside for I gave the height of the rectangles based on the standard deviation value. But I can't figure out how to get the height of the corresponding rectangle. For example given the blue rectangle I would like to return the 2 intervals in which it is included which are approximately 128.8 and 130.6. How can I do this?

enter image description here

[2] The code I used is the following:

import pandas as pd
import matplotlib.ticker as ticker
import matplotlib.pyplot as plt
import numpy as np

dfLunedi = pd.read_csv( "0.lun.csv", encoding = "ISO-8859-1", sep = ';')

dfSlotMean = dfLunedi.groupby('slotID', as_index=False).agg( NLunUn=('date', 'nunique'),NLunTot = ('date', 'count'), MeanBPM=('tempo', 'mean'), std = ('tempo','std') )
#print(dfSlotMean)

dfSlotMean.drop(dfSlotMean[dfSlotMean.NLunUn < 3].index, inplace=True)
    
df = pd.DataFrame(dfSlotMean)

df.to_csv('1.silLunedi.csv', sep = ';', index=False)

print(df)

bpmMattino = df['MeanBPM']
std = df['std']
listBpm = bpmMattino.tolist()

limInf = df['MeanBPM'] - df['std']
limSup = df['MeanBPM'] + df['std']

tick_spacing = 1
fig, ax = plt.subplots(1, 1)
for _, r in df.iterrows():
    #
    ax.plot([r['slotID'], r['slotID']+1], [r['MeanBPM']]*2, linewidth = r['std'] )
    #ax.plot([r['slotID'], r['slotID']+1], [r['MeanBPM']]*2, linewidth = r['std'])
    ax.xaxis.grid(True)
    ax.yaxis.grid(True)
    ax.yaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
    ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
    

This is the content of the csv:

    slotID  NMonUnique NMonTot     MeanBPM        std      
0        7      11       78  129.700564  29.323091  
2       11       6       63  123.372397  24.049397  
3       12       6       33  120.625667  24.029006    
4       13       5       41  124.516341  30.814985    
5       14       4       43  118.904512  26.205309    
6       15       3       13  116.380538  24.336491    
7       16       3       42  119.670881  27.416843  
8       17       5       40  125.424125  32.215865    
9       18       6       45  130.540578  24.437559  
10      19       9       58  128.180172  32.099529    
11      20       5       44  125.596045  28.060657 


Solution 1:[1]

I would advise against using linewidth to show anything related to your data. The reason being that linewidth is measured in "points" (see the matplotlib documentation), the size of which are not related to the xy-space that you plot your data in. To see this in action, try plotting with different linewidths and changing the size of the plotting-window. The linewidth will not change with the axes.

Instead, if you do indeed want a rectangle, I suggest using matplotlib.patches.Rectangle. There is a good example of how to do that in the documentation, and I've also added an even shorter example below.

To give the rectangles different colors, you can do as here here and simply get a random tuple with 3 elements and use that for the color. Another option is to take a list of colors, for example the TABLEAU_COLORS from matplotlib.colors and take consecutive colors from that list. The latter may be better for testing, as the rectangles will get the same color for each run, but notice that there are just 10 colors in TABLEAU_COLORS, so you will have to cycle if you have more than 10 rectangles.

import matplotlib.pyplot as plt
import matplotlib.patches as ptc
import random

x = 3
y = 4.5
y_std = 0.3

fig, ax = plt.subplots()
for i in range(10):
    c = tuple(random.random() for i in range(3))
    # The other option as comment here
    #c = mcolors.TABLEAU_COLORS[list(mcolors.TABLEAU_COLORS.keys())[i]]
    rect = ptc.Rectangle(xy=(x, y-y_std), width=1, height=2*y_std, color=c)
    ax.add_patch(rect)
ax.set_xlim((0,10))
ax.set_ylim((0,5))
plt.show()

Solution 2:[2]

If you define the height as the standard deviation, and the center is at the mean, then the interval should be [mean-(std/2) ; mean+(std/2)] for each rectangle right? Is it intentional that the rectangles overlap? If not, I think it is your use of linewidth to size the rectangles which is at fault. If the plot is there to visualize the mean and variance of the different categories something like a boxplot or raincloud plot might be better.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 MLRAL