-
Notifications
You must be signed in to change notification settings - Fork 1
/
preface.html
502 lines (482 loc) · 23.5 KB
/
preface.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
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-1.4.554">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>preface</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
vertical-align: middle;
}
</style>
<script src="preface_files/libs/clipboard/clipboard.min.js"></script>
<script src="preface_files/libs/quarto-html/quarto.js"></script>
<script src="preface_files/libs/quarto-html/popper.min.js"></script>
<script src="preface_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="preface_files/libs/quarto-html/anchor.min.js"></script>
<link href="preface_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="preface_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="preface_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="preface_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="preface_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">
</head>
<body class="fullcontent">
<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">
<main class="content" id="quarto-document-content">
<section id="preface" class="level1">
<h1>Preface</h1>
<p>This Quarto book contains the online documentation of the second version of <a href="arabesque.univ-eiffel.fr"><em>Arabesque</em></a>, a web application for thematic flow mapping created within the geographic flow vizualisation research program (<a href="https://geoflowiz.hypotheses.org/accueil/abstract">gflowiz</a>) funded by <a href="www.univ-eiffel.fr">Univ. Gustave Eiffel</a> (former IFSTTAR).</p>
<p><br>
The gflowiz project was originally led by Françoise Bahoken and co-directed by Étienne Côme (Univ. Gustave Eiffel), with the scientific collaboration ofLaurent Jégou (Univ. Toulouse 2 Jean Jaurès). The main developer of the first version of <em>Arabesque</em> was Thomas Bapaume (ESIEE), then Paul Fabre (UGE/IGN). Tony Hauck is developping the second version. Other contributors to the design of the app include Marion Maisonobe and Grégoire le Campion (CNRS).</p>
<p><em>Arabesque</em> is an innovative cartographic application that meets the contemporary challenges and objectives of flows and networks geovisualisation.</p>
<section id="challenges" class="level2">
<h2 class="anchored" data-anchor-id="challenges">Challenges</h2>
<p>The analysis of the dynamics of urban areas or metropolises in one hand, the delimitation of their functional areas and the spatio-temporal comparison of their patterns in the other hand, are often limited by two categories of problems inherent in data and tools.<br>
<br>
The lack of open origin-destination (OD) data sets depicting territorial interactions and interrelations limited the possibility of empirical analysis. Similarly, the lack of dedicated geovisualization and cartographic analysis tools means that many images of visual and analytical interest are no longer part of the current cartographic landscape. In addition to these specific problems regarding online OD data, it is important to focus attention on the current possibilities offered by online possibilities of OD cartography.</p>
<p>The current range of possibilities for exploring flows and networks datasets on the geoweb is symptomatic of the ongoing enthusiasm of a growing interdisciplinary community. While for a long time the efforts were limited to direct visualisation alone, applications specifically dedicated to flows have recently come on line.</p>
<p>Three development approaches seem to be coexisting. The first one seems to be dedicated to the development of large volumes of data in a digital cartographic form, as is the case with the United Nations <a href="https://comtrade.un.org/">Comtrade</a> for example. The second approach consists of applications for the visual geographical exploration of one’s own OD datasets as in <a href="https://flowmap.blue/">flowmap.blue</a>, for example. Academic applications offer different graphical models allowing co-visualization, such as the <a href="https://networkcube.github.io/vistorian/index.html">Vistorian</a> (Serrano Molinero & al., 2017) and <a href="https://www.irit.fr/netscity/">Netscity</a> (Maisonobe & al., 2019). The third approach is specific to heavy online thematic mapping software infrastructures such as <a href="#0">Magrit</a> or <a href="#0">Kepler</a> in response to the shortcomings of current editors regarding flow mapping. It is interesting to note that all these solutions are being developed in line with the growing practice of open-source development with a view to reproducibility (Giraud, Lambert, 2017).</p>
<p>Few applications, however, appear to be fully aligned with the “visualization mapping” paradigm as defined by A. Mac Eachren (2004). Indeed, efforts still seem to be focused more on displaying layers and simply exploring them. Existing tools still do little to combine within a single interface the three pillars of cartographic representation: (geo)visualization and the processing of statistical and geographic data.</p>
<p>In this context, <em>Arabesque’s</em> objectives are as follows.</p>
</section>
<section id="objectives" class="level2">
<h2 class="anchored" data-anchor-id="objectives">Objectives</h2>
<p><em>Arabesque’s</em> ambition is to meet the high demand for analysis of one’s own flow dataset in a free, open source and ergonomic way - this need corresponding to the main result of our survey conducted in 2018.<br>
<br>
<em>Arabesque</em> is part of the french Lemaire Law for a digital republic. It falls under the general objective of increasing understanding of the geographical determinants of the spatial mobility of goods, people and so on.<br>
<br>
<em>Arabesque</em> aims to respond to the need to visualize the results of fundamental or applied research within theoretical and methodological development frameworks that can be considered both transverse to several subjects (population, habitat, environment, transport, i.e.) and interdisciplinary by nature (geography, demography, environment, geomatics, engineering sciences, human and social sciences, i.e.). These subjects also contribute to the societal challenges linked to the rise of the digital society, which they help to address.</p>
<p>From a scientific point of view, <em>Arabesque</em> aims to innovate in the handling of flow and network data currently available on the geoweb (Bahoken et al, 2020). This is why it is part of the Mac Eachren (2005) new paradigm of “visualization mapping”.<br>
<em>Arabesque</em> combines in the same environment geo-visualization and geographic and statistical information processing devices - initially for descriptive purposes. On the other hand, it enables the processing of complex relational datasets, which can be both voluminous and display different dimensions of spatial mobilities (several thematic categories and/or temporalities).<br>
Particular attention is paid to rendering, both in terms of drawing and the cartographic semiology of linear features. The desire to improve the quality of the images of flows produced should lead to the development of a sensible approach to the geo-visualization of mobilities and spatial interactions.</p>
<p>Françoise Bahoken and Etienne Côme</p>
<p>Paris, Mai 2024.</p>
<p><strong>Quoted references:</strong></p>
<p>Keim D., Andrienko G., Fekete J.-D., Görg C., Kohlhammer J., Melançon G. (2008), <em>Visual Analytics: Definition, Process, and Challenges</em>, In: Kerren A. & al. (Eds.): Information Visualization, Springer-Verlag Berlin Heidelberg, LNCS 4950, pp. 154–175.</p>
<p>Mac Eachren A. (2005), <em>How Maps Work. Representation, Visualization, and Design, New-York, The Guildford Press.</em></p>
<p>Maisonobe M., Jégou L., Yakimovich N., Cabanac G. (2019), NETSCITY: a geospatial application to analyse and map world scale production and collaboration data between cities, <em>International Conference on Scientometrics and Informetrics (ISSI 2019)</em>, sep. 2019, Rome, Italy, <a href="https://hal.science/hal-02301035">〈hal-02301035〉</a></p>
<p>Giraud T., Lambert N. (2017), Reproducible cartography, in: <em>Advances in Cartography and GISsciences</em>, International Cartographic Conference, ICACI’2017, Springer, pp.173-183.</p>
<p>Serrano Molinero V., Bach B., Plaisant C., Dufournaud N.,Fekete J.-D. (2017), Understanding the Use of The Vistorian: Complementing Logs with Context Mini-Questionnaires, <em>Visualization for the Digital Humanities</em>, Oct. 2017, Phoenix, United States. <a href="https://inria.hal.science/hal-01650259">⟨hal-01650259⟩</a>.</p>
</section>
</section>
</main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
const toggleBodyColorMode = (bsSheetEl) => {
const mode = bsSheetEl.getAttribute("data-mode");
const bodyEl = window.document.querySelector("body");
if (mode === "dark") {
bodyEl.classList.add("quarto-dark");
bodyEl.classList.remove("quarto-light");
} else {
bodyEl.classList.add("quarto-light");
bodyEl.classList.remove("quarto-dark");
}
}
const toggleBodyColorPrimary = () => {
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
if (bsSheetEl) {
toggleBodyColorMode(bsSheetEl);
}
}
toggleBodyColorPrimary();
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const isCodeAnnotation = (el) => {
for (const clz of el.classList) {
if (clz.startsWith('code-annotation-')) {
return true;
}
}
return false;
}
const clipboard = new window.ClipboardJS('.code-copy-button', {
text: function(trigger) {
const codeEl = trigger.previousElementSibling.cloneNode(true);
for (const childEl of codeEl.children) {
if (isCodeAnnotation(childEl)) {
childEl.remove();
}
}
return codeEl.innerText;
}
});
clipboard.on('success', function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
let tooltip;
if (window.bootstrap) {
button.setAttribute("data-bs-toggle", "tooltip");
button.setAttribute("data-bs-placement", "left");
button.setAttribute("data-bs-title", "Copied!");
tooltip = new bootstrap.Tooltip(button,
{ trigger: "manual",
customClass: "code-copy-button-tooltip",
offset: [0, -8]});
tooltip.show();
}
setTimeout(function() {
if (tooltip) {
tooltip.hide();
button.removeAttribute("data-bs-title");
button.removeAttribute("data-bs-toggle");
button.removeAttribute("data-bs-placement");
}
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
});
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
var mailtoRegex = new RegExp(/^mailto:/);
var filterRegex = new RegExp('/' + window.location.host + '/');
var isInternal = (href) => {
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
}
// Inspect non-navigation links and adorn them if external
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool)');
for (var i=0; i<links.length; i++) {
const link = links[i];
if (!isInternal(link.href)) {
// undo the damage that might have been done by quarto-nav.js in the case of
// links that we want to consider external
if (link.dataset.originalHref !== undefined) {
link.href = link.dataset.originalHref;
}
}
}
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
const config = {
allowHTML: true,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start',
};
if (contentFn) {
config.content = contentFn;
}
if (onTriggerFn) {
config.onTrigger = onTriggerFn;
}
if (onUntriggerFn) {
config.onUntrigger = onUntriggerFn;
}
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note) {
return note.innerHTML;
} else {
return "";
}
});
}
const xrefs = window.document.querySelectorAll('a.quarto-xref');
const processXRef = (id, note) => {
// Strip column container classes
const stripColumnClz = (el) => {
el.classList.remove("page-full", "page-columns");
if (el.children) {
for (const child of el.children) {
stripColumnClz(child);
}
}
}
stripColumnClz(note)
if (id === null || id.startsWith('sec-')) {
// Special case sections, only their first couple elements
const container = document.createElement("div");
if (note.children && note.children.length > 2) {
container.appendChild(note.children[0].cloneNode(true));
for (let i = 1; i < note.children.length; i++) {
const child = note.children[i];
if (child.tagName === "P" && child.innerText === "") {
continue;
} else {
container.appendChild(child.cloneNode(true));
break;
}
}
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(container);
}
return container.innerHTML
} else {
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(note);
}
return note.innerHTML;
}
} else {
// Remove any anchor links if they are present
const anchorLink = note.querySelector('a.anchorjs-link');
if (anchorLink) {
anchorLink.remove();
}
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(note);
}
// TODO in 1.5, we should make sure this works without a callout special case
if (note.classList.contains("callout")) {
return note.outerHTML;
} else {
return note.innerHTML;
}
}
}
for (var i=0; i<xrefs.length; i++) {
const xref = xrefs[i];
tippyHover(xref, undefined, function(instance) {
instance.disable();
let url = xref.getAttribute('href');
let hash = undefined;
if (url.startsWith('#')) {
hash = url;
} else {
try { hash = new URL(url).hash; } catch {}
}
if (hash) {
const id = hash.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note !== null) {
try {
const html = processXRef(id, note.cloneNode(true));
instance.setContent(html);
} finally {
instance.enable();
instance.show();
}
} else {
// See if we can fetch this
fetch(url.split('#')[0])
.then(res => res.text())
.then(html => {
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(html, "text/html");
const note = htmlDoc.getElementById(id);
if (note !== null) {
const html = processXRef(id, note);
instance.setContent(html);
}
}).finally(() => {
instance.enable();
instance.show();
});
}
} else {
// See if we can fetch a full url (with no hash to target)
// This is a special case and we should probably do some content thinning / targeting
fetch(url)
.then(res => res.text())
.then(html => {
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(html, "text/html");
const note = htmlDoc.querySelector('main.content');
if (note !== null) {
// This should only happen for chapter cross references
// (since there is no id in the URL)
// remove the first header
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
note.children[0].remove();
}
const html = processXRef(null, note);
instance.setContent(html);
}
}).finally(() => {
instance.enable();
instance.show();
});
}
}, function(instance) {
});
}
let selectedAnnoteEl;
const selectorForAnnotation = ( cell, annotation) => {
let cellAttr = 'data-code-cell="' + cell + '"';
let lineAttr = 'data-code-annotation="' + annotation + '"';
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
return selector;
}
const selectCodeLines = (annoteEl) => {
const doc = window.document;
const targetCell = annoteEl.getAttribute("data-target-cell");
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
const lineIds = lines.map((line) => {
return targetCell + "-" + line;
})
let top = null;
let height = null;
let parent = null;
if (lineIds.length > 0) {
//compute the position of the single el (top and bottom and make a div)
const el = window.document.getElementById(lineIds[0]);
top = el.offsetTop;
height = el.offsetHeight;
parent = el.parentElement.parentElement;
if (lineIds.length > 1) {
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
height = bottom - top;
}
if (top !== null && height !== null && parent !== null) {
// cook up a div (if necessary) and position it
let div = window.document.getElementById("code-annotation-line-highlight");
if (div === null) {
div = window.document.createElement("div");
div.setAttribute("id", "code-annotation-line-highlight");
div.style.position = 'absolute';
parent.appendChild(div);
}
div.style.top = top - 2 + "px";
div.style.height = height + 4 + "px";
div.style.left = 0;
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
if (gutterDiv === null) {
gutterDiv = window.document.createElement("div");
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
gutterDiv.style.position = 'absolute';
const codeCell = window.document.getElementById(targetCell);
const gutter = codeCell.querySelector('.code-annotation-gutter');
gutter.appendChild(gutterDiv);
}
gutterDiv.style.top = top - 2 + "px";
gutterDiv.style.height = height + 4 + "px";
}
selectedAnnoteEl = annoteEl;
}
};
const unselectCodeLines = () => {
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
elementsIds.forEach((elId) => {
const div = window.document.getElementById(elId);
if (div) {
div.remove();
}
});
selectedAnnoteEl = undefined;
};
// Handle positioning of the toggle
window.addEventListener(
"resize",
throttle(() => {
elRect = undefined;
if (selectedAnnoteEl) {
selectCodeLines(selectedAnnoteEl);
}
}, 10)
);
function throttle(fn, ms) {
let throttle = false;
let timer;
return (...args) => {
if(!throttle) { // first call gets through
fn.apply(this, args);
throttle = true;
} else { // all the others get throttled
if(timer) clearTimeout(timer); // cancel #2
timer = setTimeout(() => {
fn.apply(this, args);
timer = throttle = false;
}, ms);
}
};
}
// Attach click handler to the DT
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
for (const annoteDlNode of annoteDls) {
annoteDlNode.addEventListener('click', (event) => {
const clickedEl = event.target;
if (clickedEl !== selectedAnnoteEl) {
unselectCodeLines();
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
if (activeEl) {
activeEl.classList.remove('code-annotation-active');
}
selectCodeLines(clickedEl);
clickedEl.classList.add('code-annotation-active');
} else {
// Unselect the line
unselectCodeLines();
clickedEl.classList.remove('code-annotation-active');
}
});
}
const findCites = (el) => {
const parentEl = el.parentElement;
if (parentEl) {
const cites = parentEl.dataset.cites;
if (cites) {
return {
el,
cites: cites.split(' ')
};
} else {
return findCites(el.parentElement)
}
} else {
return undefined;
}
};
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
for (var i=0; i<bibliorefs.length; i++) {
const ref = bibliorefs[i];
const citeInfo = findCites(ref);
if (citeInfo) {
tippyHover(citeInfo.el, function() {
var popup = window.document.createElement('div');
citeInfo.cites.forEach(function(cite) {
var citeDiv = window.document.createElement('div');
citeDiv.classList.add('hanging-indent');
citeDiv.classList.add('csl-entry');
var biblioDiv = window.document.getElementById('ref-' + cite);
if (biblioDiv) {
citeDiv.innerHTML = biblioDiv.innerHTML;
}
popup.appendChild(citeDiv);
});
return popup.innerHTML;
});
}
}
});
</script>
</div> <!-- /content -->
</body></html>