|
| 1 | +""" First set of some simple examples. http://datadraw.org |
| 2 | + Usage: python examples1.py .... creates some svg files in cwd |
| 3 | + Or invoked as part of the flask web app. |
| 4 | + Prerequisites: |
| 5 | + a python3.6+ virtual environment; pip -r requirements.txt |
| 6 | +""" |
| 7 | + |
| 8 | +from datadraw import DataDraw, write_svgfile |
| 9 | + |
| 10 | +from sampledata.webhits_3weeks import webhits_3weeks |
| 11 | + |
| 12 | + |
| 13 | +def run_all(): |
| 14 | + """ run examples and return the result svg objects in a dict """ |
| 15 | + ex = Examples1() |
| 16 | + svgset = {} |
| 17 | + svgset['hello_world'] = ex.hello_world() |
| 18 | + svgset['bargraph1'] = ex.bargraph1() |
| 19 | + svgset['curves1'] = ex.curves1() |
| 20 | + svgset['scatterplot1'] = ex.scatterplot1() |
| 21 | + svgset['webhits1'] = ex.webhits1() |
| 22 | + svgset['heatmap1'] = ex.heatmap1() |
| 23 | + svgset['pie1'] = ex.pie1() |
| 24 | + return svgset |
| 25 | + |
| 26 | + |
| 27 | + |
| 28 | +class Examples1: |
| 29 | + |
| 30 | + def __init__(self): |
| 31 | + self.dd = DataDraw() |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | + def hello_world(self): |
| 36 | + """ invoke the built-in test pattern """ |
| 37 | + dd = self.dd |
| 38 | + dd.svgbegin(500, 200, testpat=True) |
| 39 | + return dd.svgresult() |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | + def bargraph1(self): |
| 44 | + mydata = [('Group A', 38.4, 11.8), ('Group B', 67.4, 8.5), ('Group C', 49.2, 6.2)] |
| 45 | + dd = self.dd |
| 46 | + dd.svgbegin(width=300, height=220) |
| 47 | + dd.settext(ptsize=11, color='#777') |
| 48 | + dd.setline(color='#aaa', save=True) |
| 49 | + |
| 50 | + # set up a plotting space with fixed X and Y ranges and draw axes... |
| 51 | + dd.setspace('X', svgrange=(60,290), categorical=['Group A', 'Group B', 'Group C']) |
| 52 | + dd.setspace('Y', svgrange=(60,190), datarange=(0,100)) |
| 53 | + dd.axis('X') |
| 54 | + dd.axis('Y', grid=True) |
| 55 | + dd.plotlabels(ylabel='Score', ylabelpos=-30) |
| 56 | + |
| 57 | + # draw the column bars and error bars... |
| 58 | + for tuple in mydata: |
| 59 | + dd.bar(x=tuple[0], y=tuple[1], color='#8a8', width=18) |
| 60 | + dd.errorbar(x=tuple[0], y=tuple[1], erramt=tuple[2]) |
| 61 | + |
| 62 | + return dd.svgresult() |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | + def curves1(self): |
| 67 | + mydata = [[(0, 33, 8.4), (3, 35, 11.1), (6, 30, 5.8), (12, 34, 9.7), (24, 27, 11.3)], |
| 68 | + [(0, 49, 10.3), (3, 44, 13.9), (6, 67, 7.3), (12, 58, 13.8), (24, 75, 11.2) ]] |
| 69 | + names = ['Treated', 'Control'] |
| 70 | + colors = ['#8d8', '#88d'] |
| 71 | + dd = self.dd |
| 72 | + dd.svgbegin(width=550, height=300) |
| 73 | + dd.settext(ptsize=11, color='#777') |
| 74 | + dd.setline(color='#aaa', save=True) |
| 75 | + |
| 76 | + # set up a plotting space with fixed X and Y ranges and draw axes... |
| 77 | + dd.setspace('X', svgrange=(100,530), datarange=(0,26)) |
| 78 | + dd.setspace('Y', svgrange=(60,280), datarange=(0,100)) |
| 79 | + xstubs = [0, 3, 6, 12, 24] # irregularly spaced X stubs so supply as list |
| 80 | + dd.axis('X', stublist=xstubs) |
| 81 | + dd.axis('Y', grid=True, axisline=None, loc='left-20') |
| 82 | + dd.plotlabels(xlabel='Months after treatment', xlabelpos=-40, |
| 83 | + ylabel='O<sub>2</sub> exchange ratio %', ylabelpos=-60) |
| 84 | + |
| 85 | + # draw the two curves, error bars and data points w/ tooltips |
| 86 | + for group in [0, 1]: |
| 87 | + points = mydata[group] |
| 88 | + dd.setline(color=colors[group], width=3, ) |
| 89 | + dd.legenditem(label=names[group], sample='line') # register current color |
| 90 | + dd.curvebegin() |
| 91 | + for tuple in points: |
| 92 | + dd.curvenext(x=tuple[0], y=tuple[1]) |
| 93 | + dd.setline(restore=True) # restore to most recent 'save' |
| 94 | + for tuple in points: |
| 95 | + dd.errorbar(x=tuple[0], y=tuple[1], erramt=tuple[2]) |
| 96 | + for tuple in points: |
| 97 | + dd.gtag('begin', tooltip=f'{tuple[0]} mos, ratio = {tuple[1]} %') |
| 98 | + dd.datapoint(x=tuple[0], y=tuple[1], color='#fff', |
| 99 | + symbol='(vcircle-o)', diameter=12, opacity=1.0) |
| 100 | + dd.gtag('end') |
| 101 | + |
| 102 | + dd.legendrender(location='top', format='across') |
| 103 | + return dd.svgresult() |
| 104 | + |
| 105 | + |
| 106 | + |
| 107 | + def scatterplot1(self): |
| 108 | + mydata = [('Jean', 77, 85), ('Bill', 93, 88), ('Sarah', 78, 81), ('Ken', 62, 73), |
| 109 | + ('Gladys', 78, 86), ('Frank', 54, 62), ('Dianne', 90, 72)] |
| 110 | + dd = self.dd |
| 111 | + dd.svgbegin(width=300, height=300) |
| 112 | + dd.setline(color='#aaa') |
| 113 | + dd.settext(color='#888') |
| 114 | + |
| 115 | + # set up X and Y space with fixed dataranges and render axes... |
| 116 | + dd.setspace('X', svgrange=(80,280), datarange=(40,100)) |
| 117 | + dd.setspace('Y', svgrange=(80,280), datarange=(40,100)) |
| 118 | + dd.axis('X', tics=8, loc='min-8', axisline=None) |
| 119 | + dd.axis('Y', tics=8, loc='min-8', axisline=None) |
| 120 | + dd.plotbacking(color='#fff', outline=True) |
| 121 | + dd.plotlabels(title='Scores', ylabel='Exam 1', xlabel='Exam 2', ylabelpos=-35) |
| 122 | + |
| 123 | + for tuple in mydata: |
| 124 | + dd.gtag('begin', tooltip=f'{tuple[0]} scored {tuple[1]} and {tuple[2]}') |
| 125 | + dd.datapoint(x=tuple[2], y=tuple[1], symbol='(vcircle-o)', |
| 126 | + color='#a44', diameter=15, opacity=0.4) |
| 127 | + dd.gtag('end', tooltip=tuple[0]) |
| 128 | + |
| 129 | + return dd.svgresult() |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | + def webhits1(self): |
| 134 | + """ In a 3 week datetime X space display web hit data. For datetime formats see: |
| 135 | + https://docs.python.org/3.8/library/datetime.html#strftime-and-strptime-behavior |
| 136 | + """ |
| 137 | + dd = self.dd |
| 138 | + dd.svgbegin(width=620, height=150) |
| 139 | + dd.setline(color='#aaa') |
| 140 | + dd.settext(color='#888') |
| 141 | + dd.setdt('%Y-%m-%d %H:%M:%S.%f', weekday0=6) # beginning of week = Sunday (6) |
| 142 | + |
| 143 | + # dynamically find datetime min and max and use it to set up X space.. |
| 144 | + for timestamp in webhits_3weeks: |
| 145 | + dd.findrange(dd.intdt(timestamp)) |
| 146 | + xrange = dd.findrange_result(nearest='day') |
| 147 | + dd.setspace('X', svgrange=(20,600), datarange=xrange) |
| 148 | + |
| 149 | + dd.setspace('Y', svgrange=(60,140), datarange=(0,10)) # datarange is arbitrary |
| 150 | + |
| 151 | + # create 2 lists of datetime stubs... 1) weekday and day; 2) month 'year |
| 152 | + daystubs = dd.datestubs(xrange, inc='day', dtformat='%a\n%d', terse=True) |
| 153 | + dd.axis('X', stublist=daystubs, tics=-5) |
| 154 | + crossings = dd.datestubs(xrange, inc='month', crossings=True, dtformat="%b'%y") |
| 155 | + dd.axis('X', stublist=crossings, loc=f'bottom-32', axisline=None, stubanchor='start') |
| 156 | + |
| 157 | + # histogram of occurrances using upward clustering technique.. |
| 158 | + dd.setclustering(mode='upward', tolerance=2, offset=0.2) |
| 159 | + for timestamp in sorted(webhits_3weeks): |
| 160 | + dd.datapoint(x=dd.intdt(timestamp), y=0.1, symbol='(vrect)', diameter=4, color='#7a7') |
| 161 | + |
| 162 | + return dd.svgresult() |
| 163 | + |
| 164 | + |
| 165 | + def heatmap1(self): |
| 166 | + """ display a 10 x 10 heatmap of magnitude values """ |
| 167 | + mydata = [ [ 0, 0, 1, 3, 0, 0, 4, 3, 8, 10 ], |
| 168 | + [ 0, 1, 0, 0, 0, 4, 3, 8, 7, 3 ], |
| 169 | + [ 1, 0, 0, 0, 4, 3, 12, 7, 3, 0 ], |
| 170 | + [ 0, 0, 0, 2, 3, 9, 11, 3, 1, 0 ], |
| 171 | + [ 0, 3, 0, 4, 7, 5, 2, 0, 1, 0 ], |
| 172 | + [ 0, 0, 4, 3, 12, 16, 3, 0, 1, 0 ], |
| 173 | + [ 0, 3, 7, 11, 14, 3, 2, 0, 0, 0 ], |
| 174 | + [ 2, 4, 10, 7, 3, 0, 0, 0, 2, 0 ], |
| 175 | + [ 7, 9, 6, 2, 0, 2, 0, 1, 0, 0 ], |
| 176 | + [ 10, 8, 3, 4, 0, 0, 2, 4, 0, 0 ] ] |
| 177 | + |
| 178 | + def cellcolor(val): |
| 179 | + if val == 0: return '#000' |
| 180 | + elif val == 1: return '#303' |
| 181 | + elif val == 2: return '#606' |
| 182 | + elif val <= 4: return '#909' |
| 183 | + elif val <= 8: return '#b0b' |
| 184 | + elif val < 12: return '#d0d' |
| 185 | + return '#f0f' |
| 186 | + |
| 187 | + dd = self.dd |
| 188 | + dd.svgbegin(width=400, height=380) |
| 189 | + textstyle = 'font-family: sans-serif; font-weight: bold;' # css style |
| 190 | + dd.settext(color='#777', ptsize=12, style=textstyle) |
| 191 | + dd.setline(color='#777') |
| 192 | + |
| 193 | + # set up X and Y space with fixed ranges, and draw axes.. |
| 194 | + dd.setspace('X', svgrange=(100,350), datarange=(0,10)) |
| 195 | + dd.setspace('Y', svgrange=(100,350), datarange=(0,10)) |
| 196 | + dd.axis('X', tics=8, loc='min-8') |
| 197 | + dd.axis('Y', tics=8, loc='min-8') |
| 198 | + dd.plotbacking(color='#eee', outline=True) |
| 199 | + dd.plotlabels(ylabel='Δ density g/cm<sup>2</sup>', ylabelpos=-40, |
| 200 | + xlabel='Δ weight g', xlabelpos=-45) # 916 = Δ |
| 201 | + |
| 202 | + # render heatmap as a matrix of colored rectangles... |
| 203 | + for iy in reversed(range(10)): # top to bottom |
| 204 | + for ix in range(10): |
| 205 | + val = mydata[ix][iy] |
| 206 | + if val == None: |
| 207 | + continue |
| 208 | + dd.gtag('begin', tooltip=f'({ix},{iy}) magnitude is {val}') |
| 209 | + dd.rectangle(cx=ix+0.5, cy=iy+0.5, width=1.0, height=1.0, color=cellcolor(val)) |
| 210 | + dd.gtag('end') |
| 211 | + |
| 212 | + return dd.svgresult() |
| 213 | + |
| 214 | + |
| 215 | + |
| 216 | + def pie1(self): |
| 217 | + mydata = [ 0.33, 0.25, 0.2, 0.15, 0.07 ] |
| 218 | + dd = self.dd |
| 219 | + dd.svgbegin(width=500, height=300) |
| 220 | + textstyle = 'font-family: sans-serif; font-weight: bold;' # css style |
| 221 | + dd.settext(color='#333', style=textstyle) |
| 222 | + |
| 223 | + # set up X space and Y space for centering of pie... |
| 224 | + dd.setspace('X', svgrange=(50,400)) |
| 225 | + dd.setspace('Y', svgrange=(50,280)) |
| 226 | + |
| 227 | + dd.setline(color='#aaa', width=0.5); |
| 228 | + dd.plotbacking(outline=True, rounded=True) |
| 229 | + |
| 230 | + colors = [ '#f00', '#0f0', '#aaf', '#0ff', '#ff0', '#f0f' ] |
| 231 | + labels = [ 'Delaware', 'Vermont', 'Alabama', 'Utah', 'Arkansas' ] |
| 232 | + |
| 233 | + # render pie slices, with a legend and tooltip for each... |
| 234 | + dd.setline( color='#fff', width=4 ) # outline the slices w/ a fat white line |
| 235 | + accum = 0.4; # rotate entire pie 0.4 radians for pleasing appearance |
| 236 | + islice = 0 |
| 237 | + for val in mydata: |
| 238 | + dd.gtag('begin', tooltip=labels[islice]) |
| 239 | + dd.pieslice(pctval=val, startval=accum, color=colors[islice], |
| 240 | + outline=True, showpct=True, opacity=0.5 ) |
| 241 | + dd.gtag('end') |
| 242 | + dd.legenditem(sample='square', label=labels[islice], color=colors[islice]) |
| 243 | + accum += val |
| 244 | + islice += 1 |
| 245 | + |
| 246 | + # render the legend |
| 247 | + dd.settext( color='#888' ) |
| 248 | + dd.legendrender(title='Incidence by U.S. state') |
| 249 | + |
| 250 | + return dd.svgresult() |
| 251 | + |
| 252 | + |
| 253 | +if __name__ == "__main__": |
| 254 | + svgset = run_all() |
| 255 | + print('writing svg to files...') |
| 256 | + for key in svgset: |
| 257 | + print(f' {key}.svg ...') |
| 258 | + write_svgfile(svgset[key], f'{key}.svg') |
| 259 | + print('Done.') |
0 commit comments