def get_nuts_map_data(request): p0 = get_nuts_map(0) p1 = get_nuts_map(1) p2 = get_nuts_map(2) tab0 = Panel(child=p0, title="NUTS1") tab1 = Panel(child=p1, title="NUTS2") tab2 = Panel(child=p2, title="NUTS3") tabs = Tabs(tabs=[tab0, tab1, tab2]) tabs.sizing_mode = 'scale_both' item = json_item(tabs) item['metadata'] = 'somemetadata' response = JsonResponse(item) return response
def draw_map(request): """ Returns a rendered map with a script and div object. :param request: Django request :param nuts_level: The nuts level for which to display the map :param countries: The country code of the regions to be mapped (eg: de, nl, fr) :param pollutants: The pollutants to be mapped (eg: o3, co) :param start_date: The start_date to be mapped (eg: o3, co) :return: Returns a rendered map with a script and div object. """ # Read in paramters and set default values when no parameter is provided nuts_level = request.GET.get('nuts_level', '0') countries = request.GET.get('countries', None) start_date = request.GET.get('start_date', None) end_date = request.GET.get('end_date', None) if start_date is None: return JsonResponse("'start_date' is a required parameter.", safe=False) if end_date is None: end_date = start_date daily_levels = get_daily_data(countries=countries, pollutants=None, start_date=start_date, end_date=end_date) # Uncomment this to use dummy data for testing """ import os from eugreendeal.settings import MEDIA_ROOT json_dir = os.path.join(MEDIA_ROOT, "media", "mock_api_payloads") with open(json_dir + "/daily.json") as f: daily_levels = json.load(f) """ daily_df = gpd.GeoDataFrame() for region_key, region_value in daily_levels.items(): for date_key, date_value in region_value.items(): for pollutant_key, pollutant_value in date_value.items(): if pollutant_value is None: continue day = pollutant_value.get("day-avg-level", 0) if day is None: day = 0 dictionary = { "nuts_id": region_key.upper(), "date": date_key, "pollutant": pollutant_key.upper(), "pollutant_level": round(day, 2) } daily_df = daily_df.append(dictionary, ignore_index=True) if len(daily_df) > 0: # Aggregate daily pollutant data over date range daily_df = daily_df.groupby(["nuts_id", 'pollutant']).mean().reset_index() nuts_boundaries = get_region_boundaries_data(level=nuts_level, regions=countries) df = gpd.GeoDataFrame() level = nuts_boundaries.get(str(nuts_level)) for key, record in level.items(): dictionary = { "nuts_id": key.upper(), "name": record["name"], "country": record["country_code"].upper(), "geometry": gpd.GeoSeries(shapely.wkt.loads(record["geography"]))} df = df.append(gpd.GeoDataFrame(dictionary), ignore_index=True) df.crs = 4326 # Merge NUTS data frame with daily pollutant level dataframe df = df.merge(daily_df) #Reverse the list order of the spectrum since all the online tools put them in the oppposite order to what we want colors = ["#a50026", "#d3322b", "#f16d43", "#fcab63", "#fedc8c", "#f9f7ae", "#d7ee8e", "#a4d86f", "#64bc61"][::-1] # Define the bounds of the EU's main territories (excluding far off islands) eu_bounds = Polygon([(-25, 35), (33, 35), (33, 70), (-25, 70), (-25, 35)]) # Unique pollutants in df unique_pollutants = df.pollutant.unique() # create bokeh elements tabs_list = [] for pollutant in unique_pollutants: filtered_df = df[df.pollutant.eq(pollutant)] # get unique areas base on the region type selected pollution_values = filtered_df['pollutant_level'] min_pollution_value = pollution_values.min() max_pollution_value = pollution_values.max() color_mapper = LinearColorMapper(palette=RdYlGn11, low=min_pollution_value, low_color='green', high=max_pollution_value, high_color='red') tick_format = NumeralTickFormatter(format='0.0') color_bar = ColorBar(color_mapper=color_mapper, #ticker=FixedTicker(ticks=[min_pollution_value, 2.7, max_pollution_value - min_pollution_value, max_pollution_value]), ticker=BasicTicker(desired_num_ticks=len(colors)), formatter=tick_format, major_label_text_font_size="7px", location=(0, 0)) tools = [HoverTool( tooltips=[ ("Latitude, Longitude", "$x{0.000}, $y{0.000}"), ("Country", "@country"), ("NUTS ID", "@nuts_id"), ("Avg " + pollutant + " level", "@pollutant_level{0.0}") ] ), WheelZoomTool(), PanTool(), ResetTool()] # Clip the polygons to the EU bounds filtered_df = gpd.clip(filtered_df, eu_bounds) bokeh_figure = figure(title="Air quality by region", sizing_mode='scale_both', tools=tools, toolbar_location = None, x_axis_location=None, y_axis_location=None, match_aspect=True, border_fill_color=None ) bokeh_figure.xgrid.grid_line_color = None bokeh_figure.ygrid.grid_line_color = None geo_json_data_source = GeoJSONDataSource(geojson=json.dumps(filtered_df.__geo_interface__)) # don't use a line color. the map consists of numerous patches, so you will only see the line color bokeh_figure.patches(xs="xs", ys="ys", source=geo_json_data_source, fill_color={"field": "pollutant_level", "transform": color_mapper}, line_color=None ) bokeh_figure.name = pollutant # add colorbar if(df.nuts_id.nunique() > 1): bokeh_figure.add_layout(color_bar, 'right') tabs_list.append(Panel(child=bokeh_figure, title=bokeh_figure.name)) tabs = Tabs(tabs=tabs_list) tabs.sizing_mode = 'scale_both' # script, div = components(bokeh_figure) item = json_item(tabs) # return render(request, 'airpollution/test-maps.html', dict(script=script, div=div)) return JsonResponse(item) else: nuts_boundaries = get_region_boundaries_data(level=nuts_level, regions=countries) df = gpd.GeoDataFrame() level = nuts_boundaries.get(str(nuts_level)) for key, record in level.items(): dictionary = { "nuts_id": key.upper(), "name": record["name"], "country": record["country_code"].upper(), "geometry": gpd.GeoSeries(shapely.wkt.loads(record["geography"]))} df = df.append(gpd.GeoDataFrame(dictionary), ignore_index=True) df.crs = 4326 #Filter down to a pretty set of countries as background blank_countries = ["NL", "BE", "LU", "FR", "DE"] df = df[df.nuts_id.isin(blank_countries)] # Define the bounds of the EU's main territories (excluding far off islands) eu_bounds = Polygon([(-25, 35), (33, 35), (33, 70), (-25, 70), (-25, 35)]) # Clip the polygons to the EU bounds filtered_df = gpd.clip(df, eu_bounds) bokeh_figure = figure(title="No air quality data for the selected dates", sizing_mode='scale_both', toolbar_location = None, x_axis_location=None, y_axis_location=None, match_aspect=True, border_fill_color=None ) bokeh_figure.xgrid.grid_line_color = None bokeh_figure.ygrid.grid_line_color = None geo_json_data_source = GeoJSONDataSource(geojson=json.dumps(filtered_df.__geo_interface__)) # don't use a line color. the map consists of numerous patches, so you will only see the line color bokeh_figure.patches(xs="xs", ys="ys", source=geo_json_data_source, line_color=None, fill_color="#D3D3D3" ) # script, div = components(bokeh_figure) item = json_item(bokeh_figure) # return render(request, 'airpollution/test-maps.html', dict(script=script, div=div)) return JsonResponse(item)
def draw_bubble_map(request, start_date: str = None, end_date: str = None, pollutants: list = None): if request is not None: pollutants = request.GET.get('pollutants', ['PM25', 'PM10', 'NO2']) start_date = request.GET.get('start_date', None) end_date = request.GET.get('end_date', None) if start_date is None: return JsonResponse("'start_date' is a required parameter.", safe=False) if end_date is None: end_date = start_date bubble_data = get_target_bubblemap_data(start_date=start_date, end_date=end_date, pollutants=pollutants) # create bokeh elements _tabs = [] for k, v in bubble_data.items(): p = get_nuts_map(0, outline_map=True, include_tools=False, exclude_countries=['TR']) p.name = k # add annotation top = p.properties_with_values().get('plot_height') note1 = Label(x=10, y=50, x_units='screen', y_units='screen', text='NOTE: bubble size denotes Nuts2 Population.', render_mode='canvas', border_line_color=None, border_line_alpha=1.0, text_alpha=.5, text_font_size='12px', background_fill_color=None, background_fill_alpha=0.5) note2 = Label(x=10, y=30, x_units='screen', y_units='screen', text='NOTE: color denotes percentage of target.', render_mode='canvas', border_line_color=None, border_line_alpha=1.0, text_alpha=0.5, text_font_size='12px', background_fill_color=None, background_fill_alpha=0.5) p.add_layout(note1) p.add_layout(note2) _tabs.append(Panel(child=p, title=p.name)) tabs = Tabs(tabs=_tabs) tabs.sizing_mode = 'scale_both' color_mapper = LinearColorMapper(palette=RdYlGn11, low=.5, low_color='green', high=1.5, high_color='red') tick_format = NumeralTickFormatter(format='+0%') color_bar = ColorBar( color_mapper=color_mapper, ticker=FixedTicker(ticks=[0, .25, 0.50, .75, 1, 1.25, 1.50]), formatter=tick_format, label_standoff=9, border_line_color=None, location=(0, 0)) s_zoom = WheelZoomTool() s_pan = PanTool() s_reset = ResetTool() # create the bubbles and hover elements for t in tabs.tabs: # add colorbar t.child.add_layout(color_bar, 'right') # add bubbles glyphs = t.child.scatter(x='x', y='y', size='radius', source=bubble_data.get(t.child.name), fill_alpha=0.6, fill_color={ 'field': 'achievement', 'transform': color_mapper }, line_color=None) # add hover tool for stations hover_tool = HoverTool( renderers=[glyphs], tooltips=[("air_quality_station", "@air_quality_station"), ("Country", "@country_code_id"), ("NUTS 2", "@nuts_2_name"), ("NUTS 2 Pop", "@population"), (f"{t.child.name} Target Value", "@target_value"), ("Avg Value", "@value__avg"), ("% of Target", "@achievement{:+%0.0}")]) t.child.add_tools(hover_tool, s_zoom, s_pan, s_reset) # jupyter notebook # return tabs # django item = json_item(tabs) # item['metadata'] = 'somemetadata' return JsonResponse(item)
def draw_heatmap(request, plot_date: str = None, pollutants: list = ['PM25', 'PM10', 'NO2']): """ :param request: :param plot_date: :param pollutants: :return: """ if request is not None: pollutants = request.GET.get('pollutants', ['PM25', 'PM10', 'NO2']) plot_date = request.GET.get('plot_date', None) if plot_date is None: most_recent_date = SatelliteImageFiles.get_most_recent_date() year, month, day = most_recent_date.year, most_recent_date.month, most_recent_date.day else: year, month, day = (int(x) for x in plot_date.split('-')) # get images for the pollutants images = SatelliteImageFiles.get_dayavg_sat_images(pollutants=pollutants, year=year, month=month, day=day, category='ANALYSIS') if len(images) == 0: # if images for date not available - get the most recent date most_recent_date = SatelliteImageFiles.get_most_recent_date() year, month, day = most_recent_date.year, most_recent_date.month, most_recent_date.day # get images for the pollutants images = SatelliteImageFiles.get_dayavg_sat_images( pollutants=pollutants, year=year, month=month, day=day, category='ANALYSIS') if len(images) == 0: return JsonResponse( f"No images returned for selected date: {plot_date}", safe=False) # get targets targets = Target.objects.filter(pollutant__in=pollutants, measurement='calendar_year').values( 'pollutant_id', 'value') targets = {x.get('pollutant_id'): x.get('value') for x in targets} # get figure boundaries x_range, y_range = get_bounds() # make images a +/- % of target overage for k, img in images.items(): _i = (img / targets.get(k)) images.update({k: _i}) # max and min visible percentages min_val = .50 max_val = 1.5 # create bokeh elements tile_provider = get_provider(CARTODBPOSITRON) color_mapper = LinearColorMapper(palette=RdYlGn11, low=min_val, low_color='green', high=max_val, high_color='red') tick_format = NumeralTickFormatter(format='+0%') color_bar = ColorBar( color_mapper=color_mapper, ticker=FixedTicker(ticks=[0, .25, 0.50, .75, 1, 1.25, 1.50]), formatter=tick_format, label_standoff=9, border_line_color=None, location=(0, 0)) s_zoom = WheelZoomTool() s_pan = PanTool() s_reset = ResetTool() # setup tabs _tabs = [] for _p in pollutants: # get dataframe from image i = images.get(_p) i_gdf_filtered = _build_gdf_from_image(i, x_range, y_range, min_val) # create geo source p_geo = GeoJSONDataSource( geojson=json.dumps(i_gdf_filtered.__geo_interface__)) # create figure (canvas) p = figure( title= f'Satellite Image Average from {day}-{month}-{year} (>50% of target is shown in overlay)', x_range=x_range, y_range=y_range, sizing_mode='scale_both', x_axis_type="mercator", y_axis_type="mercator", x_axis_location=None, y_axis_location=None, tools=[s_zoom, s_pan, s_reset]) p.xgrid.grid_line_color = None p.ygrid.grid_line_color = None p.name = _p # add background map p.add_tile(tile_provider) # add heat map as points heatmap = p.circle(x='x', y='y', size=1.2, color={ 'field': 'value', 'transform': color_mapper }, alpha=.25, source=p_geo) # add colorbar p.add_layout(color_bar, 'right') # add hover tool for stations hover_tool = HoverTool(renderers=[heatmap], tooltips=[ (f"+/-% of {p.name} target", "@value{:+%0.0}"), ]) p.add_tools(hover_tool) # , s_zoom, s_pan, s_reset) # add as a tab in tabs list _tabs.append(Panel(child=p, title=p.name)) # create tabs tabs = Tabs(tabs=_tabs) tabs.sizing_mode = 'scale_both' # jupyter notebook # return tabs # django item = json_item(tabs) # item['metadata'] = 'somemetadata' return JsonResponse(item)