Beispiel #1
0
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
Beispiel #2
0
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)
Beispiel #3
0
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)
Beispiel #4
0
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)