1#!/usr/bin/env python 2# 3# 4# Licensed to the Apache Software Foundation (ASF) under one 5# or more contributor license agreements. See the NOTICE file 6# distributed with this work for additional information 7# regarding copyright ownership. The ASF licenses this file 8# to you under the Apache License, Version 2.0 (the 9# "License"); you may not use this file except in compliance 10# with the License. You may obtain a copy of the License at 11# 12# http://www.apache.org/licenses/LICENSE-2.0 13# 14# Unless required by applicable law or agreed to in writing, 15# software distributed under the License is distributed on an 16# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17# KIND, either express or implied. See the License for the 18# specific language governing permissions and limitations 19# under the License. 20# 21# 22# 23# graph-svn-dav.py by Brian W. Fitzpatrick <fitz@red-bean.com> 24# 25# This was originally a quick hack to make a pretty picture of svn DAV servers. 26# 27# I've dropped it in Subversion's repository at the request of Karl Fogel. 28# 29# Be warned this this script has many dependencies that don't ship with Python. 30 31import sys 32import os 33import fileinput 34import datetime 35import time 36import datetime 37from matplotlib import dates 38import matplotlib 39matplotlib.use('Agg') 40from matplotlib import pylab 41import Image 42 43OUTPUT_FILE = '../../www/images/svn-dav-securityspace-survey.png' 44OUTPUT_IMAGE_WIDTH = 800 45 46STATS = [ 47 ('1/1/2003', 70), 48 ('2/1/2003', 158), 49 ('3/1/2003', 222), 50 ('4/1/2003', 250), 51 ('5/1/2003', 308), 52 ('6/1/2003', 369), 53 ('7/1/2003', 448), 54 ('8/1/2003', 522), 55 ('9/1/2003', 665), 56 ('10/1/2003', 782), 57 ('11/1/2003', 969), 58 ('12/1/2003', 1009), 59 ('1/1/2004', 1162), 60 ('2/1/2004', 1307), 61 ('3/1/2004', 1424), 62 ('4/1/2004', 1792), 63 ('5/1/2004', 2113), 64 ('6/1/2004', 2502), 65 ('7/1/2004', 2941), 66 ('8/1/2004', 3863), 67 ('9/1/2004', 4174), 68 ('10/1/2004', 4187), 69 ('11/1/2004', 4783), 70 ('12/1/2004', 4995), 71 ('1/1/2005', 5565), 72 ('2/1/2005', 6505), 73 ('3/1/2005', 7897), 74 ('4/1/2005', 8751), 75 ('5/1/2005', 9793), 76 ('6/1/2005', 11534), 77 ('7/1/2005', 12808), 78 ('8/1/2005', 13545), 79 ('9/1/2005', 15233), 80 ('10/1/2005', 17588), 81 ('11/1/2005', 18893), 82 ('12/1/2005', 20278), 83 ('1/1/2006', 21084), 84 ('2/1/2006', 23861), 85 ('3/1/2006', 26540), 86 ('4/1/2006', 29396), 87 ('5/1/2006', 33001), 88 ('6/1/2006', 35082), 89 ('7/1/2006', 38939), 90 ('8/1/2006', 40672), 91 ('9/1/2006', 46525), 92 ('10/1/2006', 54247), 93 ('11/1/2006', 63145), 94 ('12/1/2006', 68988), 95 ('1/1/2007', 77027), 96 ('2/1/2007', 84813), 97 ('3/1/2007', 95679), 98 ('4/1/2007', 103852), 99 ('5/1/2007', 117267), 100 ('6/1/2007', 133665), 101 ('7/1/2007', 137575), 102 ('8/1/2007', 155426), 103 ('9/1/2007', 159055), 104 ('10/1/2007', 169939), 105 ('11/1/2007', 180831), 106 ('12/1/2007', 187093), 107 ('1/1/2008', 199432), 108 ('2/1/2008', 221547), 109 ('3/1/2008', 240794), 110 ('4/1/2008', 255520), 111 ('5/1/2008', 269478), 112 ('6/1/2008', 286614), 113 ('7/1/2008', 294579), 114 ('8/1/2008', 307923), 115 ('9/1/2008', 254757), 116 ('10/1/2008', 268081), 117 ('11/1/2008', 299071), 118 ('12/1/2008', 330884), 119 ('1/1/2009', 369719), 120 ('2/1/2009', 378434), 121 ('3/1/2009', 390502), 122 ('4/1/2009', 408658), 123 ('5/1/2009', 407044), 124 ('6/1/2009', 406520), 125 ('7/1/2009', 334276), 126 ] 127 128 129def get_date(raw_date): 130 month, day, year = map(int, raw_date.split('/')) 131 return datetime.datetime(year, month, day) 132 133 134def get_ordinal_date(date): 135 # This is the only way I can get matplotlib to do the dates right. 136 return int(dates.date2num(get_date(date))) 137 138 139def load_stats(): 140 dates = [get_ordinal_date(date) for date, value in STATS] 141 counts = [x[1] for x in STATS] 142 143 return dates, counts 144 145 146def draw_graph(dates, counts): 147 ########################################################### 148 # Drawing takes place here. 149 pylab.figure(1) 150 151 ax = pylab.subplot(111) 152 pylab.plot_date(dates, counts, 153 color='r', linestyle='-', marker='o', markersize=3) 154 155 ax.xaxis.set_major_formatter( pylab.DateFormatter('%Y') ) 156 ax.xaxis.set_major_locator( pylab.YearLocator() ) 157 ax.xaxis.set_minor_locator( pylab.MonthLocator() ) 158 ax.set_xlim( (dates[0] - 92, dates[len(dates) - 1] + 92) ) 159 160 ax.yaxis.set_major_formatter( pylab.FormatStrFormatter('%d') ) 161 162 pylab.ylabel('Total # of Public DAV Servers') 163 164 lastdate = datetime.datetime.fromordinal(dates[len(dates) - 1]).strftime("%B %Y") 165 pylab.xlabel("Data as of " + lastdate) 166 pylab.title('Security Space Survey of\nPublic Subversion DAV Servers') 167 # End drawing 168 ########################################################### 169 png = open(OUTPUT_FILE, 'w') 170 pylab.savefig(png) 171 png.close() 172 os.rename(OUTPUT_FILE, OUTPUT_FILE + ".tmp.png") 173 try: 174 im = Image.open(OUTPUT_FILE + ".tmp.png", 'r') 175 (width, height) = im.size 176 print("Original size: %d x %d pixels" % (width, height)) 177 scale = float(OUTPUT_IMAGE_WIDTH) / float(width) 178 width = OUTPUT_IMAGE_WIDTH 179 height = int(float(height) * scale) 180 print("Final size: %d x %d pixels" % (width, height)) 181 im = im.resize((width, height), Image.ANTIALIAS) 182 im.save(OUTPUT_FILE, im.format) 183 os.unlink(OUTPUT_FILE + ".tmp.png") 184 except Exception as e: 185 sys.stderr.write("Error attempting to resize the graphic: %s\n" % (str(e))) 186 os.rename(OUTPUT_FILE + ".tmp.png", OUTPUT_FILE) 187 raise 188 pylab.close() 189 190 191if __name__ == '__main__': 192 dates, counts = load_stats() 193 draw_graph(dates, counts) 194 print("Don't forget to update ../../www/svn-dav-securityspace-survey.html!") 195