Module tagmaps.classes.plotting
Module for matplotlib, seaborn, pyplot methods.
Expand source code
# -*- coding: utf-8 -*-
"""Module for matplotlib, seaborn, pyplot methods.
"""
from __future__ import absolute_import
from typing import Tuple
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch
from matplotlib.path import Path
from matplotlib.ticker import FuncFormatter
from numpy import asarray, concatenate, ones
from tagmaps.classes.shared_structure import EMOJI, LOCATIONS, TAGS, AnalysisBounds
from tagmaps.classes.utils import Utils
class TPLT:
"""Tag Maps plotting Class
To remember (because mpl/pyplot can be confusing):
- The figure is the window that the plot is in.
It's the top-level container. Each figure has a canvas
where things are painted on.
- Each figure usually has one or more axes.
These are the plots/subplots. Here, only one axes is used.
- Colorbars and other stuff are also inside the figure.
Adding a colorbar creates a new axe (unless specified otherwise)
- two modes exist, OO (object oriented) and
pyplot("state-machine interface"),
use OO-Mode if possible because it is more flexible and works
better with Jupyter Mode
for more information, see:
https://stackoverflow.com/questions/19816820/how-to-retrieve-colorbar-instance-from-figure-in-matplotlib
"""
PLOT_KWDS = {"alpha": 0.5, "s": 10, "linewidths": 0}
@staticmethod
def _get_xy_dists(bounds: AnalysisBounds) -> Tuple[float, float]:
"""Get X/Y Distances from Analysis Bounds"""
dist_y_lat = bounds.lim_lat_max - bounds.lim_lat_min
dist_x_lng = bounds.lim_lng_max - bounds.lim_lng_min
return dist_y_lat, dist_x_lng
@staticmethod
def plt_setxy_lim(axis, bounds: AnalysisBounds):
"""Set global plotting bounds basedon Analysis Bounds"""
axis.set_xlim([bounds.lim_lng_min, bounds.lim_lng_max])
axis.set_ylim([bounds.lim_lat_min, bounds.lim_lat_max])
@staticmethod
def get_fig_points(fig, points, bounds, point_size=None):
"""Get figure for numpy.ndarray of points"""
if not fig:
# create a new figure window
fig = plt.figure(1)
fig.add_subplot(111)
axis = fig.get_axes()[0]
# only one subplot (nrows, ncols, axnum)
if point_size is not None:
axis.scatter(
points.T[0],
points.T[1],
color="red",
alpha=0.5,
s=point_size,
linewidths=0,
)
else:
axis.scatter(points.T[0], points.T[1], color="red", **TPLT.PLOT_KWDS)
fig.canvas.manager.set_window_title("Preview Map")
TPLT.plt_setxy_lim(axis, bounds)
axis.tick_params(labelsize=10)
return fig
@staticmethod
def get_sel_preview(points, item, bounds, cls_type):
"""Returns plt map for item selection preview"""
# img_ratio = TPLT._get_img_ratio(bounds)
fig = None
fig = TPLT.get_fig_points(fig, points, bounds)
TPLT.set_plt_suptitle(fig, item, cls_type)
return fig
@staticmethod
def get_centroid_preview(points, item, bounds, cls_type, point_size):
"""Returns plt map for item selection preview"""
# img_ratio = TPLT._get_img_ratio(bounds)
fig = None
fig = TPLT.get_fig_points(fig, points, bounds, point_size)
TPLT.set_plt_suptitle(fig, item, cls_type)
return fig
@staticmethod
def get_cluster_preview(
points,
sel_colors,
item_text,
bounds,
mask_noisy,
cluster_distance,
number_of_clusters,
auto_select_clusters=None,
shapes=None,
fig=None,
cls_type=None,
) -> plt.figure:
"""Get cluster preview figure
Args:
points (numpy.ndarray): Point coordinates
sel_colors ([type]): Cluster colors
item_text ([type]): Text for suptitle
bounds ([type]): Bounds of plotting area
mask_noisy ([type]): Statistics for output of noisy clusters text
cluster_distance ([type]): Cluster distance
number_of_clusters (int): Total number of clusters
auto_select_clusters ([type], optional): Defaults to None.
If clusters have been auto-selected (no cluster distance)
shapes ([type], optional): Defaults to None.
Optional shapes for cluster outline/polygons.
fig ([type], optional): Defaults to None.
Optional figure for printing results.
cls_type ([type], optional): Defaults to None.
Cluster type, used to format text(s)
Returns:
figure [plt.fig]: Mpl Figure object
"""
if auto_select_clusters is None:
auto_select_clusters = False
# img_ratio = TPLT._get_img_ratio(bounds)
if not fig:
fig = plt.figure(1)
fig.add_subplot(111)
axis = fig.get_axes()[0]
# create main cluster points map
axis.scatter(points.T[0], points.T[1], c=sel_colors, **TPLT.PLOT_KWDS)
fig.canvas.manager.set_window_title("Cluster Preview")
TPLT.set_plt_suptitle(fig, item_text, cls_type)
dist_text = ""
if shapes:
for shape in shapes:
patch = TPLT._get_poly_patch(shape)
axis.add_patch(patch)
if auto_select_clusters is False:
dist_text = "@ " + str(int(cluster_distance)) + "m"
axis.set_title(f"Cluster Preview {dist_text}", fontsize=12, loc="center")
noisy_txt = f"{mask_noisy.sum()} / {len(mask_noisy)}"
axis.text(
bounds.lim_lng_max,
bounds.lim_lat_max,
f"{number_of_clusters} Clusters (Noise: {noisy_txt})",
fontsize=10,
horizontalalignment="right",
verticalalignment="top",
fontweight="bold",
)
# set plotting bounds
TPLT.plt_setxy_lim(axis, bounds)
TPLT.set_plt_tick_params(axis)
# define new figure so this one is not
# overwritten in interactive notebook mode
# plt.figure()
return fig
@staticmethod
def get_single_linkage_tree_preview(item_text, fig, cluster_distance, cls_type):
"""Gets figure for single linkage tree from HDBSCAN results"""
TPLT.set_plt_suptitle(fig, item_text, cls_type)
fig.canvas.manager.set_window_title("Single Linkage Tree")
axis = fig.get_axes()[0]
axis.set_title("Single Linkage Tree", fontsize=12, loc="center")
# plot cutting distance
y_value = Utils.get_radians_from_meters(cluster_distance)
axis.relim()
xmin = axis.get_xlim()[0]
xmax = axis.get_xlim()[1]
axis.plot(
[xmin, xmax],
[y_value, y_value],
color="k",
label=f"Cluster (Cut) Distance {int(cluster_distance)}m",
)
axis.legend(fontsize=10)
# replace y_value labels with meters text (instead of radians dist)
axis.yaxis.set_major_formatter(FuncFormatter(TPLT.y_formatter))
TPLT.set_plt_tick_params(axis)
return fig
@staticmethod
def y_formatter(y_value, __):
"""Format radians y-labels as meters for improved legibility"""
return f"{Utils.get_meters_from_radians(y_value):3.0f}m"
@staticmethod
def set_plt_suptitle(fig, item: str, cls_type):
"""Sets suptitle for plot (plt) and Cluster Type"""
TPLT._set_pltspec_suptitle(fig, item, cls_type)
@staticmethod
def _set_pltspec_suptitle(fig, item: str, cls_type=None):
"""Sets suptitle for plot (plt)"""
title = TPLT._get_pltspec_suptitle(item, cls_type)
if cls_type and cls_type == EMOJI:
plt.rcParams["font.family"] = "DejaVu Sans"
else:
plt.rcParams["font.family"] = "sans-serif"
TPLT._set_plt_suptitle_st(fig, title)
@staticmethod
def _set_plt_suptitle_st(fig, title: str):
"""Set title of plt"""
fig.suptitle(title, fontsize=18, fontweight="bold")
@staticmethod
def _get_pltspec_suptitle(item: str, cls_type=None) -> str:
"""Gets formatted suptitle for plot
- depending on clusterer type
"""
if cls_type is None:
cls_type = TAGS
title = ""
if cls_type == LOCATIONS:
title = item.upper()
elif cls_type == EMOJI:
emoji_name = Utils.get_emojiname(item)
title = f"{item} ({emoji_name})"
else:
title = item.upper()
return title
@staticmethod
def set_plt_tick_params(axis):
"""Sets common plt tick params"""
axis.tick_params(labelsize=10)
@staticmethod
def polygon_patch(polygon, **kwargs):
"""PolygonPatch function from descartes.
Source: https://github.com/geopandas/geopandas/issues/1039#issuecomment-509649752
"""
def coding(ob):
# The codes will be all "LINETO" commands, except for "MOVETO"s at the
# beginning of each subpath
n = len(getattr(ob, "coords", None) or ob)
vals = ones(n, dtype=Path.code_type) * Path.LINETO
vals[0] = Path.MOVETO
return vals
vertices = concatenate(
[asarray(polygon.exterior)[:, :2]]
+ [asarray(r)[:, :2] for r in polygon.interiors]
)
codes = concatenate(
[coding(polygon.exterior)] + [coding(r) for r in polygon.interiors]
)
return PathPatch(Path(vertices, codes), **kwargs)
@staticmethod
def _get_poly_patch(polygon):
"""Returns a matplotlib polygon-patch from shapely polygon"""
patch = TPLT.polygon_patch(
polygon, fc="#999999", ec="#000000", fill=True, zorder=-1, alpha=0.7
)
return patch
# @staticmethod
# def _get_img_ratio(bounds: AnalysisBounds
# ) -> float:
# """Gets [img] ratio form bounds."""
# dists = TPLT._get_xy_dists(bounds)
# dist_y_lat = dists[0]
# dist_x_lng = dists[1]
# # distYLat = Utils.haversine(limXMin,limYMax,limXMin,limYMin)
# # distXLng = Utils.haversine(limXMax,limYMin,limXMin,limYMin)
# img_ratio = dist_x_lng/(dist_y_lat*2)
# return img_ratio
Classes
class TPLT
-
Tag Maps plotting Class
To remember (because mpl/pyplot can be confusing): - The figure is the window that the plot is in. It's the top-level container. Each figure has a canvas where things are painted on. - Each figure usually has one or more axes. These are the plots/subplots. Here, only one axes is used. - Colorbars and other stuff are also inside the figure. Adding a colorbar creates a new axe (unless specified otherwise) - two modes exist, OO (object oriented) and pyplot("state-machine interface"), use OO-Mode if possible because it is more flexible and works better with Jupyter Mode for more information, see: https://stackoverflow.com/questions/19816820/how-to-retrieve-colorbar-instance-from-figure-in-matplotlib
Expand source code
class TPLT: """Tag Maps plotting Class To remember (because mpl/pyplot can be confusing): - The figure is the window that the plot is in. It's the top-level container. Each figure has a canvas where things are painted on. - Each figure usually has one or more axes. These are the plots/subplots. Here, only one axes is used. - Colorbars and other stuff are also inside the figure. Adding a colorbar creates a new axe (unless specified otherwise) - two modes exist, OO (object oriented) and pyplot("state-machine interface"), use OO-Mode if possible because it is more flexible and works better with Jupyter Mode for more information, see: https://stackoverflow.com/questions/19816820/how-to-retrieve-colorbar-instance-from-figure-in-matplotlib """ PLOT_KWDS = {"alpha": 0.5, "s": 10, "linewidths": 0} @staticmethod def _get_xy_dists(bounds: AnalysisBounds) -> Tuple[float, float]: """Get X/Y Distances from Analysis Bounds""" dist_y_lat = bounds.lim_lat_max - bounds.lim_lat_min dist_x_lng = bounds.lim_lng_max - bounds.lim_lng_min return dist_y_lat, dist_x_lng @staticmethod def plt_setxy_lim(axis, bounds: AnalysisBounds): """Set global plotting bounds basedon Analysis Bounds""" axis.set_xlim([bounds.lim_lng_min, bounds.lim_lng_max]) axis.set_ylim([bounds.lim_lat_min, bounds.lim_lat_max]) @staticmethod def get_fig_points(fig, points, bounds, point_size=None): """Get figure for numpy.ndarray of points""" if not fig: # create a new figure window fig = plt.figure(1) fig.add_subplot(111) axis = fig.get_axes()[0] # only one subplot (nrows, ncols, axnum) if point_size is not None: axis.scatter( points.T[0], points.T[1], color="red", alpha=0.5, s=point_size, linewidths=0, ) else: axis.scatter(points.T[0], points.T[1], color="red", **TPLT.PLOT_KWDS) fig.canvas.manager.set_window_title("Preview Map") TPLT.plt_setxy_lim(axis, bounds) axis.tick_params(labelsize=10) return fig @staticmethod def get_sel_preview(points, item, bounds, cls_type): """Returns plt map for item selection preview""" # img_ratio = TPLT._get_img_ratio(bounds) fig = None fig = TPLT.get_fig_points(fig, points, bounds) TPLT.set_plt_suptitle(fig, item, cls_type) return fig @staticmethod def get_centroid_preview(points, item, bounds, cls_type, point_size): """Returns plt map for item selection preview""" # img_ratio = TPLT._get_img_ratio(bounds) fig = None fig = TPLT.get_fig_points(fig, points, bounds, point_size) TPLT.set_plt_suptitle(fig, item, cls_type) return fig @staticmethod def get_cluster_preview( points, sel_colors, item_text, bounds, mask_noisy, cluster_distance, number_of_clusters, auto_select_clusters=None, shapes=None, fig=None, cls_type=None, ) -> plt.figure: """Get cluster preview figure Args: points (numpy.ndarray): Point coordinates sel_colors ([type]): Cluster colors item_text ([type]): Text for suptitle bounds ([type]): Bounds of plotting area mask_noisy ([type]): Statistics for output of noisy clusters text cluster_distance ([type]): Cluster distance number_of_clusters (int): Total number of clusters auto_select_clusters ([type], optional): Defaults to None. If clusters have been auto-selected (no cluster distance) shapes ([type], optional): Defaults to None. Optional shapes for cluster outline/polygons. fig ([type], optional): Defaults to None. Optional figure for printing results. cls_type ([type], optional): Defaults to None. Cluster type, used to format text(s) Returns: figure [plt.fig]: Mpl Figure object """ if auto_select_clusters is None: auto_select_clusters = False # img_ratio = TPLT._get_img_ratio(bounds) if not fig: fig = plt.figure(1) fig.add_subplot(111) axis = fig.get_axes()[0] # create main cluster points map axis.scatter(points.T[0], points.T[1], c=sel_colors, **TPLT.PLOT_KWDS) fig.canvas.manager.set_window_title("Cluster Preview") TPLT.set_plt_suptitle(fig, item_text, cls_type) dist_text = "" if shapes: for shape in shapes: patch = TPLT._get_poly_patch(shape) axis.add_patch(patch) if auto_select_clusters is False: dist_text = "@ " + str(int(cluster_distance)) + "m" axis.set_title(f"Cluster Preview {dist_text}", fontsize=12, loc="center") noisy_txt = f"{mask_noisy.sum()} / {len(mask_noisy)}" axis.text( bounds.lim_lng_max, bounds.lim_lat_max, f"{number_of_clusters} Clusters (Noise: {noisy_txt})", fontsize=10, horizontalalignment="right", verticalalignment="top", fontweight="bold", ) # set plotting bounds TPLT.plt_setxy_lim(axis, bounds) TPLT.set_plt_tick_params(axis) # define new figure so this one is not # overwritten in interactive notebook mode # plt.figure() return fig @staticmethod def get_single_linkage_tree_preview(item_text, fig, cluster_distance, cls_type): """Gets figure for single linkage tree from HDBSCAN results""" TPLT.set_plt_suptitle(fig, item_text, cls_type) fig.canvas.manager.set_window_title("Single Linkage Tree") axis = fig.get_axes()[0] axis.set_title("Single Linkage Tree", fontsize=12, loc="center") # plot cutting distance y_value = Utils.get_radians_from_meters(cluster_distance) axis.relim() xmin = axis.get_xlim()[0] xmax = axis.get_xlim()[1] axis.plot( [xmin, xmax], [y_value, y_value], color="k", label=f"Cluster (Cut) Distance {int(cluster_distance)}m", ) axis.legend(fontsize=10) # replace y_value labels with meters text (instead of radians dist) axis.yaxis.set_major_formatter(FuncFormatter(TPLT.y_formatter)) TPLT.set_plt_tick_params(axis) return fig @staticmethod def y_formatter(y_value, __): """Format radians y-labels as meters for improved legibility""" return f"{Utils.get_meters_from_radians(y_value):3.0f}m" @staticmethod def set_plt_suptitle(fig, item: str, cls_type): """Sets suptitle for plot (plt) and Cluster Type""" TPLT._set_pltspec_suptitle(fig, item, cls_type) @staticmethod def _set_pltspec_suptitle(fig, item: str, cls_type=None): """Sets suptitle for plot (plt)""" title = TPLT._get_pltspec_suptitle(item, cls_type) if cls_type and cls_type == EMOJI: plt.rcParams["font.family"] = "DejaVu Sans" else: plt.rcParams["font.family"] = "sans-serif" TPLT._set_plt_suptitle_st(fig, title) @staticmethod def _set_plt_suptitle_st(fig, title: str): """Set title of plt""" fig.suptitle(title, fontsize=18, fontweight="bold") @staticmethod def _get_pltspec_suptitle(item: str, cls_type=None) -> str: """Gets formatted suptitle for plot - depending on clusterer type """ if cls_type is None: cls_type = TAGS title = "" if cls_type == LOCATIONS: title = item.upper() elif cls_type == EMOJI: emoji_name = Utils.get_emojiname(item) title = f"{item} ({emoji_name})" else: title = item.upper() return title @staticmethod def set_plt_tick_params(axis): """Sets common plt tick params""" axis.tick_params(labelsize=10) @staticmethod def polygon_patch(polygon, **kwargs): """PolygonPatch function from descartes. Source: https://github.com/geopandas/geopandas/issues/1039#issuecomment-509649752 """ def coding(ob): # The codes will be all "LINETO" commands, except for "MOVETO"s at the # beginning of each subpath n = len(getattr(ob, "coords", None) or ob) vals = ones(n, dtype=Path.code_type) * Path.LINETO vals[0] = Path.MOVETO return vals vertices = concatenate( [asarray(polygon.exterior)[:, :2]] + [asarray(r)[:, :2] for r in polygon.interiors] ) codes = concatenate( [coding(polygon.exterior)] + [coding(r) for r in polygon.interiors] ) return PathPatch(Path(vertices, codes), **kwargs) @staticmethod def _get_poly_patch(polygon): """Returns a matplotlib polygon-patch from shapely polygon""" patch = TPLT.polygon_patch( polygon, fc="#999999", ec="#000000", fill=True, zorder=-1, alpha=0.7 ) return patch # @staticmethod # def _get_img_ratio(bounds: AnalysisBounds # ) -> float: # """Gets [img] ratio form bounds.""" # dists = TPLT._get_xy_dists(bounds) # dist_y_lat = dists[0] # dist_x_lng = dists[1] # # distYLat = Utils.haversine(limXMin,limYMax,limXMin,limYMin) # # distXLng = Utils.haversine(limXMax,limYMin,limXMin,limYMin) # img_ratio = dist_x_lng/(dist_y_lat*2) # return img_ratio
Class variables
var PLOT_KWDS
Static methods
def get_centroid_preview(points, item, bounds, cls_type, point_size)
-
Returns plt map for item selection preview
Expand source code
@staticmethod def get_centroid_preview(points, item, bounds, cls_type, point_size): """Returns plt map for item selection preview""" # img_ratio = TPLT._get_img_ratio(bounds) fig = None fig = TPLT.get_fig_points(fig, points, bounds, point_size) TPLT.set_plt_suptitle(fig, item, cls_type) return fig
def get_cluster_preview(points, sel_colors, item_text, bounds, mask_noisy, cluster_distance, number_of_clusters, auto_select_clusters=None, shapes=None, fig=None, cls_type=None) ‑>
-
Get cluster preview figure
Args
points
:numpy.ndarray
- Point coordinates
sel_colors
:[type]
- Cluster colors
item_text
:[type]
- Text for suptitle
bounds
:[type]
- Bounds of plotting area
mask_noisy
:[type]
- Statistics for output of noisy clusters text
cluster_distance
:[type]
- Cluster distance
number_of_clusters
:int
- Total number of clusters
auto_select_clusters
:[type]
, optional- Defaults to None. If clusters have been auto-selected (no cluster distance)
shapes
:[type]
, optional- Defaults to None. Optional shapes for cluster outline/polygons.
fig
:[type]
, optional- Defaults to None. Optional figure for printing results.
cls_type
:[type]
, optional- Defaults to None. Cluster type, used to format text(s)
Returns
figure [plt.fig]
- Mpl Figure object
Expand source code
@staticmethod def get_cluster_preview( points, sel_colors, item_text, bounds, mask_noisy, cluster_distance, number_of_clusters, auto_select_clusters=None, shapes=None, fig=None, cls_type=None, ) -> plt.figure: """Get cluster preview figure Args: points (numpy.ndarray): Point coordinates sel_colors ([type]): Cluster colors item_text ([type]): Text for suptitle bounds ([type]): Bounds of plotting area mask_noisy ([type]): Statistics for output of noisy clusters text cluster_distance ([type]): Cluster distance number_of_clusters (int): Total number of clusters auto_select_clusters ([type], optional): Defaults to None. If clusters have been auto-selected (no cluster distance) shapes ([type], optional): Defaults to None. Optional shapes for cluster outline/polygons. fig ([type], optional): Defaults to None. Optional figure for printing results. cls_type ([type], optional): Defaults to None. Cluster type, used to format text(s) Returns: figure [plt.fig]: Mpl Figure object """ if auto_select_clusters is None: auto_select_clusters = False # img_ratio = TPLT._get_img_ratio(bounds) if not fig: fig = plt.figure(1) fig.add_subplot(111) axis = fig.get_axes()[0] # create main cluster points map axis.scatter(points.T[0], points.T[1], c=sel_colors, **TPLT.PLOT_KWDS) fig.canvas.manager.set_window_title("Cluster Preview") TPLT.set_plt_suptitle(fig, item_text, cls_type) dist_text = "" if shapes: for shape in shapes: patch = TPLT._get_poly_patch(shape) axis.add_patch(patch) if auto_select_clusters is False: dist_text = "@ " + str(int(cluster_distance)) + "m" axis.set_title(f"Cluster Preview {dist_text}", fontsize=12, loc="center") noisy_txt = f"{mask_noisy.sum()} / {len(mask_noisy)}" axis.text( bounds.lim_lng_max, bounds.lim_lat_max, f"{number_of_clusters} Clusters (Noise: {noisy_txt})", fontsize=10, horizontalalignment="right", verticalalignment="top", fontweight="bold", ) # set plotting bounds TPLT.plt_setxy_lim(axis, bounds) TPLT.set_plt_tick_params(axis) # define new figure so this one is not # overwritten in interactive notebook mode # plt.figure() return fig
def get_fig_points(fig, points, bounds, point_size=None)
-
Get figure for numpy.ndarray of points
Expand source code
@staticmethod def get_fig_points(fig, points, bounds, point_size=None): """Get figure for numpy.ndarray of points""" if not fig: # create a new figure window fig = plt.figure(1) fig.add_subplot(111) axis = fig.get_axes()[0] # only one subplot (nrows, ncols, axnum) if point_size is not None: axis.scatter( points.T[0], points.T[1], color="red", alpha=0.5, s=point_size, linewidths=0, ) else: axis.scatter(points.T[0], points.T[1], color="red", **TPLT.PLOT_KWDS) fig.canvas.manager.set_window_title("Preview Map") TPLT.plt_setxy_lim(axis, bounds) axis.tick_params(labelsize=10) return fig
def get_sel_preview(points, item, bounds, cls_type)
-
Returns plt map for item selection preview
Expand source code
@staticmethod def get_sel_preview(points, item, bounds, cls_type): """Returns plt map for item selection preview""" # img_ratio = TPLT._get_img_ratio(bounds) fig = None fig = TPLT.get_fig_points(fig, points, bounds) TPLT.set_plt_suptitle(fig, item, cls_type) return fig
def get_single_linkage_tree_preview(item_text, fig, cluster_distance, cls_type)
-
Gets figure for single linkage tree from HDBSCAN results
Expand source code
@staticmethod def get_single_linkage_tree_preview(item_text, fig, cluster_distance, cls_type): """Gets figure for single linkage tree from HDBSCAN results""" TPLT.set_plt_suptitle(fig, item_text, cls_type) fig.canvas.manager.set_window_title("Single Linkage Tree") axis = fig.get_axes()[0] axis.set_title("Single Linkage Tree", fontsize=12, loc="center") # plot cutting distance y_value = Utils.get_radians_from_meters(cluster_distance) axis.relim() xmin = axis.get_xlim()[0] xmax = axis.get_xlim()[1] axis.plot( [xmin, xmax], [y_value, y_value], color="k", label=f"Cluster (Cut) Distance {int(cluster_distance)}m", ) axis.legend(fontsize=10) # replace y_value labels with meters text (instead of radians dist) axis.yaxis.set_major_formatter(FuncFormatter(TPLT.y_formatter)) TPLT.set_plt_tick_params(axis) return fig
def plt_setxy_lim(axis, bounds: AnalysisBounds)
-
Set global plotting bounds basedon Analysis Bounds
Expand source code
@staticmethod def plt_setxy_lim(axis, bounds: AnalysisBounds): """Set global plotting bounds basedon Analysis Bounds""" axis.set_xlim([bounds.lim_lng_min, bounds.lim_lng_max]) axis.set_ylim([bounds.lim_lat_min, bounds.lim_lat_max])
def polygon_patch(polygon, **kwargs)
-
PolygonPatch function from descartes.
Source: https://github.com/geopandas/geopandas/issues/1039#issuecomment-509649752
Expand source code
@staticmethod def polygon_patch(polygon, **kwargs): """PolygonPatch function from descartes. Source: https://github.com/geopandas/geopandas/issues/1039#issuecomment-509649752 """ def coding(ob): # The codes will be all "LINETO" commands, except for "MOVETO"s at the # beginning of each subpath n = len(getattr(ob, "coords", None) or ob) vals = ones(n, dtype=Path.code_type) * Path.LINETO vals[0] = Path.MOVETO return vals vertices = concatenate( [asarray(polygon.exterior)[:, :2]] + [asarray(r)[:, :2] for r in polygon.interiors] ) codes = concatenate( [coding(polygon.exterior)] + [coding(r) for r in polygon.interiors] ) return PathPatch(Path(vertices, codes), **kwargs)
def set_plt_suptitle(fig, item: str, cls_type)
-
Sets suptitle for plot (plt) and Cluster Type
Expand source code
@staticmethod def set_plt_suptitle(fig, item: str, cls_type): """Sets suptitle for plot (plt) and Cluster Type""" TPLT._set_pltspec_suptitle(fig, item, cls_type)
def set_plt_tick_params(axis)
-
Sets common plt tick params
Expand source code
@staticmethod def set_plt_tick_params(axis): """Sets common plt tick params""" axis.tick_params(labelsize=10)
def y_formatter(y_value, __)
-
Format radians y-labels as meters for improved legibility
Expand source code
@staticmethod def y_formatter(y_value, __): """Format radians y-labels as meters for improved legibility""" return f"{Utils.get_meters_from_radians(y_value):3.0f}m"