def json_data_record_for(request, period_str, entity_uuid, indicator_slug): entity = Entity.get_or_none(entity_uuid) if entity is None: raise Http404(_("Unknown entity UUID `{u}`").format(u=entity_uuid)) period = process_period_filter(request, period_str, 'period').get('period') if period is None: raise Http404(_("Unknown period `{p}`").format(p=period_str)) indicator = Indicator.get_or_none(indicator_slug) if indicator is None: raise Http404(_("Unknown indicator `{s}`").format(s=indicator_slug)) return JsonResponse(DataRecord.get_for(period, entity, indicator), safe=False)
def gen_map_for(entity, periods, indicator, save_as=None, with_title=True, with_legend=True, with_index=True, with_scale=True): children = sorted(entity.get_children(), key=lambda x: x.short_name) bbox = children_bounds(entity) # data = indicator.data_for(periods=periods, entity=entity) data = DataRecord.get_for(periods[-1] if periods else None, entity, indicator) # from pprint import pprint as pp ; pp(data.values()) scale = QuantileScale(values=[x['value'] for x in data.values()], colors=MAP_COLORS) def color_for(e): if data is None: return COLOR_INITIAL try: return scale.color_for_value(data[e.uuids]['value']) except KeyError: return COLOR_INITIAL # setup coordinate system xdist = bbox[2] - bbox[0] ydist = bbox[3] - bbox[1] iwidth = CANVAS_SIZE iheight = CANVAS_SIZE xratio = iwidth / xdist yratio = iheight / ydist def mmap(x, y): return int(iwidth - ((bbox[2] - x) * xratio)), \ int((bbox[3] - y) * yratio) # blank (transparent) sheet image = get_image(CANVAS_SIZE, CANVAS_SIZE) # draw each feature independently for index, child in enumerate(children): if not child.geojson.get('geometry'): continue pixels = [] if child.geojson['geometry']['type'] == 'MultiPolygon': coordinates = child.geojson['geometry']['coordinates'] else: coordinates = [child.geojson['geometry']['coordinates']] pixels = [mmap(x, y) for feature_coord in coordinates for x, y in feature_coord[0]] # draw polygon feature_draw = ImageDraw.Draw(image) feature_draw.polygon(pixels, outline=OUTLINE_COLOR, fill=color_for(child)) # draw thicker boundaries feature_draw.line(pixels, fill=OUTLINE_COLOR, width=OUTLINE_WIDTH) for pixel in pixels: feature_draw.ellipse( (pixel[0] - OUTLINE_WIDTH // 2, pixel[1] - OUTLINE_WIDTH // 2, pixel[0] + OUTLINE_WIDTH // 2, pixel[1] + OUTLINE_WIDTH // 2), fill=OUTLINE_COLOR) # draw a letter if with_index and child.gps: coords = mmap(*child.gps) negpad = CANVAS_SIZE // 80 // 2 index_font = get_font('Regular', CANVAS_SIZE // 80, mono=True) feature_draw.text( (coords[0] - negpad, coords[1] - negpad), letter_for(index), font=index_font, fill=INDEX_COLOR) if with_legend: legend = build_legend_for(scale) image.paste(legend, (CANVAS_SIZE - LEGEND_PADDING - legend.size[0], CANVAS_SIZE - LEGEND_PADDING - legend.size[1]), mask=legend) if with_title: title = build_title_for(indicator, periods, entity) export_width = image.size[0] + title.size[1] export_height = CANVAS_SIZE + title.size[1] export_image = get_image(export_width, export_height) export_image.paste(title, (0, 0), mask=title) export_image.paste(image, (title.size[1], title.size[1]), mask=image) # replace main image with new one (larger with title) image = export_image if with_index: index = build_index_for(indicator, periods, children) ileft_coords = (INDEX_PADDING, title.size[1] + INDEX_PADDING) iright_coords = (image.size[0] - index.size[0] - INDEX_PADDING, title.size[1] + INDEX_PADDING) index_coords = iright_coords if display_right(entity) else ileft_coords image.paste(index, index_coords, mask=index) if with_scale: visual_scale = build_scale_for(bbox) image.paste(visual_scale, (SCALE_PADDING, image.size[1] - SCALE_PADDING - visual_scale.size[1]), mask=visual_scale) # save end result to file or buffer if save_as: image.save(save_as, "PNG", mode="RGBA") else: return image