What is your favorite mapping package?

My requirements are:

  • Capable of plotting filled contours in the ocean
  • Land areas can be filled with the color of my choice
  • I can choose different mapping projections.
  • There are lots of sample codes available

I’m sure a log of the available mapping packages can do that. I wonder what will be the best one?


GMT.jl ticks all the boxes, except perhaps the last one (with the simpler syntax in Julia).
The mother GMT library ticks them all. Linking also this GMT6 overview article.


Hi. GMT.jl looks like a Swiss knife. You may also take a look at GeoDatasets.jl, Shapefile.jl, Makie.jl (and its derivatives).

1 Like

@leon do your tests with the packages of your choice (several of mentioned ones are not mapping packages) and tell us back your opinion.

1 Like

Many thanks for the recommendations!

It seems that GMT is a good choice. I’m surprised that no one has converted the M_map package into Julia:

M_map runs in Matlab. It uses Matlab’s (now Java) plotting libs.

1 Like

I have to admit that I am very curious about opinion of Julia Geo Community about kepler.gl. Do you think that it might be possible to use it explicitly with Julia in any foreseeable future? I just took a quick look at it, I understand its not as versatile as GMT.jl, however, I have to admit that I was impressed by its abilities and particularly its ease of use.


One thing I love M_map is because it has sample code for each type of maps, so it is super easy to use.

I wonder if anyone knows if GMT has such sample Julia codes available? It seems that the sample codes in the GMT library are not in Julia?

I have to admit that I would definitely be thrilled to have the ability to study GMT.jl examples in detail as well.

1 Like

Guys, it’s not so difficult to find them. See the documentation/gallery. For example here
and several other examples nearby.

There is also the historical collection but I’m not sure it all works. I lost the scripts file and possibly many examples (that are here more complex) may need re-work.


That’s awesome! Many thanks for sharing.

Thank you @joa-quim! I am really new to GMT.jl. Actually, I have never used it, however, several times I briefly familiarized myself with the documentation. I was not aware you are so close to it. Heaving the opportunity, may I ask you a short and a very general question? My aim is to produce about 15k plots a day consisting of i) a map in Mercator projection, ii) heatmap generated with the use of netCDF file, iii) lines of points encoded in a gpx / kml file and maybe in the future iv) additional layer with geotiff rasters. Is GMT a right tool?

Yep, sure. Just not sure what is gpx. All the rest should be trivial tasks.

Great. This might not be immediately, however, I will definitely give it a try. Many thanks!

GPX , or GPS Exchange Format, is an [XML schema] designed as a common [GPS] data format for software applications. https://en.wikipedia.org/wiki/GPS_Exchange_Format

Ah, I knew the gpx sounded vaguely familiar. And if GDAL can read/decode it then so should GMT.

I guess GDAL is another Swiss knife, and GPX is a very popular format so I am not expecting any problems in this field. I just installed GMT.jl and was able to prepare the first plots.

Cool, let me take the risk (several things may go wrong) of suggesting these commands. If you have a GDAL built with expat (you do if you installed GMT.jl on Windows), do

data = gmtread("/path/to/gpx");

… and the authors acknowledge it here! :slight_smile:


You guys make me smiling. :wink:

So far, I have been using Gadfly to prepare statistical plots and CairoMakie to do quasi geo plotting in a sense that I plotted my geo data. However, my plots were missing coastlines and there was no proper reference to latitues and longitudes. Despite it, the plots were very helpful with understanding the subject. I also used kepler.gl to do a little more interactive analysis especially in reference to GPX data. I really like the ease of use of GMT.jl in relation to plotting coastalines and geo referenced netCDF data. This is my understanding after some very preliminary tests.

I installed GMT and GMT.jl according to the info from my post: https://discourse.julialang.org/t/errors-associated-with-using-gmt/70393/18

Im on:
NAME="Ubuntu", VERSION="20.04.2 LTS (Focal Fossa)" over SSH.

Julia Version 1.8.0-DEV.829
Commit d71b77d7b6 (2021-10-27 00:39 UTC)
JULIA_EDITOR = "/home/username/.vscode-server/bin/[...]/node"

My Julia env consits of:

Status `~/data/geo_gmt/Project.toml`
  [5752ebe1] GMT v0.38.0
  [6099a3de] PythonCall v0.4.2 `https://github.com/cjdoris/PythonCall.jl.git#master`

My Conda env consists of:

Status /home/username/data/geo_gmt/PythonCallDeps.toml
Conda channels:
Conda packages:
  gmt =6.2


shell> gmt --version

shell> gdal-config --version

shell> gdal-config --libs
-L/home/username/data/geo_gmt/conda_env/lib -lgdal

shell> gdal-config --dep-libs
-lcrypto -L/home/username/data/geo_gmt/conda_env/lib -ltiledb -L/home/username/data/geo_gmt/conda_env/lib -lpoppler -ljson-c -L/home/username/data/geo_gmt/conda_env/lib -L/home/username/data/geo_gmt/conda_env/lib -lfreexl -L/home/username/data/geo_gmt/conda_env/lib -lgeos_c -L/home/username/data/geo_gmt/conda_env/lib -lwebp -L/home/username/data/geo_gmt/conda_env/lib -lkmlbase -lkmldom -lkmlengine -lkmlxsd -lkmlregionator -L/home/username/data/geo_gmt/conda_env/lib -lexpat -L/home/username/data/geo_gmt/conda_env/lib -lxerces-c -lpthread -L/home/username/data/geo_gmt/conda_env/lib -lopenjp2 -L/home/username/data/geo_gmt/conda_env/lib -lnetcdf -L/home/username/data/geo_gmt/conda_env/lib -lhdf5 -L/home/username/data/geo_gmt/conda_env/lib -lmfhdf -ldf -lgif -L/home/username/data/geo_gmt/conda_env/lib -lgeotiff -L/home/username/data/geo_gmt/conda_env -L/home/username/data/geo_gmt/conda_env/lib -lpng -L/home/username/data/geo_gmt/conda_env -L/home/username/data/geo_gmt/conda_env/lib -lcfitsio -L/home/username/data/geo_gmt/conda_env/lib -lpq -L/home/username/data/geo_gmt/conda_env/lib -lzstd -llzma -L/home/username/data/geo_gmt/conda_env/lib -lsqlite3 -L/home/username/data/geo_gmt/conda_env/lib -lproj -L/home/username/data/geo_gmt/conda_env/lib -lsqlite3 -L/home/username/data/geo_gmt/conda_env/lib -ltiff -L/home/username/data/geo_gmt/conda_env -L/home/username/data/geo_gmt/conda_env/lib -ljpeg -ldeflate -lz -L/home/username/data/geo_gmt/conda_env -L/home/username/data/geo_gmt/conda_env/lib -lpthread -lm -lrt -ldl -L/home/username/data/geo_gmt/conda_env/lib -lspatialite -L/home/username/data/geo_gmt/conda_env/lib64 -L/home/username/data/geo_gmt/conda_env/lib -ldap -ldapserver -ldapclient -L/home/username/data/geo_gmt/conda_env/lib -lcurl -L/home/username/data/geo_gmt/conda_env/lib -lxml2 -L/home/username/data/geo_gmt/conda_env/lib -lz -L/home/username/data/geo_gmt/conda_env/lib -llzma -lpthread -L/home/username/data/geo_gmt/conda_env/lib -liconv -L/home/username/data/geo_gmt/conda_env/lib -licui18n -licuuc -licudata -lm -ldl -lpthread -luuid -lpcre -lLerc -L/home/username/data/geo_gmt/conda_env/lib -lcurl -liconv -L/home/username/data/geo_gmt/conda_env/lib -lxml2 -L/home/username/data/geo_gmt/conda_env/lib -lkea -L/home/username/data/geo_gmt/conda_env/lib -lhdf5_cpp -lhdf5

shell> gdal-config --cflags

shell> gdal-config --datadir

shell> gdal-config --ogr-enabled

shell> gdal-config --gnm-enabled

shell> gdal-config --formats
derived gtiff hfa mem vrt aaigrid adrg aigrid airsar arg blx bmp bsb cals ceos ceos2 coasp cosar ctg dimap dted elas envisat ers esric fit gff gsg gxf hf2 idrisi ilwis ingr iris iso8211 jaxapalsar jdem kmlsuperoverlay l1b leveller map mrf msgn ngsgeoid nitf northwood pds prf r raw rmf rs2 safe saga sdts sentinel2 sgi sigdem srtmhgt stacta terragen tga til tsx usgsdem xpm xyz zmap rik ozi eeda plmosaic rda wcs wms wmts daas ogcapi rasterlite mbtiles grib pdf tiledb webp dods openjpeg netcdf kea hdf5 hdf4 gif png pcraster fits jpeg pcidsk postgisraster

Problem 1:

fname = "path/to/netCDF4";
G = gmtread(fname, grd=true);
imshow(G, region=:global, projection=:Mollweide, frame=:ag, title="my title", figsize=15, colorbar=true, coast=true)

The image seems to be plotteing correctly, saved to /home/username/tmp/GMTjl_tmp.png (its possible to open this file and to see the plot), however, I am getting:

ERROR: LoadError: IOError: could not spawn `xdg-open /home/username/tmp/GMTjl_tmp.png`: no such file or directory (ENOENT)
  [1] _spawn_primitive(file::String, cmd::Cmd, stdio::Vector{Any})
    @ Base ./process.jl:102
  [2] #702
    @ ./process.jl:115 [inlined]
  [3] setup_stdios(f::Base.var"#702#703"{Cmd}, stdios::Vector{Any})
    @ Base ./process.jl:199
  [4] _spawn
    @ ./process.jl:114 [inlined]
  [5] run(::Cmd; wait::Bool)
    @ Base ./process.jl:443
  [6] run
    @ ./process.jl:442 [inlined]
  [7] showfig(d::Dict{Symbol, Any}, fname_ps::String, fname_ext::String, opt_T::String, K::Bool, fname::String)
    @ GMT ~/.julia/packages/GMT/TPV4a/src/common_options.jl:3291
  [8] finish_PS_module(::Dict{Symbol, Any}, ::Vector{String}, ::String, ::Bool, ::Bool, ::Bool, ::GMTgrid{Float32, 2}, ::Vararg{Any})
    @ GMT ~/.julia/packages/GMT/TPV4a/src/common_options.jl:3428
  [9] grdimage(cmd0::String, arg1::GMTgrid{Float32, 2}, arg2::Nothing, arg3::Nothing; first::Bool, kwargs::Base.Pairs{Symbol, Any, NTuple{8, Symbol}, NamedTuple{(:show, :colorbar, :region, :frame, :title, :coast, :projection, :figsize), Tuple{Bool, Bool, Symbol, Symbol, String, Bool, Symbol, Int64}}})
    @ GMT ~/.julia/packages/GMT/TPV4a/src/grdimage.jl:126
 [10] imshow(arg1::GMTgrid{Float32, 2}; kw::Base.Pairs{Symbol, Any, NTuple{7, Symbol}, NamedTuple{(:region, :projection, :frame, :title, :figsize, :colorbar, :coast), Tuple{Symbol, Symbol, Symbol, String, Int64, Bool, Bool}}})
    @ GMT ~/.julia/packages/GMT/TPV4a/src/imshow.jl:88
 [11] top-level scope
    @ ~/data/geo_gmt/geo_gmt.jl:105
in expression starting at /home/username/data/geo_gmt/geo_gmt.jl:105

Problem 2:

data = "/path/to/gpx"

I am getting

ERROR 4: `/path/to/gpx' not recognized as a supported file format.
grdinfo (gmtapi_import_grid): Not a supported grid format [/path/to/gpx]
[Session GMT (2)]: Error returned from GMT API: GMT_GRID_READ_ERROR (18)
[Session GMT (2)]: Error returned from GMT API: GMT_GRID_READ_ERROR (18)
ERROR: LoadError: BoundsError: attempt to access 0-element Vector{GMTdataset} at index [1]
 [1] getindex(A::Vector{GMTdataset}, i1::Int64)
   @ Base ./array.jl:921
 [2] snif_GI_set_CTRLlimits(G_I::String)
   @ GMT ~/.julia/packages/GMT/TPV4a/src/imshow.jl:133
 [3] imshow(arg1::String, x::Vector{Float64}, y::Vector{Float64}; kw::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ GMT ~/.julia/packages/GMT/TPV4a/src/imshow.jl:45
 [4] imshow (repeats 3 times)
   @ ~/.julia/packages/GMT/TPV4a/src/imshow.jl:36 [inlined]
 [5] top-level scope
   @ ~/data/geo_gmt/geo_gmt.jl:116
in expression starting at /home/username/data/geo_gmt/geo_gmt.jl:116

Similar errors I am getting when trying to plot the same data that is encoded in gpx when using csv, json, geojson, kml, txt files.

I also tried gdal-config --version 3.3.1 from conda_channels = [“nasa-ames-stereo-pipeline”]. In this case, there were some conflicts when trying to install GMT 6.2.0 and there seems to be no support for gpx in this GDAL version as well.

Is there any GDAL version at Conda that is supporting gpx? How complicated / difficult is the build process? I’ve been using Linux for about 1 year. I have done only a few builds with cmake of Fortran and Go software. This is a hobby project, I can not commit all my time, however, should you be willing to provide some advice, I would be very interested to try to make it work. Also pls be informed that I might not reply immediately to your potential messages as I have some due answers to prepare also on this forum. However, I would really appreciate some additional info!

Problem 1: With one exception, GMT produces PostScript only that is automatically converted into raster formats by the psconvert program. Next, each OS calls the program that automatically displays the figs. In Linux it’s xdg-open, and that normally comes with Linux. It seems that it’s not your case. You will have to install it.

Problem 2: imshow is a convenient function that parses input and calls the grdimage or grdview modules for grids/images and in a lesser extent, the plot command for vector data. This later ability needs further improvements, specially when you pass the file name instead of the data. Please try as I said: data = gmtread("/path/to/gpx"); imshow(data) but be aware that the full control for line plots is provided by the plot function.

See this GADM example. Data comes in geopackage format.

EDIT: I remembered that gpx may not be an automatically detected format (by extension) so you probably will need to do

data = gmtread("/path/to/gpx", ogr=true);
1 Like