U.S. Counties Choropleth

I can’t seem to find any info on how to create a choropleth map with U.S. counties in Julia. Is everyone using Python/R packages for this or is there a way to do it in Julia? It would be really nice if it was possible to load a shape file like GeoJSON or TopoJSON…

Maybe the map features in VegaLite.jl can do it? Here are some map examples. The map stuff is probably the least tested part of the package, so you might well run into problems. If you do, please open issues on the repo so that we can fix things!

4 Likes

Whoa, awesome package!! Thanks!! :grinning:

1 Like

No problems at all, I loved it so much I wrote a blog post about it :grinning:.

4 Likes

Nice blog post, the maps look great! Hope that we will be able to make such nice plots with GeoJSON.jl and Makie.jl soon. Will be possible already but is more work.

Even though of course the content of your blog is very much ok, the name, “Flirt With Julia”, sounds a bit at odds with Julia Community - Standards, in particular:

In particular, do not sexualize the term “Julia” or any other aspects of the project. While “Julia” is a female name in many parts of the world, the programming language is not a person and does not have a gender.

3 Likes

Fantastic blog post, very nice!

I don’t really have insights into the whole Geo* family of packages, but we should probably at some point explore whether one could pass the geometries in that format to VegaLite.jl, in addition to pointing it to a file on disc.

I second the comment about the name of the blog, I think a slightly tweaked name that is more in line with the community standards would be more appropriate.

1 Like

:flushed: To respect the community standards, I’ve removed the reference to the blog and will be sure not to post references to it here in the future.

To be fair though, the verb flirt isn’t necessarily sexual, per se. Merriam-Webster’s dictionary defines it as follows:

intransitive verb

1: to move erratically - butterflies flirting among the flowers

2a: to behave amorously without serious intent - He flirts with every attractive woman he meets.

b: to show superficial or casual interest or liking - flirted with the idea; a novelist flirting with poetry

3: to come close to reaching or experiencing something —used with  *with* - flirting with disaster

I chose the name because Julia is a programming language that I’m only currently flirting with (as in definition 2b above) and, of course, because I too found it to be mildly provocative and playful. These facts, however, make it easy to remember and more likely to become a topic of discussion. A catchy name is important in the long run, should this be a project that I decide to maintain and grow over a longer period of time (my goal with the blog is to appeal to a broad, mainstream audience).

3 Likes

What about other countries?
Can we use shp files? They are easy to get.

Juan,

It is super easy to load any TopoJSON/GeoJSON file. Here is how I produced a map of Colombia’s Departments from a TopoJSON file I found on Github:

@vlplot(width=800, height=600) + 
@vlplot(
    mark={ 
        :geoshape,
        fill=:lightgrey,
        stroke=:white
    },
    data={
        url=URI("https://raw.githubusercontent.com/deldersveld/topojson/master/countries/colombia/colombia-departments.json"),
        format={
            typ=:topojson,
            feature=:COL_adm1
        }
    },
    projection={
        typ=:albers
    }
)

To take this one step further and generate a choropleth map, I found some data for 2017 populations and converted it into a .CSV file and then did the following:

col_pops = URI("https://gist.githubusercontent.com/mthelm85/fcd178ea16c7e89cbdeb593d0b315c00/raw/4354805731cf060242f5799d9767821640dea839/colombia_populations.csv")
@vlplot(width=800, height=600) + 
@vlplot(
    mark={ 
        :geoshape
    },
    data={
        url=URI("https://raw.githubusercontent.com/deldersveld/topojson/master/countries/colombia/colombia-departments.json"),
        format={
            typ=:topojson,
            feature=:COL_adm1
        }
    },
    transform=[{
        lookup="properties.NAME_1",
        from={
            data={
                url=col_pops,
                format={
                    typ=:csv
                }
            },
            key=:department,
            fields=["population"]
        }
    }],
    color={
        "population:q",
        scale={domain=[42777, 8000000], scheme=:reds},
        legend={title="Population"}
    },
    projection={
        typ=:albers
    }
)

Note that I couldn’t write NAME_1 as a symbol (:NAME_1) in lookup. The way that the shape file was written resulted in me having to use JavaScript dot notation "properties.NAME_1" (since JSON is JavaScript Object Notation) to access the correct lookup value (JSON object property) in the TopoJSON file.

6 Likes

Where is the list of all available countries and cities?
What about shp files?

I found the Colombia shape file by just Googling. There are also ways to build them yourself: Online GIS/CAD Data Converter | SHP, KML, KMZ, TAB, CSV, ...

What is the advantage of using this choroplet tools instead of packages specialized on geographic maps, cartography, gdal, etc.?

@mthelm85, very cool! And very glad that it appears to all work, I’m almost a bit surprised :slight_smile:

1 Like

This is awesome and you just answered one of the questions I was going to ask, because I wanted to use other data. And I’m very happy you used my country as an example, even though that map is certainly crooked.

1 Like

You can use grammar of graphics with this very easily. iirc other geo-tooling packages don’t provide the same functionality.

Parce :wink:, that’s because of the Albers projection. Changing it to a Mercator projection (switching :albers with :mercator in the code above) yields the following:

1 Like

Thank you for posting this example. I am struggling with this and will appreciate some help.

I am using a geojson file which I have downloaded: africa_geo.json.

Formatted the information up to the first country’s coordinates looks like this:

{
    "features": [
        {
            "properties": {
                "economy": "7. Least developed region",
                "iso_a3": "BEN",
                "mapcolor9": 2,
                "name_alt": null,
                "postal": "BJ",
                "wikipedia": -99,
                "homepart": 1,
                "long_len": 5,
                "abbrev": "Benin",
                "continent": "Africa",
                "note_brk": null,
                "tiny": -99,
                "formal_en": "Republic of Benin",
                "su_a3": "BEN",
                "adm0_a3_wb": -99,
                "name": "Benin",
                "subregion": "Western Africa",
                "un_a3": "204",
                "wb_a2": "BJ",
                "mapcolor13": 12,
                "su_dif": 0,
                "region_un": "Africa",
                "featurecla": "Admin-0 country",
                "subunit": "Benin",
                "brk_group": null,
                "wb_a3": "BEN",
                "filename": "BEN.geojson",
                "gdp_md_est": 12830,
                "woe_id_eh": 23424764,
                "iso_n3": "204",
                "woe_note": "Exact WOE match as country",
                "level": 2,
                "formal_fr": null,
                "pop_year": -99,
                "brk_a3": "BEN",
                "gu_a3": "BEN",
                "income_grp": "5. Low income",
                "adm0_a3": "BEN",
                "adm0_dif": 0,
                "iso_a2": "BJ",
                "geou_dif": 0,
                "abbrev_len": 5,
                "brk_name": "Benin",
                "adm0_a3_us": "BEN",
                "name_len": 5,
                "scalerank": 0,
                "admin": "Benin",
                "labelrank": 5,
                "lastcensus": 2002,
                "region_wb": "Sub-Saharan Africa",
                "adm0_a3_is": "BEN",
                "name_long": "Benin",
                "note_adm0": null,
                "sovereignt": "Benin",
                "brk_diff": 0,
                "geounit": "Benin",
                "pop_est": 8791832,
                "name_sort": "Benin",
                "woe_id": 23424764,
                "mapcolor8": 2,
                "adm0_a3_un": -99,
                "mapcolor7": 1,
                "gdp_year": -99,
                "sov_a3": "BEN",
                "type": "Sovereign country",
                "fips_10_": "BN"
            },
            "geometry": {
                "coordinates": [
                    [
                        [

]

My first problem is that I am not sure what should be used as feature= in the data section.

This code produced an empty graphic:

julia> africa = "/home/js/db_docs/programmatic_indicators/geojson/africa_geo.json"
"/home/js/db_docs/programmatic_indicators/geojson/africa_geo.json"

julia> @vlplot(width=800, height=600) + 
       @vlplot(
           mark={ 
               :geoshape,
               fill=:lightgrey,
               stroke=:white
           },
           data={
               url=africa,
               format={
                   typ=:geojson,
                   feature=:geometry
               }
           },
           projection={
               typ=:naturalEarth1
           }
       )

I want to do on the Africa map what your example did using USA data. But I don’t even get as far as the first step.

I’m struggling with the GeoJSON file at the link you posted too, Johann. A couple of things:

  1. :geojson wouldn’t be a valid option. Per the VegaLite docs, JSON :json and TopoJSON :topojson are the only valid options (for JSON files).
  2. Since I couldn’t get the original file to work, I converted it to TopoJSON and I still can’t get it to work.
  3. Loading both files (geo and topo) into mapshaper.org worked just fine, so it appears that the files are okay, they just don’t play well with VegaLite for some reason.
  4. I don’t believe :naturalEarth1 is a valid projection. The Vega documentation has a list of all valid projection types.

Lastly, I was able to get it to display some geometrical shapes, but they didn’t look anything like Africa, no matter what projection type I chose :rofl: I’m wondering if maybe a projection has already been applied to the data so when VegaLite tries to apply another projection (default is mercator), this is what’s throwing it off and causing the crazy shapes I’m getting…?

Thanks Matt for confirming my problem.

By the way, I found that naturarlEarth1 projection added was added to versions > v4.0.

Nice, thanks for sharing. FYI, here’s a TopoJSON file of Africa that works.

@vlplot(width=800, height=600) + 
@vlplot(
    mark={ 
        :geoshape,
        fill=:lightgrey,
        stroke=:white
    },
    data={
        url=URI("https://raw.githubusercontent.com/deldersveld/topojson/master/continents/africa.json"),
        format={
            typ=:topojson,
            feature=:continent_Africa_subunits
        }
    },
    projection={
        typ=:mercator
    }
)