-
Notifications
You must be signed in to change notification settings - Fork 4
/
link2GI1.html
668 lines (479 loc) · 40.4 KB
/
link2GI1.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>What is link2GI?</title>
<script type="text/javascript">
window.onload = function() {
var imgs = document.getElementsByTagName('img'), i, img;
for (i = 0; i < imgs.length; i++) {
img = imgs[i];
// center an image if it is the only element of its parent
if (img.parentElement.childElementCount === 1)
img.parentElement.style.textAlign = 'center';
}
};
</script>
<!-- Styles for R syntax highlighter -->
<style type="text/css">
pre .operator,
pre .paren {
color: rgb(104, 118, 135)
}
pre .literal {
color: #990073
}
pre .number {
color: #099;
}
pre .comment {
color: #998;
font-style: italic
}
pre .keyword {
color: #900;
font-weight: bold
}
pre .identifier {
color: rgb(0, 0, 0);
}
pre .string {
color: #d14;
}
</style>
<!-- R syntax highlighter -->
<script type="text/javascript">
var hljs=new function(){function m(p){return p.replace(/&/gm,"&").replace(/</gm,"<")}function f(r,q,p){return RegExp(q,"m"+(r.cI?"i":"")+(p?"g":""))}function b(r){for(var p=0;p<r.childNodes.length;p++){var q=r.childNodes[p];if(q.nodeName=="CODE"){return q}if(!(q.nodeType==3&&q.nodeValue.match(/\s+/))){break}}}function h(t,s){var p="";for(var r=0;r<t.childNodes.length;r++){if(t.childNodes[r].nodeType==3){var q=t.childNodes[r].nodeValue;if(s){q=q.replace(/\n/g,"")}p+=q}else{if(t.childNodes[r].nodeName=="BR"){p+="\n"}else{p+=h(t.childNodes[r])}}}if(/MSIE [678]/.test(navigator.userAgent)){p=p.replace(/\r/g,"\n")}return p}function a(s){var r=s.className.split(/\s+/);r=r.concat(s.parentNode.className.split(/\s+/));for(var q=0;q<r.length;q++){var p=r[q].replace(/^language-/,"");if(e[p]){return p}}}function c(q){var p=[];(function(s,t){for(var r=0;r<s.childNodes.length;r++){if(s.childNodes[r].nodeType==3){t+=s.childNodes[r].nodeValue.length}else{if(s.childNodes[r].nodeName=="BR"){t+=1}else{if(s.childNodes[r].nodeType==1){p.push({event:"start",offset:t,node:s.childNodes[r]});t=arguments.callee(s.childNodes[r],t);p.push({event:"stop",offset:t,node:s.childNodes[r]})}}}}return t})(q,0);return p}function k(y,w,x){var q=0;var z="";var s=[];function u(){if(y.length&&w.length){if(y[0].offset!=w[0].offset){return(y[0].offset<w[0].offset)?y:w}else{return w[0].event=="start"?y:w}}else{return y.length?y:w}}function t(D){var A="<"+D.nodeName.toLowerCase();for(var B=0;B<D.attributes.length;B++){var C=D.attributes[B];A+=" "+C.nodeName.toLowerCase();if(C.value!==undefined&&C.value!==false&&C.value!==null){A+='="'+m(C.value)+'"'}}return A+">"}while(y.length||w.length){var v=u().splice(0,1)[0];z+=m(x.substr(q,v.offset-q));q=v.offset;if(v.event=="start"){z+=t(v.node);s.push(v.node)}else{if(v.event=="stop"){var p,r=s.length;do{r--;p=s[r];z+=("</"+p.nodeName.toLowerCase()+">")}while(p!=v.node);s.splice(r,1);while(r<s.length){z+=t(s[r]);r++}}}}return z+m(x.substr(q))}function j(){function q(x,y,v){if(x.compiled){return}var u;var s=[];if(x.k){x.lR=f(y,x.l||hljs.IR,true);for(var w in x.k){if(!x.k.hasOwnProperty(w)){continue}if(x.k[w] instanceof Object){u=x.k[w]}else{u=x.k;w="keyword"}for(var r in u){if(!u.hasOwnProperty(r)){continue}x.k[r]=[w,u[r]];s.push(r)}}}if(!v){if(x.bWK){x.b="\\b("+s.join("|")+")\\s"}x.bR=f(y,x.b?x.b:"\\B|\\b");if(!x.e&&!x.eW){x.e="\\B|\\b"}if(x.e){x.eR=f(y,x.e)}}if(x.i){x.iR=f(y,x.i)}if(x.r===undefined){x.r=1}if(!x.c){x.c=[]}x.compiled=true;for(var t=0;t<x.c.length;t++){if(x.c[t]=="self"){x.c[t]=x}q(x.c[t],y,false)}if(x.starts){q(x.starts,y,false)}}for(var p in e){if(!e.hasOwnProperty(p)){continue}q(e[p].dM,e[p],true)}}function d(B,C){if(!j.called){j();j.called=true}function q(r,M){for(var L=0;L<M.c.length;L++){if((M.c[L].bR.exec(r)||[null])[0]==r){return M.c[L]}}}function v(L,r){if(D[L].e&&D[L].eR.test(r)){return 1}if(D[L].eW){var M=v(L-1,r);return M?M+1:0}return 0}function w(r,L){return L.i&&L.iR.test(r)}function K(N,O){var M=[];for(var L=0;L<N.c.length;L++){M.push(N.c[L].b)}var r=D.length-1;do{if(D[r].e){M.push(D[r].e)}r--}while(D[r+1].eW);if(N.i){M.push(N.i)}return f(O,M.join("|"),true)}function p(M,L){var N=D[D.length-1];if(!N.t){N.t=K(N,E)}N.t.lastIndex=L;var r=N.t.exec(M);return r?[M.substr(L,r.index-L),r[0],false]:[M.substr(L),"",true]}function z(N,r){var L=E.cI?r[0].toLowerCase():r[0];var M=N.k[L];if(M&&M instanceof Array){return M}return false}function F(L,P){L=m(L);if(!P.k){return L}var r="";var O=0;P.lR.lastIndex=0;var M=P.lR.exec(L);while(M){r+=L.substr(O,M.index-O);var N=z(P,M);if(N){x+=N[1];r+='<span class="'+N[0]+'">'+M[0]+"</span>"}else{r+=M[0]}O=P.lR.lastIndex;M=P.lR.exec(L)}return r+L.substr(O,L.length-O)}function J(L,M){if(M.sL&&e[M.sL]){var r=d(M.sL,L);x+=r.keyword_count;return r.value}else{return F(L,M)}}function I(M,r){var L=M.cN?'<span class="'+M.cN+'">':"";if(M.rB){y+=L;M.buffer=""}else{if(M.eB){y+=m(r)+L;M.buffer=""}else{y+=L;M.buffer=r}}D.push(M);A+=M.r}function G(N,M,Q){var R=D[D.length-1];if(Q){y+=J(R.buffer+N,R);return false}var P=q(M,R);if(P){y+=J(R.buffer+N,R);I(P,M);return P.rB}var L=v(D.length-1,M);if(L){var O=R.cN?"</span>":"";if(R.rE){y+=J(R.buffer+N,R)+O}else{if(R.eE){y+=J(R.buffer+N,R)+O+m(M)}else{y+=J(R.buffer+N+M,R)+O}}while(L>1){O=D[D.length-2].cN?"</span>":"";y+=O;L--;D.length--}var r=D[D.length-1];D.length--;D[D.length-1].buffer="";if(r.starts){I(r.starts,"")}return R.rE}if(w(M,R)){throw"Illegal"}}var E=e[B];var D=[E.dM];var A=0;var x=0;var y="";try{var s,u=0;E.dM.buffer="";do{s=p(C,u);var t=G(s[0],s[1],s[2]);u+=s[0].length;if(!t){u+=s[1].length}}while(!s[2]);if(D.length>1){throw"Illegal"}return{r:A,keyword_count:x,value:y}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:m(C)}}else{throw H}}}function g(t){var p={keyword_count:0,r:0,value:m(t)};var r=p;for(var q in e){if(!e.hasOwnProperty(q)){continue}var s=d(q,t);s.language=q;if(s.keyword_count+s.r>r.keyword_count+r.r){r=s}if(s.keyword_count+s.r>p.keyword_count+p.r){r=p;p=s}}if(r.language){p.second_best=r}return p}function i(r,q,p){if(q){r=r.replace(/^((<[^>]+>|\t)+)/gm,function(t,w,v,u){return w.replace(/\t/g,q)})}if(p){r=r.replace(/\n/g,"<br>")}return r}function n(t,w,r){var x=h(t,r);var v=a(t);var y,s;if(v){y=d(v,x)}else{return}var q=c(t);if(q.length){s=document.createElement("pre");s.innerHTML=y.value;y.value=k(q,c(s),x)}y.value=i(y.value,w,r);var u=t.className;if(!u.match("(\\s|^)(language-)?"+v+"(\\s|$)")){u=u?(u+" "+v):v}if(/MSIE [678]/.test(navigator.userAgent)&&t.tagName=="CODE"&&t.parentNode.tagName=="PRE"){s=t.parentNode;var p=document.createElement("div");p.innerHTML="<pre><code>"+y.value+"</code></pre>";t=p.firstChild.firstChild;p.firstChild.cN=s.cN;s.parentNode.replaceChild(p.firstChild,s)}else{t.innerHTML=y.value}t.className=u;t.result={language:v,kw:y.keyword_count,re:y.r};if(y.second_best){t.second_best={language:y.second_best.language,kw:y.second_best.keyword_count,re:y.second_best.r}}}function o(){if(o.called){return}o.called=true;var r=document.getElementsByTagName("pre");for(var p=0;p<r.length;p++){var q=b(r[p]);if(q){n(q,hljs.tabReplace)}}}function l(){if(window.addEventListener){window.addEventListener("DOMContentLoaded",o,false);window.addEventListener("load",o,false)}else{if(window.attachEvent){window.attachEvent("onload",o)}else{window.onload=o}}}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=n;this.initHighlighting=o;this.initHighlightingOnLoad=l;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.ER="(?![\\s\\S])";this.BE={b:"\\\\.",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(r,s){var p={};for(var q in r){p[q]=r[q]}if(s){for(var q in s){p[q]=s[q]}}return p}}();hljs.LANGUAGES.cpp=function(){var a={keyword:{"false":1,"int":1,"float":1,"while":1,"private":1,"char":1,"catch":1,"export":1,virtual:1,operator:2,sizeof:2,dynamic_cast:2,typedef:2,const_cast:2,"const":1,struct:1,"for":1,static_cast:2,union:1,namespace:1,unsigned:1,"long":1,"throw":1,"volatile":2,"static":1,"protected":1,bool:1,template:1,mutable:1,"if":1,"public":1,friend:2,"do":1,"return":1,"goto":1,auto:1,"void":2,"enum":1,"else":1,"break":1,"new":1,extern:1,using:1,"true":1,"class":1,asm:1,"case":1,typeid:1,"short":1,reinterpret_cast:2,"default":1,"double":1,register:1,explicit:1,signed:1,typename:1,"try":1,"this":1,"switch":1,"continue":1,wchar_t:1,inline:1,"delete":1,alignof:1,char16_t:1,char32_t:1,constexpr:1,decltype:1,noexcept:1,nullptr:1,static_assert:1,thread_local:1,restrict:1,_Bool:1,complex:1},built_in:{std:1,string:1,cin:1,cout:1,cerr:1,clog:1,stringstream:1,istringstream:1,ostringstream:1,auto_ptr:1,deque:1,list:1,queue:1,stack:1,vector:1,map:1,set:1,bitset:1,multiset:1,multimap:1,unordered_set:1,unordered_map:1,unordered_multiset:1,unordered_multimap:1,array:1,shared_ptr:1}};return{dM:{k:a,i:"</",c:[hljs.CLCM,hljs.CBLCLM,hljs.QSM,{cN:"string",b:"'\\\\?.",e:"'",i:"."},{cN:"number",b:"\\b(\\d+(\\.\\d*)?|\\.\\d+)(u|U|l|L|ul|UL|f|F)"},hljs.CNM,{cN:"preprocessor",b:"#",e:"$"},{cN:"stl_container",b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:a,r:10,c:["self"]}]}}}();hljs.LANGUAGES.r={dM:{c:[hljs.HCM,{cN:"number",b:"\\b0[xX][0-9a-fA-F]+[Li]?\\b",e:hljs.IMMEDIATE_RE,r:0},{cN:"number",b:"\\b\\d+(?:[eE][+\\-]?\\d*)?L\\b",e:hljs.IMMEDIATE_RE,r:0},{cN:"number",b:"\\b\\d+\\.(?!\\d)(?:i\\b)?",e:hljs.IMMEDIATE_RE,r:1},{cN:"number",b:"\\b\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",e:hljs.IMMEDIATE_RE,r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",e:hljs.IMMEDIATE_RE,r:1},{cN:"keyword",b:"(?:tryCatch|library|setGeneric|setGroupGeneric)\\b",e:hljs.IMMEDIATE_RE,r:10},{cN:"keyword",b:"\\.\\.\\.",e:hljs.IMMEDIATE_RE,r:10},{cN:"keyword",b:"\\.\\.\\d+(?![\\w.])",e:hljs.IMMEDIATE_RE,r:10},{cN:"keyword",b:"\\b(?:function)",e:hljs.IMMEDIATE_RE,r:2},{cN:"keyword",b:"(?:if|in|break|next|repeat|else|for|return|switch|while|try|stop|warning|require|attach|detach|source|setMethod|setClass)\\b",e:hljs.IMMEDIATE_RE,r:1},{cN:"literal",b:"(?:NA|NA_integer_|NA_real_|NA_character_|NA_complex_)\\b",e:hljs.IMMEDIATE_RE,r:10},{cN:"literal",b:"(?:NULL|TRUE|FALSE|T|F|Inf|NaN)\\b",e:hljs.IMMEDIATE_RE,r:1},{cN:"identifier",b:"[a-zA-Z.][a-zA-Z0-9._]*\\b",e:hljs.IMMEDIATE_RE,r:0},{cN:"operator",b:"<\\-(?!\\s*\\d)",e:hljs.IMMEDIATE_RE,r:2},{cN:"operator",b:"\\->|<\\-",e:hljs.IMMEDIATE_RE,r:1},{cN:"operator",b:"%%|~",e:hljs.IMMEDIATE_RE},{cN:"operator",b:">=|<=|==|!=|\\|\\||&&|=|\\+|\\-|\\*|/|\\^|>|<|!|&|\\||\\$|:",e:hljs.IMMEDIATE_RE,r:0},{cN:"operator",b:"%",e:"%",i:"\\n",r:1},{cN:"identifier",b:"`",e:"`",r:0},{cN:"string",b:'"',e:'"',c:[hljs.BE],r:0},{cN:"string",b:"'",e:"'",c:[hljs.BE],r:0},{cN:"paren",b:"[[({\\])}]",e:hljs.IMMEDIATE_RE,r:0}]}};
hljs.initHighlightingOnLoad();
</script>
<style type="text/css">
body, td {
font-family: sans-serif;
background-color: white;
font-size: 13px;
}
body {
max-width: 800px;
margin: auto;
padding: 1em;
line-height: 20px;
}
tt, code, pre {
font-family: 'DejaVu Sans Mono', 'Droid Sans Mono', 'Lucida Console', Consolas, Monaco, monospace;
}
h1 {
font-size:2.2em;
}
h2 {
font-size:1.8em;
}
h3 {
font-size:1.4em;
}
h4 {
font-size:1.0em;
}
h5 {
font-size:0.9em;
}
h6 {
font-size:0.8em;
}
a:visited {
color: rgb(50%, 0%, 50%);
}
pre, img {
max-width: 100%;
}
pre {
overflow-x: auto;
}
pre code {
display: block; padding: 0.5em;
}
code {
font-size: 92%;
border: 1px solid #ccc;
}
code[class] {
background-color: #F8F8F8;
}
table, td, th {
border: none;
}
blockquote {
color:#666666;
margin:0;
padding-left: 1em;
border-left: 0.5em #EEE solid;
}
hr {
height: 0px;
border-bottom: none;
border-top-width: thin;
border-top-style: dotted;
border-top-color: #999999;
}
@media print {
* {
background: transparent !important;
color: black !important;
filter:none !important;
-ms-filter: none !important;
}
body {
font-size:12pt;
max-width:100%;
}
a, a:visited {
text-decoration: underline;
}
hr {
visibility: hidden;
page-break-before: always;
}
pre, blockquote {
padding-right: 1em;
page-break-inside: avoid;
}
tr, img {
page-break-inside: avoid;
}
img {
max-width: 100% !important;
}
@page :left {
margin: 15mm 20mm 15mm 10mm;
}
@page :right {
margin: 15mm 10mm 15mm 20mm;
}
p, h2, h3 {
orphans: 3; widows: 3;
}
h2, h3 {
page-break-after: avoid;
}
}
</style>
</head>
<body>
<h1>What is link2GI?</h1>
<p>The <a href="https://CRAN.R-project.org/package=link2GI">link2GI</a> package provides a small linking tool to simplify the usage of GRASS and SAGA GIS and Orfeo Toolbox (OTB) for R users. the focus is to simplify the the accessibility of this software for non operating system specialists or highly experienced GIS geeks. Acutally it is a direct result of numerous graduate courses with R(-GIS) beginners in the hostile world of university computer pools running under extremely restricted Windows systems. </p>
<p>This vignette:</p>
<ul>
<li>shows how to use <code>link2GI</code> according to specific system requirements </li>
<li>gives some hands on examples of how to use<br/></li>
<li>give some applied examples for more efficient spatial analysis </li>
</ul>
<h1>Why link2GI now?</h1>
<p>R has quite a lot of classes for storing and dealing with spatial data. For vector data the <a href="https://CRAN.R-project.org/package=sp">sp</a> and recently the great <a href="https://CRAN.R-project.org/package=sf">sf</a> packages are well known and the raster data world is widely covered by the <a href="https://CRAN.R-project.org/package=raster">raster</a> package. Additionally external spatial data formats are interfaced by wrapping packages as <a href="https://CRAN.R-project.org/package=rgdal">rgdal</a> or <a href="https://CRAN.R-project.org/package=gdalUtils">gdalUtils</a>. For more specific links as needed for manipulating atmospheric modeling packages as <a href="https://CRAN.R-project.org/package=ncdf4">ncdf4</a> are very helpful.</p>
<p>The spatial analysis itself is often supported by wrapper packages that integrate external libraries, command line tools or a mixture of both in an R-like syntax <a href="https://CRAN.R-project.org/package=rgeos">rgeos</a>, <a href="https://CRAN.R-project.org/package=geosphere">geosphere</a>, <a href="https://CRAN.R-project.org/package=Distance">Distance</a>, <a href="https://CRAN.R-project.org/package=maptools">maptools</a>, <a href="https://CRAN.R-project.org/package=igraph">igraph</a> or <a href="https://CRAN.R-project.org/package=spatstat">spatstat</a>. </p>
<p>A comprehensive introduction to the spatial R-biotope and its backgrounds is excellently treated in <a href="https://geocompr.robinlovelace.net">Geocomputation with R</a> wich is highly recommend as a reference textbook.</p>
<p>Despite all this capabilities of spatial analysis and data handling in the world of <code>R</code>, it can be stated (at least from a non-R point of view), that there is still a enormous gap between R and the mature open source Geographic Information System (GIS) and even more Remote Sensing (RS) software community. <code>QGIS</code>, <code>GRASS GIS</code> and <code>SAGA GIS</code> are providing a comprehensive, growing and mature collection of highly sophisticated algorithms. The provided algorithms are fast, stable and most of them are well proofed. Probably most of the <code>R</code> users who are somehow related to the GI community know that there are awesome good wrapper packages for bridging this gap. For <a href="https://grass.osgeo.org/">GRASS GIS 7</a> it is <a href="https://CRAN.R-project.org/package=rgrass7">rgrass7</a> and for <a href="http://www.saga-gis.org/">SAGA GIS</a> the <a href="https://CRAN.R-project.org/package=RSAGA">RSAGA</a> package. The development of the <a href="https://CRAN.R-project.org/package=RQGIS">RQGIS</a> wrapper is the most recent outcome to provide a simple usage of the powerful <a href="https://www.qgis.org/">QGIS</a> command line interface.</p>
<p>Unfortunately one will run into a lot of technical problems depending on the choosen operating system (OS) or library dependencies or GIS software versions. In case of e.g. <code>RSAGA</code> the main problem has been that the SAGA GIS developers are not only changing the syntax and strategy of the command line interface (CLI) but also within the same release the calls differ from OS to OS. So the maintenance of RSAGA is at least laborious (but thumbs up is running again). Another example is given by <code>GRASS GIS</code> which is well known for a sophisticated setup of the environment and the spatial properties of the database. If you “just” want to use a specific GRASS algorithm from R, you will probablys get lost in setting up all OS-dependencies that are neccessary to set up a correct temporary or permanent GRASS-environment from “outside”. This is not only caused due to the strict spatial and projection requirements of GRASS but much more by challenging OS enviroments especially Windows. </p>
<p>To make it short it is a bit cumbersome to deal with all this stuff if one just want to start e.g. GRASS from the R command line for e.g. a powerful random walk cost analysis (<code>r.walk</code>) call as provided by GRASS.</p>
<h1>What means linking?</h1>
<p>Linking means simply to provide all necessary environment settings that satisfy the existing wrapper packages as well as in addition the full access to the the command line (CLI) APIs of the mentioned software tools. <code>link2GI</code> tries to analyze which software is installed to set up an temporary enviroment meeting the above mentioned needs. </p>
<h3>GRASS GIS</h3>
<p><code>GRASS GIS</code> has the most challenging requirements. It needs a bunch of environment and path variables as <strong>and</strong> a correct setup of the geographical data parameters. The <code>linkGRASS7</code> function tries to find all installations let you (optionally) choose the one you want to use and generate the necessary variables. As a result you can use both the rgrass7 package or the command line <code>API</code> of <code>GRASS</code>.</p>
<h3>SAGA GIS</h3>
<p><code>SAGA GIS</code> is a far easier to set up. Again the <code>linkSAGA</code> function tries to find all <code>SAGA</code> installations, let you (optionally) choose one and generate the necessary variables. You may also use <code>RSAGA</code> but you have to hand over the result of <code>linkSAGA</code> like <code>RSAGA::rsaga.env(path = saga$sagaPath)</code>. For a straightforward usage you may simply use the <code>R</code> system() call to interface <code>R</code> with the <code>saga_cmd</code> API. </p>
<h3>OTB</h3>
<p>The <code>Orfeo Toolbox</code> (OTB) is a very powerful remote sensing toolbox. It is widely used for classification, filtering and machine learning applications. You will find some of the implemented algorithm within different R packages but <strong>always</strong> much slower or only running on small data chunks. Due to a missing wrapper the linkage is performed to use the command line API of the <code>OTB</code>. Currently link2GI provides very basic list-based <code>OTB</code> wrapper. </p>
<h3>GDAL</h3>
<p>GDAL is perfectly integrated in R. However in some cases it is beneficial to uses system calls and grab the binaries directly. <code>link2GI</code> generates a list of all pathes and commands so you may easily use also python scripts calls and other chains. </p>
<h1>Usage of the link2GI package - Basic Examples</h1>
<h2>Brute force search usage</h2>
<p>Automatic search and find of the installed GIS software binaries is performed by the <code>find</code> functions. Depending of you OS and the number of installed versions you will get a dataframe providing the binary and module folders.</p>
<pre><code class="r"># find all SAGA GIS installations at the default search location
require(link2GI)
saga <- link2GI::findSAGA()
saga
</code></pre>
<p>Same with GRASS and OTB</p>
<pre><code class="r"># find all SAGA GIS installations at the default search location
require(link2GI)
grass <- link2GI::findGRASS()
grass
otb <- link2GI::findOTB()
otb
</code></pre>
<p>The <code>find</code> functions are providing an overview of the installed software. This functions are not establishing any linkages or changing settings.</p>
<h2>Setting up project structures</h2>
<p>If you just call link2GI on the fly , that means for a single temporary operation, there will be no need for setting up folders and project structures. If you work on a more complex project it is seems to be helpful to support this by a fixed structure. Same with existing GRASS projects wich need to be in specific mapsets and locations. </p>
<p>A straightforward (you may call it also dirty) approach is the ìnitProjfunction that creates folder structures (if not existing) and establishes (if wanted) global variables containing the pathes as strings.</p>
<pre><code class="r"># find all SAGA GIS installations at the default search location
require(link2GI)
link2GI::initProj(projRootDir = tempdir(),
projFolders = c("data/",
"data/level0/",
"data/level1/",
"output/",
"run/",
"fun/"),
path_prefix = "path_to_" ,
global =TRUE)
</code></pre>
<h2>linkSAGA - Locate and set up 'SAGA' API bindings</h2>
<p>In earlier times it has been pretty cumbersome to link the correct <code>SAGA GIS</code> version. Since the version 1.x.x of <code>RSAGA</code> things turned much better. The new <code>RSAGA::rsaga.env()</code> function is at getting the first <code>RSAGA</code> version in the search path. For using <code>RSAGA</code> with <code>link2GI</code> it is strongly recommended to call <code>RSAGA.env()</code> with the preferred path as provided by a ' <code>findSAGA()</code> call. It is also possible to provide the version number as shown below. Storing the result in adequate variables will then even give the opportunity to easyly switch between different <code>SAGA GIS</code> installations.</p>
<pre><code class="r">saga1<-link2GI::linkSAGA(ver_select = 1)
saga1
sagaEnv1<- RSAGA::rsaga.env(path = saga1$sagaPath)
</code></pre>
<h2>linkGRASS7 - Locate and set up 'GRASS 7' API bindings</h2>
<p><code>linkGRASS7</code> Initializes the session environment and the system paths for an easy access to <code>GRASS GIS 7.x.</code> The correct setup of the spatial and projection parameters is automatically performed by using either an existing and valid <code>raster</code>, <code>sp</code> or <code>sf</code> object, or manually by providing a list containing the minimum parameters needed. These properties are used to initialize either a temporary or a permanent <code>rgrass7</code> environment including the correct 'GRASS 7' database structure. If you provide none of the before mentioned objects <code>linkGRASS</code> will create a EPSG:4326 world wide location.</p>
<p>The most time consuming part on 'Windows' Systems is the search process. This can easily take 10 or more minutes. To speed up this process you can also provide a correct parameter set. Best way to do so is to call manually <code>findGRASS</code>. Then call <code>linkGRASS7</code> with the returned version arguments of your choice.</p>
<p>The function <code>linkGRASS7</code> tries to find all valid <code>GRASS GIS</code> binaries by analyzing the startup script files of <code>GRASS GIS</code>. After identifying the <code>GRASS GIS</code> binaries all necessary system variables and settings will be generated and passed to a temporary <code>R</code> environment.</p>
<p>If you have more than one valid installation and run <code>linkGRASS7</code> with the arguments <code>select_ver = TRUE</code>, then you will be ask to select one.</p>
<h4>Standard Full Search Usage</h4>
<p>Automatic search and find of <code>GRASS</code> binaries using the meuse sp data object for spatial referencing.
This is the highly recommended linking procedure. NOTE: if more than one <code>GRASS</code> installation is found the first one is selected automatically. </p>
<pre><code class="r"># get meuse data as sp object
require(link2GI)
require(sp)
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <-CRS("+init=epsg:28992")
# get meuse data as sf object
require(sf)
meuse_sf = st_as_sf(meuse,
coords =
c("x", "y"),
crs = 28992,
agr = "constant")
# create a temporary GRASS linkage using the meuse data
linkGRASS7(meuse)
</code></pre>
<h4>Typical call for standalone distro</h4>
<p>Assuming a typical standalone non-OSGeo4W installation and using the meuse sp data object for spatial referencing</p>
<pre><code class="r">linkGRASS7(meuse,c("C:/Program Files/GRASS GIS7.0.5","GRASS GIS 7.0.5","NSIS"))
</code></pre>
<h4>Typical OSGeo4W64 installation</h4>
<p>Typical <code>OSGeo4W64</code> installation using the meuse sp data object for spatial referencing</p>
<pre><code class="r">linkGRASS7(meuse,c("C:/OSGeo4W64","grass-7.0.5","osgeo4W"))
</code></pre>
<h4>Manual choosing the version</h4>
<p>Choose manually the GRASS installation additionally using the meuse <code>sf</code> object for spatial referencing</p>
<pre><code class="r">linkGRASS7(meuse_sf,
ver_select = TRUE)
</code></pre>
<h4>Choose another searchpath</h4>
<p>Choose manually the GRASS installation and change the search location additionally using the meuse <code>sf</code> object for spatial referencing</p>
<pre><code class="r">linkGRASS7(meuse_sf,
search_path = "D:/")
</code></pre>
<h4>Creating a permanent gisbase folder</h4>
<p>Creating a permanent <code>GRASS</code> gisdbase (folder structure) at “~/temp3” with the standard mapset “PERMANENT”“ and the location named "project1”. For all spatial attributes use the the meuse <code>sf</code> object.</p>
<pre><code class="r">linkGRASS7(x = meuse_sf,
gisdbase = "~/temp3",
location = "project1")
</code></pre>
<h4>Using a Permanent gisbase folder</h4>
<p>Link to the permanent <code>GRASS</code> gisdbase (folder structure) at “~/temp3” with the standard mapset “PERMANENT” and the location named “project1”. For all spatial attributes use the the meuse <code>sf</code> object.</p>
<pre><code class="r">linkGRASS7(gisdbase = "~/temp3", location = "project1",
gisdbase_exist = TRUE)
</code></pre>
<h4>Manual Setup of the spatial attributes</h4>
<p>Setting up <code>GRASS</code> manually with spatial parameters of the meuse data</p>
<pre><code class="r"> linkGRASS7(spatial_params = c(178605,329714,181390,333611,
"+proj=sterea +lat_0=52.15616055555555
+lon_0=5.38763888888889 +k=0.9999079
+x_0=155000 +y_0=463000 +no_defs
+a=6377397.155 +rf=299.1528128
+towgs84=565.4171,50.3319,465.5524,
-0.398957,0.343988,-1.8774,4.0725
+to_meter=1"))
</code></pre>
<h2>A typical usecase for the Orfeo Toolbox wrapper</h2>
<p>link2GI supports the use of the Orfeo Toolbox with a listbased simple wrapper function. Actually two functions parse the modules and functions syntax dumps and generate a command list that is easy to modify with the necessary arguments.</p>
<p>Usually you have to get the module list first:</p>
<pre><code class="r"># link to the installed OTB
otbLinks<-link2GI::linkOTB()
# get the modulelist from the linked version
algo<-parseOTBAlgorithms(gili = otbLinks)
</code></pre>
<p>Based on the modules of the current version of OTB you can then choose the module(s) you want to use.</p>
<pre><code class="r">## for the example we use the edge detection,
## because of the windows call via a batch file
## we have to distinguish the module name
ifelse(Sys.info()["sysname"]=="Windows",
algo_keyword<- "EdgeExtraction.bat",
algo_keyword<- "EdgeExtraction")
# now create the command list
algo_cmd<-parseOTBFunction(algo = algo[algo[]==algo_keyword],gili = otblink)
## print the current command
print(algo_cmd)
</code></pre>
<p>Admittedly this is a very straightforward and preliminary approach. Nevertheless it provids you a valid list of all OTB API calls that can easily manipulated for your needs. The following working example will give you an idea how to use it.</p>
<pre><code class="r">###########
### usecase
###########
## link to OTB
otblink<-link2GI::linkOTB()
path_OTB<-otblink$pathOTB
## get data
setwd(tempdir())
## get some typical data as provided by the authority
url<-"http://www.ldbv.bayern.de/file/zip/5619/DOP%2040_CIR.zip"
res <- curl::curl_download(url, "testdata.zip")
unzip(res,junkpaths = TRUE,overwrite = TRUE)
## get all available OTB modules
algo<-parseOTBAlgorithms(gili = otblink)
## for the example we use the edge detection,
## because of the windows call via a batch file
## we have to distinguish the module name
ifelse(Sys.info()["sysname"]=="Windows",
algo_keyword<- "EdgeExtraction.bat",
algo_keyword<- "EdgeExtraction")
# write it to a variable
otb_algorithm<-algo[algo[]==algo_keyword]
# now create the command list
algo_cmd<-parseOTBFunction(algo = otb_algorithm,gili = otblink)
## define the current run arguments
algo_cmd$`-in`<- file.path(getwd(),"4490600_5321400.tif")
algo_cmd$`-filter`<- "sobel"
## create out name
outName<-paste0(getwd(),"/out",algo_cmd$`-filter`,".tif")
algo_cmd$`-out`<- outName
## generate full command
command<-paste(paste0(path_OTB,"otbcli_",otb_algorithm," "),
paste(names(algo_cmd),algo_cmd,collapse = " "))
## make the system call
system(command,intern = TRUE)
##create raster
retStack<-assign(outName,raster::raster(outName))
## plot raster
raster::plot(retStack)
## End(Not run)
</code></pre>
<h1>Advanced examples</h1>
<p>A typical example is the usage of an already existing project database in <code>GRASS</code>. <code>GRASS</code> organizes all data in an internal file structure that is known as gisdbase folder, a mapset and one or more locations within this mapset. All raster and vector data is stored inside this structure and the organisation is performed by <code>GRASS</code>. So a typical task could be to work on data sets that are already stored in an existing <code>GRASS</code> structure</p>
<h2>Creating a GRASS project</h2>
<p>First of all we need some real world data. In this this case the gridded <a href="https://www.zensus2011.de/EN/2011Census/2011_Census_node.html">2011 micro zensus</a> <a href="https://www.zensus2011.de/SharedDocs/Downloads/DE/Pressemitteilung/DemografischeGrunddaten/csv_Bevoelkerung_100m_Gitter.zip;jsessionid=294313DDBB57914D6636DE373897A3F2.2_cid389?__blob=publicationFile&v=3">population data</a> of Germany. It has some nice aspects:</p>
<ul>
<li>It is provided in a typical authority format</li>
<li>It is big enough >35 Mio points </li>
<li>It is pretty instructive for a lot of spatial analysis. </li>
</ul>
<p>We also have to download a <a href="https://www.zensus2011.de/SharedDocs/Downloads/DE/Pressemitteilung/DemografischeGrunddaten/Datensatzbeschreibung_Bevoelkerung_100m_Gitter.xlsx;jsessionid=294313DDBB57914D6636DE373897A3F2.2_cid389?__blob=publicationFile&v=2">meta data description file</a> (excel sheet) for informations about projection and data concepts and so on.</p>
<pre><code class="r"> # we need some additional packages
require(link2GI)
require(curl)
# first of all we create a project folder structure
link2GI::initProj(projRootDir = paste0(tempdir(),"/link2GI_examples"),
projFolders = c("run/"),
path_prefix = "path_",
global = TRUE)
# set runtime directory
setwd(path_run)
# get some typical authority generated data
url<-"https://www.zensus2011.de/SharedDocs/Downloads/DE/Pressemitteilung/
DemografischeGrunddaten/csv_Bevoelkerung_100m_Gitter.zip;
jsessionid=294313DDBB57914D6636DE373897A3F2.2_cid389?__blob=publicationFile&v=3"
res <- curl::curl_download(url, paste0(path_run,"testdata.zip"))
# unzip it
unzip(res,files = grep(".csv", unzip(res,list = TRUE)$Name,value = TRUE),
junkpaths = TRUE, overwrite = TRUE)
fn <- list.files(pattern = "[.]csv$", path = getwd(), full.names = TRUE)
</code></pre>
<p>After downloading the data we will use it for some demonstration stuff. If you have a look the data is nothing than x,y,z with assuming some projection information.</p>
<pre><code class="r"># get the filename
# fast read with data.table
xyz <- data.table::fread(paste0(path_run,"/Zensus_Bevoelkerung_100m-Gitter.csv"))
head(xyz)
</code></pre>
<p>We can easy rasterize this data as it is intentionally gridded data.that means we have in at a grid size of 100 by 100 meters a value.</p>
<pre><code class="r"> require(RColorBrewer)
require(raster)
require(mapview)
# clean dataframe
xyz <- xyz[,-1]
# rasterize it according to the projection
r <- raster::rasterFromXYZ(xyz,crs = sp::CRS("+init=epsg:3035"))
# map it
p <- colorRampPalette(brewer.pal(8, "Reds"))
# aet resolution to 1 sqkm
mapview::mapviewOptions(mapview.maxpixels = r@ncols*r@nrows/10)
mapview::mapview(r, col.regions = p,
at = c(-1,10,25,50,100,500,1000,2500),
legend = TRUE)
</code></pre>
<p>So far nothing new. Now we create a new but permanent <code>GRASS</code> gisbase using the spatial parameters from the raster object. As you know the <code>linkGRASS7</code> function performs a full search for one or more than one existing <code>GRASS</code> installations. If a valid <code>GRASS</code> installation exists all parameter are setup und the package <code>rgrass7</code> is linked.</p>
<p>Due to the fact that the <code>gisdbase_exist</code> is by default set to FALSE it will create a new structure according to the <code>R</code> object. </p>
<pre><code class="r">require(link2GI)
# initialize GRASS and set up a permanent structure
link2GI::linkGRASS7(x = r,
gisdbase = paste0(tempdir(),"/link2GI_examples"),
location = "microzensus2011")
</code></pre>
<p>Finally we can now import the data to the <code>GRASS</code> gisdbase using the <code>rgass7</code> package functionality. </p>
<p>First we must convert the raster object to <code>GeoTIFF</code> file. Any <code>GDAL</code> format is possible but <code>GeoTIFF</code> is very common and stable.</p>
<pre><code class="r">require(raster)
require(rgrass7)
# write it to geotiff
raster::writeRaster(r, paste0(path_run,"/Zensus_Bevoelkerung_100m-Gitter.tif"),
overwrite = TRUE)
# import raster to GRASS
rgrass7::execGRASS('r.external',
flags=c('o',"overwrite","quiet"),
input=paste0(path_run,"/Zensus_Bevoelkerung_100m-Gitter.tif"),
output="Zensus_Bevoelkerung_100m_Gitter",
band=1)
# check imported data set
rgrass7::execGRASS('r.info',
map = "Zensus_Bevoelkerung_100m_Gitter")
</code></pre>
<p>Let's do now the same import as a vector data set. First we create a <code>sf</code> object. Please note this will take quite a while.</p>
<pre><code class="r"> xyz_sf = st_as_sf(xyz,
coords = c("x_mp_100m", "y_mp_100m"),
crs = 3035,
agr = "constant")
#map points
sf::plot_sf(xyz_sf)
</code></pre>
<p>The <code>GRASS</code> gisdbase already exists. So we pass <code>linkGRASS7</code> the argument <code>gisdbase_exist=TRUE</code> and import the xyz data as generic GRASS vector points.</p>
<pre><code class="r"> require(sf)
require(sp)
require(link2GI)
sf2gvec(x = xyz_sf,
obj_name = "Zensus_Bevoelkerung_100m_",
gisdbase = paste0(tempdir(),"/link2GI_examples"),
location = "microzensus2011",
gisdbase_exist = TRUE)
# check imported data set
rgrass7::execGRASS('v.info', map = "Zensus_Bevoelkerung_100m_")
</code></pre>
<h2>Usecases presented on the GEOSTAT August 2018</h2>
<p>During the <a href="http://opengeohub.org/node/146">GEOSTAT 2018</a> in Prague some more complex usescases has been <a href="https://htmlpreview.github.io/?https://github.com/gisma/link2gi2018/blob/master/link2gi2018.html">presented</a>.</p>
<h3>Find slides and materials</h3>
<p><a href="https://htmlpreview.github.io/?https://github.com/gisma/link2gi2018/blob/master/link2gi2018.html">GEOSTAT 2018</a> presentation slides.</p>
<p><a href="https://github.com/gisma/link2gi2018">link2GI GEOSTAT</a> github repository.</p>
<h3>Prerequisites</h3>
<p>Please check the R dependencies:</p>
<pre><code class="r">install.packages(c("sf", "raster", "rgdal", "gdalUtils",
"tools", "rgrass7", "sp", "RSAGA", "link2GI"))
# for the Canopy height model usecase you need to install uavRst
devtools::install_github("gisma/uavRst", ref = "master")
</code></pre>
<p>In addition you need at least one installation of the following GIS software.</p>
<ul>
<li>For <code>GRASS</code>- and <code>SAGA-GIS</code> follow the <a href="https://github.com/jannes-m/RQGIS/blob/master/vignettes/install_guide.Rmd">RQGIS installation instructions</a> as provided by Jannes Muenchow. For standalone GRASS you may have a look at the the <a href="https://gitlab.com/veroandreo/grass-gis-geostat-2018">geostat2018 instructions</a> as provided by Veronica Andreos.</li>
<li>For installing the <code>Orfeo Toolbox</code>, please follow the OTB cookbook <a href="https://www.orfeo-toolbox.org/CookBook/Installation.html">installation instructions</a>.</li>
</ul>
<p>Please download the data and scripts for the exercises.</p>
<p><strong>PLEASE NOTE:</strong> </p>
<p>If you run the following code you will create the folder <em>link2gi-master</em> in your <strong>home folder</strong>. During the tutorial it is assumed to be the root folder.</p>
<pre><code class="r">url <- "https://github.com/gisma/link2gi2018/archive/master.zip"
res <- curl::curl_download(url, paste0(tmpDir(),"master.zip"))
utils::unzip(zipfile = res, exdir = "~")
</code></pre>
<h2>The examples</h2>
<ul>
<li><p>Basic usage of SAGA and OTB calls - <a href="https://github.com/gisma/link2gi2018/blob/master/R/usecases/saga-otb/useCaseSAGA-OTB.R">SAGA & OTB basic usecase</a></p></li>
<li><p>Wrapping a <a href="https://neteler.gitlab.io/grass-gis-analysis/02_grass-gis_ecad_analysis/">GRASS GIS example</a> of Marcus Neteler as presented on GEOSTAT 2018 - <a href="https://github.com/gisma/link2gi2018/blob/master/R/usecases/grass/useCaseGRASS-Neteler2018.R">Analysing the ECA&D climatic data - reloaded</a></p></li>
<li><p>Performing a GRASS based cost analysis on a huge cost raster - <a href="https://github.com/gisma/link2gi2018/blob/master/R/usecases/cost-analysis/useCaseBeetle.R">Beetle spread over high asia</a></p></li>
<li><p>Deriving a canopy height model using a mixed API approach - <a href="https://github.com/gisma/link2gi2018/blob/master/R/usecases/uav-pc/useCaseCHM.R">Canopy Height Model from UAV derived point clouds</a></p></li>
</ul>
</body>
</html>