()
| 168 | |
| 169 | |
| 170 | def write_svg() -> None: |
| 171 | parts = [ |
| 172 | f'<svg xmlns="http://www.w3.org/2000/svg" width="{W}" height="{H}" viewBox="0 0 {W} {H}">', |
| 173 | '<rect width="100%" height="100%" fill="white"/>', |
| 174 | "<defs>", |
| 175 | '<linearGradient id="driftbar" x1="0" x2="0" y1="0" y2="1">', |
| 176 | f'<stop offset="0%" stop-color="{rgb(color_for_score(1))}"/>', |
| 177 | f'<stop offset="100%" stop-color="{rgb(color_for_score(0))}"/>', |
| 178 | "</linearGradient>", |
| 179 | "</defs>", |
| 180 | ] |
| 181 | |
| 182 | for r, method in enumerate(METHODS): |
| 183 | y = TOP + r * CELL_H |
| 184 | parts.append( |
| 185 | f'<text x="{LEFT - 28}" y="{y + CELL_H / 2 + 9}" ' |
| 186 | f'font-family="Times New Roman" font-size="23" font-weight="700" ' |
| 187 | f'text-anchor="end" fill="{rgb(TEXT)}">{method}</text>' |
| 188 | ) |
| 189 | |
| 190 | for c, (_metric, direction, values) in enumerate(METRICS): |
| 191 | x = LEFT + c * CELL_W |
| 192 | score = score_for_metric(values, r, direction) |
| 193 | parts.append( |
| 194 | f'<rect x="{x}" y="{y}" width="{CELL_W - GAP}" height="{CELL_H - GAP}" ' |
| 195 | f'fill="{rgb(color_for_score(score))}"/>' |
| 196 | ) |
| 197 | parts.append( |
| 198 | f'<text x="{x + CELL_W / 2}" y="{y + CELL_H / 2 + 8}" ' |
| 199 | f'font-family="Times New Roman" font-size="20" font-weight="700" ' |
| 200 | f'text-anchor="middle" fill="rgb(0,0,0)">{fmt(values[r])}</text>' |
| 201 | ) |
| 202 | |
| 203 | label_y = TOP + len(METHODS) * CELL_H + 49 |
| 204 | for c, (metric, direction, _values) in enumerate(METRICS): |
| 205 | x = LEFT + c * CELL_W + CELL_W / 2 |
| 206 | label = metric + (" \u2193" if direction == "down" else " \u2191") |
| 207 | parts.append( |
| 208 | f'<text x="{x}" y="{label_y}" transform="rotate(-21 {x} {label_y})" ' |
| 209 | f'font-family="Times New Roman" font-size="18" font-weight="700" ' |
| 210 | f'text-anchor="middle" fill="{rgb(TEXT)}">{label}</text>' |
| 211 | ) |
| 212 | |
| 213 | bar_x = LEFT + len(METRICS) * CELL_W + 32 |
| 214 | bar_y = TOP + 4 |
| 215 | bar_h = len(METHODS) * CELL_H - GAP |
| 216 | parts.append( |
| 217 | f'<rect x="{bar_x}" y="{bar_y}" width="14" height="{bar_h}" fill="url(#driftbar)"/>' |
| 218 | ) |
| 219 | parts.append( |
| 220 | f'<text x="{bar_x + 23}" y="{bar_y + 11}" font-family="Times New Roman" ' |
| 221 | f'font-size="17" fill="{rgb(TEXT)}">better</text>' |
| 222 | ) |
| 223 | parts.append( |
| 224 | f'<text x="{bar_x + 23}" y="{bar_y + bar_h}" font-family="Times New Roman" ' |
| 225 | f'font-size="17" fill="{rgb(TEXT)}">worse</text>' |
| 226 | ) |
| 227 | parts.append("</svg>") |
no test coverage detected