Congressional Redistricting

Congressional Redistricting preview image

1 collaborator

Light_dependent_reaction_background Luke Elissiry (Author)

Tags

(This model has yet to be categorized with any tags)
Visible to everyone | Changeable by the author
Model was written in NetLogo 6.1.1 • Viewed 284 times • Downloaded 36 times • Run 0 times
Download the 'Congressional Redistricting' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


Comments and Questions

import-pcolors error (Question)

When I try to run the model with either the "Generate" or "District" buttons I get the error: "import-pcolors: The following file is not in a supported image format:" I took a look at the file, which appears to be a text file whereas Netlogo expects an image file. Can you advise how to amend? I am hoping to adapt your code (credited of course!) into a model I'm constructing that includes randomly generated districts.

Posted over 3 years ago

Regarding importing colors from file

Hi Abe, Thanks for taking a look at this model! It has been quite a while since I last worked on it, and the code needed an update because newer versions of Netlogo had altered the import-pcolors feature to only accept images. The image files ("state 1" and "state 2") are now in the "Files" tab, and I can send you the model I used to generate the images if desired. Make sure to put the images in the same folder as the model. I also reworked the code to make it more readable and improved a lot of the mechanics so that districts remain continuous when redistricting. The largest assumption this model makes for districting is to base districts around the patches of highest population (as indicated by a darker color). This can be easily modified to make random if desired. My rationale behind this choice was that areas of higher population density (i.e. cities and towns) have similar political interests, and therefore should be represented as a unit, rather than being split up into multiple districts. If you have any further questions, please feel free to leave another comment or contact me at ljelissiry[at]gmail[dot]com, or leave a comment. Also, please send me your model if you pursue one!

Posted over 3 years ago

Following Up

Hey Luke, I figured out the source of the error, which was entirely technical (but the info may be of use to anyone else who is interested in adapting your model). The zip file download when expanded (at least on a Mac) produces the "state 1" and "state 2" png files in some kind of corrupted format. Downloading those files directly solves the error I described in my previous comment. Best, Abe

Posted about 3 years ago

Click to Run Model

patches-own [patch_pop district state counted]

to show_population_density_map
  ; clear world and import population density map
  ; map should be grayscale of population
  ca
  import-pcolors file-name

  ; initialize districts based on highest-population patches
  let num_districts 0
  ask patches [
    set patch_pop 100 * (10 - pcolor)
    set counted False
  ]

  ; determine points of highest population from density map
  let peak_pop_points []
  ask patches [
    if max [patch_pop] of neighbors < patch_pop [
      set peak_pop_points lput self peak_pop_points
    ]
  ]

  ; sort list by patch population in descending order
  set peak_pop_points sort-by [ [patch1 patch2] -> [patch_pop] of patch1 > [patch_pop] of patch2 ] peak_pop_points

  ; determine district centers, ensuring that neither the list of points nor the user-set max-districts is exceeded
  while [num_districts < length peak_pop_points and num_districts < max-districts] [
    ask item num_districts peak_pop_points [
      set num_districts num_districts + 1
      set district num_districts
      set state "edge"
      set pcolor yellow
    ]
  ]
end 

to generate_districts
  ; generate imported map of population density
  show_population_density_map
  let num_districts max ([district] of patches)

  ; expand districts to fill entire map
  while [any? patches with [state = 0]] [
    wait .1
    ask patches with [state = "edge"] [
      if any? neighbors4 with [state = 0] [
        ask one-of neighbors4 with [state = 0] [
          set district [district] of myself
          set state "edge"
          set pcolor yellow
        ]
      ]
      determine-state
    ]
  ]

  ; adjust districts to equalize population
  let total_pop sum ([patch_pop] of patches)
  let max_difference .05 ; districts can only be +/- this percent
  let done False
  while [not done] [
    wait .001

    ; cycle through districts
    let x 1
    while [x <= num_districts] [
      let district_pop sum ([patch_pop] of patches with [district = x])

      ; determine patch asking behavior depending on specified adjust-mode
      let selection []
      if adjust-mode = "smooth" [
        set selection patches with [state = "edge" and district = x]
      ]
      if adjust-mode = "jagged" [
        set selection one-of patches with [state = "edge" and district = x]
      ]

      ; increase district size if population is too low
      if district_pop < total_pop / num_districts * (1 - max_difference) [
        ask selection [
          let y neighbors4 with [state = "edge" and district != x]
          if any? y [
            ask one-of y [
              change-to x
              ask neighbors4 [determine-state]
              determine-state
            ]
          ]
        ]
      ]

      ; decrease district size if population is too high
      if district_pop > total_pop / num_districts * (1 + max_difference) [
        ask selection [
          change-to [district] of one-of neighbors4
          ask neighbors4 [determine-state]
          determine-state
        ]
      ]

      ; increment to next district
      set x x + 1
    ]

    ; check if districts are within population bounds
    ; i.e. if they have similar populations
    set done True
    set x 1
    while [x <= num_districts] [
      let district_pop sum ([patch_pop] of patches with [district = x])
      if district_pop < total_pop / num_districts * (1 - max_difference) or
      district_pop > total_pop / num_districts * (1 + max_difference) [
        set done False
      ]

      ; increment to next district
      set x x + 1
    ]
  ]

  ; show districts by color
  ask patches [
    set pcolor district * 20 - 1 - patch_pop / 120
  ]

  ; output district sizes
  let x 1
  output-print "Districts:"
  while [x <= num_districts] [
    let district_pop sum ([patch_pop] of patches with [district = x])
    output-print (word "D" x " - " district_pop " - " (int(district_pop / total_pop * 10000) / 100) "%")
    set x x + 1
  ]
  output-print "Total Population:"
  output-print total_pop
end 

to determine-state
  if-else any? neighbors4 with [district != [district] of myself]
  [
    set state "edge"
    set pcolor yellow
  ]
  [
    set state "done"
    set pcolor 9 - patch_pop / 120
  ]
end 

; have patch change to "new_district"
; checks if change keeps district continuous

to change-to [new_district]
  let original_district district
  set district new_district
  let remain_continuous True
  ask self [set remain_continuous check-continuous]
  if not remain_continuous [
    set district original_district
  ]
end 

; checks if the district(s) of the patches affected are continuous
; i.e. all patches in the district are connected

to-report check-continuous
  let report_bool True
  let affected_patches (patch-set self (neighbors4 with [district != [district] of myself]))
  ask affected_patches [
    ; define district and patches in district
    let district_name district
    let district_patches patches with [district = district_name]

    ; calculate district patches that are continuous with current patch
    ask district_patches [set counted False]
    let continuous_size 0
    ask one-of district_patches [
      set counted True
      set continuous_size count-continuous-patches
    ]

    ; calculate total patches in district
    let district_size count district_patches

    ; if the previous 2 calculations don't match, the district is not continuous
    if district_size != continuous_size [set report_bool False stop]
  ]
  report report_bool
end 

; recursive function that calculates the number of connected patches within district of patch

to-report count-continuous-patches
  let district_size 1
  let x neighbors4 with [not counted and district = [district] of myself]
  if any? x [
    ask x [set counted True]
    ask x [set district_size district_size + count-continuous-patches]
  ]
  report district_size
end 

There are 7 versions of this model.

Uploaded by When Description Download
Luke Elissiry over 3 years ago Includes file name input box. Download this version
Luke Elissiry over 3 years ago Reverted to older version Download this version
Luke Elissiry over 3 years ago Reverted to older version Download this version
Luke Elissiry over 3 years ago Now it works for Netlogo Web. Download this version
Luke Elissiry over 3 years ago Works on Netlogo Web Download this version
Luke Elissiry over 3 years ago Completely redone Download this version
Luke Elissiry almost 7 years ago Initial upload Download this version

Attached files

File Type Description Last updated
Congressional Redistricting.png preview Example output of model. over 3 years ago, by Luke Elissiry Download
state 1.png png Example 1 of population density map. over 3 years ago, by Luke Elissiry Download
state 2.png png Example 2 of population density map. over 3 years ago, by Luke Elissiry Download

This model does not have any ancestors.

This model does not have any descendants.