简体   繁体   中英

show error bar in multi line plot using matplotlib

I've created a multi line plot using marplot lib, and now I want to show the min-max value for each parameter on X-axis. My code is below:

import numpy as np
import pandas as pd
from pandas import DataFrame
import matplotlib.pyplot as plt
from matplotlib import pyplot as plt
import seaborn as sns

df = pd.DataFrame({'Time': ['D=0','D=2','D=5','D=X'],
    'Latency': [74.92, 75.32, 79.64, 100],
    'Delay': [18.2,80,82,84]
   })

  plt.plot( 'Time', 'Latency', data=df, marker='s', color='black', markersize=4,     linewidth=1, linestyle='--')
  plt.plot( 'Time', 'Delay', data=df, marker='o', color='black',  markersize=4, linewidth=1,linestyle='-')

   plt.legend()
   plt.xlabel("Time")
   plt.ylabel("Average Score (%)")
   plt.ylim(0, 100)
   plt.xlim('D=0','D=X')
   plt.savefig('Fig2.png', dpi=300, bbox_inches='tight')
   plt.show()

The interval min-max that I want to add is:

Latency: 
D=0 => {73.3, 76}
D=2 => {73.3, 80}
D=5 => {75, 83.3}
D=X => {100}
Delay:
D=0 => {0, 50}
D=2 => {50, 100}
D=5 => {68, 90}
D=X => {75, 90}

Thanks so much in advance

plt.errorbar() draws lineplots with error bars. It's parameters are quite similar to plt.plot() . The xlims need to be a bit wider to avoid the error bars being cut by the plot borders.

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

df = pd.DataFrame({'Time': ['D=0', 'D=2', 'D=5', 'D=X'],
                   'Latency': [74.92, 75.32, 79.64, 100],
                   'Delay': [18.2, 80, 82, 84]})
latency_min_max = np.array([(73.3, 76), (73.3, 80), (75, 83.3), (100, 100)]).T
latency_err = np.abs(latency_min_max - df['Latency'].to_numpy())
delay_min_max = np.array([(0, 50), (50, 100), (68, 90), (75, 90)]).T
delay_err = np.abs(delay_min_max - df['Delay'].to_numpy())

plt.errorbar('Time', 'Latency', yerr=latency_err, data=df, marker='s', capsize=2,
             color='black', markersize=4, linewidth=1, linestyle='--')
plt.errorbar('Time', 'Delay', yerr=delay_err, data=df,
             marker='o', capsize=4, color='black', markersize=4, linewidth=1, linestyle='-')
plt.legend()
plt.xlabel("Time")
plt.ylabel("Average Score (%)")
plt.ylim(0, 100)
plt.xlim(-0.2, 3.2)
plt.savefig('Fig2.png', dpi=300, bbox_inches='tight')
plt.show()

示例图

An alternative is to use plt.fill_between to create error bands:

plt.fill_between(df['Time'], latency_min_max[0, :], latency_min_max[1, :], color='red', alpha=0.2, label='Latency error')
plt.fill_between(df['Time'], delay_min_max[0, :], delay_min_max[1, :], color='blue', alpha=0.2, label='Delay error')

带误差带的绘图

First put the error values in lists:

latency_lower_err = [73.3, 73.3, 75, 100]
latency_upper_err = [76, 80, 83.3, 100]

Then subtract the data points from these values, because matplotlib needs the distance (in absolute units) from the error limit to the corresponding data point:

latency_lower_err = (latency_lower_err - df['Latency']).abs() 
latency_upper_err = (latency_upper_err - df['Latency']).abs()

Put the resulting values in a list, where the first element is the lower errors, and the second element is the upper errors:

yerr = [latency_lower_err, latency_upper_err]

Then change the call from plt.plot to plt.errorbar , adding the yerr argument:

plt.errorbar('Time', 'Latency', data=df, yerr=yerr, capsize=5, ... )

The remaining arguments are the same you previously used for plt.plot .

Result:

在此处输入图像描述

Adapt the same logic for Delay in order to get the errors for that variable, too.

You should use plt.errorbar instead of plt.plot , then assign the absolute value of the difference between the data points and the lower/upper limits as the lower/upper error values (numpy has convenient vectorization to do this). To avoid the caps of the error bars overlapping and which could be confusing, I would suggest using different colors and updating the legend.

From a presentation perspective, it would probably look nicer to have some whitespace around the axes so the data doesn't look cut off - you can set the plt.xlim and plt.ylim accordingly. Credit to @JohanC for doing this first.

import numpy as np
import pandas as pd
from pandas import DataFrame
import matplotlib.pyplot as plt
from matplotlib import pyplot as plt
import seaborn as sns

df = pd.DataFrame({'Time': ['D=0','D=2','D=5','D=X'],
    'Latency': [74.92, 75.32, 79.64, 100],
    'Delay': [18.2,80,82,84]
   })

latency_limits = np.array([[73.3,73.3,75,100],[76,80,83.3,100]])
delay_limits = np.array([[0,50,68,75],[50,100,90,90]])

latency_errors = abs(df.Latency.values - latency_limits)
delay_errors = abs(df.Delay.values - delay_limits)

yerr = np.array([[1,1,1,1],[5,5,5,5]])

fig = plt.figure()
Latency = plt.errorbar(
  x=df.Time, 
  y=df.Latency, 
  yerr=latency_errors, 
  capsize=4,
  marker='s', 
  color='red', 
  markersize=4, 
  linewidth=1, 
  linestyle='--')

Delay = plt.errorbar(
  x=df.Time, 
  y=df.Delay, 
  yerr=delay_errors,
  capsize=4,
  marker='o', 
  color='blue',  
  markersize=4, 
  linewidth=1,
  linestyle='-')

plt.legend((Latency, Delay),("Latency","Delay"))
plt.xlabel("Time")
plt.ylabel("Average Score (%)")
## widen both limits to give some whitespace to the plot
plt.ylim(-5, 105)
plt.xlim(-0.2, 3.2)
# plt.savefig('Fig2.png', dpi=300, bbox_inches='tight')
plt.margins(5,5)
plt.show()

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM