From 03c6f870ce566b274111b5732bb733f433555d1a Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Mon, 21 Jul 2014 16:26:19 +0200 Subject: [PATCH 1/2] Sofcode sqlite path for realtime --- realtime/shake_event.py | 293 ++++++++++++++++++++++++---------------- 1 file changed, 180 insertions(+), 113 deletions(-) diff --git a/realtime/shake_event.py b/realtime/shake_event.py index 04ec9adf92..5d5976c452 100644 --- a/realtime/shake_event.py +++ b/realtime/shake_event.py @@ -226,9 +226,10 @@ def grid_file_path(self): :raise: GridXmlFileNotFoundError """ LOGGER.debug('Event path requested.') - grid_xml_path = os.path.join(shakemap_extract_dir(), - self.event_id, - 'grid.xml') + grid_xml_path = os.path.join( + shakemap_extract_dir(), + self.event_id, + 'grid.xml') #short circuit if the tif is already created. if os.path.exists(grid_xml_path): return grid_xml_path @@ -300,9 +301,10 @@ def cities_to_shapefile(self, force_flag=False): """ filename = 'mmi-cities' memory_layer = self.local_cities_memory_layer() - return self.memory_layer_to_shapefile(file_name=filename, - memory_layer=memory_layer, - force_flag=force_flag) + return self.memory_layer_to_shapefile( + file_name=filename, + memory_layer=memory_layer, + force_flag=force_flag) def city_search_boxes_to_shapefile(self, force_flag=False): """Write a cities memory layer to a shapefile. @@ -323,9 +325,10 @@ def city_search_boxes_to_shapefile(self, force_flag=False): """ filename = 'city-search-boxes' memory_layer = self.city_search_box_memory_layer() - return self.memory_layer_to_shapefile(file_name=filename, - memory_layer=memory_layer, - force_flag=force_flag) + return self.memory_layer_to_shapefile( + file_name=filename, + memory_layer=memory_layer, + force_flag=force_flag) def memory_layer_to_shapefile(self, file_name, @@ -415,9 +418,10 @@ def memory_layer_to_shapefile(self, 'Failed with error: %s' % result) # Lastly copy over the standard qml (QGIS Style file) for the mmi.tif - qml_path = os.path.join(shakemap_extract_dir(), - self.event_id, - '%s.qml' % file_name) + qml_path = os.path.join( + shakemap_extract_dir(), + self.event_id, + '%s.qml' % file_name) source_qml = os.path.join(data_dir(), '%s.qml' % file_name) shutil.copyfile(source_qml, qml_path) @@ -481,7 +485,7 @@ def local_city_features(self): # Setup the cities table, querying on event bbox # Path to sqlitedb containing geonames table - db_path = os.path.join(data_dir(), 'indonesia.sqlite') + db_path = self._get_sqlite_path() uri = QgsDataSourceURI() uri.setDatabase(db_path) table = 'geonames' @@ -671,9 +675,10 @@ def city_search_box_memory_layer(self, force_flag=False): if self.search_boxes is None or force_flag: self.local_cities_memory_layer() # Now store the selection in a temporary memory layer - memory_layer = QgsVectorLayer('Polygon', - 'City Search Boxes', - 'memory') + memory_layer = QgsVectorLayer( + 'Polygon', + 'City Search Boxes', + 'memory') memory_provider = memory_layer.dataProvider() # add field defs field = QgsField('cities_found', QVariant.Int) @@ -690,16 +695,17 @@ def city_search_box_memory_layer(self, force_flag=False): result = memory_provider.addFeatures(features) if not result: - LOGGER.exception('Unable to add features to city search boxes' - 'memory layer') + LOGGER.exception( + 'Unable to add features to city search boxes memory layer') raise CityMemoryLayerCreationError( 'Could not add any features to city search boxes memory layer') memory_layer.commitChanges() memory_layer.updateExtents() - LOGGER.debug('Feature count of search box mem layer: %s' % - memory_layer.featureCount()) + LOGGER.debug( + 'Feature count of search box mem layer: %s' % + memory_layer.featureCount()) return memory_layer @@ -780,15 +786,16 @@ def sorted_impacted_cities(self, row_count=5): feature[fields.indexFromName('dir_from')]) distance_to = float( feature[fields.indexFromName('dist_to')]) - city = {'id': feature_id, - 'name': place_name, - 'mmi-int': int(mmi), - 'mmi': mmi, - 'population': population, - 'roman': roman, - 'dist_to': distance_to, - 'dir_to': direction_to, - 'dir_from': direction_from} + city = { + 'id': feature_id, + 'name': place_name, + 'mmi-int': int(mmi), + 'mmi': mmi, + 'population': population, + 'roman': roman, + 'dist_to': distance_to, + 'dir_to': direction_to, + 'dir_from': direction_from} cities.append(city) LOGGER.debug('%s features added to sorted impacted cities list.') #LOGGER.exception(cities) @@ -887,29 +894,33 @@ def impacted_cities_table(self, row_count=5): """ table_data = self.sorted_impacted_cities(row_count) table_body = [] - header = TableRow(['', - self.tr('Name'), - self.tr('Affected (x 1000)'), - self.tr('Intensity')], - header=True) + header = TableRow([ + '', + self.tr('Name'), + self.tr('Affected (x 1000)'), + self.tr('Intensity')], + header=True) for row_data in table_data: intensity = row_data['roman'] name = row_data['name'] population = int(round(row_data['population'] / 1000)) colour = mmi_colour(row_data['mmi']) - colour_box = ('
' % colour) - row = TableRow([colour_box, - name, - population, - intensity]) + colour_box = ( + '
' % colour) + row = TableRow([ + colour_box, + name, + population, + intensity]) table_body.append(row) - table = Table(table_body, header_row=header, - table_class='table table-striped table-condensed') + table = Table( + table_body, header_row=header, + table_class='table table-striped table-condensed') # Also make an html file on disk - path = self.write_html_table(file_name='affected-cities.html', - table=table) + path = self.write_html_table( + file_name='affected-cities.html', table=table) return table, path @@ -943,9 +954,10 @@ def impact_table(self): impact_row = [TableCell(self.tr('Perceived Shaking'), header=True)] for mmi in range(2, 10): header.append( - TableCell(romanise(mmi), - cell_class='mmi-%s' % mmi, - header=True)) + TableCell( + romanise(mmi), + cell_class='mmi-%s' % mmi, + header=True)) if mmi in self.affected_counts: # noinspection PyTypeChecker affected_row.append( @@ -959,17 +971,19 @@ def impact_table(self): table_body = list() table_body.append(affected_row) table_body.append(impact_row) - table = Table(table_body, header_row=header, - table_class='table table-striped table-condensed') + table = Table( + table_body, header_row=header, + table_class='table table-striped table-condensed') # noinspection PyTypeChecker path = self.write_html_table(file_name='impacts.html', table=table) return path - def calculate_impacts(self, - population_raster_path=None, - force_flag=False, - algorithm='nearest'): + def calculate_impacts( + self, + population_raster_path=None, + force_flag=False, + algorithm='nearest'): """Use the SAFE ITB earthquake function to calculate impacts. :param population_raster_path: optional. see @@ -1141,6 +1155,49 @@ def clip_layers(self, shake_raster_path, population_raster_path): return clipped_hazard, clipped_exposure + def _get_sqlite_path(self): + """Helper to determine sqlite file with geonames places in it. + + The following priority will be used to determine the path: + 1) the class attribute self.geonames_sqlite_path + will be checked and if not None and the file exists it will be + used. + 2) the environment variable 'GEONAMES_SQLITE_PATH' will be + checked and if the file exists if set it will be used. + 4) A hard coded path of + :file:`/fixtures/indonesia.sqlite` will be appended + to os.path.abspath(os.path.curdir) + 5) A hard coded path of + :file:`/usr/local/share/inasafe/indonesia.tif` + will be used. + + :returns: Path to a geonames sqlite file. + :rtype: str + + :raises: FileNotFoundError + """ + # When used via the scripts make_shakemap.sh + fixture_path = os.path.join( + data_dir(), 'indonesia.sqlite') + + local_path = '/usr/local/share/inasafe/indonesia.sqlite' + if self.geonames_sqlite_path is not None: + if os.path.exists(self.geonames_sqlite_path): + return self.geonames_sqlite_path + + if 'GEONAMES_SQLITE_PATH' in os.environ: + population_path = os.environ['GEONAMES_SQLITE_PATH'] + if os.path.exists(population_path): + return population_path + + if os.path.exists(fixture_path): + return fixture_path + + if os.path.exists(local_path): + return local_path + + raise FileNotFoundError('Geonames sqlite file could not be found') + def _get_population_path(self): """Helper to determine population raster's path. @@ -1199,16 +1256,19 @@ def render_map(self, force_flag=False): :raise Propagates any exceptions. """ - pdf_path = os.path.join(shakemap_extract_dir(), - self.event_id, - '%s-%s.pdf' % (self.event_id, self.locale)) - image_path = os.path.join(shakemap_extract_dir(), - self.event_id, - '%s-%s.png' % (self.event_id, self.locale)) - thumbnail_image_path = os.path.join(shakemap_extract_dir(), - self.event_id, - '%s-thumb-%s.png' % ( - self.event_id, self.locale)) + pdf_path = os.path.join( + shakemap_extract_dir(), + self.event_id, + '%s-%s.pdf' % (self.event_id, self.locale)) + image_path = os.path.join( + shakemap_extract_dir(), + self.event_id, + '%s-%s.png' % (self.event_id, self.locale)) + thumbnail_image_path = os.path.join( + shakemap_extract_dir(), + self.event_id, + '%s-thumb-%s.png' % ( + self.event_id, self.locale)) pickle_path = os.path.join( shakemap_extract_dir(), self.event_id, @@ -1320,8 +1380,9 @@ def render_map(self, force_flag=False): # [date] pass a map like this {'date': '1 Jan 2012'} location_info = self.event_info() LOGGER.debug(location_info) - substitution_map = {'location-info': location_info, - 'version': self.version()} + substitution_map = { + 'location-info': location_info, + 'version': self.version()} substitution_map.update(self.event_dict()) LOGGER.debug(substitution_map) @@ -1332,8 +1393,9 @@ def render_map(self, force_flag=False): result = composition.loadFromTemplate(document, substitution_map) if not result: - LOGGER.exception('Error loading template %s with keywords\n %s', - template_path, substitution_map) + LOGGER.exception( + 'Error loading template %s with keywords\n %s', + template_path, substitution_map) raise MapComposerError # Get the main map canvas on the composition and set @@ -1433,9 +1495,10 @@ def bearing_to_cardinal(self, bearing): .. note:: This method is heavily based on http://hoegners.de/Maxi/geo/ which is licensed under the GPL V3. """ - direction_list = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', - 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', - 'NW', 'NNW'] + direction_list = [ + 'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', + 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', + 'NW', 'NNW'] try: bearing = float(bearing) except ValueError: @@ -1458,13 +1521,14 @@ def event_info(self): :rtype: str """ event_dict = self.event_dict() - event_string = ('M %(mmi)s %(date)s %(time)s ' - '%(latitude-name)s: %(latitude-value)s ' - '%(longitude-name)s: %(longitude-value)s ' - '%(depth-name)s: %(depth-value)s%(depth-unit)s ' - '%(located-label)s %(distance)s%(distance-unit)s ' - '%(bearing-compass)s ' - '%(direction-relation)s %(place-name)s') % event_dict + event_string = ( + 'M %(mmi)s %(date)s %(time)s ' + '%(latitude-name)s: %(latitude-value)s ' + '%(longitude-name)s: %(longitude-value)s ' + '%(depth-name)s: %(depth-value)s%(depth-unit)s ' + '%(located-label)s %(distance)s%(distance-unit)s ' + '%(bearing-compass)s ' + '%(direction-relation)s %(place-name)s') % event_dict return event_string def event_dict(self): @@ -1614,10 +1678,11 @@ def elapsed_time(self): if hours == 0: lapse_string = '%i %s' % (minutes, self.tr('minute(s)')) else: - lapse_string = '%i %s %i %s' % (hours, - self.tr('hour(s)'), - minutes, - self.tr('minute(s)')) + lapse_string = '%i %s %i %s' % ( + hours, + self.tr('hour(s)'), + minutes, + self.tr('minute(s)')) else: # This at least one day after the quake @@ -1627,10 +1692,11 @@ def elapsed_time(self): if weeks == 0: lapse_string = '%i %s' % (days, self.tr('days')) else: - lapse_string = '%i %s %i %s' % (weeks, - self.tr('weeks'), - days, - self.tr('days')) + lapse_string = '%i %s %i %s' % ( + weeks, + self.tr('weeks'), + days, + self.tr('days')) # Convert date to GMT+7 # FIXME (Ole) Hack - Remove this as the shakemap data always @@ -1675,34 +1741,35 @@ def __str__(self): else: mmi_data = 'Not populated' - event_dict = {'latitude': self.shake_grid.latitude, - 'longitude': self.shake_grid.longitude, - 'event_id': self.event_id, - 'magnitude': self.shake_grid.magnitude, - 'depth': self.shake_grid.depth, - 'description': self.shake_grid.description, - 'location': self.shake_grid.location, - 'day': self.shake_grid.day, - 'month': self.shake_grid.month, - 'year': self.shake_grid.year, - 'time': self.shake_grid.time, - 'time_zone': self.shake_grid.time_zone, - 'x_minimum': self.shake_grid.x_minimum, - 'x_maximum': self.shake_grid.x_maximum, - 'y_minimum': self.shake_grid.y_minimum, - 'y_maximum': self.shake_grid.y_maximum, - 'rows': self.shake_grid.rows, - 'columns': self.shake_grid.columns, - 'mmi_data': mmi_data, - 'population_raster_path': self.population_raster_path, - 'impact_file': self.impact_file, - 'impact_keywords_file': self.impact_keywords_file, - 'fatality_counts': self.fatality_counts, - 'displaced_counts': self.displaced_counts, - 'affected_counts': self.affected_counts, - 'extent_with_cities': extent_with_cities, - 'zoom_factor': self.zoom_factor, - 'search_boxes': self.search_boxes} + event_dict = { + 'latitude': self.shake_grid.latitude, + 'longitude': self.shake_grid.longitude, + 'event_id': self.event_id, + 'magnitude': self.shake_grid.magnitude, + 'depth': self.shake_grid.depth, + 'description': self.shake_grid.description, + 'location': self.shake_grid.location, + 'day': self.shake_grid.day, + 'month': self.shake_grid.month, + 'year': self.shake_grid.year, + 'time': self.shake_grid.time, + 'time_zone': self.shake_grid.time_zone, + 'x_minimum': self.shake_grid.x_minimum, + 'x_maximum': self.shake_grid.x_maximum, + 'y_minimum': self.shake_grid.y_minimum, + 'y_maximum': self.shake_grid.y_maximum, + 'rows': self.shake_grid.rows, + 'columns': self.shake_grid.columns, + 'mmi_data': mmi_data, + 'population_raster_path': self.population_raster_path, + 'impact_file': self.impact_file, + 'impact_keywords_file': self.impact_keywords_file, + 'fatality_counts': self.fatality_counts, + 'displaced_counts': self.displaced_counts, + 'affected_counts': self.affected_counts, + 'extent_with_cities': extent_with_cities, + 'zoom_factor': self.zoom_factor, + 'search_boxes': self.search_boxes} event_string = ( 'latitude: %(latitude)s\n' From 8c8f88badc07e0e3c978cd561c994a5eea04d762 Mon Sep 17 00:00:00 2001 From: Akbar Gumbira Date: Tue, 22 Jul 2014 12:51:54 +0700 Subject: [PATCH 2/2] [Realtime] Fix failing tests. --- realtime/fixtures/tests/public/id/index.html | 5 ++--- realtime/shake_event.py | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/realtime/fixtures/tests/public/id/index.html b/realtime/fixtures/tests/public/id/index.html index 2913ba2ae1..b015134987 100644 --- a/realtime/fixtures/tests/public/id/index.html +++ b/realtime/fixtures/tests/public/id/index.html @@ -44,9 +44,8 @@

InaSAFE Realtime

-

Halaman ini memuat daftar peta getaran secara realtime (sebenarnya - hampir realtime) yang dihasilkan oelh kejadian getaran di wilayah - Indonesia berikut ini

+

Halaman ini memuat daftar shakemap secara realtime (hampir realtime) + yang dihasilkan oleh shake event di wilayah Indonesia


diff --git a/realtime/shake_event.py b/realtime/shake_event.py index 6429839b4a..6fad56c6a8 100644 --- a/realtime/shake_event.py +++ b/realtime/shake_event.py @@ -114,6 +114,7 @@ def __init__(self, event_id=None, locale='en', population_raster_path=None, + geonames_sqlite_path=None, force_flag=False, data_is_local_flag=False): """Constructor for the shake event class. @@ -137,6 +138,10 @@ def __init__(self, specified before calling :func:`calculate_impacts`. :type population_raster_path: str + :param geonames_sqlite_path: (Optional) Path to the geonames sqlite + that will be used. + :type geonames_sqlite_path: str + :param force_flag: Whether to force retrieval of the dataset from the ftp server. :type force_flag: bool @@ -171,6 +176,7 @@ def __init__(self, self.event_id, get_grid_source(), self.grid_file_path()) self.population_raster_path = population_raster_path + self.geonames_sqlite_path = geonames_sqlite_path # Path to tif of impact result - probably we wont even use it self.impact_file = None # Path to impact keywords file - this is GOLD here!