我使用tkinter和matplotlib编写了一个小程序,该程序绘制了正态分布曲线和置信区间。我希望该图使用plt.text()
在左上角有一个小文本框,其中包含有关用户输入的一些信息以及后端模型计算出的其他一些相关信息(例如,可靠性,范数等)。
我明确希望避免使用fig, ax = plt.subplots()
,因为这将打开两个窗口(其中一个为空,另一个包含绘图)。
但是我意识到我必须创建一个子图才能使用transform=ax.transAxes
并确保文本框出现在我的图窗口中(请参见text caption not appearing matplotlib)。没有此关键字参数,我将不得不使用显式的数据坐标,这是我不能做的,因为轴坐标可以根据用户输入而改变。
如何在不打开两个窗口的情况下将文本框放在左上角?
这是我的代码:
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
import numpy as np
import math
from scipy.stats import norm
from scipy.stats import zscore
class Application:
def __init__(self, master):
self.master = master
self.callPlotWindow()
def callPlotWindow(self):
plotdata = dict()
plotdata['reliability'] = 0.94
plotdata['sd'] = 10
plotdata['mean'] = 50
plotdata['normvalue'] = 66
plotdata['confidence_level'] = '80%'
plotdata['question'] = 'einseitig'
plotdata['hypothesis'] = 'Äquivalenzhypothese'
plotdata['plot_ci'] = 4.12298113505264
plotdata['plot_ci_lower'] = 63.93850943247368
plotdata['plot_ci_upper'] = 68.06149056752632
# turn on interactive mode
plt.ion()
# if there is already a plot window clear old plot
if plt:
plt.clf()
# create x values for normal distribution
x_normdist = np.concatenate((
np.linspace(plotdata["mean"] - 3 * plotdata["sd"], plotdata["mean"] - 2 * plotdata["sd"],endpoint=False),
np.linspace(plotdata["mean"] - 2 * plotdata["sd"], plotdata["mean"] - 1 * plotdata["sd"],endpoint=False),
np.linspace(plotdata["mean"] - 1 * plotdata["sd"], plotdata["mean"] + 1 * plotdata["sd"],endpoint=False),
np.linspace(plotdata["mean"] + 1 * plotdata["sd"], plotdata["mean"] + 2 * plotdata["sd"],endpoint=False),
np.linspace(plotdata["mean"] + 2 * plotdata["sd"], plotdata["mean"] + 3 * plotdata["sd"])
))
# plot normal distribution curve
y_normdist = norm.pdf(x_normdist,plotdata["mean"],plotdata["sd"])
plt.plot(x_normdist,y_normdist)
# create logical lists which are used for 'where'-argument in fill-between method
average = (x_normdist >= (plotdata["mean"] - 1 * plotdata["sd"])) & (x_normdist <= (plotdata["mean"] + 1 * plotdata["sd"]))
above_and_below_average = (x_normdist >= (plotdata["mean"] - 2 * plotdata["sd"])) & (x_normdist <= (plotdata["mean"] - 1 * plotdata["sd"])) | (x_normdist >= (plotdata["mean"] + 1 * plotdata["sd"])) & (x_normdist <= (plotdata["mean"] + 2 * plotdata["sd"]))
far_above_and_below_average = (x_normdist >= (plotdata["mean"] - 3 * plotdata["sd"])) & (x_normdist <= (plotdata["mean"] - 2 * plotdata["sd"])) | (x_normdist >= (plotdata["mean"] + 2 * plotdata["sd"])) & (x_normdist <= (plotdata["mean"] + 3 * plotdata["sd"]))
regions = [average,
above_and_below_average,
far_above_and_below_average
]
alpha_values = [0.75,0.5,0.25]
region_labels = [
"durchschnittlich",
"unter-/überdurchschnittlich",
"weit unter-/überdurchschnittlich"
]
# shade regions under curve, use different alpha channel values and labels
for idx,region in enumerate(regions):
plt.fill_between(x_normdist, y_normdist,color="C0",alpha=alpha_values[idx],label=region_labels[idx],where=regions[idx])
# plot confidence interval
plt.errorbar(x=plotdata["normvalue"],y=0,xerr=plotdata["plot_ci"],fmt=".k",capsize=10)
# set x and y axis title
plt.xlabel(xlabel="Normwert")
plt.ylabel(ylabel=r'$\phi_{\mu\sigma}(\mathcal{X})$')
textstr = '\n'.join((
r'$Normwert: %.2f$' % (plotdata["normvalue"], ),
r'$Reliabilität: %.2f$' % (plotdata["reliability"], ),
r'$Mittelwert des Normwertes: %.2f$' % (plotdata["mean"], ),
r'$Standardabweichung des Normwertes: %.2f$' % (plotdata["sd"],),
r'$Untere KI-Grenze: %.2f$' % (round(plotdata["plot_ci_lower"],2),),
r'$Obere KI-Grenze: %.2f$' % (round(plotdata["plot_ci_upper"],2),),
))
# these are matplotlib.patch.Patch properties
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
# create legend
plt.legend(loc='upper right', prop={'size': 8})
# place a text box in upper left in axes coords
plt.text(0.05, 0.95,textstr,fontsize=14,verticalalignment='top',bbox=props)
if __name__ == "__main__":
root = tk.Tk()
my_gui = Application(root)
root.mainloop()