Esempio n. 1
0
class KMeansLayer(BaseLayer):

    def __init__(self, data):
        self.data = data
        self.k = 2


    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])

        k_means = KMeans(n_clusters=self.k)
        k_means.fit(np.vstack([x,y]).T)
        labels = k_means.labels_

        self.cmap = create_set_cmap(set(labels), 'hsv')
        for l in set(labels):
            self.painter.set_color(self.cmap[l])
            self.painter.convexhull(x[labels == l], y[labels == l])
            self.painter.points(x[labels == l], y[labels == l], 2)
    
            
    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        ui_manager.info('Use left and right to increase/decrease the number of clusters. k = %d' % self.k)
        self.painter.batch_draw()


    def on_key_release(self, key, modifiers):
        if key == pyglet.window.key.LEFT:
            self.k = max(2,self.k - 1)
            return True
        elif key == pyglet.window.key.RIGHT:
            self.k = self.k + 1
            return True
        return False
Esempio n. 2
0
class TrailsLayer(BaseLayer):

    def __init__(self):
        self.data = read_csv('SLOCs.csv')
        self.cmap = colorbrewer(self.data['name'], alpha=220)
        self.t = self.data['timestamp'].min()
        self.painter = BatchPainter()


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter = BatchPainter()
        df = self.data.where((self.data['timestamp'] > self.t) & (self.data['timestamp'] <= self.t + 24*3600)) #set minimum time interval
        
        for name in set(df['name']):
            grp = df.where(df['name'] == name)
            self.painter.set_color('blue') #set color, default: self.cmap[name]
            x0, y0 = proj.lonlat_to_screen(grp['Slon'], grp['Slat'])
            x1, y1 = proj.lonlat_to_screen(grp['Flon'], grp['Flat'])
            self.painter.points(x0, y0, 3)
            self.painter.lines(x0,y0,x1,y1,width=3)

        self.t += 24*3600 #set animation step size

        if self.t > self.data['timestamp'].max():
            self.t = self.data['timestamp'].min()

        self.painter.batch_draw()
        ui_manager.info(epoch_to_str(self.t))


    def bbox(self):
        return BoundingBox(north=9, west=110, south=1, east=95) #set boundingbox
Esempio n. 3
0
class KMeansLayer(BaseLayer):

    def __init__(self, data):
        self.data = data


    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])

        k_means = KMeans()
        k_means.fit(np.vstack([x,y]).T)
        labels = k_means.labels_

        self.cmap = create_set_cmap(set(labels), 'hsv')
        for l in set(labels):
            try:
                self.painter.set_color(self.cmap[l])
                self.painter.convexhull(x[labels == l], y[labels == l])
                self.painter.points(x[labels == l], y[labels == l], 2)
            except Exception:
                print '=============',l,'=============='

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()


    def on_key_release(self, key, modifiers):
        return False
Esempio n. 4
0
class TrailsLayer(BaseLayer):
    def __init__(self):
        self.data = read_csv('alex.csv')
        self.cmap = colorbrewer(self.data['runner_id'], alpha=220)
        self.t = self.data['timestamp'].min()
        self.painter = BatchPainter()

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter = BatchPainter()
        df = self.data.where((self.data['timestamp'] > self.t)
                             & (self.data['timestamp'] <= self.t + 15 * 60))

        for taxi_id in set(df['runner_id']):
            grp = df.where(df['runner_id'] == taxi_id)
            self.painter.set_color(self.cmap[taxi_id])
            x, y = proj.lonlat_to_screen(grp['lon'], grp['lat'])
            self.painter.points(x, y, 10)

        self.t += 2 * 60

        if self.t > self.data['timestamp'].max():
            self.t = self.data['timestamp'].min()

        self.painter.batch_draw()
        ui_manager.info(epoch_to_str(self.t))

    # this should get modified as well moving forward
    def bbox(self):
        return BoundingBox(north=37.801421,
                           west=-122.517339,
                           south=37.730097,
                           east=-122.424474)
Esempio n. 5
0
class ConvexHullLayer(BaseLayer):

    def __init__(self, data, col, fill=True, point_size=4):
        """
        Convex hull for a set of points

        :param data: points
        :param col: color
        :param fill: whether to fill the convexhull polygon or not
        :param point_size: size of the points on the convexhull. Points are not rendered if None
        """
        self.data = data
        self.col = col
        self.fill = fill
        self.point_size=point_size


    def invalidate(self, proj):
        self.painter = BatchPainter()
        self.painter.set_color(self.col)
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        if len(x) >= 3:
            self.painter.convexhull(x, y, self.fill)
        else:
            self.painter.linestrip(x, y)

        if self.point_size > 0:
            self.painter.points(x, y, self.point_size)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
Esempio n. 6
0
class KMeansLayer(BaseLayer):
    def __init__(self, data):
        self.data = data
        self.k = 2

    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])

        k_means = KMeans(n_clusters=self.k)
        k_means.fit(np.vstack([x, y]).T)
        labels = k_means.labels_

        self.cmap = create_set_cmap(set(labels), 'hsv')
        for l in set(labels):
            self.painter.set_color(self.cmap[l])
            self.painter.convexhull(x[labels == l], y[labels == l])
            self.painter.points(x[labels == l], y[labels == l], 2)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        ui_manager.info(
            'Use left and right to increase/decrease the number of clusters. k = %d'
            % self.k)
        self.painter.batch_draw()

    def on_key_release(self, key, modifiers):
        if key == pyglet.window.key.LEFT:
            self.k = max(2, self.k - 1)
            return True
        elif key == pyglet.window.key.RIGHT:
            self.k = self.k + 1
            return True
        return False
Esempio n. 7
0
class TrailsLayer(BaseLayer):

    def __init__(self):
        self.data = read_csv('data/taxi.csv')
        self.cmap = colorbrewer(self.data['taxi_id'], alpha=220)
        self.t = self.data['timestamp'].min()
        self.painter = BatchPainter()


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter = BatchPainter()
        df = self.data.where((self.data['timestamp'] > self.t) & (self.data['timestamp'] <= self.t + 15*60))

        for taxi_id in set(df['taxi_id']):
            grp = df.where(df['taxi_id'] == taxi_id)
            self.painter.set_color(self.cmap[taxi_id])
            x, y = proj.lonlat_to_screen(grp['lon'], grp['lat'])
            self.painter.points(x, y, 10)

        self.t += 2*60

        if self.t > self.data['timestamp'].max():
            self.t = self.data['timestamp'].min()

        self.painter.batch_draw()
        ui_manager.info(epoch_to_str(self.t))


    def bbox(self):
        return BoundingBox(north=40.110222, west=115.924463, south=39.705711, east=116.803369)
Esempio n. 8
0
class ConvexHullLayer(BaseLayer):
    def __init__(self, data, col, fill=True, point_size=4):
        """
        Convex hull for a set of points

        :param data: points
        :param col: color
        :param fill: whether to fill the convexhull polygon or not
        :param point_size: size of the points on the convexhull. Points are not rendered if None
        """
        self.data = data
        self.col = col
        self.fill = fill
        self.point_size = point_size

    def invalidate(self, proj):
        self.painter = BatchPainter()
        self.painter.set_color(self.col)
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        if len(x) >= 3:
            self.painter.convexhull(x, y, self.fill)
        else:
            self.painter.linestrip(x, y)

        if self.point_size > 0:
            self.painter.points(x, y, self.point_size)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
Esempio n. 9
0
class TrailsLayer(BaseLayer):
    def __init__(self):
        self.data = read_csv('data/taxi.csv')
        self.cmap = colorbrewer(self.data['taxi_id'], alpha=220)
        self.t = self.data['timestamp'].min()
        self.painter = BatchPainter()

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter = BatchPainter()
        df = self.data.where((self.data['timestamp'] > self.t)
                             & (self.data['timestamp'] <= self.t + 15 * 60))

        for taxi_id in set(df['taxi_id']):
            grp = df.where(df['taxi_id'] == taxi_id)
            self.painter.set_color(self.cmap[taxi_id])
            x, y = proj.lonlat_to_screen(grp['lon'], grp['lat'])
            self.painter.points(x, y, 10)

        self.t += 2 * 60

        if self.t > self.data['timestamp'].max():
            self.t = self.data['timestamp'].min()

        self.painter.batch_draw()
        ui_manager.info(epoch_to_str(self.t))

    def bbox(self):
        return BoundingBox(north=40.110222,
                           west=115.924463,
                           south=39.705711,
                           east=116.803369)
Esempio n. 10
0
class GraphLayer(BaseLayer):

    def __init__(self, data, src_lat, src_lon, dest_lat, dest_lon, linewidth=1, alpha=220, color='hot'):
        """Create a graph drawing a line between each pair of (src_lat, src_lon) and (dest_lat, dest_lon)

        :param data: data access object
        :param src_lat: field name of source latitude
        :param src_lon: field name of source longitude
        :param dest_lat: field name of destination latitude
        :param dest_lon: field name of destination longitude
        :param linewidth: line width
        :param alpha: color alpha
        :param color: color or colormap
        """
        self.data = data
        self.src_lon = src_lon
        self.src_lat = src_lat
        self.dest_lon = dest_lon
        self.dest_lat = dest_lat

        self.linewidth = linewidth
        alpha = alpha
        self.color = color
        if type(self.color) == str:
            self.cmap = colors.ColorMap(self.color, alpha)


    def invalidate(self, proj):
        self.painter = BatchPainter()
        x0, y0 = proj.lonlat_to_screen(self.data[self.src_lon], self.data[self.src_lat])
        x1, y1 = proj.lonlat_to_screen(self.data[self.dest_lon], self.data[self.dest_lat])

        if type(self.color) == list:
            self.painter.set_color(self.color)
            self.painter.lines(x0, y0, x1, y1, width=self.linewidth)
        else:
            manhattan = np.abs(x0-x1) + np.abs(y0-y1)
            vmax = manhattan.max()
            distances = np.logspace(0, log10(manhattan.max()), 20)
            for i in range(len(distances)-1, 1, -1):
                mask = (manhattan > distances[i-1]) & (manhattan <= distances[i])
                self.painter.set_color(self.cmap.to_color(distances[i], vmax, 'log'))
                self.painter.lines(x0[mask], y0[mask], x1[mask], y1[mask], width=self.linewidth)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()


    def bbox(self):
        return BoundingBox.from_points(lons=np.hstack([self.data[self.src_lon], self.data[self.dest_lon]]),
                                       lats=np.hstack([self.data[self.src_lat], self.data[self.dest_lat]]))
Esempio n. 11
0
    class PointsLayer(BaseLayer):
        def __init__(self, data, color, point_size):
            self.data = data
            self.color = color
            self.point_size = point_size

        def invalidate(self, proj):
            x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
            self.painter = BatchPainter()
            self.painter.set_color(self.color)
            self.painter.points(x, y, point_size=self.point_size, rounded=True)

        def draw(self, proj, mouse_x, mouse_y, ui_manager):
            self.painter.batch_draw()
Esempio n. 12
0
class DotDensityLayer(BaseLayer):

    def __init__(self, data, color=None, point_size=2, f_tooltip=None):
        """Create a dot density map
        :param data: data access object
        :param color: color
        :param point_size: point size
        :param f_tooltip: function to return a tooltip string for a point
        """
        self.frame_counter = 0
        self.data = data
        self.color = color
        if self.color is None:
            self.color = [255,0,0]
        self.point_size = point_size
        self.f_tooltip = f_tooltip

        self.hotspots = HotspotManager()


    def invalidate(self, proj):
        self.x, self.y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])



    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        if self.f_tooltip:
            for i in range(0, len(x)):
                record = {k: self.data[k][i] for k in self.data.keys()}
                self.hotspots.add_rect(x[i] - self.point_size, y[i] - self.point_size,
                                       2*self.point_size, 2*self.point_size,
                                       self.f_tooltip(record))
        self.color= "blue" #random.choice(foo)
        self.painter.set_color(self.color)
        self.painter.points(x[self.frame_counter], y[self.frame_counter], 2*self.point_size, False)
        
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)
        self.frame_counter += 1
        time.sleep(0.4)
        if self.frame_counter == len(x):
            self.frame_counter = 0


    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])
Esempio n. 13
0
class MarkersLayer(BaseLayer):

    def __init__(self, data, marker, f_tooltip=None, marker_preferred_size=32):
        """
        Draw markers

        :param data: data access object
        :param marker: full filename of the marker image
        :param f_tooltip: function to generate a tooltip on mouseover
        :param marker_preferred_size: size in pixel for the marker images
        """
        self.data = data
        self.f_tooltip = f_tooltip
        self.marker_preferred_size = float(marker_preferred_size)
        self.marker = pyglet.image.load(marker)
        self.marker.anchor_x = self.marker.width / 2
        self.marker.anchor_y = self.marker.height / 2
        self.scale = self.marker_preferred_size / max(self.marker.width, self.marker.height)

        self.hotspots = HotspotManager()


    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])

        if self.f_tooltip:
            for i in range(0, len(x)):
                record = {k: self.data[k][i] for k in self.data.keys()}
                self.hotspots.add_rect(x[i] - self.marker_preferred_size/2,
                                       y[i] - self.marker_preferred_size/2,
                                       self.marker_preferred_size,
                                       self.marker_preferred_size,
                                       self.f_tooltip(record))

        self.painter.sprites(self.marker, x, y, self.scale)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()

        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)


    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])
Esempio n. 14
0
class MarkersLayer(BaseLayer):

    def __init__(self, data, marker, f_tooltip=None, marker_preferred_size=32):
        """
        Draw markers

        :param data: data access object
        :param marker: full filename of the marker image
        :param f_tooltip: function to generate a tooltip on mouseover
        :param marker_preferred_size: size in pixel for the marker images
        """
        self.data = data
        self.f_tooltip = f_tooltip
        self.marker_preferred_size = float(marker_preferred_size)
        self.marker = pyglet.image.load(marker)
        self.marker.anchor_x = self.marker.width / 2
        self.marker.anchor_y = self.marker.height / 2
        self.scale = self.marker_preferred_size / max(self.marker.width, self.marker.height)

        self.hotspots = HotspotManager()


    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])

        if self.f_tooltip:
            for i in range(0, len(x)):
                record = {k: self.data[k][i] for k in self.data.keys()}
                self.hotspots.add_rect(x[i] - self.marker_preferred_size/2,
                                       y[i] - self.marker_preferred_size/2,
                                       self.marker_preferred_size,
                                       self.marker_preferred_size,
                                       self.f_tooltip(record))

        self.painter.sprites(self.marker, x, y, self.scale)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()

        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)


    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])
Esempio n. 15
0
class LabelsLayer(BaseLayer):
    def __init__(self,
                 data,
                 label_column,
                 color=None,
                 font_name=FONT_NAME,
                 font_size=14,
                 anchor_x='left',
                 anchor_y='top'):
        """Create a layer with a text label for each sample

        :param data: data access object
        :param label_column: column in the data access object where the labels text is stored
        :param color: color
        :param font_name: font name
        :param font_size: font size
        :param anchor_x: anchor x
        :param anchor_y: anchor y
        """
        self.data = data
        self.label_column = label_column
        self.color = color
        self.font_name = font_name
        self.font_size = font_size
        self.anchor_x = anchor_x
        self.anchor_y = anchor_y
        if self.color is None:
            self.color = [255, 0, 0]

    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        self.painter.set_color(self.color)
        self.painter.labels(x,
                            y,
                            self.data[self.label_column],
                            font_name=self.font_name,
                            font_size=self.font_size,
                            anchor_x=self.anchor_x,
                            anchor_y=self.anchor_y)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()

    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'],
                                       lats=self.data['lat'])
Esempio n. 16
0
class QuadsLayer(BaseLayer):

    def __init__(self, data, cmap='hot_r'):
        self.data = data
        if cmap is not None:
            self.cmap = geoplotlib.colors.ColorMap(cmap, alpha=196)
        else:
            self.cmap = None
            

    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        
        w = x.max() - x.min()
        h = y.max() - y.min()
        w = np.ceil(w / 2) * 2
        h = np.ceil(h / 2) * 2
        l = max(w, h)
        
        root = QuadTree(x.min(), x.min() + l, y.min() + l, y.min())
        maxarea = (root.right - root.left) * (root.top - root.bottom)
        queue = [root]
        done = []
        while len(queue) > 0:
            qt = queue.pop()
            if qt.can_split(x, y):
                queue.extend(qt.split())
            else:
                done.append(qt)
        
        print len(queue), len(done)

        if self.cmap is not None:
            for qt in done:
                area = (qt.right - qt.left) * (qt.top - qt.bottom)
                self.painter.set_color(self.cmap.to_color(1 + area, 1 + maxarea, 'log'))
                self.painter.rect(qt.left, qt.top, qt.right, qt.bottom)
        else:
            for qt in done:
                self.painter.linestrip([qt.left, qt.right, qt.right, qt.left],
                                       [qt.top, qt.top, qt.bottom, qt.bottom], closed=True)
    
            
    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
Esempio n. 17
0
class QuadsLayer(BaseLayer):
    def __init__(self, data, cmap='hot_r'):
        self.data = data
        if cmap is not None:
            self.cmap = geoplotlib.colors.ColorMap(cmap, alpha=196)
        else:
            self.cmap = None

    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])

        w = x.max() - x.min()
        h = y.max() - y.min()
        w = np.ceil(w / 2) * 2
        h = np.ceil(h / 2) * 2
        l = max(w, h)

        root = QuadTree(x.min(), x.min() + l, y.min() + l, y.min())
        maxarea = (root.right - root.left) * (root.top - root.bottom)
        queue = [root]
        done = []
        while len(queue) > 0:
            qt = queue.pop()
            if qt.can_split(x, y):
                queue.extend(qt.split())
            else:
                done.append(qt)

        print((len(queue), len(done)))

        if self.cmap is not None:
            for qt in done:
                area = (qt.right - qt.left) * (qt.top - qt.bottom)
                self.painter.set_color(
                    self.cmap.to_color(1 + area, 1 + maxarea, 'log'))
                self.painter.rect(qt.left, qt.top, qt.right, qt.bottom)
        else:
            for qt in done:
                self.painter.linestrip([qt.left, qt.right, qt.right, qt.left],
                                       [qt.top, qt.top, qt.bottom, qt.bottom],
                                       closed=True)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
Esempio n. 18
0
class AnimatedLayer(BaseLayer):
    """
    geoplotlib 动画类图层
    """
    def __init__(self, data):
        self.data = data
        self.frame_counter = 0

    def invalidate(self, proj):
        self.x, self.y = proj.lonlat_to_screen(self.data['lon'],
                                               self.data['lat'])

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter = BatchPainter()
        self.painter.points(self.x[self.frame_counter],
                            self.y[self.frame_counter])
        self.painter.batch_draw()
        self.frame_counter += 1
Esempio n. 19
0
class DotDensityLayer(BaseLayer):


    def __init__(self, data, color=None, point_size=2, f_tooltip=None):
        """Create a dot density map

        :param data: data access object
        :param color: color
        :param point_size: point size
        :param f_tooltip: function to return a tooltip string for a point
        """
        self.data = data
        self.color = color
        if self.color is None:
            self.color = [255,0,0]
        self.point_size = point_size
        self.f_tooltip = f_tooltip

        self.hotspots = HotspotManager()


    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        if self.f_tooltip:
            for i in range(0, len(x)):
                record = {k: self.data[k][i] for k in self.data.keys()}
                self.hotspots.add_rect(x[i] - self.point_size, y[i] - self.point_size,
                                       2*self.point_size, 2*self.point_size,
                                       self.f_tooltip(record))
        self.painter.set_color(self.color)
        self.painter.points(x, y, 2*self.point_size, False)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)


    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])
Esempio n. 20
0
class LabelsLayer(BaseLayer):


    def __init__(self, data, label_column, color=None, font_name=FONT_NAME, font_size=14, anchor_x='left', anchor_y='top'):
        """Create a layer with a text label for each sample

        :param data: data access object
        :param label_column: column in the data access object where the labels text is stored
        :param color: color
        :param font_name: font name
        :param font_size: font size
        :param anchor_x: anchor x
        :param anchor_y: anchor y
        """
        self.data = data
        self.label_column = label_column
        self.color = color
        self.font_name = font_name
        self.font_size = font_size
        self.anchor_x = anchor_x
        self.anchor_y = anchor_y
        if self.color is None:
            self.color = [255,0,0]


    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        self.painter.set_color(self.color)
        self.painter.labels(x, y, self.data[self.label_column], 
                                    font_name=self.font_name,
                                    font_size=self.font_size,
                                    anchor_x=self.anchor_x, 
                                    anchor_y=self.anchor_y)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        

    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])
Esempio n. 21
0
class GridLayer(BaseLayer):
    def __init__(self,
                 lon_edges,
                 lat_edges,
                 values,
                 cmap,
                 alpha=255,
                 vmin=None,
                 vmax=None):
        self.lon_edges = lon_edges
        self.lat_edges = lat_edges
        self.values = values
        self.cmap = colors.ColorMap(cmap, alpha=alpha)

        if vmin:
            self.vmin = vmin
        else:
            self.vmin = 0

        if vmax:
            self.vmax = vmax
        else:
            self.vmax = self.values.max()

    def invalidate(self, proj):
        self.painter = BatchPainter()
        xv, yv = proj.lonlat_to_screen(self.lon_edges, self.lat_edges)

        rects = []
        cols = []
        for ix in range(len(xv) - 1):
            for iy in range(len(yv) - 1):
                d = self.values[iy, ix]
                if d > self.vmin:
                    rects.append((xv[ix], yv[iy], xv[ix + 1], yv[iy + 1]))
                    cols.append(self.cmap.to_color(d, self.vmax, 'lin'))

        self.painter.batch_rects(rects, cols)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
Esempio n. 22
0
class TrailsLayer(BaseLayer):

    def __init__(self):
        self.data = read_csv('data/taxi.csv')
        self.data = self.data.where(self.data['taxi_id'] == list(set(self.data['taxi_id']))[2])
        self.t = self.data['timestamp'].min()
        self.painter = BatchPainter()


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter = BatchPainter()
        self.painter.set_color([0,0,255])
        df = self.data.where((self.data['timestamp'] > self.t) & (self.data['timestamp'] <= self.t + 30*60))
        proj.fit(BoundingBox.from_points(lons=df['lon'], lats=df['lat']), max_zoom=14)
        x, y = proj.lonlat_to_screen(df['lon'], df['lat'])
        self.painter.linestrip(x, y, 10)
        self.t += 30
        if self.t > self.data['timestamp'].max():
            self.t = self.data['timestamp'].min()

        self.painter.batch_draw()
        ui_manager.info(epoch_to_str(self.t))
Esempio n. 23
0
class GridLayer(BaseLayer):

    def __init__(self, lon_edges, lat_edges, values, cmap, alpha=255, vmin=None, vmax=None):
        self.lon_edges = lon_edges
        self.lat_edges = lat_edges
        self.values = values
        self.cmap = colors.ColorMap(cmap, alpha=alpha)

        if vmin:
            self.vmin = vmin
        else:
            self.vmin = 0

        if vmax:
            self.vmax = vmax
        else:
            self.vmax = self.values.max()


    def invalidate(self, proj):
        self.painter = BatchPainter()
        xv, yv = proj.lonlat_to_screen(self.lon_edges, self.lat_edges)

        rects = []
        cols = []
        for ix in range(len(xv)-1):
            for iy in range(len(yv)-1):
                d = self.values[iy, ix]
                if d > self.vmin:
                    rects.append((xv[ix], yv[iy], xv[ix+1], yv[iy+1]))
                    cols.append(self.cmap.to_color(d, self.vmax, 'lin'))

        self.painter.batch_rects(rects, cols)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
Esempio n. 24
0
class VoronoiLayer(BaseLayer):
    def __init__(self,
                 data,
                 line_color=None,
                 line_width=2,
                 f_tooltip=None,
                 cmap=None,
                 max_area=1e4,
                 alpha=220):
        """
        Draw the voronoi tesselation of the points from data

        :param data: data access object
        :param line_color: line color
        :param line_width: line width
        :param f_tooltip: function to generate a tooltip on mouseover
        :param cmap: color map
        :param max_area: scaling constant to determine the color of the voronoi areas
        :param alpha: color alpha
        :return:
        """
        self.data = data

        if cmap is None and line_color is None:
            raise Exception('need either cmap or line_color')

        if cmap is not None:
            cmap = colors.ColorMap(cmap, alpha=alpha, levels=10)

        self.cmap = cmap
        self.line_color = line_color
        self.line_width = line_width
        self.f_tooltip = f_tooltip
        self.max_area = max_area

    # source: https://gist.github.com/pv/8036995
    @staticmethod
    def __voronoi_finite_polygons_2d(vor, radius=None):
        """
        Reconstruct infinite voronoi regions in a 2D diagram to finite
        regions.

        Parameters
        ----------
        vor : Voronoi
            Input diagram
        radius : float, optional
            Distance to 'points at infinity'.

        Returns
        -------
        regions : list of tuples
            Indices of vertices in each revised Voronoi regions.
        vertices : list of tuples
            Coordinates for revised Voronoi vertices. Same as coordinates
            of input vertices, with 'points at infinity' appended to the
            end.

        """

        if vor.points.shape[1] != 2:
            raise ValueError("Requires 2D input")

        new_regions = []
        new_vertices = vor.vertices.tolist()

        center = vor.points.mean(axis=0)
        if radius is None:
            radius = vor.points.ptp().max()

        # Construct a map containing all ridges for a given point
        all_ridges = {}
        for (p1, p2), (v1, v2) in zip(vor.ridge_points, vor.ridge_vertices):
            all_ridges.setdefault(p1, []).append((p2, v1, v2))
            all_ridges.setdefault(p2, []).append((p1, v1, v2))

        # Reconstruct infinite regions
        for p1, region in enumerate(vor.point_region):
            vertices = vor.regions[region]

            if all(v >= 0 for v in vertices):
                # finite region
                new_regions.append(vertices)
                continue

            # reconstruct a non-finite region
            if p1 not in all_ridges:
                continue

            ridges = all_ridges[p1]
            new_region = [v for v in vertices if v >= 0]

            for p2, v1, v2 in ridges:
                if v2 < 0:
                    v1, v2 = v2, v1
                if v1 >= 0:
                    # finite ridge: already in the region
                    continue

                # Compute the missing endpoint of an infinite ridge

                t = vor.points[p2] - vor.points[p1]  # tangent
                t /= np.linalg.norm(t)
                n = np.array([-t[1], t[0]])  # normal

                midpoint = vor.points[[p1, p2]].mean(axis=0)
                direction = np.sign(np.dot(midpoint - center, n)) * n
                far_point = vor.vertices[v2] + direction * radius

                new_region.append(len(new_vertices))
                new_vertices.append(far_point.tolist())

            # sort region counterclockwise
            vs = np.asarray([new_vertices[v] for v in new_region])
            c = vs.mean(axis=0)
            angles = np.arctan2(vs[:, 1] - c[1], vs[:, 0] - c[0])
            new_region = np.array(new_region)[np.argsort(angles)]

            # finish
            new_regions.append(new_region.tolist())

        return new_regions, np.asarray(new_vertices)

    # Area of a polygon: http://www.mathopenref.com/coordpolygonarea.html
    @staticmethod
    def _get_area(p):
        return 0.5 * abs(
            sum(x0 * y1 - x1 * y0
                for ((x0, y0), (x1, y1)) in zip(p, p[1:] + [p[0]])))

    def invalidate(self, proj):
        try:
            from scipy.spatial.qhull import Voronoi
        except ImportError:
            print('VoronoiLayer needs scipy >= 0.12')
            raise

        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        points = list(zip(x, y))
        vor = Voronoi(points)

        regions, vertices = VoronoiLayer.__voronoi_finite_polygons_2d(vor)

        self.hotspots = HotspotManager()
        self.painter = BatchPainter()

        for idx, region in enumerate(regions):
            polygon = vertices[region]

            if self.line_color:
                self.painter.set_color(self.line_color)
                self.painter.linestrip(polygon[:, 0],
                                       polygon[:, 1],
                                       width=self.line_width,
                                       closed=True)
            if self.cmap:
                area = VoronoiLayer._get_area(polygon.tolist())
                area = max(area, 1)
                self.painter.set_color(
                    self.cmap.to_color(area, self.max_area, 'log'))
                self.painter.poly(polygon[:, 0], polygon[:, 1])

            if self.f_tooltip:
                record = {k: self.data[k][idx] for k in list(self.data.keys())}
                self.hotspots.add_poly(polygon[:, 0], polygon[:, 1],
                                       self.f_tooltip(record))

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)

    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'],
                                       lats=self.data['lat'])
Esempio n. 25
0
class DelaunayLayer(BaseLayer):
    def __init__(self,
                 data,
                 line_color=None,
                 line_width=2,
                 cmap=None,
                 max_lenght=100):
        """
        Draw a delaunay triangulation of the points

        :param data: data access object
        :param line_color: line color
        :param line_width: line width
        :param cmap: color map
        :param max_lenght: scaling constant for coloring the edges
        """
        self.data = data

        if cmap is None and line_color is None:
            raise Exception('need either cmap or line_color')

        if cmap is not None:
            cmap = colors.ColorMap(cmap, alpha=196)

        self.cmap = cmap
        self.line_color = line_color
        self.line_width = line_width
        self.max_lenght = max_lenght

    @staticmethod
    def _get_area(p):
        x1, y1, x2, y2, x3, y3 = p
        return 0.5 * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2))

    def invalidate(self, proj):
        try:
            from scipy.spatial.qhull import Delaunay
        except ImportError:
            print('DelaunayLayer needs scipy >= 0.12')
            raise

        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        points = list(set(zip(x, y)))
        dela = Delaunay(points)

        edges = set()
        for tria in dela.vertices:
            edges.add((tria[0], tria[1]))
            edges.add((tria[1], tria[2]))
            edges.add((tria[2], tria[0]))

        allx0 = []
        ally0 = []
        allx1 = []
        ally1 = []
        colors = []

        for a, b in edges:
            x0, y0 = dela.points[a]
            x1, y1 = dela.points[b]

            allx0.append(x0)
            ally0.append(y0)
            allx1.append(x1)
            ally1.append(y1)

            if self.line_color:
                colors.append(self.line_color)
                colors.append(self.line_color)
            elif self.cmap:
                l = math.sqrt((x0 - x1)**2 + (y0 - y1)**2)
                c = self.cmap.to_color(l, self.max_lenght, 'log')
                colors.append(c)
                colors.append(c)

        self.painter.lines(allx0,
                           ally0,
                           allx1,
                           ally1,
                           colors,
                           width=self.line_width)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()

    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'],
                                       lats=self.data['lat'])
Esempio n. 26
0
class ShapefileLayer(BaseLayer):
    def __init__(self,
                 fname,
                 f_tooltip=None,
                 color=None,
                 linewidth=3,
                 shape_type='full'):
        """
        Loads and draws shapefiles

        :param fname: full path to the shapefile
        :param f_tooltip: function to generate a tooltip on mouseover
        :param color: color
        :param linewidth: line width
        :param shape_type: either full or bbox
        """
        if color is None:
            color = [255, 0, 0]
        self.color = color
        self.linewidth = linewidth
        self.f_tooltip = f_tooltip
        self.shape_type = shape_type

        try:
            import shapefile
        except:
            raise Exception('ShapefileLayer requires pyshp')

        self.reader = shapefile.Reader(fname)
        self.worker = None
        self.queue = queue.Queue()

    def invalidate(self, proj):
        self.painter = BatchPainter()
        self.hotspots = HotspotManager()
        self.painter.set_color(self.color)

        if self.worker:
            self.worker.stop()
            self.worker.join()
        self.queue = queue.Queue()
        self.worker = ShapeLoadingThread(self.queue, self.reader,
                                         self.shape_type, proj)
        self.worker.start()

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)

        while True:
            try:
                x, y, record = self.queue.get_nowait()
                self.painter.linestrip(x, y, self.linewidth, closed=True)
                if self.f_tooltip:
                    attr = {
                        t[0][0]: t[1]
                        for t in zip(self.reader.fields[1:], record)
                    }
                    value = self.f_tooltip(attr)
                    if self.shape_type == 'bbox':
                        self.hotspots.add_rect(x.min(), y.min(),
                                               x.max() - x.min(),
                                               y.max() - y.min(), value)
                    else:
                        self.hotspots.add_poly(x, y, value)
            except queue.Empty:
                break
Esempio n. 27
0
class GraphLayer(BaseLayer):
    def __init__(self,
                 data,
                 src_lat,
                 src_lon,
                 dest_lat,
                 dest_lon,
                 linewidth=1,
                 alpha=220,
                 color='hot'):
        """Create a graph drawing a line between each pair of (src_lat, src_lon) and (dest_lat, dest_lon)

        :param data: data access object
        :param src_lat: field name of source latitude
        :param src_lon: field name of source longitude
        :param dest_lat: field name of destination latitude
        :param dest_lon: field name of destination longitude
        :param linewidth: line width
        :param alpha: color alpha
        :param color: color or colormap
        """
        self.data = data
        self.src_lon = src_lon
        self.src_lat = src_lat
        self.dest_lon = dest_lon
        self.dest_lat = dest_lat

        self.linewidth = linewidth
        alpha = alpha
        self.color = color
        if type(self.color) == str:
            self.cmap = colors.ColorMap(self.color, alpha)

    def invalidate(self, proj):
        self.painter = BatchPainter()
        x0, y0 = proj.lonlat_to_screen(self.data[self.src_lon],
                                       self.data[self.src_lat])
        x1, y1 = proj.lonlat_to_screen(self.data[self.dest_lon],
                                       self.data[self.dest_lat])

        if type(self.color) == list:
            self.painter.set_color(self.color)
            self.painter.lines(x0, y0, x1, y1, width=self.linewidth)
        else:
            manhattan = np.abs(x0 - x1) + np.abs(y0 - y1)
            vmax = manhattan.max()
            distances = np.logspace(0, log10(manhattan.max()), 20)
            for i in range(len(distances) - 1, 1, -1):
                mask = (manhattan > distances[i - 1]) & (manhattan <=
                                                         distances[i])
                self.painter.set_color(
                    self.cmap.to_color(distances[i], vmax, 'log'))
                self.painter.lines(x0[mask],
                                   y0[mask],
                                   x1[mask],
                                   y1[mask],
                                   width=self.linewidth)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()

    def bbox(self):
        return BoundingBox.from_points(
            lons=np.hstack([self.data[self.src_lon],
                            self.data[self.dest_lon]]),
            lats=np.hstack([self.data[self.src_lat],
                            self.data[self.dest_lat]]))
Esempio n. 28
0
class GeoJSONLayer(BaseLayer):

    def __init__(self, geojson_or_fname, color='b', linewidth=1, fill=False, f_tooltip=None):
        self.color = color
        self.linewidth = linewidth
        self.fill = fill
        self.f_tooltip = f_tooltip

        if type(geojson_or_fname) == str:
            with open(geojson_or_fname) as fin:
                self.data = json.load(fin)
        elif type(geojson_or_fname) == dict:
            self.data = geojson_or_fname
        else:
            raise Exception('must provide either dict or filename')

        self.boundingbox = None
        
        for feature in self.data['features']:
            if feature['geometry']['type'] == 'Polygon':
                for poly in feature['geometry']['coordinates']: 
                    poly = np.array(poly)
                    self.__update_bbox(poly[:,0], poly[:,1])
            elif feature['geometry']['type'] == 'MultiPolygon':
                for multipoly in feature['geometry']['coordinates']:
                    for poly in multipoly: 
                        poly = np.array(poly)
                        self.__update_bbox(poly[:,0], poly[:,1])
            elif feature['geometry']['type'] == 'Point':
                lon,lat = feature['geometry']['coordinates']
                self.__update_bbox(np.array([lon]), np.array([lat]))
            elif feature['geometry']['type'] == 'LineString':
                line = np.array(feature['geometry']['coordinates'])
                self.__update_bbox(line[:,0], line[:,1])


    def __update_bbox(self, lon, lat):
        if self.boundingbox is None:
            self.boundingbox = BoundingBox(north=lat.max(), south=lat.min(), west=lon.min(), east=lon.max())
        else:
            self.boundingbox = BoundingBox(
                                    north=max(self.boundingbox.north, lat.max()),
                                    south=min(self.boundingbox.south, lat.min()),
                                    west=min(self.boundingbox.west, lon.min()),
                                    east=max(self.boundingbox.east, lon.max()))


    def invalidate(self, proj):
        self.painter = BatchPainter()
        self.hotspots = HotspotManager()

        for feature in self.data['features']:
            if isfunction(self.color):
                self.painter.set_color(self.color(feature['properties']))
            else:
                self.painter.set_color(self.color)

            if feature['geometry']['type'] == 'Polygon':
                for poly in feature['geometry']['coordinates']: 
                    poly = np.array(poly)
                    x, y = proj.lonlat_to_screen(poly[:,0], poly[:,1])
                    if self.fill:
                        self.painter.poly(x, y)
                    else:
                        self.painter.linestrip(x, y, self.linewidth, closed=True)

                    if self.f_tooltip:
                        self.hotspots.add_poly(x, y, self.f_tooltip(feature['properties']))

            elif feature['geometry']['type'] == 'MultiPolygon':
                for multipoly in feature['geometry']['coordinates']:
                    for poly in multipoly: 
                        poly = np.array(poly)
                        x, y = proj.lonlat_to_screen(poly[:,0], poly[:,1])
                        if self.fill:
                            self.painter.poly(x, y)
                        else:
                            self.painter.linestrip(x, y, self.linewidth, closed=True)

                        if self.f_tooltip:
                            self.hotspots.add_poly(x, y, self.f_tooltip(feature['properties']))
            
            elif feature['geometry']['type'] == 'Point':
                lon,lat = feature['geometry']['coordinates']
                x, y = proj.lonlat_to_screen(np.array([lon]), np.array([lat]))
                self.painter.points(x, y)
            elif feature['geometry']['type'] == 'LineString':
                line = np.array(feature['geometry']['coordinates'])
                x, y = proj.lonlat_to_screen(line[:,0], line[:,1])
                self.painter.linestrip(x, y, self.linewidth, closed=False)
            else:
                print('unknow geometry %s' % feature['geometry']['type'])


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)


    def bbox(self):
        if self.boundingbox:
            return self.boundingbox
        else:
            return BoundingBox.WORLD
Esempio n. 29
0
class GridLayer(BaseLayer):
    def __init__(self,
                 lon_edges,
                 lat_edges,
                 values,
                 cmap,
                 alpha=255,
                 vmin=None,
                 vmax=None,
                 levels=10,
                 colormap_scale='lin',
                 show_colorbar=True):
        """
        Values over a uniform grid
        
        :param lon_edges: longitude edges
        :param lat_edges: latitude edges
        :param values: matrix representing values on the grid 
        :param cmap: colormap name
        :param alpha: color alpha
        :param vmin: minimum value for the colormap
        :param vmax: maximum value for the colormap
        :param levels: number of levels for the colormap
        :param colormap_scale: colormap scale
        :param show_colorbar: show the colorbar in the UI
        """
        self.lon_edges = lon_edges
        self.lat_edges = lat_edges
        self.values = values
        self.cmap = colors.ColorMap(cmap, alpha=alpha, levels=levels)
        self.colormap_scale = colormap_scale
        self.show_colorbar = show_colorbar

        if vmin:
            self.vmin = vmin
        else:
            self.vmin = 0

        if vmax:
            self.vmax = vmax
        else:
            self.vmax = self.values[~np.isnan(self.values)].max()

    def invalidate(self, proj):
        self.painter = BatchPainter()
        xv, yv = proj.lonlat_to_screen(self.lon_edges, self.lat_edges)

        rects = []
        cols = []
        for ix in range(len(xv) - 1):
            for iy in range(len(yv) - 1):
                d = self.values[iy, ix]
                if d > self.vmin:
                    rects.append((xv[ix], yv[iy], xv[ix + 1], yv[iy + 1]))
                    cols.append(
                        self.cmap.to_color(d, self.vmax, self.colormap_scale))

        self.painter.batch_rects(rects, cols)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        if self.show_colorbar:
            ui_manager.add_colorbar(self.cmap, self.vmax, self.colormap_scale)

    def bbox(self):
        return BoundingBox(north=self.lat_edges[-1],
                           south=self.lat_edges[0],
                           west=self.lon_edges[0],
                           east=self.lon_edges[-1])
Esempio n. 30
0
class LineLayer(layers.BaseLayer):
    """
    Draws line connecting points in hurricane path
    """
    def __init__(self, data, num, color=None, point_size=2, linewidth=1, f_tooltip=None):
        """
        Creates a LineLayer for the python geoplotlib library
        :param data: DataAccessObject of latitudes and longitudes
        :param num: number of data points in dat
        :param color: color of lines, just to red if none
        :param point_size: size of points
        :param linewidth: width of lines
        :param f_tooltip: an attribute of geoplotlib's BaseLayer that is not used
        """
        self.data = data
        self.indexlst = num
        self.color = color
        if self.color is None:
            self.color = [255, 0, 0]
        self.point_size = point_size
        self.f_tooltip = f_tooltip
        self.linewidth = linewidth
        self.hotspots = HotspotManager()

    def invalidate(self, proj):
        """
        This method is called each time layers need to be redrawn, i.e. on zoom.
        Typically in this method a BatchPainter is instantiated and all the rendering is performed

        :param proj: the current Projector object
        """
        self.painter = BatchPainter()
        self.painter.set_color(self.color)

        x1, y1 = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        self.painter.points(x1, y1, 2 * self.point_size, False)
        for i in self.indexlst:
            if i < len(self.data['lon']) - 1:
                x1 = self.data['lon'][i]
                y1 = self.data['lat'][i]
                x2 = self.data['lon'][i+1]
                y2 = self.data['lat'][i+1]
                x1, y1 = proj.lonlat_to_screen(x1, y1)
                x2, y2 = proj.lonlat_to_screen(x2, y2)
                self.painter.lines(x1, y1, x2, y2, width=self.linewidth)

        if self.f_tooltip:
            for i in range(0, len(x1)):
                record = {k: self.data[k][i] for k in self.data.keys()}
                self.hotspots.add_rect(x1[i] - self.point_size, y1[i] - self.point_size,
                                       2 * self.point_size, 2 * self.point_size,
                                       self.f_tooltip(record))


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        """
        This method is called at every frame, and typically executes BatchPainter.batch_draw()
        :param proj: the current Projector object
        :param mouse_x: mouse x
        :param mouse_y: mouse y
        :param ui_manager: the current UiManager
        """
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)

    def bbox(self):
        """
        Return the bounding box for this layer
        """
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])

    def on_key_release(self, key, modifiers):
        """
        Override this method for custom handling of keystrokes
        :param key: the key that has been released
        :param modifiers: the key modifiers
        :return: True if the layer needs to call invalidate
        """
        return False
Esempio n. 31
0
class DelaunayLayer(BaseLayer):

    def __init__(self, data, line_color=None, line_width=2, cmap=None, max_lenght=100):
        """
        Draw a delaunay triangulation of the points

        :param data: data access object
        :param line_color: line color
        :param line_width: line width
        :param cmap: color map
        :param max_lenght: scaling constant for coloring the edges
        """
        self.data = data

        if cmap is None and line_color is None:
            raise Exception('need either cmap or line_color')

        if cmap is not None:
            cmap = colors.ColorMap(cmap, alpha=196)

        self.cmap = cmap
        self.line_color = line_color
        self.line_width = line_width
        self.max_lenght = max_lenght


    @staticmethod
    def _get_area(p):
        x1, y1, x2, y2, x3, y3 = p
        return 0.5*(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2))



    def invalidate(self, proj):
        try:
            from scipy.spatial.qhull import Delaunay
        except ImportError:
            print('DelaunayLayer needs scipy >= 0.12')
            raise

        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        points = list(set(zip(x,y)))
        dela = Delaunay(points)

        edges = set()
        for tria in dela.vertices:
            edges.add((tria[0], tria[1]))
            edges.add((tria[1], tria[2]))
            edges.add((tria[2], tria[0]))

        allx0 = []
        ally0 = []
        allx1 = []
        ally1 = []
        colors = []

        for a, b in edges:
            x0, y0 = dela.points[a]
            x1, y1 = dela.points[b]

            allx0.append(x0)
            ally0.append(y0)
            allx1.append(x1)
            ally1.append(y1)

            if self.line_color:
                colors.append(self.line_color)
                colors.append(self.line_color)
            elif self.cmap:
                l = math.sqrt((x0 - x1)**2+(y0 - y1)**2)
                c = self.cmap.to_color(l, self.max_lenght, 'log')
                colors.append(c)
                colors.append(c)

        self.painter.lines(allx0, ally0, allx1, ally1, colors, width=self.line_width)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()


    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])
Esempio n. 32
0
class GraphLayer(BaseLayer):
    def __init__(self,
                 data,
                 src_lat,
                 src_lon,
                 dest_lat,
                 dest_lon,
                 linewidth=1,
                 alpha=220,
                 color='hot',
                 levels=10,
                 color_by=None,
                 seg_scale='log'):
        """Create a graph drawing a line between each pair of (src_lat, src_lon) and (dest_lat, dest_lon)

        :param data: data access object
        :param src_lat: field name of source latitude
        :param src_lon: field name of source longitude
        :param dest_lat: field name of destination latitude
        :param dest_lon: field name of destination longitude
        :param linewidth: line width
        :param alpha: color alpha
        :param color: color or colormap
        :param levels: coloring levels
        :param color_by: attribute name for color, default using node distance
        :param seg_scale: coloring data segamentation sacle, 'log' or 'lin',
            'lin' only used if not by distance
        """
        self.data = data
        self.src_lon = src_lon
        self.src_lat = src_lat
        self.dest_lon = dest_lon
        self.dest_lat = dest_lat

        self.linewidth = linewidth
        alpha = alpha
        self.color = color
        if type(self.color) == str:
            self.cmap = colors.ColorMap(self.color, alpha, levels=levels)

        if color_by is None:
            self.color_by = 'distance'
        self.seg_scale = seg_scale

    def invalidate(self, proj):
        self.painter = BatchPainter()
        x0, y0 = proj.lonlat_to_screen(self.data[self.src_lon],
                                       self.data[self.src_lat])
        x1, y1 = proj.lonlat_to_screen(self.data[self.dest_lon],
                                       self.data[self.dest_lat])

        if type(self.color) == list:
            self.painter.set_color(self.color)
            self.painter.lines(x0, y0, x1, y1, width=self.linewidth)
        else:
            if self.color_by == 'distance':
                manhattan = np.abs(x0 - x1) + np.abs(y0 - y1)
                vmax = manhattan.max()
                segmentations = np.logspace(0, log10(vmax), 20)
                self.seg_scale = 'log'
            else:
                manhattan = self.data[self.color_by]
                vmax = manhattan.max()
                if self.seg_scale == 'log':
                    # value 20 maybe should be optional
                    segmentations = np.logspace(0, log10(vmax), 20)
                else:
                    # linear
                    segmentations = np.linspace(0, vmax, 20)

            for i in range(len(segmentations) - 1, 1, -1):
                mask = (manhattan > segmentations[i - 1]) & (manhattan <=
                                                             segmentations[i])
                self.painter.set_color(
                    self.cmap.to_color(segmentations[i], vmax, self.seg_scale))
                self.painter.lines(x0[mask],
                                   y0[mask],
                                   x1[mask],
                                   y1[mask],
                                   width=self.linewidth)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()

    def bbox(self):
        return BoundingBox.from_points(
            lons=np.hstack([self.data[self.src_lon],
                            self.data[self.dest_lon]]),
            lats=np.hstack([self.data[self.src_lat],
                            self.data[self.dest_lat]]))
Esempio n. 33
0
class GridLayer(BaseLayer):

    def __init__(self, lon_edges, lat_edges, values, cmap, alpha=255, vmin=None, vmax=None, levels=10, 
            colormap_scale='lin', show_colorbar=True):
        """
        Values over a uniform grid
        
        :param lon_edges: longitude edges
        :param lat_edges: latitude edges
        :param values: matrix representing values on the grid 
        :param cmap: colormap name
        :param alpha: color alpha
        :param vmin: minimum value for the colormap
        :param vmax: maximum value for the colormap
        :param levels: number of levels for the colormap
        :param colormap_scale: colormap scale
        :param show_colorbar: show the colorbar in the UI
        """
        self.lon_edges = lon_edges
        self.lat_edges = lat_edges
        self.values = values
        self.cmap = colors.ColorMap(cmap, alpha=alpha, levels=levels)
        self.colormap_scale = colormap_scale
        self.show_colorbar = show_colorbar

        if vmin:
            self.vmin = vmin
        else:
            self.vmin = 0

        if vmax:
            self.vmax = vmax
        else:
            self.vmax = self.values[~np.isnan(self.values)].max()


    def invalidate(self, proj):
        self.painter = BatchPainter()
        xv, yv = proj.lonlat_to_screen(self.lon_edges, self.lat_edges)

        rects = []
        cols = []
        for ix in range(len(xv)-1):
            for iy in range(len(yv)-1):
                d = self.values[iy, ix]
                if d > self.vmin:
                    rects.append((xv[ix], yv[iy], xv[ix+1], yv[iy+1]))
                    cols.append(self.cmap.to_color(d, self.vmax, self.colormap_scale))

        self.painter.batch_rects(rects, cols)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        if self.show_colorbar:
            ui_manager.add_colorbar(self.cmap, self.vmax, self.colormap_scale)


    def bbox(self):
        return BoundingBox(north=self.lat_edges[-1], south=self.lat_edges[0], 
                           west=self.lon_edges[0], east=self.lon_edges[-1])
Esempio n. 34
0
class VoronoiLayer(BaseLayer):

    def __init__(self, data, line_color=None, line_width=2, f_tooltip=None, cmap=None, max_area=1e4, alpha=220):
        """
        Draw the voronoi tesselation of the points from data

        :param data: data access object
        :param line_color: line color
        :param line_width: line width
        :param f_tooltip: function to generate a tooltip on mouseover
        :param cmap: color map
        :param max_area: scaling constant to determine the color of the voronoi areas
        :param alpha: color alpha
        :return:
        """
        self.data = data

        if cmap is None and line_color is None:
            raise Exception('need either cmap or line_color')

        if cmap is not None:
            cmap = colors.ColorMap(cmap, alpha=alpha, levels=10)

        self.cmap = cmap
        self.line_color = line_color
        self.line_width = line_width
        self.f_tooltip = f_tooltip
        self.max_area = max_area


    # source: https://gist.github.com/pv/8036995
    @staticmethod
    def __voronoi_finite_polygons_2d(vor, radius=None):
        """
        Reconstruct infinite voronoi regions in a 2D diagram to finite
        regions.

        Parameters
        ----------
        vor : Voronoi
            Input diagram
        radius : float, optional
            Distance to 'points at infinity'.

        Returns
        -------
        regions : list of tuples
            Indices of vertices in each revised Voronoi regions.
        vertices : list of tuples
            Coordinates for revised Voronoi vertices. Same as coordinates
            of input vertices, with 'points at infinity' appended to the
            end.

        """

        if vor.points.shape[1] != 2:
            raise ValueError("Requires 2D input")

        new_regions = []
        new_vertices = vor.vertices.tolist()

        center = vor.points.mean(axis=0)
        if radius is None:
            radius = vor.points.ptp().max()

        # Construct a map containing all ridges for a given point
        all_ridges = {}
        for (p1, p2), (v1, v2) in zip(vor.ridge_points, vor.ridge_vertices):
            all_ridges.setdefault(p1, []).append((p2, v1, v2))
            all_ridges.setdefault(p2, []).append((p1, v1, v2))

        # Reconstruct infinite regions
        for p1, region in enumerate(vor.point_region):
            vertices = vor.regions[region]

            if all(v >= 0 for v in vertices):
                # finite region
                new_regions.append(vertices)
                continue

            # reconstruct a non-finite region
            if p1 not in all_ridges:
                continue

            ridges = all_ridges[p1]
            new_region = [v for v in vertices if v >= 0]

            for p2, v1, v2 in ridges:
                if v2 < 0:
                    v1, v2 = v2, v1
                if v1 >= 0:
                    # finite ridge: already in the region
                    continue

                # Compute the missing endpoint of an infinite ridge

                t = vor.points[p2] - vor.points[p1] # tangent
                t /= np.linalg.norm(t)
                n = np.array([-t[1], t[0]])  # normal

                midpoint = vor.points[[p1, p2]].mean(axis=0)
                direction = np.sign(np.dot(midpoint - center, n)) * n
                far_point = vor.vertices[v2] + direction * radius

                new_region.append(len(new_vertices))
                new_vertices.append(far_point.tolist())

            # sort region counterclockwise
            vs = np.asarray([new_vertices[v] for v in new_region])
            c = vs.mean(axis=0)
            angles = np.arctan2(vs[:,1] - c[1], vs[:,0] - c[0])
            new_region = np.array(new_region)[np.argsort(angles)]

            # finish
            new_regions.append(new_region.tolist())

        return new_regions, np.asarray(new_vertices)


    # Area of a polygon: http://www.mathopenref.com/coordpolygonarea.html
    @staticmethod
    def _get_area(p):
        return 0.5 * abs(sum(x0*y1 - x1*y0
                             for ((x0, y0), (x1, y1)) in zip(p, p[1:] + [p[0]])))


    def invalidate(self, proj):
        try:
            from scipy.spatial.qhull import Voronoi
        except ImportError:
            print('VoronoiLayer needs scipy >= 0.12')
            raise

        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        points = list(set(zip(x,y)))
        vor = Voronoi(points)

        regions, vertices = VoronoiLayer.__voronoi_finite_polygons_2d(vor)

        self.hotspots = HotspotManager()
        self.painter = BatchPainter()


        for idx, region in enumerate(regions):
            polygon = vertices[region]

            if self.line_color:
                self.painter.set_color(self.line_color)
                self.painter.linestrip(polygon[:,0], polygon[:,1], width=self.line_width, closed=True)
            if self.cmap:
                area = VoronoiLayer._get_area(polygon.tolist())
                area = max(area, 1)
                self.painter.set_color(self.cmap.to_color(area, self.max_area, 'log'))
                self.painter.poly(polygon[:,0], polygon[:,1])

            if self.f_tooltip:
                record = {k: self.data[k][idx] for k in self.data.keys()}
                self.hotspots.add_poly(polygon[:,0], polygon[:,1], self.f_tooltip(record))


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)


    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])
Esempio n. 35
0
class KDELayer(BaseLayer):
    def __init__(self,
                 values,
                 bw,
                 cmap='hot',
                 method='hist',
                 scaling='sqrt',
                 alpha=220,
                 cut_below=None,
                 clip_above=None,
                 binsize=1,
                 cmap_levels=10,
                 show_colorbar=False):
        """
        Kernel density estimation visualization

        :param data: data access object
        :param bw: kernel bandwidth (in screen coordinates)
        :param cmap: colormap
        :param method: if kde use KDEMultivariate from statsmodel, which provides a more accurate but much slower estimation.
            If hist, estimates density applying gaussian smoothing on a 2D histogram, which is much faster but less accurate
        :param scaling: colorscale, lin log or sqrt
        :param alpha: color alpha
        :param cut_below: densities below cut_below are not drawn
        :param clip_above: defines the max value for the colorscale
        :param binsize: size of the bins for hist estimator
        :param cmap_levels: discretize colors into cmap_levels
        :param show_colorbar: show colorbar
        """
        self.values = values
        self.bw = bw
        self.cmap = colors.ColorMap(cmap, alpha=alpha, levels=cmap_levels)
        self.method = method
        self.scaling = scaling
        self.cut_below = cut_below
        self.clip_above = clip_above
        self.binsize = binsize
        self.show_colorbar = show_colorbar

    def _get_grid(self, proj):
        west, north = proj.lonlat_to_screen([proj.bbox().west],
                                            [proj.bbox().north])
        east, south = proj.lonlat_to_screen([proj.bbox().east],
                                            [proj.bbox().south])
        xgrid = np.arange(west, east, self.binsize)
        ygrid = np.arange(south, north, self.binsize)
        return xgrid, ygrid

    def invalidate(self, proj):
        self.painter = BatchPainter()
        xv, yv = proj.lonlat_to_screen(self.values['lon'], self.values['lat'])

        rects_vertices = []
        rects_colors = []

        if self.method == 'kde':
            try:
                import statsmodels.api as sm
            except:
                raise Exception('KDE requires statsmodel')

            kde_res = sm.nonparametric.KDEMultivariate(data=[xv, yv],
                                                       var_type='cc',
                                                       bw=self.bw)
            xgrid, ygrid = self._get_grid(proj)
            xmesh, ymesh = np.meshgrid(xgrid, ygrid)
            grid_coords = np.append(xmesh.reshape(-1, 1),
                                    ymesh.reshape(-1, 1),
                                    axis=1)
            z = kde_res.pdf(grid_coords.T)
            z = z.reshape(len(ygrid), len(xgrid))

            # np.save('z.npy', z)
            # z = np.load('z.npy')

            print(('smallest non-zero density:', z[z > 0][0]))
            print(('max density:', z.max()))

            if self.cut_below is None:
                zmin = z[z > 0][0]
            else:
                zmin = self.cut_below

            if self.clip_above is None:
                zmax = z.max()
            else:
                zmax = self.clip_above

            for ix in range(len(xgrid) - 1):
                for iy in range(len(ygrid) - 1):
                    if z[iy, ix] > zmin:
                        rects_vertices.append((xgrid[ix], ygrid[iy],
                                               xgrid[ix + 1], ygrid[iy + 1]))
                        rects_colors.append(
                            self.cmap.to_color(z[iy, ix], zmax, self.scaling))
        elif self.method == 'hist':
            try:
                from scipy.ndimage import gaussian_filter
            except:
                raise Exception('KDE requires scipy')

            xgrid, ygrid = self._get_grid(proj)
            H, _, _ = np.histogram2d(yv, xv, bins=(ygrid, xgrid))

            if H.sum() == 0:
                print('no data in current view')
                return

            H = gaussian_filter(H, sigma=self.bw)
            print(('smallest non-zero count', H[H > 0][0]))
            print(('max count:', H.max()))

            if self.cut_below is None:
                Hmin = H[H > 0][0]
            else:
                Hmin = self.cut_below

            if self.clip_above is None:
                self.Hmax = H.max()
            else:
                self.Hmax = self.clip_above

            if self.scaling == 'ranking':
                from statsmodels.distributions.empirical_distribution import ECDF
                ecdf = ECDF(H.flatten())

            for ix in range(len(xgrid) - 2):
                for iy in range(len(ygrid) - 2):
                    if H[iy, ix] > Hmin:
                        rects_vertices.append((xgrid[ix], ygrid[iy],
                                               xgrid[ix + 1], ygrid[iy + 1]))
                        if self.scaling == 'ranking':
                            rects_colors.append(
                                self.cmap.to_color(
                                    ecdf(H[iy, ix]) - ecdf(Hmin),
                                    1 - ecdf(Hmin), 'lin'))
                        else:
                            rects_colors.append(
                                self.cmap.to_color(H[iy, ix], self.Hmax,
                                                   self.scaling))
        else:
            raise Exception('method not supported')

        self.painter.batch_rects(rects_vertices, rects_colors)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        if self.show_colorbar:
            ui_manager.add_colorbar(self.cmap, self.Hmax, self.scaling)
Esempio n. 36
0
class ShapefileLayer(BaseLayer):

    def __init__(self, fname, f_tooltip=None, color=None, linewidth=3, shape_type='full'):
        """
        Loads and draws shapefiles

        :param fname: full path to the shapefile
        :param f_tooltip: function to generate a tooltip on mouseover
        :param color: color
        :param linewidth: line width
        :param shape_type: either full or bbox
        """
        if color is None:
            color = [255, 0, 0]
        self.color = color
        self.linewidth = linewidth
        self.f_tooltip = f_tooltip
        self.shape_type = shape_type

        try:
            import shapefile
        except:
            raise Exception('ShapefileLayer requires pyshp')

        self.reader = shapefile.Reader(fname)
        self.worker = None
        self.queue = Queue.Queue()


    def invalidate(self, proj):
        self.painter = BatchPainter()
        self.hotspots = HotspotManager()
        self.painter.set_color(self.color)

        if self.worker:
            self.worker.stop()
            self.worker.join()
        self.queue = Queue.Queue()
        self.worker = ShapeLoadingThread(self.queue, self.reader, self.shape_type, proj)
        self.worker.start()


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)

        while True:
            try:
                x, y, record = self.queue.get_nowait()
                self.painter.linestrip(x, y, self.linewidth, closed=True)
                if self.f_tooltip:
                    attr = {t[0][0]: t[1] for t in zip(self.reader.fields[1:], record)}
                    value = self.f_tooltip(attr)
                    if self.shape_type == 'bbox':
                        self.hotspots.add_rect(x.min(), y.min(), x.max()-x.min(), y.max()-y.min(), value)
                    else:
                        self.hotspots.add_poly(x, y, value)
            except Queue.Empty:
                break
Esempio n. 37
0
class HistogramLayer(BaseLayer):

    def __init__(self, data, cmap='hot', alpha=220, colorscale='sqrt',
                 binsize=16, show_tooltip=False, scalemin=0, scalemax=None, f_group=None):
        """Create a 2D histogram

        :param data: data access object
        :param cmap: colormap name
        :param alpha: color alpha
        :param colorscale: scaling [lin, log, sqrt]
        :param binsize: size of the hist bins
        :param show_tooltip: if True, will show the value of bins on mouseover
        :param scalemin: min value for displaying a bin
        :param scalemax: max value for a bin
        :param f_group: function to apply to samples in the same bin. Default is to count
        :return:
        """
        self.data = data
        self.cmap = colors.ColorMap(cmap, alpha=alpha)
        self.binsize = binsize
        self.show_tooltip = show_tooltip
        self.scalemin = scalemin
        self.scalemax = scalemax
        self.colorscale = colorscale
        self.f_group = f_group
        if self.f_group is None:
            self.f_group = lambda grp: len(grp)


    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        self.data['_xbin'] = (x / self.binsize).astype(int)
        self.data['_ybin'] = (y / self.binsize).astype(int)
        uniquevalues = set([tuple(row) for row in np.vstack([self.data['_xbin'],self.data['_ybin']]).T])
        results = {(v1,v2): self.f_group(self.data.where((self.data['_xbin'] == v1) & (self.data['_ybin'] == v2))) \
                   for v1, v2 in uniquevalues}
        del self.data['_xbin']
        del self.data['_ybin']

        self.hotspot = HotspotManager()

        if self.scalemax:
            vmax = self.scalemax
        else:
            vmax = max(results.values()) if len(results) > 0 else 0

        if vmax >= 1:
            for (ix, iy), value in results.items():
                if value > self.scalemin:
                    self.painter.set_color(self.cmap.to_color(value, vmax, self.colorscale))
                    l = self.binsize
                    rx = ix * self.binsize
                    ry = iy * self.binsize

                    self.painter.rect(rx, ry, rx+l, ry+l)
                    if self.show_tooltip:
                        self.hotspot.add_rect(rx, ry, l, l, 'Value: %d' % value)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspot.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)

    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'], lats=self.data['lat'])
Esempio n. 38
0
class GeoJSONLayer(BaseLayer):
    def __init__(self,
                 geojson_or_fname,
                 color='b',
                 linewidth=1,
                 fill=False,
                 f_tooltip=None):
        self.color = color
        self.linewidth = linewidth
        self.fill = fill
        self.f_tooltip = f_tooltip

        if type(geojson_or_fname) == str:
            with open(geojson_or_fname) as fin:
                self.data = json.load(fin)
        elif type(geojson_or_fname) == dict:
            self.data = geojson_or_fname
        else:
            raise Exception('must provide either dict or filename')

        self.boundingbox = None

        for feature in self.data['features']:
            if feature['geometry']['type'] == 'Polygon':
                for poly in feature['geometry']['coordinates']:
                    poly = np.array(poly)
                    self.__update_bbox(poly[:, 0], poly[:, 1])
            elif feature['geometry']['type'] == 'MultiPolygon':
                for multipoly in feature['geometry']['coordinates']:
                    for poly in multipoly:
                        poly = np.array(poly)
                        self.__update_bbox(poly[:, 0], poly[:, 1])
            elif feature['geometry']['type'] == 'Point':
                lon, lat = feature['geometry']['coordinates']
                self.__update_bbox(np.array([lon]), np.array([lat]))
            elif feature['geometry']['type'] == 'LineString':
                line = np.array(feature['geometry']['coordinates'])
                self.__update_bbox(line[:, 0], line[:, 1])

    def __update_bbox(self, lon, lat):
        if self.boundingbox is None:
            self.boundingbox = BoundingBox(north=lat.max(),
                                           south=lat.min(),
                                           west=lon.min(),
                                           east=lon.max())
        else:
            self.boundingbox = BoundingBox(north=max(self.boundingbox.north,
                                                     lat.max()),
                                           south=min(self.boundingbox.south,
                                                     lat.min()),
                                           west=min(self.boundingbox.west,
                                                    lon.min()),
                                           east=max(self.boundingbox.east,
                                                    lon.max()))

    def invalidate(self, proj):
        self.painter = BatchPainter()
        self.hotspots = HotspotManager()

        for feature in self.data['features']:
            if isfunction(self.color):
                self.painter.set_color(self.color(feature['properties']))
            else:
                self.painter.set_color(self.color)

            if feature['geometry']['type'] == 'Polygon':
                for poly in feature['geometry']['coordinates']:
                    poly = np.array(poly)
                    x, y = proj.lonlat_to_screen(poly[:, 0], poly[:, 1])
                    if self.fill:
                        self.painter.poly(x, y)
                    else:
                        self.painter.linestrip(x,
                                               y,
                                               self.linewidth,
                                               closed=True)

                    if self.f_tooltip:
                        self.hotspots.add_poly(
                            x, y, self.f_tooltip(feature['properties']))

            elif feature['geometry']['type'] == 'MultiPolygon':
                for multipoly in feature['geometry']['coordinates']:
                    for poly in multipoly:
                        poly = np.array(poly)
                        x, y = proj.lonlat_to_screen(poly[:, 0], poly[:, 1])
                        if self.fill:
                            self.painter.poly(x, y)
                        else:
                            self.painter.linestrip(x,
                                                   y,
                                                   self.linewidth,
                                                   closed=True)

                        if self.f_tooltip:
                            self.hotspots.add_poly(
                                x, y, self.f_tooltip(feature['properties']))

            elif feature['geometry']['type'] == 'Point':
                lon, lat = feature['geometry']['coordinates']
                x, y = proj.lonlat_to_screen(np.array([lon]), np.array([lat]))
                self.painter.points(x, y)
            elif feature['geometry']['type'] == 'LineString':
                line = np.array(feature['geometry']['coordinates'])
                x, y = proj.lonlat_to_screen(line[:, 0], line[:, 1])
                self.painter.linestrip(x, y, self.linewidth, closed=False)
            else:
                print(('unknow geometry %s' % feature['geometry']['type']))

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspots.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)

    def bbox(self):
        if self.boundingbox:
            return self.boundingbox
        else:
            return BoundingBox.WORLD
Esempio n. 39
0
class HistogramLayer(BaseLayer):
    def __init__(self,
                 data,
                 cmap='hot',
                 alpha=220,
                 colorscale='sqrt',
                 binsize=16,
                 show_tooltip=False,
                 scalemin=0,
                 scalemax=None,
                 f_group=None,
                 show_colorbar=True):
        """Create a 2D histogram

        :param data: data access object
        :param cmap: colormap name
        :param alpha: color alpha
        :param colorscale: scaling [lin, log, sqrt]
        :param binsize: size of the hist bins
        :param show_tooltip: if True, will show the value of bins on mouseover
        :param scalemin: min value for displaying a bin
        :param scalemax: max value for a bin
        :param f_group: function to apply to samples in the same bin. Default is to count
        :param show_colorbar: show colorbar
        :return:
        """
        self.data = data
        self.cmap = colors.ColorMap(cmap, alpha=alpha)
        self.binsize = binsize
        self.show_tooltip = show_tooltip
        self.scalemin = scalemin
        self.scalemax = scalemax
        self.colorscale = colorscale
        self.f_group = f_group
        if self.f_group is None:
            self.f_group = lambda grp: len(grp)
        self.show_colorbar = show_colorbar

    def invalidate(self, proj):
        self.painter = BatchPainter()
        x, y = proj.lonlat_to_screen(self.data['lon'], self.data['lat'])
        self.data['_xbin'] = (x / self.binsize).astype(int)
        self.data['_ybin'] = (y / self.binsize).astype(int)
        uniquevalues = set([
            tuple(row)
            for row in np.vstack([self.data['_xbin'], self.data['_ybin']]).T
        ])
        results = {(v1,v2): self.f_group(self.data.where((self.data['_xbin'] == v1) & (self.data['_ybin'] == v2))) \
                   for v1, v2 in uniquevalues}
        del self.data['_xbin']
        del self.data['_ybin']

        self.hotspot = HotspotManager()

        if self.scalemax:
            self.vmax = self.scalemax
        else:
            self.vmax = max(results.values()) if len(results) > 0 else 0

        if self.vmax >= 1:
            for (ix, iy), value in list(results.items()):
                if value > self.scalemin:
                    self.painter.set_color(
                        self.cmap.to_color(value, self.vmax, self.colorscale))
                    l = self.binsize
                    rx = ix * self.binsize
                    ry = iy * self.binsize

                    self.painter.rect(rx, ry, rx + l, ry + l)
                    if self.show_tooltip:
                        self.hotspot.add_rect(rx, ry, l, l,
                                              'Value: %d' % value)

    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()
        picked = self.hotspot.pick(mouse_x, mouse_y)
        if picked:
            ui_manager.tooltip(picked)
        if self.show_colorbar:
            ui_manager.add_colorbar(self.cmap, self.vmax, self.colorscale)

    def bbox(self):
        return BoundingBox.from_points(lons=self.data['lon'],
                                       lats=self.data['lat'])
Esempio n. 40
0
class AnimatedProcess(BaseLayer):

    def __init__(self, network, edgelists, show_addresses=False, save_frames=False, line_width=1.3):

        # Set network and edge lists.
        self.network = network
        self.edgelists = edgelists
        self.num_frames = len(self.edgelists)
        
        # Set flag specifying whether to show addresses.
        self.show_addresses = show_addresses

        # Set flag specifying whether to save frames.
        self.save_frames = save_frames

        # Set line width.
        self.line_width = line_width
        
        # Initialize state counter.
        self.count = 0
        
        # Initialize geolocator for retrieving addresses.
        geolocator = Nominatim(user_agent='test')

        # Set coordinates of nodes and get addresses.
        self.node_coordinates = np.empty((2, network.number_of_nodes()), dtype=float)
        self.node_addresses = []
        for idx, node in enumerate(network.nodes()):
            self.node_coordinates[:, idx] = np.array(self.network.nodes[node]['latlon'])
            if self.show_addresses:
                address = geolocator.reverse(self.node_coordinates[:, idx]).address
                self.node_addresses.append(address[:address.index(',', address.index(',') + 1)])


    def invalidate(self, proj):
        self.x, self.y = proj.lonlat_to_screen(self.node_coordinates[1, :], self.node_coordinates[0, :])
        

    def draw(self, proj, mouse_x, mouse_y, ui_manager):

        # Prepare edges for next frame.
        self.edge_src = np.empty((2, len(self.edgelists[self.count])), dtype=float)
        self.edge_dst = np.empty((2, len(self.edgelists[self.count])), dtype=float)
        for idx, edge in enumerate(self.edgelists[self.count]):
            self.edge_src[:, idx] = self.network.nodes[edge[0]]['latlon']
            self.edge_dst[:, idx] = self.network.nodes[edge[1]]['latlon']
        self.edge_src_trans_x, self.edge_src_trans_y = proj.lonlat_to_screen(self.edge_src[1, :], self.edge_src[0, :])
        self.edge_dst_trans_x, self.edge_dst_trans_y = proj.lonlat_to_screen(self.edge_dst[1, :], self.edge_dst[0, :])
        
        # Initialize painter, plot nodes and addresses.
        self.painter = BatchPainter()
        self.painter.points(self.x, self.y, point_size=10, rounded=True)
        if self.show_addresses:
            self.painter.labels(self.x, self.y, self.node_addresses, font_size=10, anchor_x='left')

        # Plot edges.
        self.painter.set_color([255, 0, 0])
        self.painter.lines(self.edge_src_trans_x, self.edge_src_trans_y, self.edge_dst_trans_x, self.edge_dst_trans_y, width=self.line_width)
        
        # Draw and increment counter.
        self.painter.batch_draw()
        if self.count < len(self.edgelists) - 1:
            self.count += 1
            self.count = self.count % self.num_frames
            print("count: {0}/{1}".format(self.count, self.num_frames))
        
        # If saving frames.
        if self.save_frames:
            GeoplotlibApp.screenshot(f'./results/animation_frames/{self.count}.png')
Esempio n. 41
0
class KDELayer(BaseLayer):

    def __init__(self, values, bw, cmap='hot', method='hist', scaling='sqrt', alpha=220,
                 cut_below=None, clip_above=None, binsize=1, cmap_levels=10):
        """
        Kernel density estimation visualization

        :param data: data access object
        :param bw: kernel bandwidth (in screen coordinates)
        :param cmap: colormap
        :param method: if kde use KDEMultivariate from statsmodel, which provides a more accurate but much slower estimation.
            If hist, estimates density applying gaussian smoothing on a 2D histogram, which is much faster but less accurate
        :param scaling: colorscale, lin log or sqrt
        :param alpha: color alpha
        :param cut_below: densities below cut_below are not drawn
        :param clip_above: defines the max value for the colorscale
        :param binsize: size of the bins for hist estimator
        :param cmap_levels: discretize colors into cmap_levels
        """
        self.values = values
        self.bw = bw
        self.cmap = colors.ColorMap(cmap, alpha=alpha, levels=cmap_levels)
        self.method = method
        self.scaling = scaling
        self.cut_below = cut_below
        self.clip_above = clip_above
        self.binsize = binsize


    def _get_grid(self, proj):
        west, north = proj.lonlat_to_screen([proj.bbox().west], [proj.bbox().north])
        east, south = proj.lonlat_to_screen([proj.bbox().east], [proj.bbox().south])
        xgrid = np.arange(west, east, self.binsize)
        ygrid = np.arange(south, north, self.binsize)
        return xgrid, ygrid


    def invalidate(self, proj):
        self.painter = BatchPainter()
        xv, yv = proj.lonlat_to_screen(self.values['lon'], self.values['lat'])

        rects_vertices = []
        rects_colors = []

        if self.method == 'kde':
            try:
                import statsmodels.api as sm
            except:
                raise Exception('KDE requires statsmodel')

            kde_res = sm.nonparametric.KDEMultivariate(data=[xv, yv], var_type='cc', bw=self.bw)
            xgrid, ygrid = self._get_grid(proj)
            xmesh, ymesh = np.meshgrid(xgrid,ygrid)
            grid_coords = np.append(xmesh.reshape(-1,1), ymesh.reshape(-1,1),axis=1)
            z = kde_res.pdf(grid_coords.T)
            z = z.reshape(len(ygrid), len(xgrid))

            # np.save('z.npy', z)
            # z = np.load('z.npy')

            print('smallest non-zero density:', z[z > 0][0])
            print('max density:', z.max())

            if self.cut_below is None:
                zmin = z[z > 0][0]
            else:
                zmin = self.cut_below

            if self.clip_above is None:
                zmax = z.max()
            else:
                zmax = self.clip_above

            for ix in range(len(xgrid)-1):
                for iy in range(len(ygrid)-1):
                    if z[iy, ix] > zmin:
                        rects_vertices.append((xgrid[ix], ygrid[iy], xgrid[ix+1], ygrid[iy+1]))
                        rects_colors.append(self.cmap.to_color(z[iy, ix], zmax, self.scaling))
        elif self.method == 'hist':
            try:
                from scipy.ndimage import gaussian_filter
            except:
                raise Exception('KDE requires scipy')

            xgrid, ygrid = self._get_grid(proj)
            H, _, _ = np.histogram2d(yv, xv, bins=(ygrid, xgrid))
            H = gaussian_filter(H, sigma=self.bw)
            print('smallest non-zero count', H[H > 0][0])
            print('max count:', H.max())

            if self.cut_below is None:
                Hmin = H[H > 0][0]
            else:
                Hmin = self.cut_below

            if self.clip_above is None:
                Hmax = H.max()
            else:
                Hmax = self.clip_above

            if self.scaling == 'ranking':
                from statsmodels.distributions.empirical_distribution import ECDF
                ecdf = ECDF(H.flatten())

            for ix in range(len(xgrid)-2):
                for iy in range(len(ygrid)-2):
                    if H[iy, ix] > Hmin:
                        rects_vertices.append((xgrid[ix], ygrid[iy], xgrid[ix+1], ygrid[iy+1]))
                        if self.scaling == 'ranking':
                            rects_colors.append(self.cmap.to_color(ecdf(H[iy, ix]) - ecdf(Hmin), 1 - ecdf(Hmin), 'lin'))
                        else:
                            rects_colors.append(self.cmap.to_color(H[iy, ix], Hmax, self.scaling))
        else:
            raise Exception('method not supported')

        self.painter.batch_rects(rects_vertices, rects_colors)


    def draw(self, proj, mouse_x, mouse_y, ui_manager):
        self.painter.batch_draw()