Skip to content

Commit

Permalink
refactor: move plotting methods to separate class
Browse files Browse the repository at this point in the history
  • Loading branch information
Sieboldianus committed Feb 13, 2019
1 parent 35ac0f5 commit 037be50
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 120 deletions.
5 changes: 3 additions & 2 deletions tagmaps/classes/cluster.py
Expand Up @@ -22,6 +22,7 @@
from tagmaps.classes.shared_structure import (EMOJI, LOCATIONS, TAGS,
AnalysisBounds, CleanedPost,
ClusterType, PreparedStats)
from tagmaps.classes.plotting import TPLT
from tagmaps.classes.utils import Utils
with warnings.catch_warnings():
# filter sklearn\externals\joblib\parallel.py:268:
Expand Down Expand Up @@ -715,7 +716,7 @@ def _get_sel_preview(self, item):
points = self._get_np_points(
item=item,
silent=True)
fig = Utils._get_sel_preview(points, item, self.bounds)
fig = TPLT._get_sel_preview(points, item, self.bounds)
return fig

def _get_cluster_preview(self, item):
Expand All @@ -726,7 +727,7 @@ def _get_cluster_preview(self, item):
self._cluster_points(
points=points,
preview_mode=True)
fig = Utils._get_cluster_preview(
fig = TPLT._get_cluster_preview(
points, self.sel_colors, item, self.bounds, self.mask_noisy,
self.cluster_distance, self.number_of_clusters,
self.autoselect_clusters)
Expand Down
15 changes: 8 additions & 7 deletions tagmaps/classes/interface.py
Expand Up @@ -18,6 +18,7 @@
from typing import List, Set, Dict, Tuple, Optional, TextIO
import traceback
import shapely.geometry as geometry
from tagmaps.classes.plotting import TPLT
from tagmaps.classes.utils import Utils
from tagmaps.classes.shared_structure import (
CleanedPost, AnalysisBounds,
Expand Down Expand Up @@ -55,7 +56,7 @@ def __init__(self,
self.abort = False
# self.floater_x = 0
# self.floater_y = 0
self.img_ratio = Utils._get_img_ratio(self._clst.bounds)
self.img_ratio = TPLT._get_img_ratio(self._clst.bounds)
self.current_display_item = None
# Initialize TKinter Interface
self.app = App()
Expand Down Expand Up @@ -254,7 +255,7 @@ def _cluster_preview(self, sel_item: Tuple[str, int]):
if self.fig1:
# plt references the last figure accessed
plt.figure(1).clf()
self.fig1 = Utils._get_cluster_preview(
self.fig1 = TPLT._get_cluster_preview(
points, sel_colors, sel_item[0], self._clst.bounds, mask_noisy,
self._clst.cluster_distance, self._clst.number_of_clusters,
self._clst.autoselect_clusters)
Expand Down Expand Up @@ -288,7 +289,7 @@ def _cluster_preview(self, sel_item: Tuple[str, int]):
# label_clusters=True)
# plt.title('Condensed Tree', fontsize=12,loc='center')
self._set_plt_suptitle(sel_item[0])
Utils.set_plt_tick_params(plt)
TPLT.set_plt_tick_params(plt)
if self.fig3:
plt.figure(3).clf()
self._set_plt_suptitle(sel_item[0])
Expand Down Expand Up @@ -344,7 +345,7 @@ def _cluster_preview(self, sel_item: Tuple[str, int]):
vals = self.fig3.get_yticks()
self.fig3.set_yticklabels(
[f'{Utils._get_meters_from_radians(x):3.1f}m' for x in vals])
Utils.set_plt_tick_params(plt)
TPLT.set_plt_tick_params(plt)
if self.create_min_spanning_tree:
if self.fig4:
plt.figure(4).clf()
Expand Down Expand Up @@ -398,7 +399,7 @@ def _cluster_preview(self, sel_item: Tuple[str, int]):
# cb.ax.set_yticklabels(
# ['{:3.1f}m'.format(getMetersFromRadians(x)) for x in vals]
# )
Utils.set_plt_tick_params(plt)
TPLT.set_plt_tick_params(plt)
self._update_scalebar()

def _set_plt_suptitle(self, item: str):
Expand All @@ -413,7 +414,7 @@ def _set_pltspec_suptitle(self, plt, item: str, cls_type=None):
plt.rcParams['font.family'] = 'DejaVu Sans'
else:
plt.rcParams['font.family'] = 'sans-serif'
Utils._set_plt_suptitle_st(plt, title)
TPLT._set_plt_suptitle_st(plt, title)

def _get_pltspec_suptitle(self, item: str, cls_type=None) -> str:
"""Gets formatted suptitle for plot
Expand Down Expand Up @@ -452,7 +453,7 @@ def _intf_selection_preview(self, sel_item: Tuple[str, int]):

def _intf_plot_points(self, item_name: str, points):
self._set_plt_suptitle(item_name)
self.fig1 = Utils._get_fig_points(
self.fig1 = TPLT._get_fig_points(
points, self.img_ratio, self._clst.bounds)

def _report_callback_exception(self, exc, val, tb):
Expand Down
122 changes: 121 additions & 1 deletion tagmaps/classes/plotting.py
@@ -1,4 +1,124 @@
# -*- coding: utf-8 -*-

"""Module for matplotlib, seaborn, pyplot methods.
"""
"""
from typing import List, Set, Dict, Tuple, Optional, TextIO, Iterable
import matplotlib.pyplot as plt
from descartes import PolygonPatch
from tagmaps.classes.shared_structure import CleanedPost, AnalysisBounds


class TPLT():
"""Tag Maps plotting Class
"""
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 _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

@staticmethod
def plt_setxy_lim(plt, bounds: AnalysisBounds):
"""Set global plotting bounds basedon Analysis Bounds"""
plt.gca().set_xlim(
[bounds.lim_lng_min, bounds.lim_lng_max])
plt.gca().set_ylim(
[bounds.lim_lat_min, bounds.lim_lat_max])

@staticmethod
def _get_fig_points(points, img_ratio, bounds):
plt.scatter(points.T[0], points.T[1],
color='red', **TPLT.PLOT_KWDS)
fig = plt.figure(num=1, figsize=(
11, int(11*img_ratio)), dpi=80)
fig.canvas.set_window_title('Preview Map')
TPLT.plt_setxy_lim(plt, bounds)
plt.tick_params(labelsize=10)
return fig

@staticmethod
def _get_sel_preview(points, item, bounds):
"""Returns plt map for item selection preview"""
img_ratio = TPLT._get_img_ratio(bounds)
fig = TPLT._get_fig_points(points, img_ratio, bounds)
plt.suptitle(item, fontsize=18, fontweight='bold')
return fig

@staticmethod
def _get_cluster_preview(
points, sel_colors, item_text, bounds, mask_noisy,
cluster_distance, number_of_clusters, auto_select_clusters=None):
if auto_select_clusters is None:
auto_select_clusters = False
# create main cluster points map
plt.scatter(points.T[0], points.T[1],
c=sel_colors, **TPLT.PLOT_KWDS)
img_ratio = TPLT._get_img_ratio(bounds)
fig1 = plt.figure(num=1, figsize=(
11, int(11*img_ratio)), dpi=80)
fig1.canvas.set_window_title('Cluster Preview')
TPLT._set_plt_suptitle_st(plt, item_text)
dist_text = ''
if auto_select_clusters is False:
dist_text = '@ ' + str(cluster_distance) + 'm'
plt.title(f'Cluster Preview {dist_text}',
fontsize=12, loc='center')
# xmax = fig1.get_xlim()[1]
# ymax = fig1.get_ylim()[1]
noisy_txt = '{} / {}'.format(mask_noisy.sum(), len(mask_noisy))
plt.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(plt, bounds)
TPLT.set_plt_tick_params(plt)
# define new figure so this one is not
# overwritten in interactive notebook mode
# plt.figure()
return fig1

@staticmethod
def set_plt_tick_params(plt):
"""Sets common plt tick params"""
plt.tick_params(labelsize=10)

@staticmethod
def _set_plt_suptitle_st(plt, title: str):
"""Set title of plt"""
plt.suptitle(title,
fontsize=18, fontweight='bold')

@staticmethod
def plot_polygon(polygon):
"""Plot a polygon in matplotlib pyplot interface"""
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111)
margin = .3
x_min, y_min, x_max, y_max = polygon.bounds
ax.set_xlim([x_min-margin, x_max+margin])
ax.set_ylim([y_min-margin, y_max+margin])
patch = PolygonPatch(polygon, fc='#999999',
ec='#000000', fill=True,
zorder=-1)
ax.add_patch(patch)
return fig
110 changes: 0 additions & 110 deletions tagmaps/classes/utils.py
Expand Up @@ -19,14 +19,12 @@
import regex
from importlib import reload
import shapely.geometry as geometry
import matplotlib.pyplot as plt
from fiona.crs import from_epsg
from pathlib import Path
from shapely.ops import transform, cascaded_union, polygonize
from datetime import timedelta
from typing import List, Set, Dict, Tuple, Optional, TextIO, Iterable
from math import radians, cos, sin, asin, sqrt
from descartes import PolygonPatch
from tagmaps.classes.shared_structure import CleanedPost, AnalysisBounds


Expand All @@ -35,7 +33,6 @@ class Utils():
Primarily @classmethods and @staticmethods
"""
PLOT_KWDS = {'alpha': 0.5, 's': 10, 'linewidths': 0}

@staticmethod
def _get_shapely_bounds(
Expand Down Expand Up @@ -475,21 +472,6 @@ def str2bool(str_text):
raise argparse.ArgumentTypeError(
'Boolean value expected.')

@staticmethod
def plot_polygon(polygon):
"""Plot a polygon in matplotlib pyplot interface"""
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111)
margin = .3
x_min, y_min, x_max, y_max = polygon.bounds
ax.set_xlim([x_min-margin, x_max+margin])
ax.set_ylim([y_min-margin, y_max+margin])
patch = PolygonPatch(polygon, fc='#999999',
ec='#000000', fill=True,
zorder=-1)
ax.add_patch(patch)
return fig

@staticmethod
def get_rectangle_bounds(points):
limYMin = np.min(points.T[1])
Expand Down Expand Up @@ -586,95 +568,3 @@ def _get_index_of_tup(
return pos
# Matches behavior of list.index
raise ValueError("list.index(x): x not in list")

@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 _get_img_ratio(bounds: AnalysisBounds
) -> float:
"""Gets [img] ratio form bounds."""
dists = Utils._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

@staticmethod
def plt_setxy_lim(plt, bounds: AnalysisBounds):
"""Set global plotting bounds basedon Analysis Bounds"""
plt.gca().set_xlim(
[bounds.lim_lng_min, bounds.lim_lng_max])
plt.gca().set_ylim(
[bounds.lim_lat_min, bounds.lim_lat_max])

@staticmethod
def _get_fig_points(points, img_ratio, bounds):
plt.scatter(points.T[0], points.T[1],
color='red', **Utils.PLOT_KWDS)
fig = plt.figure(num=1, figsize=(
11, int(11*img_ratio)), dpi=80)
fig.canvas.set_window_title('Preview Map')
Utils.plt_setxy_lim(plt, bounds)
plt.tick_params(labelsize=10)
return fig

@staticmethod
def _get_sel_preview(points, item, bounds):
"""Returns plt map for item selection preview"""
img_ratio = Utils._get_img_ratio(bounds)
fig = Utils._get_fig_points(points, img_ratio, bounds)
plt.suptitle(item, fontsize=18, fontweight='bold')
return fig

@staticmethod
def _get_cluster_preview(
points, sel_colors, item_text, bounds, mask_noisy,
cluster_distance, number_of_clusters, auto_select_clusters=None):
if auto_select_clusters is None:
auto_select_clusters = False
# create main cluster points map
plt.scatter(points.T[0], points.T[1],
c=sel_colors, **Utils.PLOT_KWDS)
img_ratio = Utils._get_img_ratio(bounds)
fig1 = plt.figure(num=1, figsize=(
11, int(11*img_ratio)), dpi=80)
fig1.canvas.set_window_title('Cluster Preview')
Utils._set_plt_suptitle_st(plt, item_text)
dist_text = ''
if auto_select_clusters is False:
dist_text = '@ ' + str(cluster_distance) + 'm'
plt.title(f'Cluster Preview {dist_text}',
fontsize=12, loc='center')
# xmax = fig1.get_xlim()[1]
# ymax = fig1.get_ylim()[1]
noisy_txt = '{} / {}'.format(mask_noisy.sum(), len(mask_noisy))
plt.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
Utils.plt_setxy_lim(plt, bounds)
Utils.set_plt_tick_params(plt)
return fig1

@staticmethod
def set_plt_tick_params(plt):
"""Sets common plt tick params"""
plt.tick_params(labelsize=10)

@staticmethod
def _set_plt_suptitle_st(plt, title: str):
"""Set title of plt"""
plt.suptitle(title,
fontsize=18, fontweight='bold')

0 comments on commit 037be50

Please sign in to comment.