Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save a partition as an assignment csv (& load) #277

Open
maxhully opened this issue Mar 9, 2019 · 3 comments
Open

Save a partition as an assignment csv (& load) #277

maxhully opened this issue Mar 9, 2019 · 3 comments
Labels
feature good first issue Good for newcomers

Comments

@maxhully
Copy link
Contributor

maxhully commented Mar 9, 2019

An assignment CSV has a column of node indices and a column with the corresponding district assignments. This CSV format seems to be common in the redistricting world. JSON probably isn't the right tool for the job since it only supports string keys.

@maxhully maxhully added good first issue Good for newcomers feature labels Mar 9, 2019
@zschutzman
Copy link
Contributor

to_csv() is pretty straightforward. Something like this should be mostly what we want. It can be put anywhere, but the reference to self.parts would need to change.

In assignment.py:

...
import csv
...

class Assignment
...

def to_csv(filename=None):
    if filename == None:
        print("Please give a filename")
        return

    with open(filename,'w') as _outfile:
        _writer = csv.writer(_outfile)
        _writer.writerow(["unit_idx", "dist_no"]
        for row in sorted([(unit,dist) for dist in self.parts.keys() for unit in self.parts.keys()[unit]]:
            _writer.writerow(row)


from_csv() could look something like this. The following will take a csv and turn it into a dictionary of the format that Assignment.from_dict() wants: each key is a geographical unit and its value is the district it's assigned to. This can be a class method of Assignment or be put somewhere else, like in a utilities.py kind of file.

...

import csv
import collections

...

# checks if a string is really just an integer wearing a fun hat
def tryint(string):
   if not isinstance(string,str): return string
   return int(string) if string.isdigit() else string

def from_csv(filename, header = True, sep = ','):
    try:
        with open(filename, 'r') as _infile:
            _reader = csv.reader(_infile, delimiter = sep)
            # throw out the header
            if header: next(_reader)
            
            # dictionary comprehension over the rows
            new_assn = {tryint(row[0]), tryint(row[1]) for row in _reader}
            
        return new_assn

    except:
        print("Could not read {}".format(filename))
        return

This will return an {int:int} dictionary if possible, otherwise an {int:string}, {string:int}, or {string:string} dictionary, to be passed to Assignment.to_dict(). This will let people rename their districts and graph's nodes to GEOIDs or something human-readable if they want. The tryint() thing is because csvs are read in as strings always, so we need to do some sort of check to see if the names can be cast to integers.

There is currently no check that the graph's node's names align with the entries in the dictionary's values in Assignment.from_dict(), or that the values in this dictionary are unique, which may cause some safety issues if we're letting users bring in assignments from sources other than the .shp or .json containing the graph.

@maxhully
Copy link
Contributor Author

You're right about the lack of a nodes check --- I ran into that issue a couple days ago. I'll make an issue.

@carlschroedl
Copy link
Contributor

👍 for this -- ward/block assignment CSV is the only valid format for submitting proposals to the Wisconsin state legislature.
Format details are here in the section "TECHNICAL SPECIFICATIONS (IF USING AN ALTERNATE TECHNOLOGY)".

I'm convening a redistricting workshop Sept 20th.
The WI state legislature accepts maps up until Oct 15th.

Is there any chance the CSV export feature could be added before either of those times?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

3 participants