AsianPlayer/TriDrive / questionnaire /scripts /make_user_study_fig_paper.py
AsianPlayer's picture
download
raw
3.64 kB
"""Table 5 -> figure: three paired-bar panels (appropriateness, timeliness, annoyance) with participant points, paired lines,
95% participant-bootstrap CIs of each condition mean, and the paired Delta with its reported CI and Wilcoxon p. Paper palette."""
import re, numpy as np, matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt, matplotlib.font_manager as fm
from matplotlib.lines import Line2D
import glob
for f in glob.glob("/usr/share/fonts/truetype/msttcorefonts/Times*.ttf"): fm.fontManager.addfont(f)
plt.rcParams.update({"font.family":"Times New Roman","font.size":7,"axes.linewidth":0.5,"xtick.major.width":0.5,"ytick.major.width":0.5,"pdf.fonttype":42})
GREY="#8C8C8C"; LAV="#DDD6E5"; LAVL="#DFEDF2"; INK="#2B2B2B"; PEACHL="#F5D8BF"; LINE="#C8C8C8"
# participant table (appendix H): ID, APP C, APP S, TIM C, TIM S, ANN C, ANN S
rows="""P01 4.00 2.50 7 1 6 --
P02 6.33 4.00 7 1 2 2
P03 4.00 1.67 4 2 2 1
P04 6.33 1.67 6 -- 3 --
P05 6.00 5.00 7 2 4 4
P06 4.33 3.67 6 4 5 1
P07 4.00 4.00 4 4 1 1
P08 3.33 3.00 4 3 5 1
P09 6.67 1.67 6 1 1 1
P10 5.67 1.67 6 1 2 1
P11 7.00 7.00 7 7 1 1
P12 3.67 3.67 5 5 2 1
P13 6.00 6.67 6 6 1 1
P14 6.50 2.67 -- 3 5 2""".splitlines()
def f(x): return np.nan if x=="--" else float(x)
D=np.array([[f(v) for v in r.split()[1:]] for r in rows])
panels=[("Appropriateness",D[:,0],D[:,1],"+1.79 [0.86, 2.75]","p = .008",True),
("Timeliness",D[:,2],D[:,3],"+2.67 [1.33, 4.08]","p = .008",True),
("Annoyance",D[:,4],D[:,5],"+1.17 [0.33, 2.08]","p = .031",False)]
rng=np.random.default_rng(20260922)
def ci(v):
b=[rng.choice(v,len(v)).mean() for _ in range(2000)]; return np.percentile(b,2.5),np.percentile(b,97.5)
fig,axes=plt.subplots(1,3,figsize=(5.5,1.08),dpi=300,gridspec_kw=dict(wspace=0.5,left=0.065,right=0.995,top=0.69,bottom=0.26))
for ax,(name,c,s,dtxt,ptxt,higher_good) in zip(axes,panels):
m=~np.isnan(c)&~np.isnan(s); c,s=c[m],s[m]; n=int(m.sum())
means=[s.mean(),c.mean()]; cis=[ci(s),ci(c)]
x=[0,1]
ax.bar(x,means,width=0.62,color=[GREY,LAV],edgecolor=[GREY,"#B9AFC9"],linewidth=0.5,zorder=1)
for xi,(lo,hi) in zip(x,cis): ax.plot([xi,xi],[lo,hi],color=INK,lw=0.8,zorder=4); ax.plot([xi-0.08,xi+0.08],[lo,lo],color=INK,lw=0.6,zorder=4); ax.plot([xi-0.08,xi+0.08],[hi,hi],color=INK,lw=0.6,zorder=4)
jit=rng.uniform(-0.13,0.13,n)
for k in range(n): ax.plot([0+jit[k],1+jit[k]],[s[k],c[k]],color=LINE,lw=0.4,zorder=2)
ax.scatter(0+jit,s,s=5,color="white",edgecolor=INK,linewidth=0.4,zorder=3); ax.scatter(1+jit,c,s=5,color="white",edgecolor=INK,linewidth=0.4,zorder=3)
ax.set_xticks(x); ax.set_xticklabels([f"openpilot\n{means[0]:.2f}",f"TriDrive\n{means[1]:.2f}"],fontsize=6.5,linespacing=1.1); ax.set_xlim(-0.55,1.55)
ax.set_ylim(0.5,7.6); ax.set_yticks([1,4,7]); ax.tick_params(length=2,pad=1.5)
for sp in ("top","right"): ax.spines[sp].set_visible(False)
ax.spines["left"].set_color(GREY); ax.spines["bottom"].set_color(GREY); ax.tick_params(colors=INK)
ax.text(0.5,1.37,f"{name} (n = {n})",ha="center",va="bottom",fontsize=7.2,color=INK,transform=ax.transAxes,fontweight="bold")
ax.text(0.5,1.09,f"$\\Delta$ {dtxt}, {ptxt}",ha="center",va="bottom",fontsize=6.3,color=INK,transform=ax.transAxes,bbox=dict(boxstyle="round,pad=0.2",fc=PEACHL,ec="none"))
axes[0].set_ylabel("Rating (1–7)",fontsize=6.5,color=INK,labelpad=1)
out="figures/user_study_bars.pdf"
fig.savefig(out); fig.savefig(out.replace(".pdf",".png"),dpi=300); print("saved",out)
for name,c,s,*_ in panels:
m=~np.isnan(c)&~np.isnan(s); print(name,int(m.sum()),round(c[m].mean(),2),round(s[m].mean(),2),round((c[m]-s[m]).mean(),2))

Xet Storage Details

Size:
3.64 kB
·
Xet hash:
1594923a457321b4c1cf2679578bf0bc7ae536bcb33f6fd31d98fad8f3c5a988

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.