问题
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
回答1:
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.
回答2:
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')
回答3:
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()
来源:https://stackoverflow.com/questions/63419636/show-error-bar-in-multi-line-plot-using-matplotlib