# How to add labels to GeoGridlines?

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

This code gets close:

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


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.

• Frame -> True, but this only works for well for equirectangular projection. See also this question. Jan 31 at 14:52

# 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}},
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],
GeoBackground->None,
GeoGridLines->None,
ImageSize->1100
]


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.

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}
];
{GeoStyling[Opacity[1]], FaceForm[White], EdgeForm[White],
GeoBoundsRegion[{{georange[[1, 1]] - 0.07,
georange[[1, 1]] - paddingsizex - 1}, {-179.9, 179.9}}]}
];
{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,
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]],
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;
MarkerScale = 1;
AxesLabelScale = 2;
Angle = (\[Pi]/180)*(-10);
Slope = 0.07;
frame = ConstructFrame[RANGE, XLines, YLines, FrameX, FrameY,
`