Source code for extractdialog

################################
#   Created on Jul 9, 2015
#
#   @author: nqian
#   @author: Grant Mercer
###############################
from Tkinter import Toplevel, Frame, TOP, BOTH, X, Button, BOTTOM,\
    LEFT
import tkMessageBox

import ccplot
from ccplot.algorithms import interp2d_12
from ccplot.hdf import HDF
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib as mpl
import numpy as np

from constants import TIME_VARIANCE
from tools.tools import interpolation_search
from log.log import logger


# noinspection PyUnresolvedReferences
[docs]class ExtractDialog(Toplevel): """ Displays a subplot containing the data bounded by a shape """ def __init__(self, root, shape, filename, x_range, y_range): """ Instantiates attributes :param: root: root Tk widget :param: shape: The shape that bounds the data :param: filename: The name of the file on display """ Toplevel.__init__(self, root) self.wm_withdraw() self.geometry('+%d+%d' % (root.winfo_rootx(), root.winfo_rooty())) print(self.geometry()) self.transient(root) logger.info('Opening ExtractDialog') self.window_frame = Frame(self) self.window_frame.pack(side=TOP, fill=BOTH, expand=True) self.canvas_frame = Frame(self.window_frame) self.canvas_frame.pack(side=TOP, fill=X) self.__root = root self.shape = shape self.filename = filename self.x_range = x_range self.y_range = y_range self.fig = Figure(figsize=(8, 5)) self.ax = self.fig.add_subplot(1, 1, 1) self.ax.set_xlabel('Time') self.ax.set_ylabel('Altitude (km)') self.ax.set_title('%s' % shape.get_tag()) self.canvas = FigureCanvasTkAgg(self.fig, master=self.canvas_frame) self.canvas.show() self.canvas.get_tk_widget().grid(row=0) self.title('Data Subplot') logger.info('Reading shape data') try: self.create_subplot() except ZeroDivisionError: logger.error('Shape too small to extract data') tkMessageBox.showerror('extractdialog', 'Shape too small to extract data') return self.update() self.deiconify() self.button_frame = Frame(self.window_frame, highlightthickness=1, highlightbackground='grey') self.button_frame.pack(side=BOTTOM, fill=X, padx=5, pady=5) but = Button(self.button_frame, text="Extract to file") but.pack(side=LEFT, padx=10, pady=10) logger.info('Creating histogram') x = self.__root.winfo_rootx() + self.winfo_x()*2 y = self.__root.winfo_rooty() self.histogram_window = Toplevel(self) self.histogram_window.geometry('+%d+%d' % (x, y)) print(self.histogram_window.geometry()) self.histogram_window.protocol('WM_DELETE_WINDOW', ExtractDialog.ignore) self.histogram_window.transient(self.__root) self.histogram_window.withdraw() self.hist_fig = Figure(figsize=(5, 2)) self.hist_ax = self.hist_fig.add_subplot(1, 1, 1) self.hist_ax.set_xlabel('Time') self.hist_ax.set_ylabel('Altitude (km)') self.hist_canvas = FigureCanvasTkAgg(self.hist_fig, master=self.histogram_window) self.hist_canvas.show() self.hist_canvas.get_tk_widget().grid(row=0) self.histogram_window.title('Histogram') # self.create_histogram() # self.histogram_window.update() # self.histogram_window.deiconify() @staticmethod def ignore(): pass
[docs] def create_subplot(self): """ Read coordinate data from the shape to determine the new bounds of the subplot. Shape bounds are taken with simple ``max()`` and ``min()`` functions, however determining their location within the time array is much more difficult as matplotlib only handles *real* locations, not relative to the numpy data arrays. To solve this issue an algorithm called ``interpolation_search`` is used, which computes the nearest time coordinate for bounding, and with a complexity of only ``O(log log(n))`` """ cords = self.shape.get_coordinates() time_cords, altitude_cords = zip(*cords) x1 = self.x_range[0] x2 = self.x_range[1] h1 = min(altitude_cords) h2 = max(altitude_cords) nz = 500 colormap = 'dat/calipso-backscatter.cmap' # TODO Show correct plot when depolarized starts working # plot = self.shape.get_plot() with HDF(self.filename) as product: time = product['Profile_UTC_Time'][x1:x2, 0] height = product['metadata']['Lidar_Data_Altitudes'] dataset = product['Total_Attenuated_Backscatter_532'][x1:x2] n_time = np.array([mpl.dates.date2num(ccplot.utils.calipso_time2dt(t)) for t in time]) min_time = min(time_cords) max_time = max(time_cords) logger.info('Applying search algorithm to determine shape bounds') x1 = int(interpolation_search(n_time, min_time, TIME_VARIANCE)) x2 = int(interpolation_search(n_time, max_time, TIME_VARIANCE)) # throws error when x1 is greater than x2, which shouldn't ever happen if abs(x1 - x2) <= 1: raise ZeroDivisionError logger.info('Setting bounds for new subplot') time = time[x1:x2] dataset = dataset[x1:x2] time = np.array([ccplot.utils.calipso_time2dt(t) for t in time]) dataset = np.ma.masked_equal(dataset, -9999) _x = np.arange(x1, x2, dtype=np.float32) _z, null = np.meshgrid(height, _x) data = interp2d_12( dataset[::], _x.astype(np.float32), _z.astype(np.float32), x1, x2, x2 - x1, h2, h1, nz) cmap = ccplot.utils.cmap(colormap) cm = mpl.colors.ListedColormap(cmap['colors']/255.0) cm.set_under(cmap['under']//255.0) cm.set_over(cmap['over']/255.0) cm.set_bad(cmap['bad']/255.0) norm = mpl.colors.BoundaryNorm(cmap['bounds'], cm.N) logger.info("Setting colormap, displaying") self.ax.imshow( data.T, extent=(mpl.dates.date2num(time[0]), mpl.dates.date2num(time[-1]), h1, h2), cmap=cm, aspect='auto', norm=norm, interpolation='nearest' ) self.ax.get_xaxis().set_major_formatter(mpl.dates.DateFormatter('%H:%M:%S'))
def create_histogram(self): cords = self.shape.get_coordinates() time_cords, altitude_cords = zip(*cords) x1 = self.x_range[0] x2 = self.x_range[1] h1 = min(altitude_cords) h2 = max(altitude_cords) nz = 500 # colormap = 'dat/calipso-backscatter.cmap' # TODO Show correct plot when depolarized starts working # plot = self.shape.get_plot() with HDF(self.filename) as product: time = product['Profile_UTC_Time'][x1:x2, 0] height = product['metadata']['Lidar_Data_Altitudes'] dataset = product['Total_Attenuated_Backscatter_532'][x1:x2] n_time = np.array([mpl.dates.date2num(ccplot.utils.calipso_time2dt(t)) for t in time]) min_time = min(time_cords) max_time = max(time_cords) logger.info('Applying search algorithm to determine shape bounds') x1 = int(interpolation_search(n_time, min_time, TIME_VARIANCE)) x2 = int(interpolation_search(n_time, max_time, TIME_VARIANCE)) logger.info('Setting bounds for new subplot') # time = time[x1:x2] dataset = dataset[x1:x2] # time = np.array([ccplot.utils.calipso_time2dt(t) for t in time]) dataset = np.ma.masked_equal(dataset, -9999) _x = np.arange(x1, x2, dtype=np.float32) _z, null = np.meshgrid(height, _x) data = interp2d_12( dataset[::], _x.astype(np.float32), _z.astype(np.float32), x1, x2, x2 - x1, h2, h1, nz) self.hist_ax.hist(data.tolist(), facecolor='green', alpha=0.75) self.hist_ax.set_xlabel('Value') self.hist_ax.set_ylabel('Count') self.hist_ax.set_xlim([0, 0.009]) self.hist_ax.set_ylim([0, 1000])