moseslukegeomap 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Moses Luke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,376 @@
1
+ Metadata-Version: 2.4
2
+ Name: moseslukegeomap
3
+ Version: 0.1.0
4
+ Summary: Turn raw GIS files (shapefile, GeoJSON, GeoPackage) into clean, publication-ready maps with automatic labels, legend, scale bar and north arrow.
5
+ Author: Moses Luke
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Moses-L/geomapclean
8
+ Project-URL: Issues, https://github.com/Moses-L/geomapclean/issues
9
+ Keywords: gis,mapping,shapefile,choropleth,cartography,epidemiology,public health,labels
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Topic :: Scientific/Engineering :: GIS
12
+ Classifier: Intended Audience :: Science/Research
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: geopandas>=0.14
17
+ Requires-Dist: pyogrio>=0.7
18
+ Requires-Dist: shapely>=2.0
19
+ Requires-Dist: pyproj>=3.4
20
+ Requires-Dist: matplotlib>=3.7
21
+ Requires-Dist: numpy>=1.24
22
+ Requires-Dist: pandas>=2.0
23
+ Requires-Dist: mapclassify>=2.6
24
+ Provides-Extra: app
25
+ Requires-Dist: streamlit>=1.32; extra == "app"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7; extra == "dev"
28
+ Requires-Dist: streamlit>=1.32; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # MosesLukeGISmapdeveloper
32
+
33
+ **Clean, labelled, publication-ready maps from raw GIS data.** Upload a zipped shapefile, GeoJSON, GeoPackage or KML and get a finished map: areas coloured by your numbers, names that do not overlap, a legend, scale bar, north arrow and grid labels.
34
+
35
+ [![tests](https://github.com/Moses-L/geomapclean/actions/workflows/ci.yml/badge.svg)](https://github.com/Moses-L/geomapclean/actions/workflows/ci.yml)
36
+
37
+ ![Nigeria geopolitical zones](examples/gallery_nigeria_zones.png)
38
+
39
+ Built by Moses Luke for researchers, epidemiologists and programme teams who have boundary files and numbers but do not want to spend an afternoon in desktop GIS software to get a tidy figure. The Python package is called `moseslukegeomap` and the command is `geomapclean`.
40
+
41
+ ## Contents
42
+
43
+ 1. [Try it in two minutes](#1-try-it-in-two-minutes)
44
+ 2. [Install](#2-install)
45
+ 3. [Prepare your data](#3-prepare-your-data)
46
+ 4. [Walkthrough: the web app](#4-walkthrough-the-web-app)
47
+ 5. [Walkthrough: a worked example with real boundaries](#5-walkthrough-a-worked-example-with-real-boundaries)
48
+ 6. [Command line reference](#6-command-line-reference)
49
+ 7. [Python reference](#7-python-reference)
50
+ 8. [How it works](#8-how-it-works)
51
+ 9. [Troubleshooting](#9-troubleshooting)
52
+ 10. [Limits](#10-limits)
53
+ 11. [Hosting a public copy](#11-hosting-a-public-copy)
54
+ 12. [Development, citing and licence](#12-development-citing-and-licence)
55
+
56
+ ## 1. Try it in two minutes
57
+
58
+ You need Python 3.10 or newer. In a terminal (PowerShell on Windows):
59
+
60
+ ```bash
61
+ pip install "moseslukegeomap[app]"
62
+ geomapclean app
63
+ ```
64
+
65
+ Your browser opens the app. Switch on **Use the built-in demo** in the left sidebar. You will see a map of an invented island with named districts coloured by a made-up coverage figure. Nothing real is shown, so you can click around safely. Then upload your own file.
66
+
67
+ Prefer no app? This writes the same demo map to a file:
68
+
69
+ ```bash
70
+ pip install moseslukegeomap
71
+ geomapclean demo -o demo.png
72
+ ```
73
+
74
+ ## 2. Install
75
+
76
+ | Step | Windows | Mac and Linux |
77
+ |---|---|---|
78
+ | 1. Get Python 3.10 or newer | Download from python.org. On the first installer screen, tick **Add python.exe to PATH**. | Usually installed already. Check with `python3 --version`. |
79
+ | 2. Open a terminal | Press the Windows key, type PowerShell, press Enter. | Open Terminal. |
80
+ | 3. Install | `pip install "moseslukegeomap[app]"` | `pip3 install "moseslukegeomap[app]"` |
81
+ | 4. Check | `geomapclean --version` | `geomapclean --version` |
82
+
83
+ Leave out `[app]` if you only want the command line and Python library. No other software is needed. There is no separate GIS installation.
84
+
85
+ If `pip` is not recognised, Python is not on your PATH. Reinstall Python with the PATH box ticked, then open a new terminal window.
86
+
87
+ ## 3. Prepare your data
88
+
89
+ **Boundary file.** One of these:
90
+
91
+ | You have | Upload |
92
+ |---|---|
93
+ | Shapefile | Zip the whole set into one `.zip`. It needs `.shp`, `.shx` and `.dbf`. Include `.prj` so the projection is known. Do not rename the files separately. |
94
+ | GeoJSON, GeoPackage, KML | The file as it is. |
95
+ | A zip holding several layers | Fine. The app lists them and you pick one. |
96
+
97
+ Each row of the boundary file should be one area, with a column of names such as `District` or `ADM2_EN`.
98
+
99
+ **Numbers to show (optional).** A CSV or Excel file with one row per area and a column with the area name:
100
+
101
+ | district | coverage_pct |
102
+ |---|---|
103
+ | Northvale | 81.2 |
104
+ | Eastmoor | 64.5 |
105
+ | Saltmarsh | 72.0 |
106
+
107
+ The names do not have to match exactly. Capital letters, extra spaces and different dash characters are ignored. Spelling differences are reported with a suggested match.
108
+
109
+ ## 4. Walkthrough: the web app
110
+
111
+ Start it with `geomapclean app`. The page has four tabs: **Make a map**, **How to use it**, **How it works** and **About**. All controls are in the left sidebar.
112
+
113
+ ### Step 1: Upload your data
114
+
115
+ Drop your zip, GeoJSON, GeoPackage or KML into the upload box. If you have loose shapefile parts instead of a zip, select all of them together.
116
+
117
+ If the file holds several layers, a list appears. Choose the layer you want to map. A second list lets you pick a polygon layer to draw as bold outlines on top, for example state borders over district boundaries.
118
+
119
+ ### Step 2: Focus on part of the map (optional)
120
+
121
+ Choose a column and one or more values, for example `ADM1_EN` is `Lagos`. Only those areas are mapped. This is the best way to get every name onto a map that has many small areas.
122
+
123
+ ### Step 3: Attach your numbers (optional)
124
+
125
+ Upload your CSV or Excel file. Then choose which map column and which table column hold the area names. The report beside the map tells you how many areas matched, which did not, and what the closest spelling might be.
126
+
127
+ ### Step 4: Choose the style
128
+
129
+ | Setting | What it does |
130
+ |---|---|
131
+ | Title, subtitle, source line | Printed on the map. Always fill in the source line. |
132
+ | Colour areas by | The column that sets the colours. Leave as none for a plain base map. |
133
+ | Method | How to group numbers: quantiles, equal interval, natural breaks (jenks) or categorical. See the table below. |
134
+ | Classes | Number of colour groups, from 2 to 9. Five is a good default. |
135
+ | Colours | The colour scale. Use a diverging scale such as RdBu only when your data has a meaningful middle. |
136
+ | Legend title | Say what the numbers are and the unit, for example "Coverage (%)". |
137
+ | Label with | Which column supplies the names. The app picks one automatically. Choose "(no labels)" to switch labels off. |
138
+ | Label case | Keep as is, Title Case or UPPER CASE. |
139
+ | Small areas | Automatic, label with a leader line, or leave unlabelled. |
140
+ | Theme | Light, paper or dark. |
141
+ | Figure width | Wider figures fit more names. Use 20 or more for a poster. |
142
+ | Show | Switch the legend, scale bar, north arrow and graticule on or off. |
143
+
144
+ ### Choosing how to group numbers
145
+
146
+ | Method | Use it when | What it does |
147
+ |---|---|---|
148
+ | Quantiles | You want to compare areas by rank, such as top fifth against bottom fifth. | Puts the same number of areas in each group. |
149
+ | Equal interval | Values are fairly evenly spread and you want a plain scale. | Splits the range into equal steps. |
150
+ | Natural breaks (jenks) | Values form clusters. | Cuts where the data has gaps. |
151
+ | Categorical | The column holds categories such as zone or type. | One colour per category. |
152
+ | Manual (command line and Python) | You need set cut-offs such as 50, 80 and 95 per cent. | Uses the breaks you give. |
153
+
154
+ Different methods can tell different stories from the same data. State the method in your figure caption.
155
+
156
+ ### Step 5: Read the report
157
+
158
+ The panel next to the map shows features mapped, the projection used, labels placed and skipped, and any join problems. Read it before you export. A warning that areas are shown as "No data" almost always means a spelling mismatch in your table.
159
+
160
+ ### Step 6: Download
161
+
162
+ Switch on **Prepare high-resolution files**. You get a PNG at 300 dpi for documents and slides, an SVG you can edit in Inkscape or Illustrator, and a PDF for journals.
163
+
164
+ ## 5. Walkthrough: a worked example with real boundaries
165
+
166
+ This example uses national boundaries for Nigeria from the UN OCHA Common Operational Datasets (COD-AB). Download the Nigeria administrative boundaries from the Humanitarian Data Exchange and check the terms of use there. The zip holds layers for the country, 37 states, 774 LGAs and more.
167
+
168
+ **Goal:** a map of the six geopolitical zones, then a map of every LGA in Lagos State.
169
+
170
+ ### Map 1: zones, using a table
171
+
172
+ The file `examples/nigeria_geopolitical_zones.csv` lists each state and its zone.
173
+
174
+ ```bash
175
+ geomapclean inspect nga_boundaries.zip
176
+ ```
177
+
178
+ This lists every layer with its feature count and columns. The state layer is `nga_admbnda_adm1_osgof_20190417.shp` and its name column is `ADM1_EN`.
179
+
180
+ ```bash
181
+ geomapclean draw nga_boundaries.zip \
182
+ --layer nga_admbnda_adm1_osgof_20190417.shp \
183
+ --join examples/nigeria_geopolitical_zones.csv --join-key ADM1_EN=state \
184
+ --color-by geopolitical_zone --classification categorical \
185
+ --legend-title "Geopolitical zone" \
186
+ --title "Nigeria: geopolitical zones" \
187
+ --source "Boundaries: UN OCHA / OSGOF, COD-AB Nigeria (2019)." \
188
+ --label-case title -o zones.png
189
+ ```
190
+
191
+ The command prints `join: 37 of 37 map areas matched`, which confirms every state found its zone. The result is the map at the top of this page. (On Windows PowerShell, put the command on one line or end each line with a backtick instead of a backslash.)
192
+
193
+ ### Map 2: every LGA in one state
194
+
195
+ Mapping all 774 LGAs at once leaves most names off, because they cannot fit. Focus on one state instead:
196
+
197
+ ```bash
198
+ geomapclean draw nga_boundaries.zip --layer nga_admbnda_adm2_osgof_20190417.shp \
199
+ --where ADM1_EN=Lagos --title "Lagos State: Local Government Areas" \
200
+ --width 12 -o lagos.png
201
+ ```
202
+
203
+ ![Lagos LGAs](examples/gallery_lagos_lgas.png)
204
+
205
+ All 20 names appear. The central, crowded LGAs get a short leader line so their names stay readable. Because the Lagos extent is wide and short, the projection and the page shape were chosen for you.
206
+
207
+ ### Map 3: the whole country with state outlines
208
+
209
+ ```bash
210
+ geomapclean draw nga_boundaries.zip --layer nga_admbnda_adm2_osgof_20190417.shp \
211
+ --overlay-layer nga_admbnda_adm1_osgof_20190417.shp \
212
+ --title "Nigeria: 774 Local Government Areas" --width 12 -o nigeria_lgas.png
213
+ ```
214
+
215
+ ![Nigeria LGAs](examples/gallery_nigeria_lgas.png)
216
+
217
+ State names are drawn in bold capitals, and LGA names appear wherever they fit without crowding. The command tells you how many were left out and how to name more of them.
218
+
219
+ ## 6. Command line reference
220
+
221
+ ```text
222
+ geomapclean inspect FILE list layers, feature counts and columns
223
+ geomapclean draw FILE -o OUTPUT [options] draw a map
224
+ geomapclean demo -o demo.png draw the built-in demo
225
+ geomapclean app [streamlit options] start the web app
226
+ ```
227
+
228
+ `FILE` can be a zip, a folder, a `.shp`, `.geojson`, `.gpkg` or `.kml`. The output format comes from the file ending: `.png`, `.svg`, `.pdf`, `.jpg` or `.tif`.
229
+
230
+ | Option | Meaning |
231
+ |---|---|
232
+ | `--layer NAME` | Layer to draw when the file has several. Use the names printed by `inspect`. |
233
+ | `--overlay-layer NAME` | Polygon layer drawn as bold outlines on top. |
234
+ | `--where COL=VAL[,VAL]` | Keep only matching rows, for example `ADM1_EN=Lagos,Ogun`. |
235
+ | `--join FILE --join-key MAPCOL=TABLECOL` | Attach a CSV or Excel table by area name. |
236
+ | `--title`, `--subtitle`, `--source` | Text on the map. |
237
+ | `--color-by COL` | Column that sets the colours. |
238
+ | `--classification` | `auto`, `quantiles`, `equal`, `jenks`, `manual` or `categorical`. |
239
+ | `-k N` | Number of classes. |
240
+ | `--bins 10,20,50` | Break values for manual classification. |
241
+ | `--cmap NAME`, `--reverse-cmap` | Matplotlib colour scale, for example `Blues`, `viridis`, `RdBu`. |
242
+ | `--legend-title`, `--legend-loc` | Legend text, and corner (`upper left`, `lower right` and so on). |
243
+ | `--decimals N` | Decimal places in legend ranges. |
244
+ | `--label-column COL` | Column for names. Default picks one automatically. |
245
+ | `--label-case` | `as-is`, `title` or `upper`. |
246
+ | `--overflow` / `--no-overflow` | Force leader-line labels for small areas on or off. |
247
+ | `--label-max N` | Label at most N areas, largest first. |
248
+ | `--no-labels`, `--no-legend`, `--no-scale-bar`, `--no-north-arrow`, `--no-graticule`, `--no-frame`, `--no-crs-note` | Switch parts off. |
249
+ | `--theme` | `light`, `paper` or `dark`. |
250
+ | `--font NAME` | Preferred font. Falls back if it is not installed. |
251
+ | `--width INCHES` | Figure width. Default 10. |
252
+ | `--dpi N` | Resolution for PNG, JPG and TIF. Default 300. |
253
+ | `--crs auto\|EPSG` | Projection. `auto` chooses one. Give a code such as `32632` to force it. |
254
+ | `--assume-crs EPSG` | Projection to assume when the file has none. |
255
+ | `--credit` | Add a small "made with" line. |
256
+
257
+ ## 7. Python reference
258
+
259
+ ```python
260
+ import geopandas as gpd
261
+ from moseslukegeomap import make_map, MapOptions, join_table, read_table
262
+
263
+ states = gpd.read_file("states.shp")
264
+ table = read_table("coverage.csv")
265
+ states, report = join_table(states, table, left_on="STATE", right_on="state")
266
+ print(report["unmatched_in_map"], report["suggestions"]) # check the join
267
+
268
+ result = make_map(
269
+ states,
270
+ MapOptions(title="Coverage by state", color_by="coverage", k=5,
271
+ legend_title="Coverage (%)", source="Source: programme data, 2026"),
272
+ )
273
+ result.save("coverage.png", dpi=300) # also .svg, .pdf, .jpg, .tif
274
+ print(result.report) # labels placed and skipped, projection, notes
275
+ ```
276
+
277
+ `make_map(layer, options=None, overlay=None, **overrides)` returns a result with `.save(path, dpi)`, `.to_bytes(format, dpi)` and `.report`. Any option can also be passed directly, for example `make_map(states, title="X", theme="dark")`.
278
+
279
+ | `MapOptions` field | Default | Meaning |
280
+ |---|---|---|
281
+ | `title`, `subtitle`, `source` | none | Text printed on the map. |
282
+ | `labels` | `True` | Draw names. |
283
+ | `label_column` | `"auto"` | Name column. |
284
+ | `label_case` | `"as-is"` | `"as-is"`, `"title"` or `"upper"`. |
285
+ | `label_font_max`, `label_font_min` | 11, 5.5 | Text size range in points. |
286
+ | `label_overflow` | `None` | `None` is automatic, `True` uses leader lines, `False` leaves small areas blank. |
287
+ | `label_max` | none | Cap on the number of labels. |
288
+ | `color_by` | none | Column that sets the colours. |
289
+ | `classification` | `"auto"` | `quantiles`, `equal`, `jenks`, `manual`, `categorical`. |
290
+ | `k`, `bins` | 5, none | Class count, or manual breaks. |
291
+ | `cmap`, `reverse_cmap` | `YlOrRd`, `False` | Colour scale. |
292
+ | `legend`, `legend_title`, `legend_loc`, `decimals` | on, column name, `"auto"`, auto | Legend settings. |
293
+ | `north_arrow`, `scale_bar`, `graticule`, `frame`, `crs_note` | all `True` | Map furniture. |
294
+ | `theme`, `font`, `width_in` | `"light"`, auto, 10 | Look and size. |
295
+ | `point_size`, `line_width` | 5, 1 | For point and line layers. |
296
+ | `crs`, `assume_crs` | `"auto"`, none | Projection handling. |
297
+ | `credit` | `False` | Small "made with" line. |
298
+
299
+ Errors that you can fix (wrong column, missing projection, unreadable file) raise `moseslukegeomap.DataError` with a plain message.
300
+
301
+ ## 8. How it works
302
+
303
+ Every upload goes through the same stages. Your original file is never changed.
304
+
305
+ | Stage | What happens |
306
+ |---|---|
307
+ | Read | Zipped shapefiles, loose parts, GeoJSON, GeoPackage and KML are opened. Unzipping refuses unsafe paths. |
308
+ | Clean | Empty features are dropped, 3D is flattened, invalid polygons are repaired, the dominant geometry type is kept. A missing projection is assumed to be WGS 84 only if the numbers look like longitude and latitude. Otherwise the tool stops and asks. |
309
+ | Project | A small area gets a UTM zone. A country or region gets a Lambert azimuthal equal-area projection centred on the data. A world map gets Equal Earth. The choice is printed under the map. |
310
+ | Colour | Values are grouped into classes. Categories use a colour-blind-safe palette. Missing values get a "No data" class. |
311
+ | Lay out | Legend, scale bar and north arrow are placed in the emptiest corners. Margin is added if no corner is clear. |
312
+ | Label | Names are placed largest area first. See below. |
313
+ | Export | One layout is written as PNG, SVG, PDF, JPG or TIFF. Text is placed in points, so the layout is identical at any resolution. |
314
+
315
+ ### How the names are placed
316
+
317
+ 1. Each name is measured in the chosen font.
318
+ 2. For each area, the tool finds the point furthest from its edges.
319
+ 3. It tries the largest text size that fits inside the area, down to a minimum. Long names can split onto two lines.
320
+ 4. The name is kept only if it touches no earlier name, the legend, the scale bar or the north arrow.
321
+ 5. Text is white with a dark outline on dark fills, and dark with a white outline on light fills.
322
+ 6. Areas that are too small are left blank, or, if allowed, named beside the area with a thin leader line that avoids other text.
323
+
324
+ The test suite checks that no two pieces of text overlap, and the same check was run on every layer of a national boundary dataset during development.
325
+
326
+ ## 9. Troubleshooting
327
+
328
+ | What you see | Likely cause and fix |
329
+ |---|---|
330
+ | `pip` or `geomapclean` is not recognised | Python is not on your PATH. Reinstall Python with **Add python.exe to PATH** ticked and open a new terminal. |
331
+ | "No map data found" | The zip has no `.shp`, `.geojson`, `.gpkg` or `.kml` inside, or it is damaged. |
332
+ | "has no .dbf file" | The shapefile set is incomplete. Zip all parts together. |
333
+ | "The file has no coordinate system" | `.prj` is missing and the numbers are not longitude and latitude. Add the `.prj`, or pass `--assume-crs` with the EPSG code (in Python, `assume_crs=`). |
334
+ | "This upload holds several layers" | Choose one with `--layer`. Run `geomapclean inspect FILE` to see the names. |
335
+ | Areas show as "No data" | Their names did not match your table. Read the `join:` lines in the report, fix the spelling, and run again. |
336
+ | "repeated keys" | Two rows in your table have the same area name once case and spaces are ignored. Each area needs one row. |
337
+ | "too many for a categorical map" | The column has more than 20 different values. Use a numeric method, or group the categories first. |
338
+ | "is not numeric" | You asked for ranges on a text column. Use categorical, or clean the numbers in your table. |
339
+ | No labels drawn | No name column was found. Pass `--label-column` with the right column. |
340
+ | Many names missing | The areas are too small at this size. Use `--where` to map one region, raise `--width`, or add `--overflow`. |
341
+ | Text looks different on another computer | The preferred font was not installed and a fallback was used. Set `--font` to a font you have. |
342
+
343
+ ## 10. Limits
344
+
345
+ - Scale bar and north arrow are approximate. They are accurate near the map centre and drift slightly at the edges.
346
+ - Very large layers (over about 600,000 vertices) are lightly simplified for drawing, with no visible change at map scale.
347
+ - One thematic layer is drawn, with an optional outline layer on top. There are no basemap tiles, satellite images, rasters or inset maps. Use QGIS when you need those.
348
+ - It cannot name every area on a very dense map at a normal page size. It reports how many it left out.
349
+ - It does not check whether your boundaries are correct or current.
350
+
351
+ ## 11. Hosting a public copy
352
+
353
+ The repository contains `streamlit_app.py` and `requirements.txt`, which is what Streamlit Community Cloud needs.
354
+
355
+ 1. Sign in at share.streamlit.io with your GitHub account.
356
+ 2. Choose **Create app**, select the repository `Moses-L/geomapclean`, branch `main`, and main file `streamlit_app.py`.
357
+ 3. Deploy. The first build takes a few minutes.
358
+
359
+ The app processes uploads in memory and does not store them. Even so, tell users not to upload sensitive or identifiable data to a shared public server. For confidential data, each person should run the app on their own computer.
360
+
361
+ ## 12. Development, citing and licence
362
+
363
+ ```bash
364
+ git clone https://github.com/Moses-L/geomapclean
365
+ cd geomapclean
366
+ pip install -e ".[dev]"
367
+ pytest
368
+ ```
369
+
370
+ **Boundary data.** The package ships only a small invented demo layer ("Null Island"). The example maps use the UN OCHA / OSGOF Nigeria boundaries (COD-AB, 2019). Check the publisher's terms for any boundary data you use, and credit it on your map.
371
+
372
+ **Citing.** Use the "Cite this repository" button on GitHub, or the DOI on the release page once it is archived on Zenodo. Suggested wording for methods sections: "Maps were produced with MosesLukeGISmapdeveloper (geomapclean), Luke M."
373
+
374
+ **Licence.** MIT. See `LICENSE`.
375
+
376
+ **Author.** Moses Luke. GitHub: [Moses-L](https://github.com/Moses-L). ORCID: [0000-0002-0600-6660](https://orcid.org/0000-0002-0600-6660).