<jupyter_start><jupyter_text>chorogrid tutorial, part 1: Colorbin classThis class can be used independently of the Chorogrid class shown in part 2, and vice-versa, but they work well together.This allows you to input a parallel list of ids (e.g. state abbreviations) and quantities (e.g. unemployment rate), and it will output a list of colors<jupyter_code># import the class
from chorogrid import Colorbin

# read the docs
help(Colorbin)<jupyter_output>Help on class Colorbin in module chorogrid.Colorbin:

class Colorbin(builtins.object)
 |  Instantiate with a list of quantities and colors, then retrieve 
 |  the following attributes:
 |  .colors_out : output list of colors, same length as quantities
 |  .fenceposts : divisions between bins
 |  .labels: one per color
 |  .fencepostlabels: one per fencepost
 |  .complements: list of colors, see set_complements, below
 |  
 |  attributes that can be changed:
 |  .proportional : if True, all bins have fenceposts same distance
 |                  apart (with default bin_min, bin_mid and bin_max)
 |                : if False, all bins have (insofar as possible) the same
 |                  number of members
 |                : note that this can break if not every quantity is 
 |                  unique
 |  .bin_min, .bin_max, .bin_mid
 |  .decimals : if None, no rounding; otherwise round to this number
 |  
 |  methods:
 |  .set_decimals(n): just what it sounds like
 |  .recalc(fenceposts[...]<jupyter_text>You'll need to supply a list of colors in hex format; I recommend the library ``colorlover``. For now, I'll just enter a diverging list of six colors, ranging from dark brown to light brown/blue to dark blue.With ``colorlover`` installed, they were produced with the following code:    import colorlover as cl    colors = cl.scales['6']['div']['PuOr']    def rgb2hex(list_of_tuples):        output = []        for r, g, b in list_of_tuples:            output.append("{0:02x}{1:02x}{2:02x}".format(int(r), int(g), int(b)))        return output    colors = rgb2hex(cl.to_numeric(colors))<jupyter_code>mycolors = ['#b35806', '#f1a340', '#fee0b6', '#d8daeb', '#998ec3', '#542788']<jupyter_output><empty_output><jupyter_text>We also need some data. I've prepared one column from the U.S. Census<jupyter_code>import pandas as pd
df = pd.read_csv('chorogrid/sample_data/sample_state_data.csv')
df.tail()<jupyter_output><empty_output><jupyter_text>Now we can instantiate the ``Colorbin`` class with the quantity column in the dataframe, plus our list of six colors. Note that you don't have to use pandas, you could pass two lists instead.<jupyter_code># I've stated the proportional and decimals args, but left them at their defaults for now.
mybin = Colorbin(df['Percent_living_in_same_home_as_one_year_ago'], mycolors, proportional=True, decimals=None)<jupyter_output><empty_output><jupyter_text>``Colorbin`` has automatically chosen six 'bins' representing the range of quantities. You can retrieve them with the ``.fenceposts`` attribute. Note that because there are six bins in this case, there are seven fenceposts: bin 1 is fencepost 0-1, bin 2 is 1-2 ... bin 6 is 6-7.<jupyter_code>mybin.fenceposts<jupyter_output><empty_output><jupyter_text>Note that these are floats. To see what the class will output as text that can be used in a map legend, use .fencepostlabels<jupyter_code>mybin.fencepostlabels<jupyter_output><empty_output><jupyter_text>We also have a list of colors the same length as the quantities we passed to the constructor, corresponding to the fenceposts.<jupyter_code>print(mybin.colors_out[:10]+ ['...'])<jupyter_output>['#f1a340', '#542788', '#d8daeb', '#fee0b6', '#998ec3', '#d8daeb', '#fee0b6', '#fee0b6', '#d8daeb', '#fee0b6', '...']<jupyter_text>Back to the fenceposts. That's a lot of decimals, let's change it.After changing an attribute, the output fenceposts/labels and/or colors will not be changed until the ``.recalc()`` method is called. Calling ``.recalc(fenceposts=False)`` just recalculates the colors (which would have little or no effect in this case, since we are just changing the decimals, so only colors right near a fencepost might change); calling ``.recalc(True)`` recalculates the fenceposts, and then the colors.<jupyter_code>mybin.set_decimals(1)
mybin.recalc(fenceposts=True)
mybin.fencepostlabels<jupyter_output><empty_output><jupyter_text>You can see how many ids fall in each bin with the ``.count_bins()`` method.<jupyter_code>mybin.count_bins()<jupyter_output>count  label
=====  =====
    1  77.7-79.8
    4  79.8-81.8
   16  81.8-83.9
   17  83.9-86.0
    8  86.0-88.0
    5  88.0-90.1<jupyter_text>If you want the fenceposts to be easier-to-read whole numbers, or any specific numbers, just reassign the ``.fenceposts`` attribute.<jupyter_code>mybin.fenceposts = [77,80,82,84,86,88,91]
mybin.recalc(fenceposts=False) # if this were true, the fenceposts would be changed back to what they were originally
mybin.count_bins()<jupyter_output>count  label
=====  =====
    1  77-80
    5  80-82
   15  82-84
   17  84-86
    8  86-88
    5  88-91<jupyter_text>If you want each bin to contain(approximately) the same number of ids, you can pass ``proportional=False`` to the constructor. Note that having a choropleth with unequally-sized bins can be misleading to the viewer.<jupyter_code>mybin = Colorbin(df['Percent_living_in_same_home_as_one_year_ago'], mycolors, proportional=False, decimals=None)
mybin.count_bins()<jupyter_output>count  label
=====  =====
    8  77.7-82.7
    7  82.7-83.6
    8  83.6-84.7
   11  84.7-85.6
    8  85.6-86.6
    9  86.6-90.1<jupyter_text>Finally, there is the function ``calc_complements`` that can be used to ensure text that overlays a choropleth is visible. Choose a level of 'darkness' of the greyscale version of the colors (0 is black, 1 is white), a font color for dark backgrounds and a font color for light backgrounds.<jupyter_code>mybin.calc_complements(0.5, '#ffffff', '#000000')
for i, (color, complement) in enumerate(zip(mybin.colors_out, mybin.complements)):
    if i<10:
        print(color, complement)<jupyter_output>#b35806 #ffffff
#542788 #ffffff
#998ec3 #000000
#f1a340 #000000
#542788 #ffffff
#d8daeb #000000
#f1a340 #000000
#f1a340 #000000
#fee0b6 #000000
#fee0b6 #000000
{'fraction_non_alphanumeric': 0.10466602748481943, 'fraction_numerical': 0.047619047619047616, 'mean_word_length': 4.433159722222222, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '469508', 'license': 'MIT', 'n_tokens_mistral': 2248, 'n_tokens_neox': 2036, 'n_words': 699, 'path': 'tutorial_1_Colorbin.ipynb', 'repo_name': 'CheoR/chorogrid', 'size': '6258'}