Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERROR: GMT: Expects a Matrix for input #396

Closed
htyeim opened this issue Jul 15, 2020 · 28 comments
Closed

ERROR: GMT: Expects a Matrix for input #396

htyeim opened this issue Jul 15, 2020 · 28 comments

Comments

@htyeim
Copy link
Contributor

htyeim commented Jul 15, 2020

It seems that users can't use makecpt between gmtbegin() and gmtend()

ERROR: GMT: Expects a Matrix for input

using GMT

vvalues = (0.0, 70.0)

gmtbegin()
gmtfig("test.png")
cb_jet = makecpt(color=:jet, range=vvalues, 
                    continuous=true);

colorbar(pos=(anchor = :TC, length = (9.5, 0.2), 
        horizontal = true, offset = (0, 2.17),),
        color=cb_jet, 
        frame=(annot = :auto, ticks = :auto, 
                    xlabel = "test",),
        par=(FONT_LABEL = 9, FONT_ANNOT_PRIMARY = 5, MAP_LABEL_OFFSET = 0.01,),
        x_offset=0,
        y_offset=-0.4,
        # Vd = Vd,
        R="0/1/0/1",
)
gmtend()

works fine

using GMT

vvalues = (0.0, 70.0)
cb_jet = makecpt(color=:jet, range=vvalues, 
                    continuous=true);

gmtbegin()
gmtfig("test.png")

colorbar(pos=(anchor = :TC, length = (9.5, 0.2), 
        horizontal = true, offset = (0, 2.17),),
        color=cb_jet, 
        frame=(annot = :auto, ticks = :auto, 
                    xlabel = "test",),
        par=(FONT_LABEL = 9, FONT_ANNOT_PRIMARY = 5, MAP_LABEL_OFFSET = 0.01,),
        x_offset=0,
        y_offset=-0.4,
        # Vd = Vd,
        R="0/1/0/1",
)
gmtend()

This might imply that one must do all makecpt before starting a session?
But in my case, I usually plot several axes in one figure (session), and it is necessary to use different cpts, especially when making movies.
I found that the last line of makecpt begins with global current_cpt. The gmt document says
"In classic mode we write the CMT to standard output, while under modern mode we simply save the CPT as the current session CPT (but see -H). " ref. However, I haven't found the corresponding H parameter in GMT.jl's makecpt...
Is this the problem?

@htyeim
Copy link
Contributor Author

htyeim commented Jul 15, 2020

OK, I have found that adding " -H " in makecpt would solve the problem....
Maybe it's a new feature of gmt and haven't been added to GMT.jl?

using GMT

vvalues = (0.0, 70.0)

gmtbegin()
gmtfig("test.png")
cb_jet = makecpt(" -H ", color=:jet, range=vvalues, 
                    continuous=true);

colorbar(pos=(anchor = :TC, length = (9.5, 0.2), 
        horizontal = true, offset = (0, 2.17),),
        color=cb_jet, 
        frame=(annot = :auto, ticks = :auto, 
                    xlabel = "test",),
        par=(FONT_LABEL = 9, FONT_ANNOT_PRIMARY = 5, MAP_LABEL_OFFSET = 0.01,),
        x_offset=0,
        y_offset=-0.4,
        # Vd = Vd,
        R="0/1/0/1",
)
gmtend()

@joa-quim
Copy link
Member

joa-quim commented Jul 15, 2020

Sorry, it's not listed in header help but it does exist. Line 93 of makecpt.jl

if (IamModern[1] && ((val = find_in_dict(d, [:H :save])[1]) !== nothing))  cmd *= " -H"  end

@htyeim
Copy link
Contributor Author

htyeim commented Jul 15, 2020

Got it, thanks!


I have been trying to use movie, so far, the result is negative 😰 .
It generates a complete set of sh files. But one of the reasons I only use GMT.jl is that I never want to learn the complex usage of bash (or whatever sh...).

Here I can only provide some feedback...
I read the page.
Then I mkdir gmttmp, in Julia activate . add GMT#master, and copied the example code, and ran it in the tmp directory.
What I got is shown below:

julia> include("test_movie.jl")
        movie main_script.sh -C15x15x100 -Nglobe -Lf -A -P -T360
coast [WARNING]: ${MOVIE_WIDTH} not a valid number and may not be decoded properly.
coast [ERROR]: Could not decode ${MOVIE_FRAME}, return NaN.
coast [ERROR]: Option -J parsing failure. Correct syntax:
        -Jg<lon0>/<lat0>[/<horizon>]/<scale> OR -JG<lon0>/<lat0>[/<horizon>]/<width>
          <horizon> is distance from center to perimeter (<= 90, default 90)
          <scale> is <1:xxxx> or <radius> (in cm)/<lat>, or use <width> in cm
coast [ERROR]: Offending option -JG${MOVIE_FRAME}/20/${MOVIE_WIDTH}
coast [WARNING]: ${MOVIE_WIDTH} not a valid number and may not be decoded properly.
coast [ERROR]: Could not decode ${MOVIE_FRAME}, return NaN.
coast [ERROR]: Option -J parsing failure. Correct syntax:
        -Jg<lon0>/<lat0>[/<horizon>]/<scale> OR -JG<lon0>/<lat0>[/<horizon>]/<width>
          <horizon> is distance from center to perimeter (<= 90, default 90)
          <scale> is <1:xxxx> or <radius> (in cm)/<lat>, or use <width> in cm
coast [ERROR]: Offending option -JG${MOVIE_FRAME}/20/${MOVIE_WIDTH}
coast [WARNING]: ${MOVIE_WIDTH} not a valid number and may not be decoded properly.
coast [ERROR]: Could not decode ${MOVIE_FRAME}, return NaN.
coast [ERROR]: Option -J parsing failure. Correct syntax:
        -Jg<lon0>/<lat0>[/<horizon>]/<scale> OR -JG<lon0>/<lat0>[/<horizon>]/<width>
coast [WARNING]: ${MOVIE_WIDTH} not a valid number and may not be decoded properly.
          <horizon> is distance from center to perimeter (<= 90, default 90)
coast [ERROR]: Could not decode ${MOVIE_FRAME}, return NaN.
          <scale> is <1:xxxx> or <radius> (in cm)/<lat>, or use <width> in cm
coast [ERROR]: Offending option -JG${MOVIE_FRAME}/20/${MOVIE_WIDTH}
coast [ERROR]: Option -J parsing failure. Correct syntax:
        -Jg<lon0>/<lat0>[/<horizon>]/<scale> OR -JG<lon0>/<lat0>[/<horizon>]/<width>
          <horizon> is distance from center to perimeter (<= 90, default 90)
          <scale> is <1:xxxx> or <radius> (in cm)/<lat>, or use <width> in cm
coast [ERROR]: Offending option -JG${MOVIE_FRAME}/20/${MOVIE_WIDTH}
coast [WARNING]: ${MOVIE_WIDTH} not a valid number and may not be decoded properly.
coast [ERROR]: Could not decode ${MOVIE_FRAME}, return NaN.
coast [ERROR]: Option -J parsing failure. Correct syntax:
        -Jg<lon0>/<lat0>[/<horizon>]/<scale> OR -JG<lon0>/<lat0>[/<horizon>]/<width>
          <horizon> is distance from center to perimeter (<= 90, default 90)
          <scale> is <1:xxxx> or <radius> (in cm)/<lat>, or use <width> in cm
coast [ERROR]: Offending option -JG${MOVIE_FRAME}/20/${MOVIE_WIDTH}
coast [WARNING]: ${MOVIE_WIDTH} not a valid number and may not be decoded properly.
coast [ERROR]: Could not decode ${MOVIE_FRAME}, return NaN.
coast [ERROR]: Option -J parsing failure. Correct syntax:
        -Jg<lon0>/<lat0>[/<horizon>]/<scale> OR -JG<lon0>/<lat0>[/<horizon>]/<width>
          <horizon> is distance from center to perimeter (<= 90, default 90)
          <scale> is <1:xxxx> or <radius> (in cm)/<lat>, or use <width> in cm
coast [ERROR]: Offending option -JG${MOVIE_FRAME}/20/${MOVIE_WIDTH}
coast [WARNING]: ${MOVIE_WIDTH} not a valid number and may not be decoded properly.
coast [ERROR]: Could not decode ${MOVIE_FRAME}, return NaN.
coast [ERROR]: Option -J parsing failure. Correct syntax:
        -Jg<lon0>/<lat0>[/<horizon>]/<scale> OR -JG<lon0>/<lat0>[/<horizon>]/<width>
          <horizon> is distance from center to perimeter (<= 90, default 90)
          <scale> is <1:xxxx> or <radius> (in cm)/<lat>, or use <width> in cm
coast [ERROR]: Offending option -JG${MOVIE_FRAME}/20/${MOVIE_WIDTH}
end [WARNING]: Figure # 1 (../globe_001) was registered but no matching PostScript-|+ file found - skipping
end [WARNING]: Figure # 1 (../globe_006) was registered but no matching PostScript-|+ file found - skipping
end [WARNING]: Figure # 1 (../globe_005) was registered but no matching PostScript-|+ file found - skipping
end [WARNING]: Figure # 1 (../globe_003) was registered but no matching PostScript-|+ file found - skipping
end [WARNING]: Figure # 1 (../globe_000) was registered but no matching PostScript-|+ file found - skipping
end [WARNING]: Figure # 1 (../globe_004) was registered but no matching PostScript-|+ file found - skipping
end [WARNING]: Figure # 1 (../globe_002) was registered but no matching PostScript-|+ file found - skipping

The julia shell has being staying at this point and no further process... So I can't produce the gif as in the document...


the content in the directory after finishing these commands

drwx------ 2 t t 20480 Jul 15 18:23 globe
-rw-r--r-- 1 t t   112 Jul 15 18:23 main_script.sh
-rw-r--r-- 1 t t   524 Jul 15 12:15 Manifest.toml
-rw-r--r-- 1 t t    52 Jul 15 12:15 Project.toml
-rw-r--r-- 1 t t   300 Jul 15 18:22 test_movie.jl

In globe directory, there are a lot of sh file, but the movie_params_* files start from movie_params_007.sh (no 001-006). This might cause the problem (?).

Using sh files seems too complex to me. I think, for me, the best procedure might be this:

gmtbegin()
gmtfig(:inmemory) #  which means I want to store it in memory and then use it as a background picture
# some code balabal
tmp = gmtend() # the background tmp structure data is assigned to tmp

#===========================#

allframes = []

for ii in 1:360 # or whatever frames
  gmtfig(:inmemory) # or maybe save to png 
  gmtbegin() # or gmtbegin(tmp) ?
     this_background = copy(tmp) # start from the background
    # some other code
  
  thisframe = gmtend() # again store the data in memory when gmtend
  push!(allframes, thisframe,)
end

#=============================#

movie(allframes,"filename.mp4") 
# or maybe this can move to each frame: https://juliaio.github.io/VideoIO.jl/stable/writing/#Iterative-Encoding-1

It's only my personal thinking. The main feature is to provide a way to store the temporary figure data for later manipulation. Another thing is to provide function that user can define crop region (maybe the canvas, but I can't check it as the movie example above hasn't completed....).
I have never checked the gmt code, so this might be impossible now.

@joa-quim
Copy link
Member

OK, I see already a problem. The movie examples in Unix use, e.g. \${MOVIE_FRAME} but the code that I generate lacks the leading slash. I think that's the cause of the error

coast [WARNING]: ${MOVIE_WIDTH} not a valid number and may not be decoded properly.

The idea with movie.jl is that one do not need to fuzz with the shell scripts. But apparently not yet.
You don't need to create a tmp dir, movie does that for you (the name=... option).

Start by using Vd=2 and run the command in the bash shell like I said before. This avoids hanging the Julia REPL in case things go wrong. You will probably also need to edit main_script.sh and change pscoast to coast (this is something I will fix in later commits).

@joa-quim
Copy link
Member

joa-quim commented Jul 15, 2020

Installed GMT & Julia in my Centos8 VM. Fixed the names and slash issues (in master). And both of these worked

julia> function main_sc()
           coast(region=:global, proj=(name=:Ortho, center=("MOVIE_FRAME",20)), figsize="MOVIE_WIDTH", land=:maroon, water=:turquoise, frame=:g, X=0, Y=0)
       end
main_sc (generic function with 1 method)

julia> movie(main_sc, name=:globe, frames=360, gif=true, canvas="15x15x100", label=:f, progress=true, Vd=1)
        movie main_script.sh -C15x15x100 -Nglobe -Lf -A -P -T360
movie [NOTICE]: Running: gm convert -delay 4 -loop 1 +dither globe/globe_*.png globe.gif

and running with Vd=2 plus running this on bash

gmt movie main_script.sh -C15x15x100 -Nglobe -Lf -A -P -T360

@htyeim
Copy link
Contributor Author

htyeim commented Jul 16, 2020

It works also in Archlinux

(@v1.4) pkg> activate .
 Activating environment at `~/test_GMT/Project.toml`

julia> include("test_movie.jl")
        movie main_script.sh -C15x15x100 -Nglobe -Lf -A -P -T360
movie [NOTICE]: Running: gm convert -delay 4 -loop 1 +dither globe/globe_*.png globe.gif
118.279850 seconds (3.60 M allocations: 169.211 MiB, 0.03% gc time)

julia> 

But the convertion from the figures to the gif consumes a lot of memory

test

It might related to that gm convert loads all figures before converting (similar to this).


I also don't have a clear idea how to input complex data for each frame when all the plotting are done in sh....
For example the data shown below:
1

2

All axes involve contour interpolation of different data (stored in sqlite data file ~120GB). And the interpolation is very slow. Even I use the HPC at my laboratory the plotting can last for days...
For one specie, all the figures at 2161 different times will take 6 hours

-rw-r--r-- 1 t t 101035 Jul 15 15:03 output_deni_ptep_000000001_6.000277777777779.png
-rw-r--r-- 1 t t 282511 Jul 15 21:03 output_deni_ptep_000002161_9.000277777777782.png

So I run three julia at the same time on the HPC 😄
hpc_3julia
Anyway it's another story.

For converting from pngs to mp4, I use Iterative-Encoding which could save a lot of memory...
I tried Single-step-Encoding when I write the related code. But it costumes a lot memory (as now gm convert do) so I changed to Iterative-Encoding.

Here is the final output (after hours of plotting)
test.mp4.zip

@joa-quim
Copy link
Member

That example is using gif but you could change the format to mpeg by using format="mp4" which uses ffmpeg. However, you are right. The biggest problem with movie.jl is that the scripts cannot use Julia code because there is no Julia involved in the computations. All Julia does is to convert syntax. We can think in expanding the movie.c capabilities to call Julia, via system calls, but given the Time-to-first-plot issues in Julia, I'm afraid the total time would be very large. I don't know a way of doing repeated system calls to the same Julia process.

So you never tried to try to reuse the mesh in contour to do further interpolations. You can raise this issue in the forum.
Nice movie.

@htyeim
Copy link
Contributor Author

htyeim commented Jul 16, 2020

I think that the procedure of current movie function is very similar to my code, plot each figure and then combine them together. In general, I prefer to do all things in one language (Julia now). So I may try the function later...

I think I ran some example code related to interpolation (triangulate) but I haven't tried to implement something based on it (the output data is complex for me 🤣 )

@htyeim
Copy link
Contributor Author

htyeim commented Jul 16, 2020

Since the document in master branch has been updated (-H makecpt), this issue could be closed~

@htyeim htyeim closed this as completed Jul 16, 2020
@joa-quim
Copy link
Member

What the movie program has is the facilities to calculate perspective, viewpoint and so on that allow doing movies like those in the animations much easier. But I agree that it should be possible to reason Julia only ... but that TTFP delay is deadly.

@joa-quim
Copy link
Member

(the output data is complex for me 🤣 )

Nothing really complicated. You have two files. One with the data triplets (x,y,z) and another with 3 indices per row of each traingle. The indices in second file refer to line numbers in first file.

@htyeim
Copy link
Contributor Author

htyeim commented Jul 17, 2020

I have tested triangulate extensively in the past few hours. But I haven't got result I want.

data preparation

using GMT
using BenchmarkTools

    R = :g
    G = gmt("grdmath -R$R -I0.5 X Y MUL =");
    xyz = grd2xyz(G)


    t1 = triangulate(xyz, )
    fn_tg = "triangulate.txt"
    gmtwrite(fn_tg, t1)
    fn_ds = "xyz.txt"
    gmtwrite(fn_ds, xyz)
    
    cb_jet = makecpt(color=:jet, range=(-4e4, 4e4, 1e3))

some benchmark

  1. triangulate
julia> @benchmark t1 = triangulate(xyz, )
BenchmarkTools.Trial: 
  memory estimate:  17.83 MiB
  allocs estimate:  240
  --------------
  minimum time:     229.609 ms (0.00% GC)
  median time:      239.570 ms (0.00% GC)
  mean time:        244.705 ms (2.01% GC)
  maximum time:     289.117 ms (16.21% GC)
  --------------
  samples:          21
  evals/sample:     1
  1. gmtread
julia> @benchmark xyz_read = gmtread(fn_ds)
BenchmarkTools.Trial: 
  memory estimate:  5.97 MiB
  allocs estimate:  205
  --------------
  minimum time:     114.579 ms (0.00% GC)
  median time:      116.363 ms (0.00% GC)
  mean time:        116.408 ms (0.03% GC)
  maximum time:     119.399 ms (0.22% GC)
  --------------
  samples:          43
  evals/sample:     1

So the main part of time might be used to triangulate.

case 1 no mesh information: 374.942 ms

    @benchmark contour(xyz,
                    pen="0.15p,+c",
                    # mesh="0.01p",
                    # index=t1,
                    # index=fn_tg,
                    annot=(labels = (font = 1, prefix = "test ",),),
                    color=cb_jet,
                    # Vd = 1,
                    region=R,
                    # show=true,
                    # fmt=:png
                )
BenchmarkTools.Trial: 
  memory estimate:  12.19 MiB
  allocs estimate:  3317
  --------------
  minimum time:     360.554 ms (0.16% GC)
  median time:      374.942 ms (0.00% GC)
  mean time:        376.999 ms (0.03% GC)
  maximum time:     422.016 ms (0.11% GC)
  --------------
  samples:          14
  evals/sample:     1 

case 2 mesh information in file: 318.378 ms

    @benchmark contour(xyz,
                    pen="0.15p,+c",
                    # mesh="0.01p",
                    # index=t1,
                    index=fn_tg,
                    annot=(labels = (font = 1, prefix = "test ",),),
                    color=cb_jet,
                    # Vd = 1,
                    region=R,
                    # show=true,
                    # fmt=:png
                )
BenchmarkTools.Trial: 
  memory estimate:  12.19 MiB
  allocs estimate:  3321
  --------------
  minimum time:     312.193 ms (0.14% GC)
  median time:      318.378 ms (0.00% GC)
  mean time:        321.183 ms (0.03% GC)
  maximum time:     339.904 ms (0.00% GC)
  --------------
  samples:          16
  evals/sample:     1

case 3 mesh information in Mx3 array: Segmentation fault

    @time contour(xyz,
            pen="0.15p,+c",
            # mesh="0.01p",
            index=t1[1].data,
            # index=fn_tg,
            annot=(labels = (font = 1, prefix = "MLAT ",),),
            # fill = true,
            color=cb_jet,
            # Vd = 1,
            region=R,
            # show=true,
            # fmt=:png
        )
signal (11): Segmentation fault
in expression starting at REPL[170]:1
gmt_strtok at /usr/lib/libgmt.so (unknown line)
GMT_Create_Options at /usr/lib/libgmt.so (unknown line)
unknown function (ip: 0x353435322f302e35)
Allocations: 98529301 (Pool: 98521771; Big: 7530); GC: 108

[1]    1111131 segmentation fault (core dumped)  julia

It seems that if the mesh information is provided, the contour would be some speedup (maybe the time would be spent in gmtread instead of triangulate). If the Mx3 array (as said at doc) could be passed directly, the time could be decreased more(?), but when passing the array to contour, a signal (11): Segmentation fault will rise...

@joa-quim
Copy link
Member

joa-quim commented Jul 17, 2020

OK, will investigate the crash. The index=... code in pscontour.jl is silly but a quick fix revealed some other problem but GMT should not crash. This also revealed another bug in GMT (tried to read binary files to see if that would speed up but stumped in that bug).

@htyeim
Copy link
Contributor Author

htyeim commented Jul 17, 2020

Thank you~ I think I almost become a bug trigger 😂

@joa-quim
Copy link
Member

I have that gift myself as well.

@joa-quim
Copy link
Member

joa-quim commented Jul 17, 2020

One big reason for slowness is the file reading. GMT is slow reading files because it does check an a lot of possible cases. Speeding it up has been one thing I push but it's still waiting.
I get much better results if I convert first the triangulate.txt into a binary file and use it instead. To be quick I did the conversion with plain GMT in command line. e.g.

gmtconvert triangulate.txt -bo3f > triangulate.bin

The julia version is supposed to work too but that's something I have not tested.
Next I do

julia> @benchmark contour(xyz,pen="0.15p,+c",annot=(labels=(font=1, prefix ="test"),), color=cb_jet, region=:g, index="triangulate.bin", binary_in="3f")
BenchmarkTools.Trial:
  memory estimate:  12.19 MiB
  allocs estimate:  3303
  --------------
  minimum time:     258.477 ms (0.00% GC)
  median time:      262.019 ms (0.00% GC)
  mean time:        264.937 ms (0.39% GC)
  maximum time:     314.136 ms (0.00% GC)
  --------------
  samples:          19
  evals/sample:     1

which is almost half the time I get with the triangulate.txt ascii version. So fixing contour.jl to allow the index=... work should give even better times.

@joa-quim
Copy link
Member

And after fixing it

@benchmark contour(xyz,pen="0.15p,+c",annot=(labels=(font=1, prefix ="test"),), color=cb_jet, region=:g, index=t1)
BenchmarkTools.Trial:
  memory estimate:  24.06 MiB
  allocs estimate:  3406
  --------------
  minimum time:     192.260 ms (0.00% GC)
  median time:      196.015 ms (1.83% GC)
  mean time:        196.225 ms (1.03% GC)
  maximum time:     214.475 ms (1.78% GC)
  --------------
  samples:          26
  evals/sample:     1

Will commit to master this afternoon

@joa-quim
Copy link
Member

joa-quim commented Jul 17, 2020

You should now be able to do

gmtconvert(t1, binary_out="3f", write="triangulate.bin")

but dumb of me. I think you could already have written

gmtwrite("triangulate.bin", t1, binary_out="3f")

@htyeim
Copy link
Contributor Author

htyeim commented Jul 18, 2020

Thank you!!!

BenchmarkTools.Trial: 
  memory estimate:  24.06 MiB
  allocs estimate:  3452
  --------------
  minimum time:     113.849 ms (0.00% GC)
  median time:      122.205 ms (0.31% GC)
  mean time:        124.151 ms (0.18% GC)
  maximum time:     148.674 ms (0.27% GC)
  --------------
  samples:          41
  evals/sample:     1

About three times faster (374.942/122.205), 👍
I will try to modify my code with this style. For plotting related to simulation results, as the grid in general is fixed, this kind of speedup would be great helpful. I hope I could use GMT.jl (gmt) to plot anything I want (simple and fast)

@joa-quim
Copy link
Member

I hope I could use GMT.jl (gmt) to plot anything I want

Which ones are you not able to plot with GMT? (I know not everything is possible)

@htyeim
Copy link
Contributor Author

htyeim commented Jul 19, 2020

One of the things I have tried but haven't got any results is this one:
screenshot
ref
I tried to plot the grid in this configuration but I couldn't find any related post/example (code script) which could be a start point for me (copy, modify gradually, then finish...)

@joa-quim
Copy link
Member

The plot looks trivial (plot3d) but the not sure if the field lines could be computed with mgd77magref (not ported to GMT.jl verbose, only monolithic) or what it would take to lets us compute them.

@joa-quim
Copy link
Member

joa-quim commented Jul 19, 2020

Maybe start a new issue with this, and probably in GMT itself since the plotting should be easy as long as we have all necessary data.

@htyeim
Copy link
Contributor Author

htyeim commented Jul 19, 2020

The data can be produced by some other program (a lot of simulation code in ionosphere need to use grids based on geomagnetic field). I will try to prepare an example (with data and code in Julia) and open a new issue later. Thank you~

@joa-quim
Copy link
Member

joa-quim commented Jul 19, 2020

Have you looked at mgd77magref (GMT potential supplements)?

@htyeim
Copy link
Contributor Author

htyeim commented Jul 19, 2020

I have just checked it (and IGRF and CM4/CM5 and Dst and F10.7...) Actually all these things are needed in my research! But I write my own Julia program to download, read, manage them.... For this function, I think it's very useful (but... I really want to do all the things in one language 😂 )

@joa-quim
Copy link
Member

(but... I really want to do all the things in one language 😂 )

Nothing stops you to. See the monolithic way in the manual (in case the GMT supplements do what's needed) ... or start porting the potential supplement.

@htyeim
Copy link
Contributor Author

htyeim commented Jul 19, 2020

OK, no problem I will check them! Still the GMT.jl (gmt) can surprise me when I though I have enough feelings about it!! What's more, it's completely free!!! Thank you~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants