#!/usr/bin/python # # convert -delay 5 `ls -rt *.png` animation.gif import sys import getopt import GeoIP from pylab import * from time import ctime import matplotlib from matplotlib.numerix import ma from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas from matplotlib.toolkits.basemap import Basemap from matplotlib.colors import LogNorm from matplotlib.ticker import LogFormatterMathtext as JefFormatter gi = GeoIP.open("/usr/share/GeoIP/GeoLiteCity.dat", GeoIP.GEOIP_MEMORY_CACHE) # turn interactive mode on for dynamic updates. If you aren't in # interactive mode, you'll need to use a GUI event handler/timer. #p.ion() #alphas = p.arange(0,1,0.01) #x = 2*p.pi*alphas #print x.shape #lines=[] #for i in xrange(len(alphas)): # lines.append(p.scatter([x[i]], [p.sin(x[i])],alpha=alphas[i],edgecolor=(0,0,0,0))) # #for i in xrange(len(alphas)): # for j in xrange(len(lines)): # a=lines[j].get_alpha() # lines[j].set_alpha(a+0.1 % 1) # update the data # p.draw() # redraw the canvas def draw_client_animation(clients=None,r={}): iplist={} lons={} lats={} for client in clients.keys(): client_hour=int((clients[client]['epoch']-min_epoch)/3600) if not iplist.has_key(client_hour): iplist[client_hour]=set([]) iplist[client_hour].add(client) cummulative_iplist={} for hour in xrange(frame_hours): current_hour_epoch=min_epoch+3600*hour framefilename=outdir+"/"+frame_prefix+"%d" % (hour,)+"."+frame_filetype if not cummulative_iplist.has_key(hour): cummulative_iplist[hour]=set([]) m = Basemap(llcrnrlon=r['ll_lon'],llcrnrlat=r['ll_lat'],urcrnrlon=r['ur_lon'],urcrnrlat=r['ur_lat'],\ resolution='l',projection='cyl') for h in xrange(hour+1): # print h, len(iplist[h]) if iplist.has_key(h): cummulative_iplist[hour].update(iplist[h]) print h, len(cummulative_iplist[hour]) Z,C=parse_iplist(cummulative_iplist[hour],m,clients) if iplist.has_key(hour): if not lons.has_key(hour): lons[hour]=[] for ip in iplist[hour]: lons[hour].append(clients[ip]['lon']) if not lats.has_key(hour): lats[hour]=[] for ip in iplist[hour]: lats[hour].append(clients[ip]['lat']) # plot them as filled circles on the map. # first, create a figure. dpi=100 dimx=800/dpi dimy=400/dpi fig=figure(1,figsize=(dimx,dimy), dpi=dpi, frameon=True, facecolor='blue',edgecolor='white') clf() ax=fig.add_axes([0.05,0.1,0.8,0.8],axisbg=(0.05,0.65,0.05)) canvas = FigureCanvas(fig) # draw coasts and fill continents. m.drawcoastlines(linewidth=0.5) m.drawcountries(linewidth=0.5) m.drawlsmask([100,100,100,0],[100,210,210,255]) palette = cm.YlOrRd print len(lats),len(lons),Z.shape m.imshow(Z,palette,extent=(m.xmin,m.xmax,m.ymin,m.ymax), norm=LogNorm(),interpolation='gaussian') if lons.has_key(hour) :s=m.scatter(lons[hour],lats[hour],s=5,c='b',edgecolor=(0,0,0,0),alpha=0.8) if lons.has_key(hour-1):s=m.scatter(lons[hour-1],lats[hour-1],s=5,c='b',edgecolor=(0,0,0,0),alpha=0.5) if lons.has_key(hour-2):s=m.scatter(lons[hour-2],lats[hour-2],s=5,c='b',edgecolor=(0,0,0,0),alpha=0.2) l,b,w,h = ax.get_position() cax = axes([l+w+0.005, b, 0.03, h]) colorbar(cax=cax,format=JefFormatter()) # draw colorbar figtext(l+w+0.1,0.5,"Client Density: clients per km^2",va="center",ha="center",rotation="vertical",fontsize=10) figtext(0.05,0.05,footer,backgroundcolor='white',fontsize="smaller",va="bottom") figtext(0.05,0.95,header,backgroundcolor='white',fontsize="smaller",va="top") figtext(0.055,0.11,"Time: %s" % (ctime(current_hour_epoch),),backgroundcolor='white',fontsize="smaller",va="bottom") figtext(0.641,0.11,"Total Clients: %-12d " % (len(cummulative_iplist[hour]),),backgroundcolor='white',fontsize="smaller",va="bottom") canvas.print_figure(framefilename, dpi=100,facecolor='white',edgecolor='white') if stats : for country,count in countries.items(): print country," :: ",count def parse_iplist(iplist,m,clients,latpixels=180,lonpixels=360,lat_smooth=1,lon_smooth=1): rad_deg=pi/180.0 r0=6378.1 latscale=(m.ymax-m.ymin)/latpixels lonscale=(m.xmax-m.xmin)/lonpixels lat_array=arange(m.ymin,m.ymax+latscale,latscale) lon_array=arange(m.xmin,m.xmax+lonscale,lonscale) maxlat=len(lat_array)-1 maxlon=len(lon_array)-1 Z=zeros((len(lat_array),len(lon_array)),dtype='float') seen_countries={} f = open(inputfile, 'r') for ip in iplist: # print clients[ip].keys() country_code=clients[ip]['cc'] # Deal with client if stats == True: if seen_countries.has_key(country_code) : seen_countries[country_code]+=1 else : seen_countries[country_code]=1 lat=clients[ip]['lat'] lon=clients[ip]['lon'] if ( lat == 0.0 ) and ( lon == 0.0 ) : # print "Lat/Lon 0.0:",country_code lat = -89.0 i_lat=int(float((lat-lat_array[0]))/float(latscale)) i_lon=int(float((lon-lon_array[0]))/float(lonscale)) for i in xrange(-int(lat_smooth),int(lat_smooth+1),1): for j in xrange(-int(lon_smooth),int(lon_smooth+1),1): if ( i_lat+i >= 0 ) and (i_lat+i < maxlat) : if ( i_lon+j >= 0) and ( i_lon+j < maxlon) : Z[i_lat+i,i_lon+j]+=1.0 f.close() # End of file, now do summary density calculation for i in xrange(len(lat_array)): area=r0*r0*rad_deg*lonscale*abs( sin(rad_deg*(lat_array[i]-latscale/2.0) )-sin(rad_deg*(lat_array[i]+latscale/2.0) ) ) for j in xrange(len(lon_array)): if area == 0.0 : Z[i,j]=0.0 else: Z[i,j]=Z[i,j]/area/(2.0*lon_smooth+1)/(2.0*lat_smooth+1) # Lon,Lat=meshgrid(lon_array,lat_array) # X,Y=m(Lon,Lat) Z = where(Z <= 0.,1.e10,Z) Z = ma.masked_values(Z, 1.e10) return Z,seen_countries def parse_file(): clients={} min_epoch=float('inf') max_epoch=int(0) if not (timingfile is None): try: f = open(timingfile, 'r') for line in f: epoch=int(line.strip().split()[0].strip()) ip=line.strip().split()[1].strip() gir=None try: gir = gi.record_by_addr(ip) except: continue if not clients.has_key(ip): clients[ip]={} clients[ip]['epoch']=epoch if gir != None: clients[ip]['cc']=str(gir['country_code']) clients[ip]['lat']=gir['latitude'] clients[ip]['lon']=gir['longitude'] else : clients[ip]['cc']='AP' clients[ip]['lat']=0.0 clients[ip]['lon']=0.0 if epoch < clients[ip]['epoch'] : clients[ip]['epoch']=epoch if epoch < min_epoch : min_epoch=epoch if epoch > max_epoch : max_epoch=epoch f.close() except: print "Error parsing timingfile %s" % timingfile sys.exit(2) return clients,min_epoch,max_epoch def parse_regions(region=None): r={} if region is None: r={'name':'World','ll_lat':-90,'ur_lat':90,'ll_lon':-180,'ur_lon':180} else: if not (regionsfile is None): try: f = open(regionsfile, 'r') for line in f: if region==line.strip().split(":")[0].strip(): r['name']=line.strip().split(":")[0].strip() r['ll_lat']=float(line.strip().split(":")[1]) r['ur_lat']=float(line.strip().split(":")[2]) r['ll_lon']=float(line.strip().split(":")[3]) r['ur_lon']=float(line.strip().split(":")[4]) break f.close() except: print "Error parsing regionsfile %s" % regionsfile sys.exit(2) return r def usage(): print "%s --header=header --footer=footer --input=inputfile --output=outputfile --indir=indir" % sys.argv[0] +\ " --region=region --regionsfile=regionsfile --outdir=outdir -v" def main(): try: opts, args = getopt.getopt(sys.argv[1:], "h:f:i:o:v:r:s",\ ["help","verbose","stats","list-regions","indir=","outdir=","input=","output=","footer=","header=","region=","regionsfile=","timingfile="]) except getopt.GetoptError: # print help information and exit: usage() sys.exit(2) global header, footer, inputfile,outputfile,indir,outdir, stats, verbose,timingfile global frame_prefix,frame_filetype,fade_hours,frame_hours,min_epoch,max_epoch verbose = False stats = False listregions=False regionsfile=None inputfile=None outputfile=None region=None header="" footer="" indir='./' outdir='./animation-frames/' frame_prefix=None frame_filetype='png' timingfile=None for o, a in opts: if o in ("-h","--header"): header = a if o in ("-f","--footer"): footer = a if o in ("-i","--input"): inputfile = a if o in ("-o","--output"): outputfile = a if o == "--indir": indir = a if o == "--outdir": outdir = a if o == "--regionsfile": regionsfile = a if o == "--timingfile": timingfile = a if o in ("-r","--region"): region = a if o in ("-v","--verbose"): verbose = True if o in ("-s","--stats"): stats = True if o in ("--help"): usage() sys.exit() if o in ("--list-timing"): listtiming=True if outputfile is None : outputfile = outdir+'/clientmap.png' if inputfile is None : inputfile = indir+'/ips.txt' if regionsfile is None : regionsfile = indir+'/regions.txt' if timingfile is None : timingfile = indir+'/f7.txt' if frame_prefix is None : frame_prefix='frame_' clients,min_epoch,max_epoch=parse_file() r=parse_regions(region) fade_hours=3 frame_hours=(max_epoch-min_epoch)/3600+1+fade_hours print min_epoch,max_epoch,frame_hours draw_client_animation(clients,r) if __name__ == "__main__": sys.exit(main())