codexpast-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford2017imperative-cable-tv-decorator.py
past-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford/2017/imperative-cable-tv-decorator.py
"""Draw the extended UML class diagram; write the PNG to cwd."""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle,Polygon
plt.rcParams.update({'font.family':'DejaVu Sans','font.size':12})
fig,ax=plt.subplots(figsize=(12,7),dpi=100,facecolor='white')
ax.set(xlim=(0,12),ylim=(0,7));ax.axis('off')
ax.text(6,6.85,'Cable TV accounts: optional packages as decorators',ha='center',fontsize=18,weight='bold')
def box(x,y,w,h,name,body,color='#edf3fb',italic=False):
ax.add_patch(Rectangle((x,y),w,h,facecolor=color,edgecolor='#334155',lw=1.5,zorder=3))
ax.plot([x,x+w],[y+h-.48,y+h-.48],color='#334155',lw=1,zorder=4)
ax.text(x+w/2,y+h-.24,name,ha='center',va='center',fontstyle='italic'if italic else'normal',weight='bold',zorder=4)
ax.text(x+.12,y+h-.62,body,ha='left',va='top',linespacing=1.5,zorder=4)
def triangle_up(x,y):
ax.add_patch(Polygon([(x,y),(x-.13,y-.25),(x+.13,y-.25)],closed=True,facecolor='white',edgecolor='#334155',lw=1.4,zorder=2))
box(4.5,5.2,3,1.35,'«trait» CableTV','+ cost: Double\n+ packages: String')
box(.7,3.3,2.6,1.1,'BasicPlan','cost £30; basic description')
box(5.1,3.15,3.2,1.45,'Packages (abstract)','− account: CableTV\nqueries delegate to account',italic=True)
box(.4,.9,3,1.15,'Movies','cost adds £10\npackages appends Movies')
box(4.5,.9,3,1.15,'HDChannels','cost adds £7\npackages appends HD channels')
box(8.5,.9,3,1.15,'Sports','cost adds £5\npackages appends Sports',color='#dcfce7')
# Interface realizations: dashed stems and hollow triangles at CableTV.
ax.plot([2,2,5.25,5.25],[4.4,4.8,4.8,4.95],ls='--',color='#334155',lw=1.4)
triangle_up(5.25,5.2)
ax.plot([6.7,6.7],[4.6,4.95],ls='--',color='#334155',lw=1.4)
triangle_up(6.7,5.2)
# Directed association: no lifetime/ownership diamond is claimed.
ax.plot([8.3,10.5,10.5,7.75],[3.85,3.85,5.85,5.85],color='#334155',lw=1.3)
ax.annotate('',(7.5,5.85),(7.85,5.85),arrowprops={'arrowstyle':'->','lw':1.3,'color':'#334155'})
ax.text(10.55,5.05,'account: CableTV\n1',ha='right',va='center',fontsize=11)
# Concrete decorators inherit Packages through a shared generalization stem.
for x in [1.9,6,10]:ax.plot([x,x],[2.05,2.55],color='#334155',lw=1.4)
ax.plot([1.9,10],[2.55,2.55],color='#334155',lw=1.4)
ax.plot([6.7,6.7],[2.55,2.9],color='#334155',lw=1.4)
triangle_up(6.7,3.15)
ax.text(6,.35,'Hollow triangle: general classifier. Dashed line: interface realization. Solid line: inheritance or association.',ha='center',fontsize=11)
fig.subplots_adjust(left=.015,right=.985,bottom=.015,top=.985)
fig.savefig(Path(__file__).with_suffix('.png').name,facecolor='white')
plt.close(fig)