Datenvisualisierung

Berücksichtigt sehbehinderte Personen bei der Einbeziehung von Datenvisualisierungen. Datentabellen können dabei eine Alternative zu den Datenvisualisierungen für Screen-Reader sein. Berücksichtigt auch die Farbauswahl für farbenblinde Personen. Weitere Emfpehlungen sind:

  • ❌ Verlasst euch nicht auf Farben um die Daten zu erklären

  • ❌ Verwendet keine kontrastarmen Farben

  • ❌ Versteckt keine wichtigen Daten hinter Interaktionen

  • ❌ Überfordert euer Publikum nicht mit zu vielen Informationen

  • ❌ Verlasst euch nicht auf hover-Effekte; diese funktionieren nicht auf Mobilgeräten

  • ❌ Verzichtet auf Animationen und Scroll-Hijacking, wenn diese nicht wesentlich zur Erklärung der Daten beitragen

  • ✅ Beachtet bereits beim Design die Zugänglichkeit

  • ✅ Beachtet auch kleinere Displays, z.B. bei Mobilgeräten

  • ✅ Verwendet kontrastreiche Farben und Muster

  • ✅ Verwendet Etiketten und Legenden

  • ✅ Übersetzt die Daten in eine klare Sprache

  • ✅ Gebt Kontext an und erklärt die Visualisierung

D3.js

D3.js ist eine Javascript-Bibliothek zur Datenvisualisierung. Um Datenvisualisierungen zugänglicher zu machen, haben wir ein paar Tipps zusammengestellt:

  1. Um die Farben zu erläutern, könnt ihr eine Legende hinzufügen, z.B. mit:

    const legend = chart.append("g").attr("aria-label", "Legend");
    

    Alternativ kann auch ein Titel hinzugefügt werden:

    const legend = chart.append("g");
    legend.append("text")
        .text("Legend")
        .attr("class", "legendTitle");
    
  2. Nun können wir die Erläuterungen hinzufügen, z.B.:

    legend.append("rect")
      .attr("fill", function(d){return hot(d) });
    
    legend.append("text")
       .text(">30 °C");
    
  3. Erläutern der Daten, z.B. für ein Balkendiagramm:

    chart.selectAll(".label")
      .data(data)
      .enter().append("text")
      .text(row => row.year);
    
  4. Optisch sind die Daten jetzt schon sehr viel zugänglicher, aber mit Bedienhilfen werden nun auch die Tage auf der x-Achse erschlossen, und würden z.B. alle vorgelesen werden. Die Zugänglichkeit würde deutlich erhöht werden, wenn die Ausgabe so etwas liefern würde wie Die durchschnittliche Jahrestemperatur betrug 2011 9,6 Grad Celsius.

    Hierfür sollten dann nicht zunächst die Daten durchlaufen werden und anschließend die Achsenbeschriftungen sondern jedes Datum mit der zugehörigen Erläuterung:

    const ticks = chart.selectAll(".tick")
      .data(data)
      .enter().append("g")
      .attr("class", "tick");
    
    ticks.append("text")
      .text((data) => data.year);
    
    ticks.append("text")
      .text(row => row.temperature)
      .attr("class", "label");
    

    Dies gibt folgendes XML aus:

    <g>
      <text>2011</text>
      <text>9,6 °C</text>
    </g>
  5. Bei vielen Achswerten sollten evtl. nicht alle Werte auf der Achse angezeigt werden. display: none; oder visibility: hidden sind jedoch keine Lösung, da die Werte dann z.B. auch nicht vorgelesen würden. Wir können jedoch die Positionierung der Achsenbeschriftungen so verändern, dass sie außerhalb des sichtbaren Rahmens stehen.

Vega

Vega ist eine deklarative Sprache zum Erstellen, Speichern und Teilen interaktiver Visualisierungsdesigns. Ab Version 5.11 unterstützt sie einige ARIA-Attribute für die Ausgabe von SVG-Dateien:

aria

schließt ARIA-Attribute in SVG-Dateien ein. Der Standardwert ist true. Bei false wird das aria-hidden-Attribut für die entsprechende SVG-Gruppe gesetzt.

description

liefert in aria-label eine Textbeschreibung des SVG-ELements, wenn aria den Wert true hat.

Mit Flight Passengers Example gibt es ein Beispiel für die Verwendung der Vega-Anweisungen aria- und description durch Vega-Lite:

../_images/flight-passengers.svg
  • Die horizontalen Linien sollen nicht zugänglich werden. Daher wurde in der Vega-Konfigurationsdatei flight-passengers.vg.json die horizontale Linie mit "aria": false, ausgezeichnet.

    108  "marks": [
    109    {
    110      "type": "line",
    111      "aria": false,
    112      "from": {"data": "traffic"},
    113      "encode": {
    114        "enter": {
    115          "x": {"scale": "x", "field": "unit0"},
    116          "y": {"scale": "y", "field": "change"},
    117          "stroke": {"value": "steelblue"},
    118          "strokeWidth": {"value": 3}
    119        }
    120      },
    121      "zindex": 2
    122    },
    

    In der generierten SVG-Datei flight-passengers.svg erhält die zugehörige Gruppe dadurch die Annotation aria-hidden="true":

    69                    <g class="mark-line role-mark" aria-hidden="true">
    70                        <path d="M24.000000019013836,20.112588094658268L93.2076502901645,26.132110486376767L160.09289618980006,14.924455087752282L229.2076502860901,20.695076449129235L298.32240438238017,9.587662748507821L362.9781420853612,109.65285552622753L432.0000000067907,164.6837644873604" stroke="steelblue" stroke-width="3"/>
    71                    </g>
    
  • Die Markierungen in der Zeitachse erhalten hingegen eine ausführliche Beschreibung (Englisch description) mit Monat, Jahr und prozentualer Veränderung zum Vorjahr:

    123    {
    124      "type": "symbol",
    125      "from": {"data": "traffic"},
    126      "encode": {
    127        "enter": {
    128          "description": {
    129            "signal": "timeFormat(datum.unit0, '%B %Y') + ': ' + format(datum.change, '+.1%') + ' change from prior year'"
    130          },
    131          "tooltip": {
    132            "signal": "format(datum.change, '+.1%')"
    133          },
    134          "x": {"scale": "x", "field": "unit0"},
    135          "y": {"scale": "y", "field": "change"},
    136          "fill": {"value": "steelblue"}
    137        }
    138      },
    139      "zindex": 2
    140    }
    

    In der generierten SVG-Datei erhalten die Pfade dadurch ein entsprechendes aria-label:

    72                    <g class="mark-symbol role-mark" role="graphics-object" aria-roledescription="symbol mark container">
    73                        <path aria-label="October 2019: +6.1% change from prior year" role="graphics-symbol" aria-roledescription="symbol mark" transform="translate(24.000000019013836,20.112588094658268)" d="M4,0A4,4,0,1,1,-4,0A4,4,0,1,1,4,0" fill="steelblue"/>
    74                        <path aria-label="November 2019: +2.0% change from prior year" role="graphics-symbol" aria-roledescription="symbol mark" transform="translate(93.2076502901645,26.132110486376767)" d="M4,0A4,4,0,1,1,-4,0A4,4,0,1,1,4,0" fill="steelblue"/>
    75                        <path aria-label="December 2019: +9.7% change from prior year" role="graphics-symbol" aria-roledescription="symbol mark" transform="translate(160.09289618980006,14.924455087752282)" d="M4,0A4,4,0,1,1,-4,0A4,4,0,1,1,4,0" fill="steelblue"/>
    76                        <path aria-label="January 2020: +5.7% change from prior year" role="graphics-symbol" aria-roledescription="symbol mark" transform="translate(229.2076502860901,20.695076449129235)" d="M4,0A4,4,0,1,1,-4,0A4,4,0,1,1,4,0" fill="steelblue"/>
    77                        <path aria-label="February 2020: +13.4% change from prior year" role="graphics-symbol" aria-roledescription="symbol mark" transform="translate(298.32240438238017,9.587662748507821)" d="M4,0A4,4,0,1,1,-4,0A4,4,0,1,1,4,0" fill="steelblue"/>
    78                        <path aria-label="March 2020: −55.6% change from prior year" role="graphics-symbol" aria-roledescription="symbol mark" transform="translate(362.9781420853612,109.65285552622753)" d="M4,0A4,4,0,1,1,-4,0A4,4,0,1,1,4,0" fill="steelblue"/>
    79                        <path aria-label="April 2020: −93.6% change from prior year" role="graphics-symbol" aria-roledescription="symbol mark" transform="translate(432.0000000067907,164.6837644873604)" d="M4,0A4,4,0,1,1,-4,0A4,4,0,1,1,4,0" fill="steelblue"/>
    80                    </g>