def generate_streamed_json_response(): cartogram_gen_output = b'' current_loading_point = "null" # We have to format our JSON manually, since we're not sending a complete object. # On the client side, Oboe.js is intelligent enough to parse this and get the loading information and cartogram output yield '{"loading_progress_points":[' for source, line in cartwrap.generate_cartogram( cartogram_handler.gen_area_data(values), cartogram_handler.get_gen_file(), settings.CARTOGRAM_EXE): if source == "stdout": cartogram_gen_output += line else: s = re.search(r'max\. abs\. area error: (.+)', line.decode()) if s != None: current_loading_point = s.groups(1)[0] # We always include the loading progress, even if it hasn't changed. # This makes life easier on the client side yield '{{"loading_point": {}, "stderr_line": "{}"}},'.format( current_loading_point, line.decode()) # We create a fake last entry because you can't have dangling commas in JSON yield '{"loading_point":0, "stderr_line": ""}],"cartogram_data":' if cartogram_handler.expect_geojson_output(): # Just confirm that we've been given valid JSON. Calculate the extrema if necessary cartogram_json = json.loads(cartogram_gen_output.decode()) if "bbox" not in cartogram_json: cartogram_json[ "bbox"] = geojson_extrema.get_extrema_from_geojson( cartogram_json) else: cartogram_json = gen2dict.translate( io.StringIO(cartogram_gen_output.decode()), settings.CARTOGRAM_COLOR, cartogram_handler.remove_holes()) cartogram_json['unique_sharing_key'] = unique_sharing_key cartogram_json = json.dumps(cartogram_json) if settings.USE_DATABASE: cartogram_entry = CartogramEntry.query.filter_by( string_key=unique_sharing_key).first() if cartogram_entry != None: cartogram_entry.cartogram_data = cartogram_json db.session.commit() yield cartogram_json yield "}"
def cartogram(): if 'handler' not in request.form: return Response('{"error":"badrequest"}', status=400, content_type="application/json") if request.form['handler'] not in cartogram_handlers: return Response('{"error":"badhandler"}', status=404, content_type="application/json") handler = request.form['handler'] cartogram_handler = cartogram_handlers[handler] if 'values' not in request.form: return Response('{"error":"badrequest"}', status=400, content_type="application/json") values = request.form['values'].split(";") # The existing verificaiton code expects all floats. To avoid modifying it, we replace the string "NA" with the # number 0.0 for verification purposes only. values_to_verify = [] try: for i in range(len(values)): if values[i] == "NA": values_to_verify.append(0.0) else: values[i] = float(values[i]) values_to_verify.append(values[i]) except ValueError: return Response('{"error":"badvalues"}', status=400, content_type="application/json") if cartogram_handler.validate_values(values_to_verify) != True: return Response('{"error":"badvalues"}', status=400, content_type="application/json") unique_sharing_key = "" if 'unique_sharing_key' in request.form: unique_sharing_key = request.form['unique_sharing_key'] lambda_result = awslambda.generate_cartogram( cartogram_handler.gen_area_data(values), cartogram_handler.get_gen_file(), settings.CARTOGRAM_LAMBDA_URL, settings.CARTOGRAM_LAMDA_API_KEY, unique_sharing_key) cartogram_gen_output = lambda_result['stdout'] if cartogram_handler.expect_geojson_output(): # Just confirm that we've been given valid JSON. Calculate the extrema if necessary cartogram_json = json.loads(cartogram_gen_output) if "bbox" not in cartogram_json: cartogram_json["bbox"] = geojson_extrema.get_extrema_from_geojson( cartogram_json) else: cartogram_json = gen2dict.translate(io.StringIO(cartogram_gen_output), settings.CARTOGRAM_COLOR, cartogram_handler.remove_holes()) cartogram_json['unique_sharing_key'] = unique_sharing_key if settings.USE_DATABASE: cartogram_entry = CartogramEntry.query.filter_by( string_key=unique_sharing_key).first() if cartogram_entry != None: cartogram_entry.cartogram_data = json.dumps(cartogram_json) db.session.commit() return Response(json.dumps({'cartogram_data': cartogram_json}), content_type='application/json', status=200)
cartogram_output = "" for source, line in cartwrap.generate_cartogram(area_data, handler.get_gen_file(), settings.CARTOGRAM_EXE): if source == "stderr": print("Generating {}: {}".format(sysname, line.decode())) else: cartogram_output += line.decode() if handler.expect_geojson_output(): cartogram_json = json.loads(cartogram_output) if "bbox" not in cartogram_json: cartogram_json["bbox"] = geojson_extrema.get_extrema_from_geojson( cartogram_json) else: cartogram_json = gen2dict.translate(io.StringIO(cartogram_output), settings.CARTOGRAM_COLOR, handler.remove_holes()) cartogram_json['tooltip'] = tooltip with open("static/cartdata/{}/population.json".format(sysname), 'w') as population_json_file: json.dump(cartogram_json, population_json_file)
def generate_cartogram_set(maps, cartogram_executable, default_color): maximum_progress = 95.0 current_progress = 0.0 main_average_density = 0.0 map_number = 1 for cart_map in maps: cartogram_gen = "" cartogram_json = {} cartogram_area = 0.0 cartogram_average_density = 0.0 initial_area_error = None one_region_cartogram = False yield "loading", { 'loading_point': current_progress, 'stderr_line': 'Computing Map {} of {}'.format(map_number, len(maps)) } for source, line in generate_cartogram(cart_map['area_data'], cart_map['gen_file'], cartogram_executable): if source == "stdout": map_gen += line else: s = re.search(r'max\. abs\. area error: (.+)', line.decode()) if s != None: if initial_area_error == None: initial_area_error = float(s.groups(1)[0]) current_progress = ( 0 if map_number == 1 else maximum_progress / map_number) + (maximum_progress / len(maps)) * 0.2 else: current_progress = ( 0 if map_number == 1 else maximum_progress / map_number) + ( ((initial_area_error - float(s.groups(1)[0])) / ((initial_area_error - 0.01))) * ((maximum_progress / len(maps)))) area_search = re.search(r'total cartogram area: (.+)', line.decode()) if area_search != None: cartogram_area = float(area_search.groups(1)[0]) one_region_search = re.search( r'WARNING: There is only one region. The output cartogram will', line.decode()) if one_region_search != None: one_region_cartogram = True yield "loading", { 'loading_point': current_progress, 'stderr_line': line.decode() } # Now we want to calculate the average density cartogram_average_density = sum([ float(entry.split(' ')[1]) for entry in cart_map['area_data'].split('\n') ]) / cartogram_area if map_number == 1: main_average_density = cartogram_average_density cartogram_json = gen2dict.translate( io.StringIO(cartogram_gen.decode()), default_color) # If we're not dealing with the main map (i.e., the first one) and we # only one region, then we need to do the scaling here. if map_number != 1 and one_region_cartogram: # In this case, cartogram_average_density is the same as the user- # supplied area for the one region in this map. scaling_factor = math.sqrt(cartogram_average_density / main_average_density) for feature in cartogram_json['features']: for pair in feature['coordinates']: pair[0] *= scaling_factor pair[1] *= scaling_factor yield "output", cartogram_json map_number += 1
import gen2dict import sys with open(sys.argv[1]) as map_gen_file: gen_json = gen2dict.translate(map_gen_file, "#aaaaaa", True) with open(sys.argv[2], "w") as svg_file: max_x = gen_json["extrema"]["max_x"] min_x = gen_json["extrema"]["min_x"] max_y = gen_json["extrema"]["max_y"] min_y = gen_json["extrema"]["min_y"] width = max_x - min_x height = max_y - min_y scale = 750.0 / width width *= scale height *= scale def x_transform(x): return (x - min_x) * scale def y_transform(y): return ((max_y - min_y) - (y - min_y)) * scale svg_file.write("""<svg version="1.1" baseProfile="full"