def create_slider(districts_file, population_file, households_file, persons_file, transmission_log): """ Create plot with interactive slider. """ ####################################### # Gather information about districts. # ####################################### districts = {} districts[0] = (0,0,0) latitudes = [] longitudes = [] with open(districts_file, 'r') as district_file: reader = csv.DictReader(district_file, delimiter=';') for row in reader: d_id = int(row['id']) x = float(row['latitude'].replace(",", ".")) y = float(row['longitude'].replace(",", ".")) pop_size = int(row['pop_size']) # Don't add districts with incorrect location data if abs(x) < 90 and abs(y) < 180: latitudes.append(x) longitudes.append(y) districts[d_id] = (x, y, pop_size) # Use Smopy to get map image for the given region (calculated from min/max latitudes/longitudes in districts file) region_map = smopy.Map((min(latitudes), min(longitudes), max(latitudes), max(longitudes)), z=9) ################################################################## # Gather information about persons and households in simulation. # ################################################################## # Check how long each person stays ill (= infectious) when infected. person_infectiousness = {} with open(persons_file, 'r') as person_file: reader = csv.DictReader(person_file, delimiter=';') for row in reader: person_infectiousness[int(row['id'])] = row['end_infectiousness'] # For each person, fetch the household ID person_households = [] with open (population_file, 'r') as pop_file: reader = csv.DictReader(pop_file, delimiter=";") for row in reader: person_households.append(int(float(row['household_id']))) # For each household, fetch the district it belongs to. households = {} with open(households_file, 'r') as hh_file: reader = csv.DictReader(hh_file, delimiter=';') for row in reader: hh_id = int(row['id']) d_id = int(row['district_id']) households[hh_id] = d_id ######################################## # Gather information about infections. # ######################################## prepare_csv_transmissions(transmission_log, "infections.csv") infections = {} with open('./infections.csv', 'r') as infections_file: reader = csv.DictReader(infections_file, delimiter=",") for row in reader: person_id = int(row['person_id']) if (person_id < len(person_infectiousness) + 1): hh_id = person_households[person_id] district = households[hh_id] start_infected = int(row['begin_infection']) end_infected = start_infected + int(person_infectiousness[person_id]) for day in range(start_infected, end_infected + 1): if day in infections: # add extra infection if district in infections[day]: infections[day][district] += 1 else: infections[day][district] = 1 else: # add first infection infections[day] = {} infections[day][district] = 1 ################## # Create figure. # ################## fig, ax = plt.subplots() fig.canvas.set_window_title("Evolution of disease spread") plt.subplots_adjust(bottom=0.25) # Legend for circles sizes (representing district population sizes). l1 = plt.scatter([],[], s=4, facecolors='none', edgecolors='black') l2 = plt.scatter([],[], s=16, facecolors='none', edgecolors='black') l3 = plt.scatter([],[], s=64, facecolors='none', edgecolors='black') l4 = plt.scatter([],[], s=256, facecolors='none', edgecolors='black') l5 = plt.scatter([],[], s=1024, facecolors='none', edgecolors='black') labels = ["< 224", "< 327", "< 525", "< 5000", "> 5000"] leg = plt.legend([l1, l2, l3, l4, l5], labels, ncol=5, frameon=False, fontsize=10, handlelength=2, loc = 8, bbox_to_anchor = [0.5,-0.15], handletextpad=1, title='District sizes', scatterpoints = 1) leg.get_title().set_position((0, -35)) # Scatterplot to represent districts + fraction of infected per district. region_map.show_mpl(ax) l = plt.scatter([], [], alpha=0.5) l.axes.get_xaxis().set_ticks([]) l.axes.get_yaxis().set_ticks([]) axcolor = 'lightgoldenrodyellow' ax_day = plt.axes([0.12, 0.1, 0.79, 0.03], axisbg=axcolor) sday = Slider(ax_day, 'Day', 0.1, 100.0, valinit=1, valfmt='%0.0f') plt.subplots_adjust(bottom=0.15) # Legend for colors (representing fraction of infected in district). data_range = [0, 100] m = cm.ScalarMappable(cmap=cm.autumn_r) m.set_array(data_range) c = plt.colorbar(m,ax=ax, shrink=0.5, orientation="horizontal") c.set_label("Fraction of district infected") ############################### # Update function for slider. # ############################### def update(val): """ Update the plot according to the value of the slider. """ day = int(round(sday.val)) xs = [] ys = [] offsets = [] sizes = [] colors = [] if (day in infections): day_infections = infections[day] for key, value in districts.iteritems(): x, y = region_map.to_pixels((value[0], value[1])) district_size = value[2] circle_size = 0 if (district_size <= 224): circle_size = 4 elif (district_size <= 327): circle_size = 16 elif (district_size <= 525): circle_size = 64 elif (district_size <= 5000): circle_size = 256 else: circle_size = 1024 if key in day_infections: num_infections = day_infections[key] xs.append(x) ys.append(y) offsets.append([x, y]) sizes.append(circle_size) colors.append([1, 1 - (float(num_infections) / district_size), 0]) l.set_offsets(offsets) l.set_sizes(sizes) l.set_facecolors(np.array(colors)) fig.canvas.draw_idle() # Execute update() when value of slider changes sday.on_changed(update) plt.show()
def create_map(district_file, pop_file, households_file, persons_file, transmissions_log): """ Create .png map image for each simulation day in the given files. """ ######################################################################## # Gather information (location & population size) about the districts. # ######################################################################## districts = {} districts[0] = (0, 0, 0) latitudes = [] longitudes = [] with open(district_file, 'r') as district_file: reader = csv.DictReader(district_file, delimiter=";") for row in reader: d_id = int(row['id']) latitude = float(row['latitude'].replace(",", ".")) longitude = float(row['longitude'].replace(",", ".")) pop_size = int(row['pop_size']) # Don't add districts with incorrect location data if abs(latitude) < 90 and abs(longitude) < 180: districts[d_id] = (latitude, longitude, pop_size) latitudes.append(latitude) longitudes.append(longitude) # Use Smopy to get map image for the given region (calculated from min/max latitudes/longitudes in districts file) region_map = smopy.Map( (min(latitudes), min(longitudes), max(latitudes), max(longitudes)), z=9) ################################################################## # Gather information about persons and households in simulation. # ################################################################## # Check how long each person stays ill (= infectious) when infected. person_infectiousness = {} with open(persons_file, 'r') as person_file: reader = csv.DictReader(person_file, delimiter=';') for row in reader: person_infectiousness[int(row['id'])] = row['end_infectiousness'] # For each person, fetch the household ID person_households = [] with open(pop_file, 'r') as pop_file: reader = csv.DictReader(pop_file, delimiter=";") for row in reader: person_households.append(int(float(row['household_id']))) # For each household, fetch the district it belongs to. households = {} with open(households_file, 'r') as hh_file: reader = csv.DictReader(hh_file, delimiter=';') for row in reader: hh_id = int(row['id']) d_id = int(row['district_id']) households[hh_id] = d_id ######################################## # Gather information about infections. # ######################################## prepare_csv_transmissions(transmissions_log, "infections.csv") infections = {} max_infect = 0 with open('./infections.csv', 'r') as infections_file: reader = csv.DictReader(infections_file, delimiter=",") for row in reader: person_id = int(row['person_id']) if (person_id < len(person_infectiousness) + 1): hh_id = person_households[person_id] district = households[hh_id] start_infected = int(row['begin_infection']) end_infected = start_infected + int( person_infectiousness[person_id]) for day in range(start_infected, end_infected + 1): if day in infections: # add extra infection if district in infections[day]: infections[day][district] += 1 if infections[day][district] > max_infect: max_infect = infections[day][district] else: infections[day][district] = 1 else: # add first infection infections[day] = {} infections[day][district] = 1 ######################################################### # Create the actual map images for each simulation day. # ######################################################### for day in range(0, 100): ax = region_map.show_mpl() cases = False if (day in infections): cases = True day_infections = infections[day] for i, district_info in districts.iteritems(): x, y = region_map.to_pixels(district_info[0], district_info[1]) # Calculate circle size from district size district_size = district_info[2] circle_size = 0 if (district_size <= 224): # first quartile circle_size = 2 elif (district_size <= 327): # second quartile circle_size = 4 elif (district_size <= 525): # third quartile circle_size = 8 elif (district_size <= 5000): # 4th quartile split in two, to accentuate really big districts circle_size = 16 else: circle_size = 32 # no infections -> districts are not shown # otherwise: spectrum from red (few infections) to yellow (lot of infections) if (cases) and (i in day_infections): num_infections = day_infections[i] R = 1 # normalize # of infections to number between 0 and 1 #G = float(num_infections) / max_infect G = 1 - (float(num_infections) / district_size) B = 0 col = (R, G, B) ax.plot(x, y, marker='o', color=col, ms=circle_size, mew=1) ############################################# # Create legends for circle sizes & colors. # ############################################# l1 = plt.scatter([], [], s=4, facecolors='none', edgecolors='black') l2 = plt.scatter([], [], s=16, facecolors='none', edgecolors='black') l3 = plt.scatter([], [], s=64, facecolors='none', edgecolors='black') l4 = plt.scatter([], [], s=256, facecolors='none', edgecolors='black') l5 = plt.scatter([], [], s=1024, facecolors='none', edgecolors='black') labels = ["< 224", "< 327", "< 525", "< 5000", "> 5000"] leg = plt.legend([l1, l2, l3, l4, l5], labels, ncol=5, frameon=False, fontsize=10, handlelength=2, loc=8, handletextpad=1, title='District sizes', scatterpoints=1, bbox_to_anchor=(0.5, -0.15)) leg.get_title().set_position((0, -50)) data_range = [0, 100] m = cm.ScalarMappable(cmap=cm.autumn_r) m.set_array(data_range) c = plt.colorbar(m, orientation="horizontal") c.set_label("Fraction of district infected") ########################### # Save map image to .png. # ########################### fig_title = "day " + str(day) plt.title(fig_title) fig_file = "map_" + str(day) + ".png" plt.savefig(fig_file)