# visualizer_map.py # Walker M. White (wmw2), Steve Marschner (srm2), Lillian Lee (ljl2) # November 1, 2013 """Visualization App to verify that k-means works This visualizer handles longitude-latitude data, and plots it on a map of North America. Visualization is limited to 2d points and k values < 15. Data is read from CSV (comma separated values, which can be saved from spreadsheet applications) files that have latitude and longitude as the last two columns.""" import sys import matplotlib import numpy import math import traceback matplotlib.use('TkAgg') # Modules to embed matplotlib in a custom Tkinter window from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg # implement the default mpl key bindings from matplotlib.backend_bases import key_press_handler from matplotlib.figure import Figure # Library for reading map data import shapefile # GUI support for loading data files import os import Tkinter as Tk import tkFileDialog import tkMessageBox import tkFont # The k-means implementation import kmeans # Maximum allowable value of k MAX_K_VAL = 14 def parse_data(data): """Return: 3-element list equivalent to file line Precondition: data is a line from a CSV file.""" if data[0] == '#': return None return map(float,data.split(',')[-2:][::-1]) class Visualizer(object): """Instance is a visualization app. INSTANCE ATTRIBUTES: _root: TCL/TK graphics backend [TK object] _canvas: MatPlotLib canvas [FigureCanvas object] _axes: MatPlotLib axes [Axes object] _ds: Data set [Dataset object] _cing: Clustering of dataset [Clustering object] _count: Number of steps executed [int >= 0] _finish: Whether the computation is done [bool] There are several other attributes for GUI widgets (buttons and labels). We do not list all of them here.""" def __init__(self, filename=None): """Initializer: Make a visualization app""" self._root = Tk.Tk() self._root.wm_title("CS 1110 Clustering Assignment Visualizer") self._ds = None self._cing = None # Start the application self._config_canvas() self._config_control() self._canvas.show() self._config_map() # Load data if provided if filename is not None: self._load_file(filename) Tk.mainloop() def _config_map(self): """Load up map data so that map drawing is fast later.""" shapes = shapefile.Reader('ne_110m_land/ne_110m_land').shapes() self._land_polygons = map(lambda s: numpy.array(s.points), shapes) def _config_canvas(self): """Load the MatPlotLib drawing code""" # Create the drawing canvas figure = Figure(figsize=(6,6), dpi=100, facecolor="#ccccff") self._canvas = FigureCanvasTkAgg(figure, master=self._root) self._canvas._tkcanvas.pack(side=Tk.LEFT, expand=True, fill=Tk.BOTH) # Initialize the scatter plot self._axes = figure.add_axes((0,0,1,1), frameon=False, axisbg='none') def _config_control(self): """Create the control panel on the right hand side This method is WAY too long, but GUI layout code is typically like this. Plus, Tkinter makes this even worse than it should be.""" panel = Tk.Frame(master=self._root) panel.columnconfigure(0,pad=3) panel.columnconfigure(1,pad=3) panel.rowconfigure(0,pad=3) panel.rowconfigure(1,pad=0) panel.rowconfigure(2,pad=23) panel.rowconfigure(3,pad=3) panel.rowconfigure(4,pad=3) panel.rowconfigure(5,pad=3) panel.rowconfigure(6,pad=13) title = Tk.Label(master=panel,text='K Means Control',height=3) wfont = tkFont.Font(font=title['font']) wfont.config(weight='bold',size=20) title.grid(row=0,columnspan=2, sticky='we') title.config(font=wfont) divider = Tk.Frame(master=panel,height=2, bd=1, relief=Tk.SUNKEN) divider.grid(row=1,columnspan=2, sticky='we') # Label and button for managing files. label = Tk.Label(master=panel,text='Data Set: ',height=2) wfont = tkFont.Font(font=label['font']) wfont.config(weight='bold') label.config(font=wfont) label.grid(row=2,column=0, sticky='e') self._filebutton = Tk.Button(master=panel, text='