17
$\begingroup$

Is it possible to use a background image in a polygon without rasterizing the polygon?

I tried with textures, but they seem to be viable only for simple polygons.

I want to put a flag as the background of the polygon that represents a country shape. I can do this for one country by rasterizing the polygon:

ImageAdd[
    Graphics[CountryData["Monaco", "Polygon"]], 
    CountryData["Monaco", "Flag"]
]

monaco

But by rasterizing the polygon, I make it difficult to apply this procedure to several neigboring countries and assemble them together.

I would like to put each country flag in the background of, for example:

Graphics[
    {EdgeForm[White], 
     CountryData[#, "Polygon"] & /@ {"Venezuela", "Colombia"}}]  

colombia and venezuela


Solution

After seeing cormullion answer, I was able to do what I wanted:

Graphics[
 {EdgeForm[Black],
  {{Texture[ImageReflect[CountryData[#, "Flag"], Top -> Right]], 
    CountryData[#, "Polygon"] /. 
      {Polygon[a_] :> Polygon[First[a], VertexTextureCoordinates -> 
       Transpose[Rescale /@ Transpose[First[CountryData[#, "Coordinates"]]]]]}} & /@ 
CountryData["SouthAmerica"]}}]

southamerica

The key part is the use of Rescale[].

$\endgroup$
3
  • $\begingroup$ I wish Mathematica had more advanced vector-graphics and layering; this is so simple in a drawing program. A good solution would preserve everything as vector with no rasterized textures, but I don't think it can be done in a general way. -- edit I didn't notice that the Flag data is already raster. I guess Texture makes the most sense in that case. $\endgroup$
    – Mr.Wizard
    Commented Feb 4, 2012 at 23:45
  • $\begingroup$ You may find ImagePad useful if you want small flags inside country borders $\endgroup$
    – Szabolcs
    Commented Feb 5, 2012 at 1:00
  • 1
    $\begingroup$ One caveat: This texture-based approach leads to a graphic that cannot be exported to PDF (on Macs, at least). This seems worth mentioning since you specifically asked for a method preserving the vector character of the borders. Just in case anyone encounters this, a workaround for this problem is to export to svg first, and then use Inkscape to convert to PDF. $\endgroup$
    – Jens
    Commented Feb 5, 2012 at 19:24

3 Answers 3

12
$\begingroup$

This example is from the documentation for Texture in Mathematica version 8:

With[{vc = 
 Transpose[
  Rescale /@ Transpose[First[CountryData[#, "Coordinates"]]]]}, 
Show[CountryData[#, "Shape"], 
 ImageSize -> {{100}, {100}}] /. {RGBColor[__] :> 
  Texture[ImageReflect[Image[CountryData[#, "Flag"]], 
    Top -> Right]], 
 Polygon[a_] :> 
  Polygon[First[a], VertexTextureCoordinates -> vc]}] & /@ 
CountryData["SouthAmerica"]

but I don't know whether it does what you need. Still, it looks pretty.

flags

$\endgroup$
4
$\begingroup$

Try:

Graphics[{EdgeForm[White], {{Texture[Image[CountryData[#, "Flag"]]], 
  Polygon[First@First[CountryData[#, "Polygon"]], 
   VertexTextureCoordinates ->Transpose[
     Rescale /@ Transpose[First@First[CountryData[#, 
         "Polygon"]]]]]}} & /@ {"Venezuela", "Colombia"}}]

which gives

maps and flags

$\endgroup$
4
  • $\begingroup$ Note that your country coordinates are somewhat rotated (transposed). $\endgroup$
    – Artes
    Commented Feb 5, 2012 at 0:33
  • $\begingroup$ Thank you @Artes. I need to change Coordinates to Polygon in the first argument of Polygon. $\endgroup$
    – kglr
    Commented Feb 5, 2012 at 0:36
  • $\begingroup$ Now, country polygons are correctly oriented while flags are rotated. $\endgroup$
    – Artes
    Commented Feb 5, 2012 at 0:50
  • $\begingroup$ @Artes, thank you again. Just noticed, that OP alrady put together the solution more than an hour ago. $\endgroup$
    – kglr
    Commented Feb 5, 2012 at 1:46
2
$\begingroup$

For coastal countries with a lot of islands, CountryData[tag,"Polygon"] gives something of the form Polygon[{island1, island2, island3,...}], where island1 and the like is another list of latitudes and longitudes.

The case is simpler for inland countries. CountryData[tag,"Polygon"] gives Polygon[{island1}], where island1 is simply the mainland, and is itself a list of latitudes and longitudes.

An example can be given using UK and Venezuela:

Table[Length /@ First[CountryData[country, "Polygon"]], {country, {"UnitedKingdom", "Venezuela"}}]

The result is:

{{20, 25, 31, 54, 52, 63, 141, 195, 1927}, {491}}

which means that UK is made up of 9 polygons/islands, and Venezuela only 1.

To fill a country's land with its own flag, we must be careful to apply the flag texture to all the islands. The important thing is to treat each island of a country one by one.

To apply a texture to any polygon, we must first come up with a function that can yield the correct VertexTextureCoordinates. For example:

countryRescale1[polygon_] := (Transpose[Rescale /@ Transpose[First[polygon]]])

The function accepts as argument a polygon of an island of a country, which is of the form Polygon[{{x1,y1},{x2,y2},...}}]. We obtain the list of coordinates with First[].

We apply transpose to the list of coordinates {{x1,y1},{x2,y2},...}}, so that we group all the x's together, and y's together: {{x1, x2, x3, ...}, {y1, y2, y3, ...}}. We apply to it Rescale[], so that x's and y's are both rescaled from 0 to 1 separately. Then apply transpose to group them back into {{x1,y1},{x2,y2},...}}, where x and y is now in [0,1].

Then we can overlay the flag onto a country. Let's use Hong Kong (though not a country, but it has many islands) as an example. The important thing is to treat each island of a country one by one.

Graphics[{EdgeForm[Black], Texture[CountryData["HongKong", "Flag"]], 
  Polygon[#, VertexTextureCoordinates -> countryRescale1[Polygon[#]]] & /@
  First[CountryData["HongKong", "Polygon"]]}]

We map the pure function Polygon[#, VertexTextureCoordinates -> countryRescale1[Polygon[#]]]& to the expression First[CountryData["HongKong", "Polygon"]], which in itself is a list of islands { {{x1, y1}, {x2, y2}, ..., {xn,yn}}, {{x1, y1}, {x2, y2}, ...}, ... }.

So it's just like:

Graphics[{EdgeForm[Black], Texture[CountryData["HongKong", "Flag"]],
  {Polygon[], Polygon[], Polygon[] ... }]

The result looks like this:

Hong Kong with the islands

For Argentina, the island province Tierra del Fuego (the bottom right triangular piece of land) is also treated with the flag:

Argentina with the island

The final thing left to do is to apply this to all countries to make a world flag map:

Graphics[{EdgeForm[Black], Table[{Texture[CountryData[c, "Flag"]], 
  Polygon[#, VertexTextureCoordinates -> countryRescale1[Polygon[#]]] & /@  
  First[CountryData[c, "FullPolygon"]]}, {c, CountryData[]}]}, ImageSize -> 700]

The result looks like this:

enter image description here

For better flags, one can refer to this post: Why do some CountryData flags render at low resolution?

$\endgroup$
2
  • $\begingroup$ I have used the better flags, 500px ones from Why do some CountryData flags render at low resolution? to create a world flag map. What is the right way to export it so that I can zoom in and see even Hong Kong? Should I use 200px, 500px, or 1000px for the flags? $\endgroup$
    – Jonas
    Commented Jun 8, 2014 at 7:06
  • $\begingroup$ What do you think of this piece of code Graphics[{EdgeForm[Black],{Texture[CountryData[#1,"Flag"]],Polygon[#,VertexTextureCoordinates->countryRescale1[Polygon[#]]]&/@First[CountryData[#1,"FullPolygon"]]}&/@CountryData[]},ImageSize->200] as compared to the one using Table[]? $\endgroup$
    – Jonas
    Commented Jun 8, 2014 at 7:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.