예제 #1
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
예제 #2
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]]))
예제 #3
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'])
예제 #4
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]]))
예제 #5
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
예제 #6
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]]))
예제 #7
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')
예제 #8
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'])