Exemplo n.º 1
0
def fig_uo_coverage_grid(lad20cd: str, uo_sensors: gpd.GeoDataFrame,
                         theta: int, save_dir: Path):
    """Calculate the coverage the Urban Observatory sensor network provides on a square
    grid. Figure name: urb_obs_coverage_grid_theta_{theta}_nsensors_{n_sensors}.png

    Parameters
    ----------
    lad20cd : str
        Local authority code
    uo_sensors : gpd.GeoDataFrame
        Urban Observatory sensor locations
    theta : int
        Coverage distance to use
    save_dir : Path
        Directory to save figure
    """
    fig, ax = get_fig_grid(nrows_ncols=(1, 1))
    ax = ax[0]
    cmap = "Greens"
    plot_uo_coverage_grid(lad20cd,
                          uo_sensors=uo_sensors,
                          ax=ax,
                          legend=False,
                          cmap=cmap)
    add_colorbar(ax, cmap=cmap, label="Coverage")
    add_scalebar(ax)
    t_str = f"theta_{theta}"
    n_str = f"nsensors_{len(uo_sensors)}"
    save_fig(fig, f"urb_obs_coverage_grid_{t_str}_{n_str}.png", save_dir)
Exemplo n.º 2
0
def fig_single_obj(thetas: list, n_sensors: list, results: dict,
                   all_groups: dict, save_dir: Path):
    """Save figures showing optimised networks with different parameters (number of
    sensors and coverage distance, theta) for each objective. Names of saved figures:
    "{plot_obj}_{thetas}_{n_sensors}.png", where `plot_obj` is the objective name from
    all_groups.

    Parameters
    ----------
    thetas : list
        Theta (coverage distance) values to plot (must exist in results)
    n_sensors : list
        Network sizes (number of sensors) to plot (must exist in results)
    results : dict
        Previous optimisation results (e.g. from
        networks_single_obj.make_single_obj_networks)
    all_groups : dict
        Short name (keys) and long title (values) for each objective to plot
    save_dir : Path
        Directory to save figures in.
    """
    n_figs = len(thetas) * len(n_sensors)
    n_rows = floor(sqrt(n_figs))
    n_cols = ceil(n_figs / n_rows)
    for plot_obj in all_groups.keys():
        fig, grid = get_fig_grid(nrows_ncols=(n_rows, n_cols))
        i = 0
        for t in thetas:
            for s in n_sensors:
                r = results[plot_obj][f"theta{t}"][f"{s}sensors"]
                plot_optimisation_result(
                    r,
                    title=
                    f"n = {s}, $\\theta$ = {t} m, c = {r['total_coverage']:.2f}",
                    ax=grid[i],
                    show=False,
                    legend=False,
                    sensor_size=50,
                    sensor_color="green",
                    sensor_edgecolor="yellow",
                    sensor_linewidth=1.5,
                )
                if i == 1:
                    add_scalebar(grid[i])

                i += 1

        add_colorbar(grid[-1], label="Coverage", cmap="Greens")

        fig.suptitle(all_groups[plot_obj]["title"], y=0.87, fontsize=20)
        t_str = "theta" + "_".join(str(t) for t in thetas)
        n_str = "nsensors" + "_".join(str(n) for n in n_sensors)
        save_fig(fig, f"{plot_obj}_{t_str}_{n_str}.png", save_dir)
Exemplo n.º 3
0
def fig_importance(
    lad20cd: str,
    groups: dict,
    oa_weights: dict,
    theta: float,
    save_dir: Path,
    vmax: float = 0.06,
):
    """Save a figure showing the "importance" of each output area for each objective,
    where importance is the overall coverage of the whole local authority provided
    by a network with a single sensor placed in that output area. Name of figure:
    demographics_importance.png

    Parameters
    ----------
    lad20cd : str
        Local authority code to generate results for
    groups : dict
        Name and title of each population group/objective
    oa_weights : dict
        Weight for each output area for each group/objective
    theta : float
        Coverage distance
    save_dir : Path
        Directory to save figure in
    vmax : float, optional
        Max value for colour scale, by default 0.06
    """
    fig, grid = get_fig_grid()

    for i, g in enumerate(groups.items()):
        name = g[0]
        title = g[1]["title"]
        plot_oa_importance(
            lad20cd,
            oa_weights[name],
            theta=theta,
            vmax=vmax,
            ax=grid[i],
            show=False,
            legend=False,
            title=title,
        )
        if i == 1:
            add_scalebar(grid[i])

    add_colorbar(grid[-1], vmax=vmax, label="Importance")
    save_fig(fig, "demographics_importance.png", save_dir)
Exemplo n.º 4
0
def fig_density(
    lad20cd: str,
    oa: gpd.GeoDataFrame,
    all_groups: dict,
    save_dir: Path,
    vmax: float = 6,
):
    """Save a figure showing the density of each demographic variable/objective for each
    output area (OA), measured as the fraction of the population in that OA divided by
    the area of the OA. Name of figure: demographics_density.png

    Parameters
    ----------
    lad20cd : str
        Local authority code to generate results for
    oa : gpd.GeoDataFrame
        Data frame with stats for each variable in each output area (e.g. from
        calc_oa_density)
    all_groups : dict
        Short name (keys) and long title (values) for each objective
    save_dir : Path
        Directory to save figure in
    vmax : float, optional
        Max value for colour scale, by default 6
    """
    fig, grid = get_fig_grid()

    for i, g in enumerate(all_groups.items()):
        name = g[0]
        title = g[1]["title"]
        plot_oa_weights(
            lad20cd,
            100 * oa[f"{name}_reld"],
            title=title,
            vmax=vmax,
            ax=grid[i],
            legend=False,
            show=False,
        )
        if i == 1:
            add_scalebar(grid[i])

    add_colorbar(grid[-1], vmax=vmax, label=r"Density [% / $\mathrm{km}^2$]")
    save_fig(fig, "demographics_density.png", save_dir)
Exemplo n.º 5
0
def fig_uo_sensor_locations(lad20cd: str, uo_sensors: gpd.GeoDataFrame,
                            save_dir: Path):
    """Show the location of all sensors in the Urban Observatory network (points only).
    Figure nane: urb_obs_sensors_nsensors_{N}.png (where {N} is the no. sensors in the
    UO network)

    Parameters
    ----------
    lad20cd : str
        Local authority code
    uo_sensors : gpd.GeoDataFrame
        Urban Observatory sensor locations
    save_dir : Path
        Directory to save figure
    """
    fig, ax = plt.subplots(1, 1, figsize=(15, 15))
    plot_sensors(lad20cd, uo_sensors, centroids=False, ax=ax)
    add_scalebar(ax)
    save_fig(fig, f"urb_obs_sensors_nsensors_{len(uo_sensors)}.png", save_dir)
Exemplo n.º 6
0
def fig_uo_coverage_oa(uo_coverage: dict, theta: float, all_groups: dict,
                       save_dir: Path):
    """Plot the coverage of each output area provide by the Urban Observatory
    sensors. Figure name: urb_obs_coverage_oa_theta_{theta}_nsensors_{n_sensors}.png

    Parameters
    ----------
    uo_coverage : dict
        Coverage of each output area with the Urban Observatory network (e.g. from
        get_uo_coverage_oa)
    theta : float
        Coverage distance to use
    all_groups : dict
        Short name (keys) and long title (values) for each objective
    save_dir : Path
        Directory to save figure
    """
    title = f"Urban Observatory: Coverage with $\\theta$ = {theta} m\n"
    for name, params in all_groups.items():
        title += f"{params['title']}: {uo_coverage[name]['total_coverage']:.2f}, "
    title = title[:-2]

    fig, ax = get_fig_grid(nrows_ncols=(1, 1))
    plot_optimisation_result(
        uo_coverage[name],
        title=title,
        ax=ax[0],
        show=False,
        legend=False,
        sensor_size=50,
        sensor_color="green",
        sensor_edgecolor="yellow",
        sensor_linewidth=1.5,
    )
    add_scalebar(ax[0])
    add_colorbar(ax[0], cmap="Greens", label="Coverage")

    t_str = f"theta_{theta}"
    n_str = f"nsensors_{uo_coverage['n_sensors']}"
    save_fig(fig, f"urb_obs_coverage_oa_{t_str}_{n_str}.png", save_dir)
Exemplo n.º 7
0
def fig_uo_coverage_oa_diff(
    lad20cd: str,
    uo_coverage: dict,
    theta: float,
    all_groups: dict,
    networks: dict,
    save_dir: Path,
):
    """Show the coverage difference of each outupt area between the Urban Observatory
    network and networks optimised for the coverage of single objectives (single
    population sub-groups). Figure name:
    urb_obs_coverage_difference_oa_theta_{theta}_nsensors_{n_sensors}.png

    Parameters
    ----------
    lad20cd : str
        Local authority code
    uo_sensors : gpd.GeoDataFrame
        Urban Observatory sensor locations
    theta : float
        Coverage distance to use
    all_groups : dict
        Short name (keys) and long title (values) for each objective
    networks : dict
        Previous optimisation results (e.g. from
        networks_single_obj.make_single_obj_networks)
    save_dir : Path
        Directory to save figure
    """
    fig, grid = get_fig_grid()
    cmap = get_diff_cmap()
    n_uo_oa = uo_coverage["n_sensors"]

    for i, (name, params) in enumerate(all_groups.items()):
        uo_cov = uo_coverage[name]["oa_coverage"]
        uo_cov = pd.DataFrame(uo_cov).set_index("oa11cd")
        uo_cov.rename(columns={"coverage": "urb_obs"}, inplace=True)

        greedy_cov = networks[name][f"theta{theta}"][f"{n_uo_oa}sensors"][
            "oa_coverage"]
        greedy_cov = pd.DataFrame(greedy_cov).set_index("oa11cd")
        greedy_cov.rename(columns={"coverage": "greedy"}, inplace=True)

        compare_nets = uo_cov.join(greedy_cov)
        compare_nets["diff"] = compare_nets["greedy"] - compare_nets["urb_obs"]
        compare_nets["diff"].describe()

        oa_shapes = get_oa_shapes(lad20cd)
        oa_shapes = oa_shapes.join(compare_nets["diff"])

        vmin = -1
        vmax = 1
        oa_shapes.plot(column="diff",
                       alpha=0.85,
                       cmap=cmap,
                       ax=grid[i],
                       vmin=vmin,
                       vmax=vmax)

        ctx.add_basemap(
            grid[i],
            source="http://a.tile.stamen.com/toner/{z}/{x}/{y}.png",
            crs=oa_shapes.crs.to_epsg(),
        )

        grid[i].set_axis_off()
        grid[i].set_title(params["title"])

    add_scalebar(grid[1])
    add_colorbar(grid[-1],
                 cmap=cmap,
                 label="Coverage Difference",
                 vmin=vmin,
                 vmax=vmax)
    fig.suptitle(
        f"Comparisons with Urban Observatory Network (n = {n_uo_oa}, $\\theta$ = {theta} m)",
        y=0.87,
        fontsize=20,
    )

    t_str = f"theta_{theta}"
    n_str = f"nsensors_{n_uo_oa}"
    save_fig(fig, f"urb_obs_coverage_difference_oa_{t_str}_{n_str}.png",
             save_dir)
Exemplo n.º 8
0
def fig_uo_coverage_grid_diff(
    lad20cd: str,
    uo_sensors: gpd.GeoDataFrame,
    theta: float,
    all_groups: dict,
    networks: dict,
    save_dir: Path,
):
    """Show the coverage difference, on a square grid, between the Urban Observatory
    network and networks optimised for the coverage of single objectives (single
    population sub-groups). Figure name:
    urb_obs_coverage_difference_grid_theta_{theta}_nsensors_{n_sensors}.png

    Parameters
    ----------
    lad20cd : str
        Local authority code
    uo_sensors : gpd.GeoDataFrame
        Urban Observatory sensor locations
    theta : float
        Coverage distance to use
    all_groups : dict
        Short name (keys) and long title (values) for each objective
    networks : dict
        Previous optimisation results (e.g. from
        networks_single_obj.make_single_obj_networks)
    save_dir : Path
        Directory to save figure
    """
    uo_sensors_xy = np.array(
        [uo_sensors["geometry"].x.values, uo_sensors["geometry"].y.values]).T
    oa = get_oa_shapes(lad20cd)
    bounds = oa["geometry"].bounds
    xlim = (bounds["minx"].min(), bounds["maxx"].max())
    ylim = (bounds["miny"].min(), bounds["maxy"].max())
    grid_size = 100
    uo_cov = coverage_grid(uo_sensors_xy,
                           xlim,
                           ylim,
                           theta=theta,
                           grid_size=grid_size)

    n_uo_oa = uo_sensors["oa11cd"].nunique()

    fig, grid = get_fig_grid()
    cmap = get_diff_cmap()
    vmin = -1
    vmax = 1
    for i, (name, params) in enumerate(all_groups.items()):
        greedy_sensors = pd.DataFrame(
            networks[name][f"theta{theta}"][f"{n_uo_oa}sensors"]["sensors"])
        greedy_sensors = np.array(greedy_sensors[["x", "y"]])
        greedy_cov = coverage_grid(greedy_sensors,
                                   xlim,
                                   ylim,
                                   theta=theta,
                                   grid_size=grid_size)
        cov_diff = uo_cov.copy()
        cov_diff["coverage"] = greedy_cov["coverage"] - uo_cov["coverage"]

        plot_coverage_grid(
            lad20cd,
            cov_diff,
            ax=grid[i],
            vmin=vmin,
            vmax=vmax,
            legend=False,
            cmap=cmap,
            title=params["title"],
        )
    add_scalebar(grid[1])
    add_colorbar(grid[-1],
                 cmap=cmap,
                 vmin=vmin,
                 vmax=vmax,
                 label="Coverage Difference")

    fig.suptitle(
        f"Comparisons with Urban Observatory Network (n = {n_uo_oa}, $\\theta$ = {theta} m)",
        y=0.87,
        fontsize=20,
    )
    t_str = f"theta_{theta}"
    n_str = f"nsensors_{n_uo_oa}"
    save_fig(fig, f"urb_obs_coverage_difference_grid_{t_str}_{n_str}.png",
             save_dir)
Exemplo n.º 9
0
def fig_max_min_coverage(
    lad20cd: str,
    scores: np.ndarray,
    objs: list,
    theta: float,
    n_sensors: int,
    solutions: np.ndarray,
    inputs: dict,
    save_dir: float,
):
    """Plot the network that maximises the minimum coverage across all objectives.

    Parameters
    ----------
    lad20cd : str
        Local authority code
    scores : np.ndarray
        Coverage values for each objective in each candidate network
    objs : list
        Names of objectives in the order they appear in scores
    theta : float
        Coverage distance to use
    n_sensors : int
        No. of sensors in the network
    solutions : np.ndarray
        Sensor output area indices for each candidate network
    inputs : dict
        Optimisation inputs from networks_multi_objs.get_multi_obj_inputs
    save_dir : float
        Directory to save figure
    """
    # find network that has the maximum minimum coverage across all objectives
    # (i.e. find network where all objectives have a coverage of at least t, for
    # highest possible t)
    t = scores.min()
    delta = 0.001
    remaining = len(scores)
    while remaining > 0:
        t += delta
        remaining = (scores > t).all(axis=1).sum()
    t -= delta
    best_idx = (scores > t).all(axis=1).argmax()

    sensor_idx = solutions[best_idx].astype(int)
    sensor_dict = [{
        "oa11cd": inputs["oa11cd"][idx],
        "x": inputs["oa_x"][idx],
        "y": inputs["oa_y"][idx],
    } for idx in sensor_idx]

    coverage = calc_coverage(lad20cd,
                             sensor_dict,
                             oa_weight=inputs["oa_weight"]["pop_total"],
                             theta=theta)
    coverage["sensors"] = sensor_dict
    coverage["lad20cd"] = lad20cd

    title = "".join(f"{obj} = {score:.2f}, "
                    for obj, score in zip(objs, scores[best_idx]))

    title = title[:-2]
    title += f"\n(n = {n_sensors}, $\\theta$ = {theta} m)"

    fig, ax = get_fig_grid(nrows_ncols=(1, 1))
    plot_optimisation_result(
        coverage,
        title=title,
        ax=ax[0],
        show=False,
        legend=False,
        sensor_size=50,
        sensor_color="green",
        sensor_edgecolor="yellow",
        sensor_linewidth=1.5,
    )
    add_scalebar(ax[0])
    add_colorbar(ax[0], cmap="Greens", label="Coverage")
    save_fig(
        fig,
        f"multiobj_compromise_theta{theta}_{n_sensors}sensors_cov{round(t, 3)}.png",
        save_dir,
    )
Exemplo n.º 10
0
def fig_max_child_work_above_threshold(
    lad20cd: str,
    scores: np.ndarray,
    objs: list,
    threshold: float,
    theta: float,
    n_sensors: int,
    solutions: np.ndarray,
    inputs: dict,
    work_name: str,
    child_name: str,
    save_dir: Path,
):
    """From a set of candidate networks, plot the one that maximsies coverage of
    children whlist also keeping the coverage of worklplaces above a minimum threshold.
    Figure name:
    multiobj_wplace{work_cov}_child{child_cov}_theta{theta}_{n_sensors}sensors.png

    Parameters
    ----------
    lad20cd : str
        Local authority code
    scores : np.ndarray
        Coverage values for each objective in each candidate network
    objs : list
        Names of objectives in the order they appear in scores
    threshold : float
        Only consider networks with at least this coverage of workplaces
    theta : float
        Coverage distance to use
    n_sensors : int
        No. of sensors in the network
    solutions : np.ndarray
        Sensor output area indices for each candidate network
    inputs : dict
        Optimisation inputs from networks_multi_objs.get_multi_obj_inputs
    work_name : str
        Name of the workplace objective
    child_name : str
        Name of the coverage of children objective
    save_dir : Path
        Directory to save the figure
    """
    work_idx = objs.index(work_name)
    child_idx = objs.index(child_name)
    if (scores[:, work_idx] < threshold).all():
        print(
            f"No networks with workplace coverage > {threshold}, skipping figure"
        )
        return

    network_idx = scores[scores[:, work_idx] > threshold, child_idx].argmax()
    sensor_idx = solutions[
        scores[:, work_idx] > threshold][network_idx].astype(int)
    cov = scores[scores[:, work_idx] > threshold][network_idx]

    sensor_dict = [{
        "oa11cd": inputs["oa11cd"][idx],
        "x": inputs["oa_x"][idx],
        "y": inputs["oa_y"][idx],
    } for idx in sensor_idx]

    # select weight for 1st objective
    # (weights don't matter for calculating coverage of each OA, only for calculating
    # overrall coverage)
    w = list(inputs["oa_weight"].values())[0]
    coverage = calc_coverage(lad20cd, sensor_dict, oa_weight=w, theta=theta)
    coverage["sensors"] = sensor_dict
    coverage["lad20cd"] = lad20cd

    title = "".join(f"{obj} = {score:.2f}, " for obj, score in zip(objs, cov))
    title = title[:-2]
    title += f"\n(n = {n_sensors}, $\\theta$ = {theta} m)"

    fig, ax = get_fig_grid(nrows_ncols=(1, 1))
    plot_optimisation_result(
        coverage,
        title=title,
        ax=ax[0],
        show=False,
        legend=False,
        sensor_size=50,
        sensor_color="green",
        sensor_edgecolor="yellow",
        sensor_linewidth=1.5,
    )
    add_scalebar(ax[0])
    add_colorbar(ax[0], cmap="Greens", label="Coverage")
    save_fig(
        fig,
        f"multiobj_wplace{round(cov[3], 2)}_child{round(cov[1], 2)}_theta{theta}_{n_sensors}sensors.png",
        save_dir,
    )
Exemplo n.º 11
0
def fig_two_objs_spectrum(
    lad20cd: str,
    plot_objs: list,
    scores: np.ndarray,
    solutions: np.ndarray,
    inputs: dict,
    all_groups: dict,
    theta: float,
    n_sensors: int,
    save_dir: Path,
):
    """Save a figure showing a range of networks varying from maximal coverage of one
    objective to maximal coverage of another, showing the trade-offs between the two.
    Figure name: 2obj_spectrum_theta{theta}_{n_sensors}sensors.png

    Parameters
    ----------
    lad20cd : str
        Local authority code
    plot_objs : list
        Names of the two objectives to plot
    scores : np.ndarray
        Coverage values for each objective in each candidate network
    solutions : np.ndarray
        Output area indices for each sensor in each candidate network
    inputs : dict
        Optimisation inputs from networks_two_objs.get_two_obj_inputs
    all_groups : dict
        Short name (keys) and long title (values) for each objective
    theta : float
        Coverage distance to use
    n_sensors : int
        Number of sensors in the candidate networks
    save_dir : Path
        Directory to save the figure
    """
    population_size = len(scores)
    rank_idx = scores[:, 0].argsort()
    ranks_to_plot = np.linspace(0, population_size - 1, 4).astype(int)

    fig, ax = get_fig_grid()
    for i, rank in enumerate(ranks_to_plot):
        idx = rank_idx[rank]
        sensor_idx = solutions[idx].astype(int)
        sensor_dict = [{
            "oa11cd": inputs["oa11cd"][idx],
            "x": inputs["oa_x"][idx],
            "y": inputs["oa_y"][idx],
        } for idx in sensor_idx]
        coverage = calc_coverage(
            lad20cd,
            sensor_dict,
            oa_weight=inputs["oa_weight"][plot_objs[0]],
            theta=theta,
        )
        coverage["sensors"] = sensor_dict
        coverage["lad20cd"] = lad20cd

        title = "".join(
            f"{all_groups[obj]['title']} = {score:.2f}, "
            for obj, score in zip(["pop_elderly", "workplace"], scores[idx]))
        title = title[:-2]

        plot_optimisation_result(
            coverage,
            title=title,
            ax=ax[i],
            show=False,
            legend=False,
            sensor_size=50,
            sensor_color="green",
            sensor_edgecolor="yellow",
            sensor_linewidth=1.5,
        )

    add_scalebar(ax[1])
    add_colorbar(ax[-1], cmap="Greens", label="Coverage")
    fig.suptitle(f"n = {n_sensors}, $\\theta$ = {theta} m",
                 y=0.87,
                 fontsize=20)
    save_fig(fig, f"2obj_spectrum_theta{theta}_{n_sensors}sensors.png",
             save_dir)