| |
|
|
| import matplotlib as mpl |
| import matplotlib.pyplot as plt |
| import numpy as np |
| import plotly.graph_objects as go |
| import PIL.Image |
|
|
| from utils.viz_2d import add_text |
| from .parser import Groups |
|
|
|
|
| class GeoPlotter: |
| def __init__(self, zoom=12, **kwargs): |
| self.fig = go.Figure() |
| self.fig.update_layout( |
| mapbox_style="open-street-map", |
| autosize=True, |
| mapbox_zoom=zoom, |
| margin={"r": 0, "t": 0, "l": 0, "b": 0}, |
| showlegend=True, |
| **kwargs, |
| ) |
|
|
| def points(self, latlons, color, text=None, name=None, size=5, **kwargs): |
| latlons = np.asarray(latlons) |
| self.fig.add_trace( |
| go.Scattermapbox( |
| lat=latlons[..., 0], |
| lon=latlons[..., 1], |
| mode="markers", |
| text=text, |
| marker_color=color, |
| marker_size=size, |
| name=name, |
| **kwargs, |
| ) |
| ) |
| center = latlons.reshape(-1, 2).mean(0) |
| self.fig.update_layout( |
| mapbox_center=dict(zip(("lat", "lon"), center)), |
| ) |
|
|
| def bbox(self, bbox, color, name=None, **kwargs): |
| corners = np.stack( |
| [bbox.min_, bbox.left_top, bbox.max_, bbox.right_bottom, bbox.min_] |
| ) |
| self.fig.add_trace( |
| go.Scattermapbox( |
| lat=corners[:, 0], |
| lon=corners[:, 1], |
| mode="lines", |
| marker_color=color, |
| name=name, |
| **kwargs, |
| ) |
| ) |
| self.fig.update_layout( |
| mapbox_center=dict(zip(("lat", "lon"), bbox.center)), |
| ) |
|
|
| def raster(self, raster, bbox, below="traces", **kwargs): |
| if not np.issubdtype(raster.dtype, np.integer): |
| raster = (raster * 255).astype(np.uint8) |
| raster = PIL.Image.fromarray(raster) |
| corners = np.stack( |
| [ |
| bbox.min_, |
| bbox.left_top, |
| bbox.max_, |
| bbox.right_bottom, |
| ] |
| )[::-1, ::-1] |
| layers = [*self.fig.layout.mapbox.layers] |
| layers.append( |
| dict( |
| sourcetype="image", |
| source=raster, |
| coordinates=corners, |
| below=below, |
| **kwargs, |
| ) |
| ) |
| self.fig.layout.mapbox.layers = layers |
|
|
|
|
| map_colors = { |
| "building": (84, 155, 255), |
| "parking": (255, 229, 145), |
| "playground": (150, 133, 125), |
| "grass": (188, 255, 143), |
| "park": (0, 158, 16), |
| "forest": (0, 92, 9), |
| "water": (184, 213, 255), |
| "fence": (238, 0, 255), |
| "wall": (0, 0, 0), |
| "hedge": (107, 68, 48), |
| "kerb": (255, 234, 0), |
| "building_outline": (0, 0, 255), |
| "cycleway": (0, 251, 255), |
| "path": (8, 237, 0), |
| "road": (255, 0, 0), |
| "tree_row": (0, 92, 9), |
| "busway": (255, 128, 0), |
| "void": [int(255 * 0.9)] * 3, |
| } |
|
|
|
|
| class Colormap: |
| colors_areas = np.stack([map_colors[k] for k in ["void"] + Groups.areas]) |
| colors_ways = np.stack([map_colors[k] for k in ["void"] + Groups.ways]) |
|
|
| @classmethod |
| def apply(cls, rasters): |
| return ( |
| np.where( |
| rasters[1, ..., None] > 0, |
| cls.colors_ways[rasters[1]], |
| cls.colors_areas[rasters[0]], |
| ) |
| / 255.0 |
| ) |
|
|
| @classmethod |
| def add_colorbar(cls): |
| ax2 = plt.gcf().add_axes([1, 0.1, 0.02, 0.8]) |
| color_list = np.r_[cls.colors_areas[1:], cls.colors_ways[1:]] / 255.0 |
| cmap = mpl.colors.ListedColormap(color_list[::-1]) |
| ticks = np.linspace(0, 1, len(color_list), endpoint=False) |
| ticks += 1 / len(color_list) / 2 |
| cb = mpl.colorbar.ColorbarBase( |
| ax2, |
| cmap=cmap, |
| orientation="vertical", |
| ticks=ticks, |
| ) |
| cb.set_ticklabels((Groups.areas + Groups.ways)[::-1]) |
| ax2.tick_params(labelsize=15) |
|
|
|
|
| def plot_nodes(idx, raster, fontsize=8, size=15): |
| ax = plt.gcf().axes[idx] |
| ax.autoscale(enable=False) |
| nodes_xy = np.stack(np.where(raster > 0)[::-1], -1) |
| nodes_val = raster[tuple(nodes_xy.T[::-1])] - 1 |
| ax.scatter(*nodes_xy.T, c="k", s=size) |
| for xy, val in zip(nodes_xy, nodes_val): |
| group = Groups.nodes[val] |
| add_text( |
| idx, |
| group, |
| xy + 2, |
| lcolor=None, |
| fs=fontsize, |
| color="k", |
| normalized=False, |
| ha="center", |
| ) |
| plt.show() |
|
|