|
| 1 | +# This script is used to import boundary polygons and other information |
| 2 | +# from shapefiles representing areas of census geography |
| 3 | + |
| 4 | +# Run as: ./manage.py mapit_UK_import_soa_2011 shapefile.shp --type=lsoa |
| 5 | +# --commit |
| 6 | + |
| 7 | +from django.core.management.base import LabelCommand |
| 8 | +from django.contrib.gis.gdal import DataSource |
| 9 | +from mapit.models import Area, Generation, Country, Type, NameType, CodeType |
| 10 | +from django.conf import settings |
| 11 | +from enum import Enum |
| 12 | +from mapit.management.command_utils import save_polygons |
| 13 | + |
| 14 | + |
| 15 | +class GeographyType(Enum): |
| 16 | + """ |
| 17 | + allowed geographic imports |
| 18 | + """ |
| 19 | + lsoa = "lsoa" |
| 20 | + msoa = "msoa" |
| 21 | + soa = "soa" |
| 22 | + dz = "dz" |
| 23 | + lz = "lz" |
| 24 | + |
| 25 | + def __str__(self): |
| 26 | + return self.value |
| 27 | + |
| 28 | + |
| 29 | +class Command(LabelCommand): |
| 30 | + help = 'Creates Super Output Area boundaries from ONS/Scot Gov/OSNI shapefiles' |
| 31 | + label = '<ONS SOA shapefile>' |
| 32 | + |
| 33 | + def add_arguments(self, parser): |
| 34 | + super(Command, self).add_arguments(parser) |
| 35 | + parser.add_argument('--commit', action='store_true', |
| 36 | + dest='commit', help='Actually update the database') |
| 37 | + parser.add_argument('--type', dest='file_type', help="options: lsoa, msoa, soa, dz, lz", |
| 38 | + type=GeographyType, choices=list(GeographyType) |
| 39 | + ) |
| 40 | + parser.add_argument('--generalized', action='store_true', |
| 41 | + dest='generalized', help='Is shape generalised?') |
| 42 | + |
| 43 | + def handle_label(self, filename, **options): |
| 44 | + self.stdout.write("Importing from %s" % filename) |
| 45 | + |
| 46 | + current_generation = Generation.objects.current() |
| 47 | + new_generation = Generation.objects.new() |
| 48 | + |
| 49 | + file_type = options["file_type"].value.lower() |
| 50 | + generalized = options["generalized"] |
| 51 | + |
| 52 | + if file_type == "lsoa": # England and Wales |
| 53 | + feat_name = 'LSOA11NM' |
| 54 | + feat_code = 'LSOA11CD' |
| 55 | + elif file_type == "msoa": # England and Wales |
| 56 | + feat_name = 'MSOA11NM' |
| 57 | + feat_code = 'MSOA11CD' |
| 58 | + elif file_type == "soa": # super output areas - NI |
| 59 | + feat_name = 'SOA_LABEL' |
| 60 | + feat_code = 'SOA_CODE' |
| 61 | + elif file_type == "dz": # datazone - scotland |
| 62 | + feat_name = 'Name' |
| 63 | + feat_code = 'DataZone' |
| 64 | + elif file_type == "iz": # intermediate zone - scotland |
| 65 | + feat_name = 'Name' |
| 66 | + feat_code = 'InterZone' |
| 67 | + else: |
| 68 | + raise Exception( |
| 69 | + "Need to specify a small area type (lsoa, dz, soa, lz, msoa)") |
| 70 | + |
| 71 | + if file_type in ["lsoa", "dz", "soa"]: |
| 72 | + area_type = 'OLF' |
| 73 | + elif file_type in ["msoa", "iz"]: |
| 74 | + area_type = 'OMF' |
| 75 | + |
| 76 | + if generalized: |
| 77 | + area_type = area_type[:2] + "G" |
| 78 | + |
| 79 | + ds = DataSource(filename) |
| 80 | + layer = ds[0] |
| 81 | + for feat in layer: |
| 82 | + # retrieve name and code, and set country |
| 83 | + name = feat[feat_name].value |
| 84 | + code = feat[feat_code].value |
| 85 | + if code[:2] == "95": |
| 86 | + country = "N" |
| 87 | + else: |
| 88 | + country = code[0] |
| 89 | + |
| 90 | + self.stdout.write(" looking at '%s' (%s)" % (name, code)) |
| 91 | + |
| 92 | + g = feat.geom.transform(settings.MAPIT_AREA_SRID, clone=True) |
| 93 | + |
| 94 | + # skip if the SOA already exists in db (SOAs don't change) |
| 95 | + areas = Area.objects.filter(type__code=area_type, codes__code=code) |
| 96 | + if len(areas): |
| 97 | + m = areas[0] |
| 98 | + # check that we are not about to skip a generation |
| 99 | + if m.generation_high and current_generation and m.generation_high.id < current_generation.id: |
| 100 | + raise Exception("Area %s found, but not in current generation %s" % (m, current_generation)) |
| 101 | + if m.generation_high != new_generation and options['commit']: |
| 102 | + m.generation_high = new_generation |
| 103 | + m.save() |
| 104 | + continue |
| 105 | + |
| 106 | + print("Adding %s (%s) %s" % (name, code, feat.geom.geom_name)) |
| 107 | + m = Area( |
| 108 | + name=name, |
| 109 | + type=Type.objects.get(code=area_type), |
| 110 | + country=Country.objects.get(code=country), |
| 111 | + generation_low=new_generation, |
| 112 | + generation_high=new_generation, |
| 113 | + ) |
| 114 | + |
| 115 | + poly = [g] if g is not None else [] |
| 116 | + |
| 117 | + if options['commit']: |
| 118 | + m.save() |
| 119 | + m.names.update_or_create(type=NameType.objects.get( |
| 120 | + code='S'), defaults={'name': name}) |
| 121 | + m.codes.update_or_create(type=CodeType.objects.get( |
| 122 | + code='ons'), defaults={'code': code}) |
| 123 | + save_polygons({m.id: (m, poly)}) |
0 commit comments