#!/usr/bin/python # Chart.py # 2005 Mar 07 . ccr # This program produces charts from the FARS data. It reads a .csv # file on standard input. from __future__ import division import sys import os import pylab ZERO=0 SPACE=' ' NULL='' NUL='\x00' NA=-1 def UnQuote(aStr): aStr=aStr.strip() if aStr[ZERO] in ['"',"'"]: return aStr[1:-1] else: return aStr def Val(aStr): aStr=UnQuote(aStr) if aStr.find('.')==NA: return int(aStr) else: return float(aStr) class cSeries(dict): def __init__(self): dict.__init__(self) __Input=sys.stdin __Line=__Input.readline()[:-1] while __Line!=NULL: __Cols=__Line.split(',') __Label=UnQuote(__Cols[ZERO]) __Values=[Val(__Col) for __Col in __Cols[1:]] self[__Label]=pylab.array(__Values) __Line=__Input.readline()[:-1] return class cPlot(object): def __init__(self): self.SetColors() self.SetFonts() self.SetDimensionsInches() self.SetFigure() self.SetAxesProportions() self.SetAxes() return def SetColors(self): self.fBG='cornsilk' self.fFGList=['cornflowerblue','brown'] return def SetFonts(self): self.fFontTitle={'family':'serif','size':24} self.fFontAxisLabel={'family':'serif','size':14} self.fFontXTicks={'family':'serif','size':14,'rotation':'vertical'} self.fFontYTicks={'family':'serif','size':14} self.fFontLegend={'family':'serif','size':14} return def SetDimensionsInches(self,aWidth=8.0,aHeight=4.0): self.fWidth=aWidth self.fHeight=aHeight return def SetFigure(self): self.fFigure=pylab.figure(figsize=(self.fWidth,self.fHeight)) return def SetAxesProportions(self,aHorFraction=0.6,aVerFraction=0.6): __XMarg=(1.0-aHorFraction)*0.5 __YMarg=(1.0-aVerFraction)*0.5 self.fAxesProportions=[__XMarg,__YMarg,aHorFraction,aVerFraction] return def SetAxes(self): self.fAxes=pylab.axes(self.fAxesProportions,axisbg=self.fBG) self.fXAxis=pylab.get(self.fAxes,'xaxis') self.fYAxis=pylab.get(self.fAxes,'yaxis') return def SetTickMarks(self,aRight=True,aTop=True): if aRight: pass else: self.fYAxis.tick_left() if aTop: pass else: self.fXAxis.tick_bottom() return def SetGrid(self,aHor=True,aVer=True): pylab.grid() self.fXGridLines=pylab.get(self.fAxes,'xgridlines') self.fYGridLines=pylab.get(self.fAxes,'ygridlines') if aHor: pass else: pylab.set(self.fYGridLines,color=self.fBG) if aVer: pass else: pylab.set(self.fXGridLines,color=self.fBG) pylab.set(self.fXGridLines,linestyle='-') pylab.set(self.fYGridLines,linestyle='-') return def SetTickFonts(self): __YTickLabels=pylab.get(self.fAxes,'yticklabels') pylab.set(__YTickLabels,**self.fFontYTicks) __XTickLabels=pylab.get(self.fAxes,'xticklabels') pylab.set(__XTickLabels,**self.fFontXTicks) return def Display(self,aLabel,aShow=False,aSave=False): if aSave:pylab.savefig(aLabel+'.jpg',dpi=90) if aShow:pylab.show() return def SetYScale(self,aYMin,aYMax): pylab.ylim(aYMin,aYMax) return class cBarPlot(cPlot): def __init__(self,aLabel,aTitle=None,aYMin=ZERO,aYMax=None): self.fIsMultiline=isinstance(aLabel,list) cPlot.__init__(self) if self.fIsMultiline: __Patches=self.SetPlot(aLabel) else: __Patches=self.SetPlot([aLabel]) if self.fIsMultiline: __Name='%s with %s' % (aLabel[ZERO],aLabel[1]) self.SetLegend(__Patches,aTitle,'upper center') else: __Name=aLabel self.SetTitle(__Name,aTitle) if aYMax is None: pass else: self.SetYScale(aYMin,aYMax) self.SetGrid(aVer=False) self.Display(__Name,aSave=True) return def SetLegend(self,aPatches,aLabels,aLocation): __Legend=pylab.figlegend(aPatches,aLabels,aLocation) __Text=pylab.get(__Legend,'texts') __Frame=pylab.get(__Legend,'frame') pylab.set(__Frame,facecolor=self.fBG) pylab.set(__Text,**self.fFontLegend) return def SetTitle(self,aLabel,aTitle=None): if aTitle is None: self.fTitle=pylab.title(aLabel) else: self.fTitle=pylab.title(aTitle) pylab.set(self.fTitle,**self.fFontTitle) return def SetPlot(self,aLabels): __Curves=len(aLabels) self.fTickProportion=0.74 self.fBarProportion=self.fTickProportion/__Curves __XMin=1983-self.fTickProportion __XMax=2003+self.fTickProportion __X=DATA['Year'] __Curve=ZERO __Result=[] for __Label in aLabels: __Y=DATA[__Label] __Result.append(pylab.bar(__X-0.5*self.fTickProportion+self.fBarProportion*__Curve, __Y, self.fBarProportion, color=self.fFGList[__Curve])[ZERO]) __Curve+=1 pylab.xlim(__XMin,__XMax) pylab.xticks(__X) self.SetTickMarks(aTop=False) self.SetTickFonts() return __Result class cScatterPlot(cPlot): def __init__(self,aXLabel,aYLabel,aXCaption=None,aYCaption=None,aYMin=ZERO,aYMax=None): cPlot.__init__(self) self.SetXLabel(aXLabel,aXCaption) self.SetYLabel(aYLabel,aYCaption) self.SetPlot(aXLabel,aYLabel) if aYMax is None: pass else: self.SetYScale(aYMin,aYMax) self.SetGrid() self.Display('%s vs %s' % (aYLabel,aXLabel),aSave=True) return def SetAxesProportions(self,aHorFraction=0.3,aVerFraction=0.6): __XMarg=(1.0-aHorFraction)*0.5 __YMarg=(1.0-aVerFraction)*0.75 self.fAxesProportions=[__XMarg,__YMarg,aHorFraction,aVerFraction] return def SetColors(self): self.fBG='honeydew' self.fFGList=['brown'] return def SetFonts(self): self.fFontTitle={'family':'serif','size':24} self.fFontAxisLabel={'family':'serif','size':14} self.fFontXTicks={'family':'serif','size':14,'rotation':'vertical'} self.fFontYTicks={'family':'serif','size':14} return def SetXLabel(self,aLabel,aTitle=None): if aTitle is None: self.fXLabel=pylab.xlabel(aLabel) else: self.fXLabel=pylab.xlabel(aTitle) pylab.set(self.fXLabel,**self.fFontAxisLabel) return def SetYLabel(self,aLabel,aTitle=None): if aTitle is None: self.fYLabel=pylab.ylabel(aLabel) else: self.fYLabel=pylab.ylabel(aTitle) pylab.set(self.fYLabel,**self.fFontAxisLabel) return def SetPlot(self,aXLabel,aYLabel,aMarker='s',aPt2=36): __X=DATA[aXLabel] __Y=DATA[aYLabel] pylab.scatter(__X,__Y, marker=aMarker, s=aPt2, c=self.fFGList[ZERO]) self.SetTickFonts() return DATA=cSeries() DATA['MC M VMT']=pylab.array(( 8760, 8784, 9086, 9397, 9506, 10024, 10371, 9557, 9178, 9557, 9906, 10240, 9797, 9920, 10081, 10283, 10584, 10469, 9639, 9552, 9539 )) DATA['MC Registrations']=pylab.array(( 5585112, 5479822, 5444404, 5198993, 4885772, 4584284, 4420420, 4259462, 4177365, 4065118, 3977856, 3756555, 3767029, 3871599, 3826373, 3879450, 4152433, 4346068, 4903056, 5004156, 5370035 )) DATA['MC K Registrations']=DATA['MC Registrations']/1000 DATA['Percent MC Drivers < 25']=DATA['MC Drivers Under 25']/DATA['MC Drivers']*100.0 DATA['Percent MC Drivers >= 40']=DATA['MC Drivers 40 or Over']/DATA['MC Drivers']*100.0 DATA['Percent MCs <= 250 cc']=DATA['MCs <= 250 cc Displacement']/(DATA['MC Drivers']- DATA['MCs Unknown Displacement'])*100.0 DATA['Percent MCs >= 1000 cc']=DATA['MCs >= 1000 cc Displacement']/(DATA['MC Drivers']- DATA['MCs Unknown Displacement'])*100.0 DATA['Predicted MC Rider Fatalities']=-692.12*DATA['MC Mean Age']+8093.44 DATA['Residuals']=DATA['Predicted MC Rider Fatalities']-DATA['MC-Rider Fatalities'] if True: cBarPlot('MC-Rider Fatalities', aTitle='Motorcycle Rider Fatalities') cBarPlot('Fatalities', aTitle='All Traffic Fatalities') cScatterPlot('MC-Rider Fatalities', 'Fatalities', aXCaption='Motorcycle Rider Fatalities', aYCaption='All Traffic Fatalities') cBarPlot('MC M VMT', aTitle='Motorcycle VMT (Millions)') cScatterPlot('MC-Rider Fatalities', 'MC M VMT', aXCaption='Motorcycle Rider Fatalities', aYCaption='Motorcycle VMT (Millions)') cBarPlot('MC K Registrations', aTitle='Motorcycle Registrations (Thousands)') cScatterPlot('MC-Rider Fatalities', 'MC K Registrations', aXCaption='Motorcycle Rider Fatalities', aYCaption='Motorcycle Registrations (Thousands)') cBarPlot('Percent MC Drivers < 25', aTitle='Percent of Drivers < 25', aYMax=100.0) cScatterPlot('MC-Rider Fatalities', 'Percent MC Drivers < 25', aXCaption='Motorcycle Rider Fatalities', aYCaption='Percent of Drivers < 25') cBarPlot('Percent MC Drivers >= 40', aTitle='Percent of Drivers >= 40', aYMax=100.0) cScatterPlot('MC-Rider Fatalities', 'Percent MC Drivers >= 40', aXCaption='Motorcycle Rider Fatalities', aYCaption='Percent of Drivers >= 40') cBarPlot('Percent MCs <= 250 cc', aTitle='Percent of Motorcycles <= 250 cc', aYMax=100.0) cScatterPlot('MC-Rider Fatalities', 'Percent MCs <= 250 cc', aXCaption='Motorcycle Rider Fatalities', aYCaption='Percent of Motorcycles <= 250 cc') cBarPlot('Percent MCs >= 1000 cc', aTitle='Percent of Motorcycles >= 1000 cc', aYMax=100.0) cScatterPlot('MC-Rider Fatalities', 'Percent MCs >= 1000 cc', aXCaption='Motorcycle Rider Fatalities', aYCaption='Percent of Motorcycles >= 1000 cc') cBarPlot('MC Mean Age', aTitle='Average Motorcycle Age') cScatterPlot('MC-Rider Fatalities', 'MC Mean Age', aXCaption='Motorcycle Rider Fatalities', aYCaption='Average Motorcycle Age') cBarPlot(['MC-Rider Fatalities','Predicted MC Rider Fatalities'], aTitle=['Actual Motorcycle Rider Fatalities','Predicted Motorcycle Rider Fatalities']) cScatterPlot('MC-Rider Fatalities', 'Residuals', aXCaption='Motorcycle Rider Fatalities') # Fin