My question here is fairly basic, and I'm sure I'm overlooking something basic. I know about CountryData for creating shapes of entire countries, and it works, to an extent; I can plot geographical data on it with the coordinates, but I'd like to have a magnified view of a state alone. The goal is to be able to measure borderlines. Is there built-in functionality for this, or do I have to import a shape file of a state?
- $\begingroup$ Related: Mathematica North America map. $\endgroup$Andrew Cheong– Andrew Cheong2014-03-22 02:27:55 +00:00Commented Mar 22, 2014 at 2:27
- $\begingroup$ You'll need shape files. Another similar question is this one $\endgroup$bobthechemist– bobthechemist2014-03-22 03:17:21 +00:00Commented Mar 22, 2014 at 3:17
2 Answers
There is no built in option, however for the US it's very easy because the coordinates of the state borderlines are all over the Internet. This led me to one such data set. I'll include how I cleaned it up, like this:
data = Import["http://econym.org.uk/gmap/states.xml"]; name[{"name" -> n_, ___}] := n coordinates[XMLElement["point", {"lat" -> lat_, "lng" -> lng_}, {}]] := {lat, lng} states = {name@Part[#, 1], coordinates /@ Part[#, 2]} & /@ Partition[Cases[data, XMLElement["state", state__] :> state, Infinity], 2]; However there is no point in redoing those things over and over. You might as well define states like this (the link leads to Pastebin where the list of coordinates is available. The list is too large to post here.)
To draw a specific state you can do something like this:
state[name_] := states /. {___, {name, pts_}, ___} :> (ToExpression /@ pts) ImageReflect[ImageRotate[Graphics[{ RGBColor[0.896, 0.8878, 0.8548], EdgeForm[GrayLevel[0]], Polygon[state["Indiana"]], PointSize[Medium], Red, Point[CityData[{"Clinton", "Indiana", "United States"}, "Coordinates"]], Point[CityData[{"Indianapolis", "Indiana", "United States"}, "Coordinates"]] }], Pi/2], Right] 
Of course you will be able to design better utility functions than I have to stuff away operations such as ImageReflect and ImageRotate.
Just another example to show how this can be used to draw the US map in it's entirety. You could very easily style each state individually.
ImageReflect[ImageRotate[Graphics[{ RGBColor[0.896, 0.8878, 0.8548], EdgeForm[GrayLevel[0]], Polygon[state[First@#] & /@ ( states /. { {"Hawaii", __} -> Sequence[], {"Alaska", __} -> Sequence[] } )], PointSize[Medium], Red, Point[CityData[{"Clinton", "Indiana", "United States"}, "Coordinates"]], Point[CityData[{"Indianapolis", "Indiana", "United States"}, "Coordinates"]] }], Pi/2], Right] 
(I know your purpose is not visualization, but someone will surely come along sooner or later looking for how to do visualization.)
Update
As of Mathematica 10 we don't have to find data sources ourselves.
indiana = GeoGraphics[{ GeoStyling["OutlineMap"], Polygon[ Entity["AdministrativeDivision", {"Indiana", "UnitedStates"}]]}, GeoBackground -> None, Frame -> True, FrameTicks -> None ] 
To extract the polygon coordinates we may do this:
pts = Cases[indiana, Polygon[data_] :> data, Infinity]; (* To plot the polygon: Graphics[Polygon[First@pts]] *) Or we can get the polygon like this:
EntityValue[Entity["AdministrativeDivision", {"Indiana", "UnitedStates"}], "Polygon"] - $\begingroup$ Thank you so much! I had already worked out a similar approach before your answer, in part from the comments above, but this has helped streamline it a bit. Just as a side question, is there any way to make your two points above different sizes in the same
Graphicsfunction? $\endgroup$Smith W.– Smith W.2014-03-23 02:18:39 +00:00Commented Mar 23, 2014 at 2:18 - $\begingroup$ @SmithW. Yes, you can easily change the settings in between graphics primitives, for example
{Red, PointSize[Small], Point[{0,0,0}], Green, PointSize[Large], Point[{1,0,0}]}creates two different points with different colors and sizes. Look upPointsSizeto see how you can specify different sizes. $\endgroup$2014-03-23 02:31:03 +00:00Commented Mar 23, 2014 at 2:31 - 1$\begingroup$ Technically, both
GeoGraphicsandEntityuse wolfram-alpha, so they're dependent on external data sources. $\endgroup$rcollyer– rcollyer2014-08-22 12:35:37 +00:00Commented Aug 22, 2014 at 12:35 - $\begingroup$ @rcollyer Thanks, I changed my wording. $\endgroup$2014-08-22 12:55:07 +00:00Commented Aug 22, 2014 at 12:55
As mentioned this is dead easy now with Entity:
GeoGraphics[ With[{h = RandomReal[.9], s = RandomReal@{.4, .8}, b = RandomReal@{.4, .6}}, { EdgeForm@Hue[h, s, b + .2], Hue[h, s + .2, b - .2], Polygon@#} ] & /@ (EntityList[ EntityClass["AdministrativeDivision", "AllUSStatesPlusDC"]] // DeleteCases[#, Entity["AdministrativeDivision", {"DistrictOfColumbia" | "Alaska" | "Hawaii", "UnitedStates"}]] &) // RandomSample[#, 15] & ] And with all the Geo* functionality we can get things like perimeters trivially:
In[90]:= Map[(#[[2, 1]] -> QuantityMagnitude@ GeoDistance@ Apply[Join]@First@First@EntityValue[#, "Polygon"]) &, EntityList@ EntityClass["AdministrativeDivision", "AllUSStatesPlusDC"]]~RandomSample~15 Out[90]= {"NorthCarolina" -> 3500.57, "Connecticut" -> 682.115, "Tennessee" -> 1278.5, "SouthDakota" -> 1265.04, "Hawaii" -> 1440.61, "Delaware" -> 502.202, "Florida" -> 6264.55, "Iowa" -> 1089.67, "Alaska" -> 58774.3, "Oklahoma" -> 1565.76, "Missouri" -> 1428.25, "Arkansas" -> 1286.78, "Texas" -> 4460.52, "WestVirginia" -> 1136.57, "NewHampshire" -> 529.748} - $\begingroup$ +1, but I would not call it "dead easy"... $\endgroup$Anton Antonov– Anton Antonov2017-05-20 22:52:06 +00:00Commented May 20, 2017 at 22:52
