Exemplo n.º 1
0
def main():
    objs = load(data_path('zoning_height_2000.geojson'))

    new_zones = defaultdict(int)
    for i, o in enumerate(objs):
        prop = o['properties']

        zoning_code = prop['zoning']
        if zoning_code is None:
            prop['fill'] = UNKNOWN
            prop['homes'] = 0
            continue

        height_code = prop['height_lim']

        height = parse_height(height_code) if height_code is not None else None
        if height is not None:
            homes_height = units_per_height(height_code, height, zoning_code)
        else:
            homes_height = 1e9

        zoning_code = zoning_code.split('/')[0].strip()

        try:
            homes_zoning = units_per_density_limit(zoning_code,
                                                   waiverless_adus=False)
        except NewZoneDetected:
            area = sq_ft(o['geometry'])
            new_zones[zoning_code] += area
            homes_zoning = 0
            print(prop)

        homes = min(homes_zoning, homes_height)
        prop['homes'] = homes
        prop['homes_zoning'] = homes_zoning
        prop['homes_height'] = homes_height
        prop['fill'] = color(homes) if homes_zoning != -999 else UNKNOWN

    stats = key_stats(objs, lot_size=LOT_SIZE, all_area_denom=True)
    stats['city'] = 'San Francisco'
    stats['center'] = [-122.42936665634733, 37.75967613988033]
    stats['zoom'] = 11.75

    os.makedirs(generated_path('sf2000'), exist_ok=True)
    dump('generated/sf2000/density_map.geojson', objs)

    with open(generated_path('sf2000/key_data.json'), 'w') as f:
        json.dump(stats, f)

    if new_zones:
        print('New Zones: \n\t' + '\n\t'.join(new_zones.keys()))
        print(new_zones)
        return -1
Exemplo n.º 2
0
 def dumpall():
     dump(generated_path('sf/lot_building_zoning.geojson'), lots)
     dump(generated_path('sf/building_not_found_for_lot.geojson'),
          not_found)
Exemplo n.º 3
0
def main():
    lots = load(generated_path('sf/lot_building_zoning.geojson'))

    new_lots = []
    too_tall = too_tall_nonwarehouse = 0

    for lot in lots:
        prop = lot['properties']
        zoning = prop['zoning']

        # must be a residential zone
        if prop['zoning']['homes'] <= 0:
            continue

        # cannot have any homes on it
        if float(prop['resunits']) > 0:
            continue

        # must be at least 10k sq ft
        if prop['sqft'] < 10e3:
            continue

        # affordable devs won't build taller than 85ft due to cost
        height = min(zoning['height'], 85)

        homes_zoning = units_per_density_limit(zoning['zoning'],
                                               lot_size=prop['sqft'])
        homes_height = units_per_height(zoning['height_str'],
                                        height,
                                        zoning['zoning'],
                                        lot_size=prop['sqft'])
        oldhomes = min(homes_zoning, homes_height)

        newhomes = units_per_height('', height, '', prop['sqft'])

        # affordable projects need at least 50 homes to get funding
        if newhomes < 50:
            continue

        # skip lots that could have built affordable housing already
        if oldhomes >= 50:
            continue

        # make it bright green
        prop['fill'] = '#7eb100'
        prop['opacity'] = 0.7

        max_height = 0
        for building in prop.get('buildings', []):
            height_ft = METER_TO_FEET * float(
                building['properties']['hgt_mediancm']) / 100.0
            max_height = max(max_height, height_ft)
            print('\t', height_ft)

        prop['max_building_height'] = max_height
        prop['oldhomes'] = oldhomes
        prop['newhomes'] = newhomes
        if 'buildings' in prop:
            del prop['buildings']

        CANNOT_DEMOLISH = {
            'fill': '#c60003',
            'opacity': 0.2,
        }

        # demolishing non-warehouse buildings taller than 35ft is too expensive
        if prop['landuse'] != 'PDR' and max_height > 35:
            too_tall_nonwarehouse += 1
            prop['infeasible_reason'] = (
                'demolishing non-warehouse buildings taller than 35ft is too expensive'
            )
            prop.update(CANNOT_DEMOLISH)

        # demolishing buildings taller than 50ft is too expensive
        if max_height > 50:
            too_tall += 1
            prop['infeasible_reason'] = (
                'demolishing buildings taller than 50ft is too expensive')
            prop.update(CANNOT_DEMOLISH)

        new_lots.append(lot)

        print(newhomes, oldhomes, prop['sqft'], prop['zoning']['height'])

    print(len(new_lots), too_tall, too_tall_nonwarehouse)

    dump(generated_path('sf/prop_e.geojson'), new_lots)
Exemplo n.º 4
0
def main():
    features = load(generated_path('sf/lot_building_zoning.geojson'))

    r = Results()
    r.num_lots = len(features)
    r.num_units = 0
    r.num_illegal_lots = 0
    r.num_illegal_units = 0
    r.num_units_in_illegal_building = 0
    illegal_homes = []
    nozones = []
    reason_count = defaultdict(int)
    lot_sizez = {}
    for i, obj in enumerate(features):
        print(i + 1, '/', len(features))
        prop = obj['properties']
        zoning = prop.get('zoning')
        if not zoning:
            nozones.append(obj)
            continue

        units = int(prop['resunits'])
        r.num_units += units

        if units == 0:
            continue

        area = sq_ft(obj['geometry'])

        min_area = 4000 if zoning['zoning'] == 'RH-1(D)' else 2500

        allowed_units_density = units_per_density_limit(zoning['zoning'],
                                                        lot_size=area,
                                                        per_lot_size=False,
                                                        waiverless_adus=False)

        if allowed_units_density < 0:
            continue

        max_median_height = (max(
            float(b['properties']['hgt_mediancm'])
            for b in prop['buildings']) /
                             30.48 if prop.get('buildings') else 0)

        illegal_units = 0
        reasons = []

        if area + AREA_BUFFER < min_area:
            lot_sizez[area] = obj
            illegal_units = units
            reason_count['lot too small'] += units
            reasons.append('lot too small')

        if units > allowed_units_density:
            illegal_units = max(illegal_units,
                                units - int(allowed_units_density))
            reason_count['too dense'] += units - int(allowed_units_density)
            if allowed_units_density == 0:
                reasons.append('no housing allowed here')
            else:
                reasons.append('too dense')

        if max_median_height - HEIGHT_BUFFER > zoning['height']:
            total_building_volume = sum(
                (float(b['properties']['hgt_mediancm']) / 30.48) *
                sq_ft(b['geometry']) for b in prop['buildings'])

            # calulate how many units each building would allow if its height
            # were chopped off at the zoning height (assuming even density of
            # units per building volume for each lot - definitely an incorrect
            # assumption but it's the best guess we can make)
            allowed_units = 0
            for b in prop['buildings']:
                building_height = float(
                    b['properties']['hgt_mediancm']) / 30.48

                building_area = sq_ft(b['geometry'])
                units_proportion = units * building_area * building_height / total_building_volume

                if building_height - HEIGHT_BUFFER > zoning['height']:
                    allowed_units += units_proportion * zoning[
                        'height'] / building_height
                else:
                    allowed_units += units_proportion

            allowed_units = int(round(allowed_units))
            if allowed_units < units:
                illegal_units = max(illegal_units, units - allowed_units)
                reason_count['too tall'] += units - allowed_units
                reasons.append('too tall')

        if illegal_units > 0:
            r.num_illegal_lots += 1
            r.num_illegal_units += illegal_units
            r.num_units_in_illegal_building += units

            obj['properties'] = {
                'address': address(prop),
                'units': units,
                'illegal_units': illegal_units,
                'allowed_units_density': allowed_units_density,
                'zoning_code': zoning['zoning'],
                'allowed_height': zoning['height'],
                'max_median_height': max_median_height,
                'lot_sq_ft': area,
                'minimum_lot_sq_ft': min_area,
                'fill': color(illegal_units),
                'reasons': ', '.join(reasons),
                'year_built': int(prop.get('yrbuilt')) or 'unknown',
            }
            illegal_homes.append(obj)

    print(r.results())

    key = []
    for i, c in enumerate(COLORS):
        key.append({
            'num': i + 1,
            'color': c,
        })

    key_data = {
        'key': key,
        'reason_counts': reason_count,
    }
    key_data.update(r.asdict())

    assert not nozones
    dump('generated/sf/illegal_homes.geojson', illegal_homes)

    with open(generated_path('sf/illegal_homes_key_data.json'), 'w') as f:
        json.dump(key_data, f)
Exemplo n.º 5
0
from lib.fileutil import load, dump, generated_path, data_path
from lib.calc.sf import address

FILENAME = 'sf/lot_building_zoning.geojson'

lots = load(generated_path(FILENAME))
for lot in lots:
    prop = lot['properties']
    new_address = address(prop)
    print(prop['address'], '->', new_address)
    prop['address'] = new_address

dump(generated_path(FILENAME), lots)
Exemplo n.º 6
0
 def dumpall():
     dump(generated_path('sf/lot_zoning.geojson'), lot_zoning)
     dump(generated_path('sf/zone_not_found_for_lot.geojson'), not_found)