Icon Category

Information Visualization

5 ECTS; Winter Term; Dr. Roberto Grosso

Tabs

Description

Information visualization deals with the graphical representation of abstract data without spatial structure. Abstract data visualization uses visual metaphors and interaction to extract information from the data. Typical application scenarios are analyzing financial transactions, social networks, bioinformatics, geography, text analysis, or visualization of software source code.

Course Content

In this lecture, different techniques are presented to visualize different types of data. In particular, the following topics are covered
  • Data types and Colors
  • Multivariate Data
  • Networks
  • Hierarchies
  • Text Visualization

Educational objectives and skills

Educational objectives and skills of this course are:
  • listen und identifizieren die unterschiedlichen Algorithmen der Informationsvisualisierung
  • veranschaulichen die Methoden zur Visualisierung von Graphen und Netzwerke und bestimmen ihre Unterschiede
  • klassifizieren Algorithmen zur Visualisierung multivariater Daten und erklären ihrer Funktionsweise
  • erklären und charakterisieren Techniken für die Text-Visualisierung und veranschaulichen die Methoden zur Visualisierung zeitabhängiger Daten
  • lernen Visualisierungswerkzeuge kennen und wenden diese zur Lösung praxisrelevanten Aufgaben der Informationsvisualisierung
  • sind in der Lage, die vorgestellten Algorithmen der Informationsvisualisierung in JavaScript zu implementieren

Materials

Information Visualization
  • Robert Spence: Information Visualization: Design for Interaction
  • Stuart K. Card, Jock Mackinlay, Ben Shneiderman: Readings in Information Visualization – Using Vision to Think
  • Benjamin B. Bederson, Ben Shneiderman: The Craft of Information Visualization – Readings and Reflections
  • Tamara Munzner: Visualization Analysis and Design
  • Colin Ware: Information Visualization, Perception for Design (third edition)
  • Ricardo Mazza: Introduction to Information Visualization
  • Robert Spence: Information Visualization - An Introduction
Networks / Graphs
  • Network theory
    • Graph Theory, Reinhard Diestel
    • Graphentheorie, Peter Tittmann
    • Graphs, Networks and Algorithms, Dieter Jungnickel
  • Network analysis
    • Networks, 2nd Edition, Mark Newman
    • Graph Theory and Complex Networks: An Introduction, Maarten van Steen

Examination

  • e-Prüfung (electronic exam within the StudOn-Exam platfrom)
  • 90 min
  • theory, exercises and programming exercises

Information Visualization (InfoVIS)

Force directed layout of the social network Les Miserables.
{ getResources: function() { const url = 'https://www.studon.fau.de/file4834377_download.html'//'https://www.studon.fau.de/file3447273_download.html' return [ { name: 'lesmiserables', uri: url, type: 'json' } ] }, setupDOM: function(canvasElement, outputElement, scope) { canvasElement.css("border", 'none') // #cc3300 scope.find("#allow_run_button").css('display','none') }, init: function(canvasElement, outputElement, scope, runner) { const t = ` <form> <div id="D3EigenvectorCentrality-Menu" style="float: left"> <label for="cLayout-style" style="font-family: sans-serif; font-size: 1.1em; float: left">Choose a centrality:</label> <select class="form-control text-left" id="d3-eigenvector-layout_01"> <option value="eigenvector">Eigenvector Centrality</option> <option value="degreecentr">Degree Centrality</option> </select> </div> </form> <div id='targetD3_eigenvector_layout_01'></div> ` canvasElement[0].innerHTML = '' + t const width = canvasElement.width() const height = canvasElement.height() const base = d3.select(canvasElement.get(0)) const svg = base.append('svg') svg .attr('class', 'closeness-centrality-short') .attr('width', width) .attr('height', height) const g = svg.append('g') //g.attr('transform', `translate(${width/2}, ${height/2})`) const n0 = canvasElement.get(0) n0.svg = svg n0.g = g n0.width = width runner() n0.height = height canvasElement.get(0).children[2].style.border = 'solid #b11226' runner() }, addArgumentsTo(args) { args.lesmiserables = this.lesmiserables }, reset(canvasElement) {}, update: function(txt, json, canvasElement, outputElement) { const n0 = canvasElement.get(0) const svg = n0.svg const g = n0.g const width = n0.width const height = n0.height g.selectAll('*').remove() const margin = {top: 30, bottom: 30, left: 30, right: 30} const iw = width - margin.left - margin.right const ih = height - margin.top - margin.bottom const center = {x: margin.left + iw/2, y: margin.top + ih/2} const {nodes, links} = json //return const gSet = new Set() nodes.forEach( n => { gSet.add(n.group) }) const lineGenerator = d3.line().curve(d3.curveBasis) const colors = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c', '#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#D2691E','#b15928'] const colorScale = d3.scaleOrdinal() .domain(Array.from(gSet).sort()) .range(colors) // text scaling const minRad = 4 const maxRad = 19 const nScale = d3.scaleLinear() .domain([d3.min(nodes, d => d.c), d3.max(nodes, d => d.c)]) .range([minRad, maxRad]) const dScale = d3.scaleLinear() .domain([d3.min(nodes, d => d.degree), d3.max(nodes, d => d.degree)]) .range([minRad, maxRad]) nodes.forEach ( n => n.r = nScale(n.c)) // layout const simulation = d3.forceSimulation(nodes) .force('link', d3.forceLink(links)) .force('charge', d3.forceManyBody().strength(-55)) .force('center', d3.forceCenter(center.x,center.y).strength(0.1)) .force('x', d3.forceX().x(center.x)) //.strength( 0.01 ) .force('y', d3.forceY().y(center.y + 1))// .strength( 0.01 ) .force('collision', d3.forceCollide().radius( function(d) { return 1.25 * d.r })) .alpha(0.2) .alphaDecay(0.0001) const beta = 0.2 const link = g.append("g") .attr('fill', 'none') .attr("stroke-opacity", 0.6) .selectAll("path") .data(links) .join("path") .attr("stroke-width", d => Math.log(d.value+3) ) //Math.sqrt(d.value)) .attr('stroke', d => { const g = d.source.c > d.target.c ? d.source.group : d.target.group return colorScale(g) }) .attr('d', d => { const d0 = [d.source.x, d.source.y] const d2 = [d.target.x, d.target.y] const x = (d0[0] + d2[0]) / 2 const y = (d0[1] + d2[1]) / 2 const vx = (d2[0] - d0[0]) / 2 const vy = (d2[1] - d0[1]) / 2 const d1 = [x - beta * (vy), y + beta * vx] return lineGenerator([d0, d1, d2]) }) const node = g.append('g') .attr("stroke", "#fff") .attr("stroke-width", 1.5) .selectAll("circle") .data(nodes) .join("circle") .attr('class', 'eigenvector-node') .attr('r', d => d.r) .attr("cx", d => d.x) .attr("cy", d => d.y) .attr("fill", d => colorScale(d.group)) .call(drag(simulation)) node.append('title') .text(d => d.name + ', c: ' + d.c.toFixed(2) + ', deg: ' + d.degree) simulation.on("tick", () => { link .attr('d', d => { const d0 = [d.source.x, d.source.y] const d2 = [d.target.x, d.target.y] const x = (d0[0] + d2[0]) / 2 const y = (d0[1] + d2[1]) / 2 const vx = (d2[0] - d0[0]) / 2 const vy = (d2[1] - d0[1]) / 2 const d1 = [x - beta * (vy), y + beta * vx] return lineGenerator([d0, d1, d2]) }) node .attr("cx", d => d.x) .attr("cy", d => d.y); }) function drag (simulation) { function dragstarted(event) { if (!event.active) simulation.alphaTarget(0.3).restart() event.subject.fx = event.subject.x event.subject.fy = event.subject.y } function dragged(event) { event.subject.fx = event.x event.subject.fy = event.y } function dragended(event) { if (!event.active) simulation.alphaTarget(0) event.subject.fx = null event.subject.fy = null } return d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended) } // drag() d3.select("#d3-eigenvector-layout_01").on("change", function () { centrality(this.value) }) function centrality(value) { if (value === 'degreecentr') { nodes.forEach( n => n.r = dScale(n.degree)) d3.selectAll('circle.eigenvector-node').transition().duration(1200).attr('r', d => d.r) } else if (value === 'eigenvector') { nodes.forEach( n => n.r = nScale(n.c)) d3.selectAll('circle.eigenvector-node').transition().duration(1200).attr('r', d => d.r) } simulation.force('collision').initialize(nodes) simulation.alpha(0.5) simulation.restart() } } // update }// Eigenvector Centrality // Remark: - the property nodes[i].neighbors is an array containing the neighbor nodes // of node i // - write the centrality as follows: nodes[i].c = centralityvalue // - you might use the function normalize(b) to normalize the vector in the power iteration // - the function error(b0, b1) estimate the approximation error // @param {[Objects]} nodes, array of nodes // @param {Number} maxIter, maximum number of iterations // @param {Number} epsilon, approximation error function eigenvector( nodes, maxIter, epsilon ){ const nrNodes = nodes.length let b0 = new Array(nrNodes).fill(0).map( function() { return 1 + 0.01 * (Math.random() - 1) } ) let b1 = new Array(nrNodes).fill(0) let err = epsilon + 0.1 while(maxIter > 0 && err > epsilon) { b1.fill(0) nodes.forEach( n => { n.neighbors.forEach( g => { b1[n.id] += b0[g.id] }) }) normalize(b1) err = error(b0,b1) b0 = [...b1] maxIter-- } const maxb0 = Math.max(...b0) b0.forEach ( (e,i) => nodes[i].c = (e / maxb0) ) } // eigenvector() const miserables = args.lesmiserables // the graph const { nodes, links } = miserables // make graph undirected for(let i = 0; i < nodes.length; i++) { nodes[i].neighbors = [] nodes[i].c = 0 nodes[i].id = i } for(let e of links){ let S = nodes[e.source] let T = nodes[e.target] S.neighbors.push( T ) T.neighbors.push( S ) } for (let i = 0; i < nodes.length; i++) { nodes[i].degree = nodes[i].neighbors.length } function error(b0,b1) { let err = 0 //b0.forEach( (b,i) => err += (b0[i]-b1[i])*(b0[i]-b1[i]) ) for (let i = 0; i < b0.length; i++) { err += (b0[i]-b1[i])*(b0[i]-b1[i]) } return Math.sqrt(err) } function norm( b ) { return Math.sqrt( b.reduce( (e1,e2) => e1 + e2*e2, 0 )) } function normalize( b ) { const s = norm(b) for( let i = 0; i < b.length; i++) { b[i] /= s } } // compute layout and draw function draw(nodes, links) { const maxIter = 20 const epsilon = 0.001 eigenvector(nodes, maxIter, epsilon) for(let n of nodes) delete n.neighbors } draw(nodes, links) console.log(JSON.stringify({ nodes: nodes, links: links }))
Remark: Programming skills are a prerequisite for this course.
Requirements: It is recommended to have passed the following modules before taking this course
  • Algorithmik kontinuierlicher Systeme, Module-No. 93000 
  • Computer Graphics, Module-No. 43821

StudOn-Course

Courses

Course Link

InfoVIS

This course is offered only in the summer term. The course is organized into the following learning units - Data types and Colors - Multivariate Data - Networks - Hierarchies - Text Visualization —
Tu 12:15 - 13:45  
Roberto Grosso  
Summer 2024: | | » campo  
To access this item you need to be logged in and to have appropriate permissions.