7
$\begingroup$

I'm trying to make a graph that looks like this:

A map projection with labelled gridlines

This code gets close:

GeoGraphics[GeoRange -> {{20, 35}, {110, 140}}, 
 GeoRangePadding -> None, 
 GeoBackground -> 
  GeoStyling[{"Coastlines", "Land" -> RGBColor[0.65, 0.65, 0.65], 
    "Ocean" -> White}], GeoGridLines -> {3, 7}]

enter image description here

But I can't figure out how to get the gridlines to be labeled with $110^\circ \text{E}$ etc. I guess it can be hard-coded with some annoying combination of Legended and Placed but there's got to be a better way? None of the examples on the GeoGraphics reference look quite like this.

$\endgroup$
1
  • 3
    $\begingroup$ Frame -> True, but this only works for well for equirectangular projection. See also this question. $\endgroup$
    – Domen
    Jan 31, 2023 at 14:52

1 Answer 1

3
$\begingroup$

Edit May 3, 2023 (most recent)

The latest version of this function is being developed (for some definition of the word "developed") here. The main function is FancyGeoFrame[ticksX, ticksY, opts].

SetDirectory[NotebookDirectory[]];
<<FancyGeoFrame`

(*
The frame will have four black corners can therefore look slightly nicer if there 
are an even number of X and Y ticks, but it isn't required.
*)
ticksX={110,115,120,125,130,135,140};
ticksY={20,23,26,29,32,35};

{frame,newrange} = FancyGeoFrame[ticksX, ticksY, 
    FancyBoxesSize->{{0.5,0.5},{0.45,0.45}},
    FancyTicksPadding->{2,3},
    FancyTicksMag->2.5, 
    FancyTicksAngle->{0,-5}*Pi/180,
    FancyTicksYDelta->0.2];

world={
    GeoStyling[Opacity[1]], 
    FaceForm[LightGray], 
    EdgeForm[None], 
    CountryData["World", "Polygon"]
    };

GeoGraphics[
    Join[world,frame],
    GeoRange->Reverse[newrange],
    GeoRangePadding->{None,None},
    GeoBackground->None,
    GeoGridLines->None,
    ImageSize->1100
]

enter image description here

The following options are available

  • FancyBoxesSize -> {{left, right}, {bottom, top}} specifies the width of the boxes on each side.
  • FancyTicksPadding->{bottom, left} specifies how far away the tick labels are from the frame.
  • FancyTicksMag->mag specifies how large the tick labels are.
  • FancyGridlinesOpacity->op specifies the opacity of the gridlines.
  • FancyTicksAngle->{bottom, left} specifies the rotation of the labels. On the y axis, the labels are rotated uniformly and on the x axis they are rotated concentrically. This can make the labels look nicer if their angle roughly matches the angle of the gridlines.
  • FancyTicksYDelta->delta specifies the "slope" of the labels on the y axis. This can make the labels look nicer if the lower labels are too far away from the y axis.

Original Answer

I have written the following function to create the frame and axes labels. This function does not "just work" by any stretch of the imagination, it requires a lot of parameter tweaking to get it to look right and I'm truly sorry if you have to use this. Note that I'm using MaTeX to get a professional font.

ConstructFrame[georange_, nx_, ny_, deltax_, deltay_, paddingsizex_, 
  paddingsizey_, axesmag_, textmag_, angle_, slope_] := 
 Module[{xrng, yrng, bw, labelerx, labelery, boxes = {}, 
   paddingboxes = {}, gridlines = {}, xlabels = {}, ylabels = {}, 
   world},
  xrng = 
   Range[georange[[2, 1]], georange[[2, 2]], 
    Ceiling[(georange[[2, 2]] - georange[[2, 1]])/nx]];
  yrng = 
   Range[georange[[1, 1]], georange[[1, 2]], 
    Ceiling[(georange[[1, 2]] - georange[[1, 1]])/ny]];
  If[xrng[[-1]] != georange[[2, 2]], AppendTo[xrng, georange[[2, 2]]]];
  If[yrng[[-1]] != georange[[1, 2]], AppendTo[yrng, georange[[1, 2]]]];
  bw[i_] := If[OddQ[i], Black, White];
  (*Constructing x boxes*);
  Do[
   AppendTo[boxes,
    {GeoStyling[Opacity[1]], FaceForm[bw[i]], EdgeForm[Black], 
     GeoBoundsRegion[{{georange[[1, 1]], 
        georange[[1, 1]] + deltax}, {xrng[[i]], xrng[[i + 1]]}}]}
    ];
   AppendTo[boxes,
    {GeoStyling[Opacity[1]], FaceForm[bw[i]], EdgeForm[Black], 
     GeoBoundsRegion[{{georange[[1, 2]], 
        georange[[1, 2]] - deltax}, {xrng[[i]], xrng[[i + 1]]}}]}
    ],
   {i, 1, Length[xrng] - 1}
   ];
  (*Constructing y boxes*);
  Do[
   AppendTo[boxes,
    {GeoStyling[Opacity[1]], FaceForm[bw[i]], EdgeForm[Black], 
     GeoBoundsRegion[{{yrng[[i]], yrng[[i + 1]]}, {georange[[2, 1]], 
        georange[[2, 1]] + deltay}}]}
    ];
   AppendTo[boxes,
    {GeoStyling[Opacity[1]], FaceForm[bw[i]], EdgeForm[Black], 
     GeoBoundsRegion[{{yrng[[i]], 
        yrng[[i + 1]]}, {georange[[2, 2]] - deltay, 
        georange[[2, 2]]}}]}
    ],
   {i, 1, Length[yrng] - 1}
   ];
  (*Constructing x padding boxes*);
  AppendTo[paddingboxes,
   {GeoStyling[Opacity[1]], FaceForm[White], EdgeForm[White], 
    GeoBoundsRegion[{{georange[[1, 1]] - 0.07, 
       georange[[1, 1]] - paddingsizex - 1}, {-179.9, 179.9}}]}
   ];
  (*Constructing y padding boxes*);
  AppendTo[paddingboxes,
   {GeoStyling[Opacity[1]], FaceForm[White], EdgeForm[White], 
    GeoBoundsRegion[{{-89.9, 89.9}, {georange[[2, 1]] - paddingsizey, 
       georange[[2, 1]] - 0.03}}]}
   ];
  (*Constructing x gridlines*);
  Do[AppendTo[gridlines,
    {Opacity[0.2], Black, 
     GeoPath[{{georange[[1, 1]], xrng[[i]]}, {georange[[1, 2]], 
        xrng[[i]]}}]}], {i, 1, Length[xrng]}];
  (*Constructing y gridlines*);
  Do[AppendTo[gridlines,
    {Opacity[0.2], Black, 
     GeoPath[{{yrng[[i]], georange[[2, 1]]}, {yrng[[i]], 
        georange[[2, 2]]}}, "Rhumb"]}], {i, 1, Length[yrng]}];
  (*Constructing x labels*);
  labelerx[xval_] := 
   If[xval == 0, MaTeX["0^\\circ", Magnification -> textmag], 
    If[xval < 0, 
     MaTeX[ToString[Abs[xval]] <> "^\\circ \\, \\text{W}", 
      Magnification -> textmag], 
     MaTeX[ToString[xval] <> "^\\circ \\, \\text{E}", 
      Magnification -> textmag]]];
  Do[AppendTo[xlabels,
    {GeoMarker[{georange[[1, 1]] - paddingsizex/4, xrng[[i]]}, 
      Text[labelerx[xrng[[i]]]], "Alignment" -> Center, 
      "Scale" -> axesmag]}], {i, 2, Length[xrng] - 1}];
  (*Constructing y labels*);
  labelery[yval_] := 
   If[yval == 0, MaTeX["0^\\circ", Magnification -> textmag], 
    If[yval < 0, 
     MaTeX[ToString[Abs[yval]] <> "^\\circ \\, \\text{S}", 
      Magnification -> textmag], 
     MaTeX[ToString[yval] <> "^\\circ \\, \\text{N}", 
      Magnification -> textmag]]];
  Do[AppendTo[ylabels,
    {GeoMarker[{yrng[[i]], 
       georange[[2, 1]] - paddingsizey/1.1 - 
        slope*(i - Length[yrng/2])}, 
      Rotate[ Text[labelery[yrng[[i]]]], angle], 
      "Alignment" -> Center, "Scale" -> axesmag]}], {i, 1, 
    Length[yrng] - 1}];
  (*world shapes*);
  world = {GeoStyling[Opacity[0.5]], 
    FaceForm[RGBColor[0.65, 0.65, 0.65]], 
    EntityValue[Entity["GeographicRegion", "World"], 
     EntityProperty["GeographicRegion", "Polygon"]]};
  Join[{world, boxes, gridlines, paddingboxes, xlabels, ylabels}]
  ]

Now we can make the plot.

RANGE = {{20, 35}, {110, 140}};
XLines = 8;
YLines = 5;
FrameX = 0.2;
FrameY = 0.3;
PaddingX = 2.5;
PaddingY = 1.5;
MarkerScale = 1;
AxesLabelScale = 2;
Angle = (\[Pi]/180)*(-10);
Slope = 0.07;
frame = ConstructFrame[RANGE, XLines, YLines, FrameX, FrameY, 
   PaddingX, PaddingY, MarkerScale, AxesLabelScale, Angle, Slope];
RANGE = RANGE - {{PaddingX, 0}, {PaddingY, 0}};

GeoGraphics[frame,
 GeoRange -> RANGE,
 GeoRangePadding -> None,
 GeoBackground -> White,
 GeoGridLines -> None,
 ImageSize -> 1100]

enter image description here

$\endgroup$

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.