Heute soll es mal um ein für ein Radblog eher ungewöhnliches Thema gehen. Datentabellen, Visualisierung und Programmierung. Aber ich führe ja auch kein gewöhnliches Blog. Deswegen möchte ich euch gerne an meinen Eskapaden teilhaben lassen. Und die sind recht kurzfristig und fast aus einer Laune heraus zwischen den Feiertagen entstanden. Und ich möchte das ausnahmsweise mal genau so kurzfristig und hoffentlich auch kompakt bloggen. Frei nach dem Motto:
Programmieren, um zu Planen – und Bloggen, um zu lernen
Mir hilft es, das Recherchierte sinnvoll und nachvollziehbar aufzubereiten, euch hilft es vielleicht, Anregungen und Tips zu finden und alle gemeinsam kommen wir auf neue Ideen. Denn – was hier gleich folgt ist ganz und gar nicht mein tägliches Brot (wäre sonst auch langweilig) und aufgrund der Kürze der Beschäftigung (die Python Entwicklungsumgebung habe ich z.B. erst 5 Tage vor dem Schreiben der ersten Worte dieses Artikels installiert und auch die anderen Tools habe ich recherchiert, selektiert und dann sofort ausprobiert) wird der eine oder andere alte Hase vielleicht direkt Ansätze zur Verbesserung oder Weiterentwicklung sehen – und so soll es ja auch sein.
Nichts desto trotz hat sich dieser Artikel zu einem vollständigen Tutorial diverser verschiedener Möglichkeiten und der dazu betrachteten Schritte entwickelt. Wenn ihr vielleicht auch unahbhängig vom Radfahren Bedarf an der Diagramm-Erstellung auch aber nicht nur für die Webpräsentation aus und mit Excel, Google Sheets, Google Charts, JavaScript, Notion, Tableau oder Python mit Matplotlib oder Plotly habt, dann seid ihr hier richtig.
Worum geht’s?
Wir wollen uns eine Übersicht von coolen Bike-Events für das Jahr 2022 basteln. Aber nicht nur das! Wir sind ja hoffentlich nicht nur auf einen Schwerpunkt beim Radfahren fixiert, sondern wir haben ein breites Spektrum an Interessen. Von Eintages-Gravel-Events über Bikepacking – nicht nur auf der Straße sondern auch off-road – bis vielleicht sogar 24h-Rennen oder auch Zeitfahren.
Nun gibt es zwar diverse Eventübersichten und auch Kalendarien im Netz zu finden (mehr dazu in einem Folge-Artikel), aber so schön die alle auch sind – irgendwas fällt zwangsweise hinten rüber oder wird nicht abgebildet. Und was zumindest für meine Interessensgebiete zutrifft: es sind mehr und mehr Mehrtages-Events darunter.
Man kam also sowieso schon nie umhin, sich selbst eine Liste an interessanten Events nach persönlichen Wünschen und zeitlichen Möglichkeiten zusammen zu suchen. Und bei Mehrtages-Events oder längere Zeiträume umfassenden Serien (denke z.B. an die Orbit 360 Gravelserie ergeben die reinen Start-Datums-Einträge wenig wahre Übersicht, wie es um Überschneidungen mit anderen Events oder um den dazwischen liegenden Zeitraum für Erholung, Anreise und andere Aktivitäten bestellt ist.
Eine möglichst robuste und informative Eigenübersicht muss also her. Und dazu eine passende Visualisierung entweder als Timeline oder als Gantt-Chart.
Wenn sich dann daraus dann hinterher die Möglichkeit ergibt, auch ganz andere Datensätze (z.B. eine Eventdatenbank eines separaten Kurators) zu visualisieren; das ggfs. auch direkt in eine Webseite einbinden zu können oder auch die eigene Liste hier von mir für Euch zu veröffentlichen – um so besser.
Das wird dann aber in einem Folge-Artikel geschehen. Hier soll es erst mal um das „Wie“ und „Warum“ gehen.
Motivation und „Lastenheft“
Wie geschildert, hat sich das Thema dieses Blogbeitrags recht kurzfristig ergeben. Ich war natürlich mal wieder dabei, mir eine Übersicht zu verschaffen, welche Events denn für mich so in diesem Jahr interessant sein könnten. Bzw. auch, welche Möglichkeiten sich zwischen den bereits fixierten Mehrtages-Rennen „MittelgebireClassique“ Ende Mai bis Anfang Juni und dem „Transcontinental Race No 8“ Ende Juli bis Anfang August so ergeben und da hinein passen.
Und als ich da so wieder meine übliche Excel-Tabelle in völlig freier Form befüllte und mal wieder mit Zellen-Einfügen hier und manuell nach Monaten hin- und herschiebend dort beschäftigt war und dann auch noch meine separaten Recherchen nach möglichen Zeitfahrevents zusammenführen wollte, sagte ich mir: „Stop! Das ist vollkommener Murks.“
Wenn schon, dann wird das jetzt eine durchgehende Liste mit allen nötigen Feldern (also im Grunde eine relationale Datenbank mit zunächst mal einer Tabelle – gerne mehr wenn benötigt). Und es ist egal in welcher Reihenfolge da welche Events drin stehen – sortiert und selektiert wird später über die entsprechenden Felder (also Spalten). Und dann ist es auch egal, womit die Liste erstellt wird und worin sie gepflegt wird. Und auch, wo und wie sie visualisiert und damit interagiert wird. Also Trennung von Daten und Frontend. Was im (vielleicht) einfachsten Fall ja trotzdem alles in einem Programm (z.B. Excel) geschehen kann. Was aber auch problemlos an andere Frontends weitergebbar und visualisierbar sein soll.
Also meine Motivation war:
- Wiederverwendbarkeit
- Werkzeug-Unabhängigkeit
- Robustheit
- Lernen
Und die Aufgaben, die ich daraus für die Datentabelle abgeleitet habe, lauten wie folgt:
- aufstellen einer Event-Datenbank als eine unsortierte Tabelle (oder ggfs. auch mehrere; relationales Datenbankkonzept)
- Die Events sollen nach diversen Typen kategorisierbar sein. U.a. nach ihrer Art: Bikepacking Road, Bikepacking Gravel, Expo etc. aber z.B. auch nach Routentyp: fixed Route, free Route etc.
- Neben den üblichen Daten wie angegebene oder erwartbare Streckenlänge oder dem Veranstaltungsdatum sollen auch die Dauern der Events abgebildet werden (ein TCR z.B. mit 14 Tagen, ein Wochenendcamp mit 2 oder 3 Tagen usw.)
- Ich möchte meinen Anmeldestatus sehen können bzw. welche Events ich fest vorhabe, als Eventual-Position fixiere (gerade in Pandemie-Zeiten immer noch wichtig) oder welche ich generell wie interessant finde (also ein Ranking und auch Prioritäten zuweisen können)
- Und darüber hinaus möchte ich natürlich ein paar allgemeine Informationen zum Event selbst im Zugriff haben: Worum geht’s, wo ist der Start- und Zielort, Wann beginnt die Anmeldephase sowie persönliche Notizen.
Und die Aufgaben für das Frontend sind dann diese hier:
- Es soll ein separates „Frontend“ sein, was im einfachsten Fall einfach ein neues Tabellenblatt innerhalb z.B. Excel ist.
- Darin soll idealerweise möglich sein
- Sortierung nach Startdatum (oder auch beliebig wählbar)
- Hervorheben von Events je nach Status (Teilnahme fix, Anmeldung geplant)
- Filtern nach Event-Art
- Clusterung nach Monaten oder Quartalen in der Tabellen- bzw. Listenansicht
- Visuelle Darstellung in einer Jahresübersicht als Timeline mit Repräsentation der Event-Dauer. Für schnellen Überblick, wieviel Lücke zwischen zwei Events ist, ob sich Überschneidungen ergeben, wo sich besonders viele Events häufen.
Welche Werkezuge und Methoden schauen wir uns an?
Zum Lernen und zum Austesten, was man denn da so alles machen kann – natürlich ohne jedweden Anspruch an Vollständigkeit – und um ein paar Neigungen nachzugehen, zeige ich die Abbildung dieser Forderungen nun auf sieben verschiedene Arten.
Ich fange mit der Definition der nötigen Felder und den Grundüberlegungen in MS Excel an und bleibe da dann der Einfachheit halber zunächst und zeige zwei verschiedene Möglichkeiten der Visualisierung. Einmal mit einer Timeline-Darstellung auf Basis eines x-y-Diagramms und einmal als Gantt-Chart auf Basis eines Balkendiagramms. Excel ist mir da immer noch deutlich lieber als Google Sheets.
Google Sheets wiederum ist ganz praktisch für die Zusammenarbeit von Teams direkt über das Web und verspricht auch die eine oder andere Schnittstelle bzw. das direkte Online-Abgreifen über eine freigegebene Tabelle. Sehr große Unterschiede zu MS Excel bestehen nicht – das schauen wir uns daher nur ganz knapp an.
Das waren jetzt zwei Tabellenkalkulationen. Und beide bieten nicht wirklich ein dediziertes Gantt-Diagramm oder gar eine Timeline-Ansicht (wenn sie das hätten, hätte ich gar nicht den Bedarf für diese Übung gehabt). Aber dafür haben wir ja die Trennung von Daten und Visualisierung. Notion.so ist eine Umgebung, die für ihre eigene Organisation auf Datenbank-Strukturen setzt und seit einiger Zeit auch eine schöne Timeline-View anbietet. Hört sich gut an – das probieren wir als nächstes aus.
Notion mag nicht das Programm für jeden sein und es rein nur für eine Timeline-Visualisierung zu nutzen, ist vielleicht auch nicht super sinnvoll. Andererseits – es würde auch erlauben, die Eventdatenbank direkt selbst darin zu entwickeln und zu befüllen. Und das nicht nur alleine, sondern auch als Online-Zusammenarbeit. Und schon dies könnte es auch interessant machen.
Bevor wir dann die sprichwörtlichen Kanonen auf Spatzen richten und uns dedizierten Business Inteligence und Data Visualisation Werkzeugen zuwenden, zunächst ein Blick auf reine Diagramm-Bibliotheken. Google Charts ist eine solche. Diagramme kommen raus – aber Daten und Formatierungsanweisungen müssen rein. Und zwar über JavaScript. Dafür kann das Ergebnis auch direkt in eine Webseite integriert werden.
Als nächstes schauen wir uns Tableau an. Genauer: Tableau.public. Ein gar nicht mal kleiner Anteil von Euch (wenn ich von den Antworten in meinen Instagram-Stories ausgehe) ist nicht nur irgendwo in der IT zu Hause, sondern beschäftigt sich auch mit Business Intelligence oder Data Visualisierung. Das sind nun für unseren Bike-Kalender tatsächlich die sprichwörtlichen Kanonen. Aber ich hatte mir schon gedacht, dass das genau die Pakete sind, die mir hoffentlich die richtigen Diagramme mit allen Fähigkeiten out-of-the-box bieten würden. Und das auch schön interaktiv befüll-, bedien- und erforschbar. Tatsächlich wurde Tableau nur einmal als Vorschlag genannt, als ich mein Vorhaben und erste Vorschau-Bildchen in Instagram postete. Und MS PowerBI gleich 5 mal. Das deckt sich lustigerweise mit der Markteinordnung für Analytics und Business Intelligence Platforms gemäß Gartner (ihr könnt ja mal kurz nach „gartner magic quadrant for analytics and business intelligence platforms“ googeln).
Ich habe mir ein paar davon weiter angeschaut bzw. mir dazu Artikel durchgelesen und ein paar Videos geschaut. MS PowerBI ist sehr weit verbreitet, hat aber vielleicht auch eher die „langweiligere“ und mehr auf verstaubtes big corporate ausgerichtete Diagramm-Ästhetik im Vergleich zu Tableau. Viel gravierender ist allerdings, dass die einzige frei verwendbare Version die Desktop Version ist. Die es leider nicht für MacOS gibt. Und eine Web-Version wird nicht angeboten. Von daher: uninteressant. Tableau ist in der vollen Version auch nicht gerade preiswert. Aber als Student oder Akademiker bekommt man es kostenlos. Und als Tableau.public bekommt man es ebenfalls kostenlos – und es läuft auch nativ auf MacOS.
Weitere Möglichkeiten in der Business Intelligence und Analytics Welt könnte z.B. Metabase sein. Das ist Open Source und auch kostenlos, sofern ein eigener Server aufgesetzt wird. Ich habe es mir aber nicht näher angeschaut, da mir der Overhead viel zu hoch erschien.
Wo ich den Overhead als am niedrigsten eingeschätzt hatte, war das Google Data Studio Ebenfalls eine BI und Data View Lösung und kostenlos. Aber nach dem Ausprobieren musste ich feststellen, dass es für meine Zwecke eine No-Show ist. Da fehlt schon einiges an Diagramm-Typen. Eine geeignete Timeline-View gibt es nicht und selbst ein Gantt-Chart muss man sich wie in Excel oder Google Sheets durch trickreiche Verwendung eines gestapelten Balkendiagramms selber basteln. Damit nicht genug – dass ist in Google Data Studio auch noch wesentlich unbefriedigender erstell- und bedienbar. Aber der kurze Abstecher war nicht fruchtlos, bin ich doch von dort auf die schon erwähnten eigenständigen Google Charts gestoßen. Ein paar von diesen lassen sich auch in Google Data Studio einbinden – aber komischerweise nicht alle. Und genau das, das wir hier brauchen, eben auch nicht.
Für die Google Charts brauchten wir ja schon JavaScript. Und wo ich doch schon mal mit Code in Berührung gekommen war und um meine jahrzehntelang verrosteten Programmierkenntnisse mal wieder etwas aufzufrischen, habe ich mir dann direkt auch mal Python angesehen. Vielleicht nur zum kleinen Teil als genau das Werkzeug, um eine Bike-Event-Übersicht zu erzeugen. Eher als kleine Extramotivation, mal den Start in die Programmiersprache zu beginnen, die sich gleichermaßen für Data Science und Data Analytics wie auch für Web und App Entwicklung eignet und sich dort großer Beliebtheit erfreut. Und die damit auch sehr praktisch ist, Trainings-Daten automatisiert auszuwerten. Das macht sie für mich nicht nur im privaten und dort auch nicht nur im sportbezogenen, sondern auch im beruflichen Feld sehr interessant. Für Python selbst gibt es diverse Visualisierungsbibliotheken. Wir schauen uns dort Matplotlib und Plotly an.
Über das folgende Inhaltsverzeichnis könnt ihr per Klick direkt zum entsprechenden Abschnitt zu springen:
1.) MS Excel und die Grundstruktur meiner Datentabelle
2.) MS Excel als integriertes Frontend (inkl. Gantt-Chart)
3.) Google Sheets als integriertes Frontend (inkl. Gantt-Chart)
4.) Google Charts mit JavaScript
5.) Notion
6.) Tableau.public
7.) Python, nötigste Grundlagen und Event-Timeline mit Matplotlib
8.) Python und Event-Timeline mit Plotly (aus .csv-Datei)
9.) Python und Event-Timeline mit Plotly (aus Excel-Datei)
Also los!
MS Excel und die Grundstruktur meiner Datentabelle
Ich gehe jetzt einfach mal davon aus (und das ist sicher nicht unbegründet), dass ihr wisst, was eine Tabellenkalkulation und was Microsoft Excel ist. Und nicht nur das, sondern dass ihr es auch selbst schon mindestens einmal benutzt habt oder es sich eh auf eurem Rechner befindet und ihr je nach Lebensalter schon jahrzehntelange Erfahrung mit diesem Programm habt.
1. Schritt: Überlegen, welche Datenfelder benötigt werden
Im einfachsten Fall kann das der Name des Events und der Veranstaltungstag sein (bzw. das Startdatum bei mehrtägigen Veranstaltungen). Zwei Felder, mehr nicht. Das reicht aber bei weitem nicht, um das im vorhergehenden Abschnitt angerissene Lastenheft zu erfüllen und um einen sinnvollen Überblick zu erhalten.
Ich habe mir die folgenden Felder überlegt:
- Record_ID: klassisch relational wäre dies ein ein-eindeutiger Identifizierungsschlüssel, ich müsste also Vorkehrung dafür tragen, dass nicht eine ID aus Versehen mehrfach vergeben wird. Für meine Zwecke hier ist dies aber gar nicht so stringent notwendig. Ja – ich brächte dieses Feld gar nicht. Trotzem kann es ganz praktisch sein, eine laufende Nummer zu haben und auch nach dieser sortieren zu können
- Event_Name_Short: Der Name der Veranstaltung, gerne auch als Abkürzung, wenn es eine gut eingeführte oder offizielle Variante ist: TCRNo8 z.B. für das Transcontinental Race No 8. Kompakt, damit Tabellen-, Legenden- und Achsenbeschriftungen übersichtlich bleiben.
- Event_Name_Long: Der vollständige Name der Veranstaltung, z.B. Transcontinental Race No 8
- Series_Name: Oftmals gehören Rennen zu jährlich etablierten Veranstaltungen (beim TCRNo 8 wäre das das TCR ohne Nummer oder ohne Jahreszahl) oder es gibt mehrere unterschiedliche Austragungen im Jahr, die zu einer Serie gehören (z.B. Zeitfahrserie Nord)
- Beschreibung: allgemeine, kurze Beschreibung der Veranstaltung
- Startort: Wo ist der Start?
- Land: In welchem Land?
- Region: Anstelle von nur „Deutschland“, könnte hier dann „Schwarzwald“ stehen. Oder im Falle eines Transcontinental dann „Europa“ anstelle nur des Startlandes.
- Zielort: Wichtig bei Punkt zu Punkt-Veranstaltungen…
- Zielland: … die ja auch länderüberschreitend sein können
- Length: Genaue oder geschätzte Streckenlänge in km
- Climbing: Genaue oder geschätzter Gesamtanstieg, sofern Info vorliegt
- Date_Start: mit die wichtigste Info – an welchem Tag ist die Veranstaltung bzw. fällt der Startschuss
- Date_Registry_atstart: Soll nicht den Anmeldestart sondern die Vor-Ort-Registrierung beinhalten. Ist debattierbar, im Endeffekt ist es doch immer meist der Vortag oder derselbe Tag vor dem Start und eigentlich uninteressant; habe ich im weiteren Verlauf festgestellt
- Approx_Days: zweitwichtigste Info – wie lange dauert die Veranstaltung. Und zwar in von mir geschätzten Tagen für mein Leistungsniveau. Aber noch ohne Anreise, Abreise und Puffer. Also reine Fahrtzeit. Warum Tage und z.B. kein Enddatum? 1. Nicht jede Veranstaltung gibt ein Enddatum an. Und selbst wenn (z.B. offizielle Finisherparty o.ä.) muss das nicht die Zeit sein, die ich oder ihr dafür ansetzen würdet. 2.) Um ein Enddatum einzutragen, muss man sich ja trotzdem ersteinmal überlegen, wie lange man für die Veranstaltung ansetzt und dann erst im zweiten Schritt das dazugehörige Datum ermitteln – das ist aufwendig und das überlassen wir lieber dem Computer. 3.) Je nach Visualisierungslösung ist mal das Eine (Dauer) und mal das Andere (Enddatum) erforderlich – wir nutzen also den Weg, der für uns als Mensch am einfachsten ist.
- URL: Webseite des Rennens
- Kategorie: hier kann man jetzt überlegen – wie fein soll sollen die Veranstaltungen nach Art unterteilt werden? Untergrund? Modus (also Bikepacking, Rennen, Brevet, RTF)? Distanzklassen? Zu granuliert ist dann auch ungünstig. Ich habe mich erst einmal für nur zwei Felder entschieden. Kategorie und Route-Type. Und in diesem Kategorie-Feld wird dann also der Untergrund und Modus direkt mitabgebildet. Dieses Feld soll keine freien Einträge zulassen, sondern befüllt sich aus einer Kategorie-Liste, aus der man auswählen muss.
- route_type: fixed route oder free route (auch hier als feste Auswahl)
- Meldegebühr: Was kostet die Anmeldung
- Anmeldestart: sofern Info vorliegt (manchmal wäre Anmelde-Ende auch ganz interessant, aber zur Not kommt das in’s nächste Feld)
- weitere_Notizen: hier kommt alles hinein, was mir speziell noch interessant erscheint. Details zur Anmeldung etc.
- general_rating: Durch die Vielzahl an aufgenommenen Veranstaltungen ist nicht alles gleich interessant für mich – hier kann ein Ranking vorgenommen werden.
- prio_2022: Ein Event kann für mich super spannend sein (general_rating) aber für dieses Jahr einfach nicht zur Debatte stehen (Terminkollision, kein Urlaub, was auch immer). Ob es gar nicht möglich ist, oder vielleicht doch die zweite oder dritte Fallback-Option ist, gibt diese Prio an.
- angemeldet: wie schon die Felder Kategorie und route_type ist dies kein freies Eingabefeld, sondern wird aus einer Liste mit den folgenden vier Eingrägen befüllt [ ja, nein, geplant, Backup Plan / eventuell]
- kfz_kilometer: Habe ich mal als Anreise-Proxy aufgenommen. Bei zwei gleich interessanten Rennen im selben Zeitraum kann es ja durchaus relevant sein, ob man eines der beiden dreimal so weit zum Start fahren müsste. Bzw. ganz generell ist es mehr als nice to know. Gleiches gilt für die daraus abgeleitete…
- kfz_Dauer: Wie lange dauert dann die Anfahrt?
Für Euch könnten durchaus andere oder weitere Felder bzw. Aufteilungen interessant sein. Lasst es mich gerne in den Kommentaren wissen bzw. passt euch die Tabelle gerne beim Nachbauen nach eurem Gusto an.
Übrigens: Wenn ihr diese und die folgenden Schritte direkt an meinen Beispieldaten nachvollziehen (bzw. direkt die gerade genannten Felder aus einer fertigen Tabelle übernehmen) möchtet, könnt ihr das im Vorgriff auf das im nächsten Kapitel erst angesprochene Google Sheets mit dieser von mir für euch als „Betrachter“ freigegebenen Google Tabelle machen.
Bei der Felderbenennung habt ihr einen wilden Mix aus Deutsch und Englisch gesehen, wichtiger noch aber ist: kein Feldname hat ein Leerzeichen. Wäre nicht unbedingt erforderlich, macht einem das Leben im Zweifelsfall für alle denkbaren Weiterverwendungen der Datentabelle aber sehr viel einfacher.
2. Schritt: Die Feldnamen in ein separates Tabellenblatt („events“ in der ersten Zeile jeweils in die Spalten eintragen (habe ich natürlich direkt mit dem ersten Schritt kombiniert ;-))

3. Schritt: in einem weiteren Tabellenblatt „Field_Values“ die Vorgabewerte für die 3 Felder „Kategorie“, „route_type“ und „angemeldet“ definieren

Für das Feld „Kategorie“ möchte ich hier meine derzeitigen Überlegungen und Definitionen, die mit den Einträgen zusammenstehen, erläutern:
- Bikepacking Road, unsupported: Gibt es noch „reine“ Straßenevents? Ja, die gibt es zwar, aber anscheinend wird da mehr und mehr „Gravel“ oder gar „hike-a-bike“ eingeschleust – für die Extra-Dosis Abenteuer. Es ist also fast zu überlegen, ob man ein Road-Event nicht doch eher in die folgende Kategorie, nämlich Gravel, einordnet…
- Bikepacking Gravel, unsupported
- Bikepacking Off-Road, unsupported: Im Zweifel ist ein „Nicht-Straße“ Bikepacking-Event immer eher „Off-Road“ als Gravel. Warum? Weil sehr oft das Terrain eine Mischung aus Hike-a-Bike, Bergpfaden, übelst wurzeligen oder steinigen Waldwegen und anderem ist und daher tendenziell mit besser mit einem MTB oder einem auf maximale Reifenbreite getrimmten Gravel-„Trekker“ bewältigt werden können. Reine Gravel-Bikepacking Rennen mit wohlkuratierten Wegen bzw. in Gegenden, wo tatsächlich fast nur Strade-Bianche-artige Wege, unbefestigete aber gute Feldwege und auch mal diverse Nebenstraßen vorliegen, sind eher selten.
- Gravel
- 24 h
- GranFondo
- TT
- Expo: Messen oder Ausstellungen (teilweise mit Eventcharakter) wie z.B. eine cyclingworld Düsseldorf oder auch Gravelgames.cc
- Camp: Eine Mehrtages-Veranstaltung (oft Wochenende) mit mehr als nur 2 Tagen Radeln sondern auch Weiterem wie BBQ, Musik, Übernachtung etc.
- Touridee: zum Einplanen und Freihalten von Zeiträumen für eigene Tour- und Bikepacking-Ideen
- Bikepacking Gravel, Event/Group: <- durchgehendes oder mit festen Übernachtungsspots / festen Etappen durchgeführtes Event, zwar mit Gepäck am Rad aber mit straßenseitig gestütztem Support (Verpflegungsstellen, Gepäcktransport o.ä.)
- Singlestage, Event/Group: <- ein (auch überlanges) Rennen oder Brevet, das auch in Gruppen gefahren werden kann und wo es straßenseitig gestützten Support gibt (Verpflegungsstellen, Gepäcktransport o.ä.).
- Multistage, Event/Group: <- ein Rennen oder eine Gruppenausfahrt über mehrere Etappen mit Übernachtungen dazwischen und straßenseitig gestützten Support (Verpflegungsstellen, Mittagscamp, Gepacktransport). Beispiele: Transalp (als Rennen) oder Tour des Grandes Alpes (als Rennrad-Reise-Veranstaltung)
Natürlich könnte man das über ein separates Feld „Untergrund (Gravel, Offroad, Straße)“ o.ä. noch entzerren – oder auch noch weiter ziselieren. Wenn es aber gar zu viele Kategorien werden und jede einzelne dann nur noch mit einer oder zwei Veranstaltungen befüllt wäre, macht eine Selektion dann auch keinen Sinn mehr.
4. Schritt: Für jedes dieser drei Felder denn folgenden Schritt durchführen: Die Funktion „Datenüberprüfung“ im Menü „Daten“ mit der entsprechenden Spalte bzw. den entsprechenden Feldern im Tabellenblatt „events“ ausgewählt benutzen, darin dann „Liste“ aus der Dropdown-Liste auswählen und schließlich den Bereich im Tabellenblatt „Field_Values“ auswählen:
Fertig! Jetzt kann die Liste befüllt werden!
Das muss nicht in einem Rutsch geschehen. Immer, wenn euch wieder eine Veranstaltung einfällt oder ihr auf eine aufmerksam gemacht werdet oder eine neue Übersicht entdeckt habt, könnt ihr einfach Zeile um Zeile, also Event um Event anhängen. Um Sortierung oder Einordnung braucht ihr euch keine Gedanken zu machen. Auch am Status oder an der Priorisierung kann sich später gerne noch etwas ändern.
Ihr könnt die Liste so wie sie dann ist, auch sofort als .csv Datei (comma separated values) exportieren und anderswo importieren (falls das entsprechende Programm oder der entsprechende Gegenüber keine Exceldatei direkt verwenden kann).
MS Excel als integriertes Frontend
Wir bleiben erst einmal in Excel und loten nun die Darstellungsoptionen aus. Daten filtern, Zellen bzw. besser ganze Zeilen mit den Events hervorheben, für die wir z.B. schon angemeldet sind und dann weitere, die in die nähere Auswahl kommen etc. Und schließlich auch eine grafische Übersicht.
Liste sortieren, Filtermöglichkeit hinzufügen und diverse Events farblich hervorheben
- Schritt: ein neues, leeres Tabellenblatt erzeugen: „Bike_Events_2022“. Das Blatt „Events“ bleibt der reinen Datenhaltung vorbehalten.
- Schritt: Die erste Zeile mit den Spaltennamen vom Blatt „Events“ in das neue Blatt kopieren und dann den gesamten Bereich der eigentlichen Datenliste im Blatt „Events“ im Sinne der Formel „=Events!A2“ usw. ausfüllen. So wird jede spätere Änderung in den eigentlichen Daten auch in unserem Frontend-Blatt „Bike_Events_2022“ abgebildet.
- Schritt: Mit allen Felder beinhaltenden Spalten der 1. Zeile ausgewählt im Menü „Daten“ die Funktion „Filtern“ anklicken. Damit erhalten alle Überschriften einen Dropdown-Menü-Pfeil mit dem wir eine Sortierung und auch Filterung auswählen können.

- Schritt: In der Spalte „Date_Start“ aufsteigende Sortierung wählen.
So ist die Liste schon einmal chronologisch sortiert und wir können sie erkunden. Vielleicht sind wir ja schon fix für einige Veranstaltungen angemeldet und haben es für andere schon vor. Dann wäre es ja gut, wenn diese Events in der Liste hervorgehoben werden. Und zwar nicht manuell, sondern automatisch in Abhängigkeit des Feldes „angemeldet“.
Dafür nutzen wir die Funktion „Bedingte Formatierung“ direkt im Menü „Start“. Standardmäßig wird dann aber immer nur die betreffende Zelle im Format angepasst. Wir wollen aber die gesamte Zeile hervorheben. Also…
- Schritt: „Bedingte Formatierung“ anklicken und dort „Regeln zum Hervorheben von Zellen / Textinhalt…“ auswählen.
![[Bike-events_excel_bedingteFormatierung_01.png]]
- Schritt: dort „Formel zur Ermittlung der zu formatierenden Zellen verwenden“ selektieren. Das Auswahlfeld auf die erste Inhaltszelle der „angemeldet“ Spalte setzen, was bei mir in „=$X$2“ resultiert. Das $-Zeichen vor 2 wird entfernt, damit die Regel später per Autoausfüllen bzw. Formatübertragung in der Spalte nach unten kopiert werden kann. Und ein ‚=“ja“‚ wird für die erste Formatierungsregel angehängt. Und in Formatieren mit: kann die Formatierung ausgewählt werden.
- Schritt: Jetzt dehnen wir diese Formatierungsregel auf die gesamte Listenbreite aus. Wieder im Menü „Start“ die Funktion „Bedingte Formatierung“ wählen und dort den untersten Eintrag „Regeln verwalten“ selektieren. Und im Feld „Angewendet auf“ wird dann die gewünschte Zeilenbreite ausgewählt. In meinem Fall von $A2 : $Z2. Die $-Zeichen bei den Zeilennummern werden wieder entfernt. Nicht davon ablenken lassen, dass im Screenshot $A$2:$Z$69 steht: Wenn man die Regel einmal vom Bereich her ausgeweitet hat bzw. das Menü mehrfach öffnet, macht da Excel sein eigenes Ding raus…
Und voilà: meine Events, für die ich bereits fix angemeldet bin, werden in der gesamten Zeile grün hinterlegt und die Events, für die ich die Anmeldung geplant habe, in Ocker.
Eine einfache Timeline-Ansicht als Aufwärmübung
Excel bietet keine direkte Zeitachsen-Ansicht, kein Gantt-Diagramm und auch keine Kalendar-Visualisierung als fertiges Diagram an. Auf meiner Suche durch das Web und zuvor durch die mitgelieferten Vorlagen in Excel, ob und wie man sich durch trickreiche Anpassung von bestehenden Diagrammen trotzdem an solche Visualisierungen annähern kann, bin ich auf zwei interessante Möglichkeiten gestoßen, die ich euch nicht vorenhalten möchte.
Hier die erste von zwei Varianten. Eine schöne vertikale Zeitachse auf Basis eines x-y-Diagrammes. Es ist nicht ganz das, was wir hier eigentlich suchen und es würde für sehr viele und eng aufeinanderfolgende bzw. überlappende Ereignisse schnell unübersichtlich werden. Aber es ist schnell gemacht, sehr ansehnlich und gut für weitere Dinge brauchbar.
- Schritt: Im Start-Fenster von Excel bzw. im Menü „Datei“ die Funktion „Neu von Vorlage“ auswählen und dort nach „Zeitachse“ suchen und die entsprechende neue Datei erzeugen. Dies führt zu diesem Bild:
Ganz ansprechend, nicht? Hier sieht man auch sofort den Aufbau. Eine Zeitspalte, in dem Fall das Jahr – prima, das tauschen wir gegen unsere Spalte Startdatum aus. Das ist augenscheinlich die Y-Achse. Und eine Hilfsspalte „Position“, die die X-Werte und damit die Position der roten Kästchen links und rechts der Zeitachse festlegt. Ok – das ist fix angepasst…
- Schritt: In unserer Exceltabelle im Tabellenblatt „Bike_Events_2022“ eine neue Spalte „Position“ an unsere Liste rechts anfügen und mit Werten von -100 bis +100 nach Gefühl befüllen. Ich spare mir hier einen Algorithmus oder die Positionsfestlegung nach irgendwelchen Kriterien – es geht nur um ein kurzes Proof of Concept.
- Schritt: Das Diagramm aus der Vorlagendatei kopieren und in unsere Excel-Datei in das Tabellenblatt „Bike_Events_2022“ unter der Liste einfügen.
- Schritt: In das Diagramm hineinklicken, „Datenquelle auswählen“ selektieren und darin entsprechend für die X-Werte die neue Spalte „Position“ und für die Y-Werte die Spalte „Date_Start“ auswählen. Nach Geschmack würzen, äh, Titel, Schriftgrößen etc. nach Wunsch anpassen und… Fertig!
Wie gesagt, ganz ansehnlich in meinen Augen. Aber mit den angesprochenen Problemen bei dichterer Eventfolge und vor allem: In dieser Form fehlt eine ganz wichtige Eigenschaft. Nämlich die visuelle Darstellung der zeitlichen Dauer der Veranstaltungen. Ggfs. könnte man jetzt über den Workaround von Fehlerindikatoren etwas versuchen – meine Tests waren da aber unbefriedigend. Deshalb wenden wir uns jetzt dem eigentlich gesuchten Ergebnis zu.
Die finale Timeline-View als Gantt-Chart
Eigentlich ist ein Gantt-Diagramm (auch als Balkenplan bekannt) ein Instrument des klassischen Projektmanagements. Solche Dinge wie kritische Pfade, Start-Ende-Beziehungen und Abhängigkeiten benötigen wir hier aber gar nicht. Für uns ist der Balken- bzw. Timeline-Aspekt wichtig – die Darstellung einer Aktivität über eine Dauer und die X-Achse bitteschön nicht nur als schnöde Zahlen, sondern als Zeitelemente. Idealerweise je nach Zoomstufe als Tage, Wochen, Monate oder Quartale angezeigt.
Mal sehen, wie weit wir damit in Excel kommen. Spoiler: sehr weit; fast zu einem für mich perfekten Ergebnis sogar.
Ihr werdet bei den Excel-Dateivorlagen vielleicht bei der Zeitachsen-Suche einige mit „Gantt…“ betitelte Vorlagen entdeckt haben. Leider handelt es sich dabei ausnahmslos um recht komplexe und fast immer mit diversen automatischen Verweisen, Feldformeln und sogar Makros hinterlegten Dateien. Die auch alle für sehr bestimmte Zwecke (wofür man klassischerweise Gantt-Charts so nutzt) ausgerichtet sind. Kurzum – absolut keine sinnvolle Basis für unsere Zwecke.
In den Weiten des Internets bin ich schließlich auf die passende Idee gestoßen, die sich recht einfach anpassen und anwenden lässt. Sie basiert auf dem 2D-Balken Diagramm in der Variante „Gestapelte Balken“. Diese Auswahl seht ihr im folgenden Bild rechts und links daneben schon das Endergebnis, dass am Ende erhalten wird.
- Schritt: Auch hier müssen wir wieder ein Hilfsfeld erzeugen. Wir hängen also wieder eine neue Spalte an unsere Liste an und überschreiben sie mit „Days_from_Jan1st“. Das wird die Länge unseres ersten Balkens.
- Schritt: In die erste Datenzelle geben wir die folgende Formel ein: „=TAGE(M2;DATUM(JAHR(M2);1;1))“. M2 ist die erste Zelle in der Spalte „Date_Start“, also unser Start-Datum. Die Funktion „Tage“ gibt die Anzahl der Tage zwischen zwei Datumswerten zurück. Der erste Datumswert ist das Startdatum, der zweit der 1. Januar des Jahres in dem das Startdatum liegt – das erledigt die Funktion „Datum“.
- Schritt: Mit gedrückter CMD-Taste (Mac) oder STRG-Taste (PC) die Spalten „Event_Name_Short“, „Approx_Days“ und „Days_from_Jan1st“ hervorheben und im Menü „Einfügen“ das gestapelte 2D-Balkendiagramm auswählen.
Das sieht doch schon vielversprechend aus. Wir müssen nur noch die Balkenreihenfolge umkehren (Days_from_Jan1st soll der erste und Approx_Days der zweite Balken sein) und diverse Formatierungsanpassungen nach Wunsch vornehmen. Also…
- Schritt: In das Diagramm klicken, „Datenquelle auswählen“ wählen und im Feld Legendeneinträge einfach mit dem Pfeil den ersten Eintrag nach unten schieben.
- Für eine aufsteigende Sortierung der Events in der Reihenfolge, wie sie in unserer Liste nach Start-Datum sortiert sind, genügt ein Doppelklick auf die Y-Achse und das Setzen des Häkchens bei „Kategorien in umgekehrter Reihenfolge“

- Schritt: für das Feintuning könnten wir jetzt den ersten Balken ganz ausblenden bzw. mit weisser Füllung versehen. Mir gefällt es, eine leichte Führungslinie stehen zu lassen und dazu auch die Gitterlinien der Zeitachsen-Einteilung durchscheinen zu lassen. Das können wir recht „fancy“ gestalten, indem wir die erste Datenreihe nicht nur transparent sondern sogar mit einem Farbverlauf füllen. Im folgenden Bild seht ihr, wie ich diesen eingestellt habe. Von oben bis fast ganz unten 100 % transparent und dann einen kleinen, sehr engen Blaugradienten:
- Schritt: Es fehlt noch das im oberen Bild schon erfolgte Anordnen der Beschriftung an der Unterseite des Diagramms und der Darstellung von Datumswerten anstelle der Tages-Nummern. Das geht per Doppelklick in die X-Achse – ihr werdet es alle kennen, aber der Vollständigkeit halber stelle ich auch diesen Schritt dar. In den Achsenoptionen wählt ihr (nicht im Bild) unten unter „Zahl“ ein gewünschtes Datumsformat aus und dann brauchen wir noch die Darstellungsgrenzen (ein Jahr von Tag 0 bis Tag 365) und die Einteilung der Hauptstriche.
Tja – und genau bei diesem letzten Schritt der Hauptstriche (und vielleicht bei fehlender Zoom-Interaktion im Diagramm selbst) ist der einzige kleine Schönheitsfehler versteckt.
Wir können dort halt nur ganzzahlige Werte eingeben. Und keine Datums-Größen. Wie z.B. 1 Monat. Oder 1 Quartal. So haben wir nur die Wahl, ob wir da z.B. 30 oder 31 (Tage sind es ja) eingeben. Und sehr schnell passt es dann halt nicht mehr mit den Monatsgrenzen. Was aber tatsächlich nur ein Schönheitsfehler ist. Einen visuellen Anhalt über die ungefähren Monatsgrenzen und diese auch Taggenau korrekt beschriftet hat man ja doch.
Das Diagramm macht auch alle Selektionen bzw. Filterungen in der zugehörigen Liste mit. Werden nur Veranstaltungen einer bestimmten Kategorie selektiert, dann zeigt das Balkendiagramm auch nur diese Veranstaltungen an. Darüber hinaus können wir manuell einzelne Veranstaltungen hervorheben, in dem wir ihnen eine andere Farbe zuweisen. Wie ich es im Beispiel für den Zeitraum der Orbit 360 Gravel Serie gemacht habe.
So gesehen fast schon die perfekte One-Stop-Lösung in Excel. Zumindest für den eigenen Gebrauch. Trotzdem – allein schon für den Lerneffekt, aber auch für Veröffentlichungszwecke in z.B. einer Webseite – schauen wir uns noch weitere Lösungen an, wie wir unsere ja nun in Excel vorliegende Tabelle visualisieren können.
Google Sheets
Wer sich mit Tabellenkalkulationen bzw. Excel auskennt – und wie gesagt, wer ist nicht damit schon irgendwann einmal in Berührung gekommen? – der wird sich auch schnell in Google Sheets bzw. in Deutsch mit Google Tabellen zurecht finden. Oder, wessen erste Berührungen mit Office-ähnlichen Softwareprodukten erst später als 2006 stattfanden (ja, ich bin alt), hat vielleicht sogar seine ersten Schritte anstelle mit MS Excel mit Google Sheets gemacht. Schließlich ist diese Web-Applikation frei und kostenlos benutzbar. Und manche ziehen sie gar vor, weil sie Google Sheets in Verbindung mit anderen Produkten des Google-Ökosystems einsetzen und/oder weil sie die Möglichkeiten der Online-Zusammenarbeit bzw. des Bereitstellens von Tabellen Online nutzen möchten.
Und das ist auch der einzige Grund, warum ich es hier für die Zwecke einer Bike-Event-Übersicht mitbetrachte. Denn das kann ja auch ganz praktisch sein, eine Tabelle entweder nur lesend frei zu geben oder auch editierbar, so das Dritte die Daten ergänzen und eigene Events einfügen können.
Rein von den Funktionen her und deren Zugriff bevorzuge ich aber eine lokal laufende Applikation und da dann MS Excel deutlich gegenüber Google Sheets. Von daher belasse ich es hier nur bei einer sehr kurzen Darstellung. Im Grunde kann man alle wesentlichen Schritte zur Erstellung der Basistabelle und zur Erstellung eines separaten Tabellenblattes als „Front-End“ auch in Google Sheets nachempfinden.
Ich habe es mir einfach gemacht, und für das Austesten einfach die Inhalte der Tabelle meines Frontend-Tabellenblattes „Bike_Events_2022“ kopiert und in einem frischen Google Sheets Dokument eingefügt.
Bei den Diagrammen gilt ebenfalls das Gleiche wie für Excel – man muss sich mit einem X-Y-Diagramm oder einem gestapelten 2D-Balkendiagramm selbst eine Timeline-Übersicht bauen. Passendere Diagramme gibt es hier genausowenig.
Das Balkendiagramm ist auch genau so schnell erstellt wie in Excel. Ich finde allerdings, dass die Formatierungsoptionen nicht ganz so reichhaltig sind. Es ist aber gut genug und was die Abschnitt-Einteilung der X-Achse betrifft, unterliegt es dem gleichen Schönheitsfehler wie in Excel (nur fixe ganzzahlige Intervalle angebbar).
So sieht das dann beispielsweise in Google Sheets aus:
Wie im vorangegangenen Kapitel bei der Aufführung der Datenfelder für die Exceltabelle schon angegeben, habe ich diese Tabelle für euch zum experimentieren freigegeben. Wenn Ihr Änderungen vornehmen wollt, kopiert euch einfach die Inhalte in eine eigene Google-Tabelle.
Google Charts (und Javascript)
Eine Möglichkeit, diesen Google Sheet einer weiteren Visualisierung zu zuführen, sind die Google Charts. Diese sind aber bei weitem nicht auf Google Sheets als Datengrundlage beschränkt, sondern können u.a. auch .csv-Dateien, JSON und anderes einlesen.
Google Charts ist Bestandteil der Google Developers Tools und stellt interaktive Funktionen und Bibliotheken bereit, um interaktive grafische Diagramme zu erzeugen und direkt in Webseiten einzubinden. Um die Daten bereitzustellen und die Art und Weise des Aussehens und der Interaktion der Diagramme zu steuern, muss man JavaScript benutzen.
Nun bin ich weder ein JavaScript Guru, noch hatte ich vorhergehende Erfahrung mit Google Charts. Das, was ihr im folgenden lest, ist das Ergebnis von wenigen Stunden Recherche und Basteln und buchstäblich in einem Tag erzeugt wurden. Das meine ich mit „bloggen, um zu lernen“. Wer Verbesserungs- oder Erweiterungsvorschläge hat – gerne in den Kommentaren hinterlassen. Wer genauso bei Null mit JavaScript und GoogleCharts anfängt wie ich – mit wenigen Zeilen Code in einer einfachen .html-Datei kann man eine interaktive Online-Timeline-Übersicht von Bike-Events erstellen.
Dazu brauchen wir einen einfachen Text-Editor, der uns bei der Erzeugung von reinen ASCII-Textdateien kein Bein stellt (was bei unbedarfter Benutztung des bordeigenen TextEditors von MacOS schnell mal passieren kann), ich empfehle Sublime Text, und einen Webbrowser. Ich habe zum Testen Google Chrome benutzt, weil sich Safari trotz Selektion von „lokale Dateieinschränkungen deaktivieren“ nicht zum Ausführen von lokalen HTML-Dateien mit Javascript-Inhalt überreden lies.
Es geht aber auch direkt online über den Service „jsfiddle.net“. Der ist praktischerweise direkt zum Üben und Testen in der Google Charts Dokumentation mit den jeweiligen kurzen Beispielen verlinkt. Mehr dazu sofort im nächsten Schritt.
Zunächst mal blättern wir uns durch das Angebot der möglichen Charts hindurch, die sehr schön in einer Galerie dargestellt werden. Und siehe da: es gibt ein Timeline-Chart das genau das verspricht, was wir suchen.
- Schritt: Den Timeline Chart Guide aus der Galerie aufrufen:
Wenn dort steht: „Overview“ und „A simple example“, dann ist das auch tatsächlich so. In meinen Augen eine auch oder gerade für blutige Anfänger hervoragend geeignete und gut lesbare Einführung. Daumen hoch, Google!
Ganz links oben seht ihr die diversen Charts als Liste. Ausgewählt ist gerade „Timelines“. Darunter seht ihr den Abschnitt „How to Draw Charts“, welcher ebenfalls eine sehr gute und einfache Einführung beinhaltet. Und ganz rechts seht ihr die Outline des in der Mitte dargestellten Guide. Und dort in der Mitte unten in dem kleinen Kasten könnt ihr auch schon das „Code it yourself on JSFiddle“ lesen. Da einmal draufgeklickt und ihr landet in einem neuen Browsertab mit folgendem Inhalt:

Und schon kann man nach Herzenslust experimentieren. Unten rechts ist das Ausgabefenster des entsprechenden Diagramms. Das sieht doch auch schon recht nahe nach dem aus, was wir anstelle von historischen US-Präsidenten mit Bike-Events machen wollen.
- Schritt: Ich habe den Inhalt des JSFiddle-Fensters in eine reine Textdatei überführt. Dabei ist wichtig, dass die in JSFiddle separaten Fensterinhalte HTML und Javascript in eine gemeinsame HTML-Struktur überführt werden. D.h. der Script-Part ist im head der HTML-Datei und der Body beinhaltet im einfachsten Fall nur eine Zeile mit dem Aufruf des entsprechenden DIV-Elements:
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Event' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'GranGuanche Gravel', new Date(2022, 2, 19), new Date(2022, 2, 26) ],
[ 'Orbit 360 Gravel Series', new Date(2022, 5, 4), new Date(2022, 7, 14) ],
[ 'TCR No8', new Date(2022, 6, 24), new Date(2022, 7, 7) ]]);
chart.draw(dataTable);
}
</script>
</head>
<body>
<div id="timeline" style="height: 180px;"></div>
</body>
</html>
Und ich habe in den Beispieldaten schon die Präsidenten und bloßen Jahreszahlen gegen drei Bike-Events mit den jeweiligen tagesgenauen Daten ausgetauscht.
Ihr seht auch schon: dieses Timeline-Chart möchte nicht den Startzeitpunkt und dann die Dauer eines Ereignisses (unsere in der Datentabelle bereitstehenden Felder „Date_Start“ und „Approx_Days“), sondern den Startzeitpunkt und den Endzeitpunkt. Dazu müssen wir uns später also etwas überlegen.
Zunächst mal testen wir das kleine Skript komplett lokal, ohne uns um das Funktionieren einer Datenanbindung an die Quelldaten kümmern zu müssen. Nun – komplett lokal bis auf natürlich den Online-Aufruf der timeline package. Ohne das geht es nicht. Aber die Daten erzeugen wir komplett lokal im Skript selbst. Das geschieht in den mit dataTable
beginnenden Zeilen.
Wenn wir diese Zeilen als .html-Datei lokal abspeichern und dann die Datei in Google Chrome ziehen, sollte das Ergebnis wie folgt aussehen:
Wie ihr seht, erscheint sogar ein schönes und sinnvoll befülltes Flyout, wenn man mit dem Mauszeiger über einen Balken verweilt. Und das, ohne das wir es gesondert konfiguriert oder z.B. eine „Duration“ irgendwo als eigenes Feld definiert hätten.
Die nächste Stufe ist jetzt, anstelle dieser lokal im Skript erzeugten und durch function drawChart() {var dataTable = new google.visualization.DataTable();...
definierten Daten unsere Datentabelle zu übergeben. Das wollen wir über die Google Sheets Tabelle machen und dafür wird anstelle der dataTable
ein entsprechendes Query Objekt var query = new google.visualization.Query
benutzt.
- Schritt: Doch zuvor müssen wir erst noch das benötigte Feld mit dem End-Datum unserer Veranstaltungen erzeugen. Das geht in Excel wie auch in Google Sheets gleichermaßen einfach und alle nötigen Infos haben wir schon in unserer Basistabelle. Nämlich Startdatum und Dauer der Events. Die neue Spalte „Date_End“ wird mit der einfachen Formel „Date_Start“ + „Approx_Days“; in meinem kleinen Beispiel Google Sheet also mit C2+B2 erzeugt:
- Schritt: Die Datei muss freigegeben werden. Dazu reicht es, auf „Freigeben“ zu klicken und sich einen Abruf-Link für Jedermann zu generieren, den man per „Link kopieren“ in die Zwischenablage kopiert.
- Schritt: Dieser Link wird genau so in den
google.visualization.Query
-Aufruf eingefügt und der Rest des Skriptes entsprechend angepasst. Das sieht dann so aus:
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('47', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1hx22kKan0avRKr7bcktREIj1wbGS8uS21F3QSBxUK6U/edit?usp=sharing');
query.send(handleQueryResponse);
}
function handleQueryResponse(response) {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var data = response.getDataTable();
chart.draw(data);
}
</script>
</head>
<body>
<div id="timeline" style="height: 580px;"></div>
</body>
</html>
Und voilà – wenn ihr diese Zeilen wieder in eine .html-Datei verpackt und diese in eurem Browser aufruft, sieht das Ergebnis so aus:
Dadurch, dass in der eingedampften Test-Tabelle in der zweiten Spalte die Dauer in Tagen aufgeführt ist, werden diese auch direkt in der Darstellung der Balken zusätzlich als Zahlenwert ausgegeben. Praktisch.
Ihr könnt dieses Beispiel übrigens auch genauso gut wieder in JSFiddle.net ausführen. Da funktioniert es sogar noch ein kleines bisschen besser. Warum? Das hängt mit dieser Zeile zusammen:
google.charts.load('current', {'packages':['timeline']});
Diese Zeile veranlasst den Loader, die entsprechende Chartfunktionalität, bzw. die Visualization API für das angegebene Chartpackage – hier, Timeline – zu laden.
Beachte das current
, das ist die Versions-Angabe und besagt genau das – nutze die aktuelle, stabile Version. Das sollte man normalerweise wohl auch immer tun. Allein schon, um sicherzustellen, dass die aus der aktuellen Dokumentation übernommenen Angaben und Funktionen auch genau damit funktionieren. Was bei alten, eingefrorenen Versionen ja nicht der Fall sein muss. Diese werden aber trotzdem noch vorgehalten. Was praktisch und hilfrreich ist. Denn mit current
funktioniert das erste Testskript mit den drei lokal im Skript erzeugten Dateneinträgen sowohl bei mir von der lokalen .html-Datei wie auch in JSFiddle.net. Das zweite Testskript mit dem einlesen der Google Sheets Tabelle funktionert so aber nur in JSFiddle.net. Der Aufruf der lokalen .html Datei führt stets zu einem Timeout: „Error in query: Request timed out“
Doof – denn diese Vorgehensweise steht ja so eins zu eins in der aktuellen Timeline Charts-Dokumentation sowie den Einsteiger-Guides zur Anbindung an eine Google Tabelle. Mit einiger Recherche bin ich dann darauf gestoßen, dass es mit der Version 47 aber problemlos funktionieren soll. In der Tat, das tut es auch. Daher findet ihr im vorhergehenden Beispiel-Code auch die entsprechende Zeile:
google.charts.load('47', {'packages':['timeline']});
Wunderbar – proof of Concept erfolgreich durchgeführt. Wir haben eine seprate Datenbank (hier als Beispiel eine online abrufbare Google Tabelle) und haben eine interaktive Timeline-Darstellung zur direkten Einbindung ein eine Webseite erzeugt. Jetzt könnte man sicher noch weiter an der Formatierung dieser Darstellung feilen bzw. sich Gedanken um eine ganze Webseite drum herum machen. Für mich ist allerdings die erste Neugier gestillt und weitere Visualisierungsmöglichkeiten sollen erkundet werden.
Weiter geht es daher mit…
Notion.so
Exkurs: Was ist Notion und warum sind Cloud- und Subscription-only Systeme gerade für persönliches Wissensmanagement problembehaftet
Was ist Notion? Notion sagt von sich selbst, ein all-in-one Workspace für dich und dein Team zu sein. Es ist eine Notiz- und Projektmanagement-Software, die auch sehr häufig und gern für persönliches Wissensmanagement, Aufgabenmanagement und solche Dinge verwendet wird. Und es erfreute sich gerade in den letzten zwei Jahren auch einem starken Hypetrend (ihr braucht da nur mal nach Notion auf Youtube suchen). Deswegen hatte ich es mir vor rund einem Jahr auch mal angesehen, als ich auf der Suche nach einer Aktualisierung meiner persönlichen Notizen und Wissensmanagement-Lösung war. Es wurde allerdings sehr schnell klar, das Notion dafür definitiv nicht das Programm meiner Wahl war und ist. Denn es hat gleich mehrere gravierende Nachteile, die niemand für persönliche und wichtige Daten in Kauf nehmen sollte und die darüber hinaus auch die Reibungslosigkeit und Performance des Einsatzes der Software selbst vermindern.
Ich brauche euch alle meine Vorbehalte gegenüber Notion und anderen, rein abo-basierten und rein online-basierten Notiz- und Knowledgemanagement-Tools gar nicht aufzählen – bei Interesse schaut einfach mal in diesen Artikel hinein, der sie alle Punkt für Punkt aufzählt und erläutert.
In dem Zusammenhang sind auch die Gedanken und Prinzipien des Teams von Craft, einer noch relativ neuen und sehr vielversprechenden Notiz-Software sehr wertvoll und wichtig. Es freut mich wirklich sehr, dass es immer noch oder immer wieder Software-Entwickler gibt, die nicht den einfachen Weg des „alles online, alles auf unsere (gemieteten) Server“ gehen: Your Data is Yours – Our thoughts on Data Ownership and Accessibility
Und zu guter Letzt hier ein Artikel, der am Beispiel von MS OneNote sehr schön aufzeigt, wie eingesperrt man sein kann und welcher Aufwände es bedarf, sich da mehr schlecht als recht gegen abzusichern bzw. seine Inhalte zu migrieren, wenn die Software oder die Dienstleistung seitens des Herstellers bis zur Unkenntlichkeit verändert oder ganz eingestellt wird: OneNote-Katastrophenschutz. Ich kann diesen Artikel sehr gut nachempfinden, habe ich doch früher selbst sehr gerne OneNote benutzt. Solange es noch lokale Dateien in verschiedenen Formaten sowohl lesen als auch schreiben konnte. Lokal und Cloud: Best of both worlds. Nur Cloud, und gerade wenn sie so seltsam restriktiv wie die Kombination des aktuellen OneNote mit OneDrive ist – absolut unbrauchbar!
Übrigens, bevor ich jetzt wieder zum eigentlichen Thema komme: mein PKM-Tool der Wahl ist Obsidian, mit dem ich seit einem Jahr sehr zufrieden bin. In dieser Software entsteht auch gerade dieser Artikel. Von der Recherche bis zum finalen Schreiben, inklusive aller nötiger Formatierungen (Markdown) wie Überschriften, Listen und Code-Snippets. Ich kann den gesamten Text kopieren und in den WordPress-Editor werfen und alles passt. Nur die Bilder muss ich noch separat zufügen.
Zurück zur Timeline-Erstellung in Notion
Für die Zusammenarbeit von verteilten Teams ist eine Online-Datenbasis natürlich unabdingbar. Und die Integration von Tabellen als nahtloser Strukturbestandteil von Notion, der super einfach in verschiedenen „Views“ dargestellt werden kann, ist für unsere Zwecke sehr von Vorteil. Man kann einfachst zwischen Table-View, Board-View oder Calendar-View umschalten und das funktioniert sehr gut und ist auch leicht konfigurier- und anpassbar. Um so erfreuter war ich, als ich gesehen habe, dass vor einigen Monaten von Notion auch eine Timeline-View eingeführt wurde. Das könnte ja genau das richtige sein, dachte ich mir. War es auch, und deshalb findet ihr hier auch meine Experimente in Notion.
Notion würde es auch gestatten, die Datentabelle, wie wir ganz zu anfang überlegt und in Excel erstellt haben, in Notion selbst zu erstellen. Und Notion würde darüber hinaus auch Möglichkeiten zur Kollaboration bieten. Also die Tabelle durch Dritte wie Leser, die ihre eigenen Tipps oder Veranstalter, die ihre eigenen Events eingeben möchten, befüllen zu lassen.
Wir haben diese Tabelle aber ja bereits und wollen Notion hier nur als Front-End benutzen. Wenn ich das richtig überblicke, dann kann sich Notion selbst nicht an andere Datenquellen andocken, wie es richtige Frontends, Visualisierungs-APIs (wie Google Charts) oder z.B. Business Analytics Pakete tun können. Das ist nicht die Philosophie dieser Software. Daten, mit denen in Notion gearbeitet werden soll, müssen importiert werden.
Um das folgende Nachzuvollziehen braucht ihr natürlich einen Notion-Account. Es gibt auch einen kostenlosen Plan. Aber anmelden muss man sich. Das geht über die Webseite von Notion.
Nun – entweder habt ihr ohnehin schon einen Notion-Account oder ihr seid trotz (oder wegen ;-)) meiner zuvor geäußerten Vorbehalte neugierig geworden und wollt euch Notion selbst einmal anschauen. Dann – nur zu. Probieren schadet nichts. Oder ihr lest erst einmal so weiter und schaut euch mein Endergebnis an.
- Schritt: Benötigtes Importformat feststellen. In dem oben gezeigten Import-Fenster wird schon klar: der einzig sinnvolle und mögliche Weg, Tabellen-Daten nach Notion zu importieren, läuft über .csv-Dateien. Also speichern wir unser Excel-Tabellenblatt mit den Ursprungsdaten als .csv.
- Schritt ist dann das feststellen, dass Notion sehr wählerisch mit dem Datumsformat ist und dass es keinen einfachen und nur einen sehr aufwendigen, programmatischen Weg gibt (wenn überhaupt), aus fehlinterpretierten Zahlen innerhalb Notion einen Datumswert zu erzeugen!
- Schritt also: Sicherstellen, dass alle Datums-Felder in einem Format formatiert sind, das Notion beim Import auch tatsächlich als Datum interpretiert und importiert. D.h. 01.03.22 funktioniert nicht, aber 2022-03-01 funktioniert. Wir nehmen diese Formatierung innerhalb Excel vor und exportieren dann also erst unsere .csv-Datei.
- Schritt: In unserem Notion eine neue Seite erzeugen und in dieser den Import-Befehl über die drei Punkte ganz oben rechts am Rand auswählen. Das führt zu dem oben dargestellten Fenster der Import-Möglichkeiten. CSV auswählen, im Datei-Dialog die entsprechende Datei wählen und nach kurzer Zeit ist die Datei importiert:
Wir können jetzt direkt unterschiedliche unterschiedliche Sichten auf diese Tabellendaten wählen. Das geschieht über den Eintrag „+ Add a view“ direkt unter der Überschrift.
- Schritt: Add a View: Timeline View auswählen und anklicken. Und schon erscheint diese sehr elegante und gut navigierbare Timeline-Ansicht! Das ist schon sehr fein, muss ich sagen. Das untere Bild zeigt die Events schon nach aufsteigendem Startdatum sortiert, das habe ich über das Menü „Sort“ eingestellt.
Für die zeitliche Einordnung wurde automatisch das richtige Feld benutzt – sicher, weil das Startdatum die erste Datumsspalte in der Tabelle ist. Was aber noch fehlt, ist die Darstellung eines Balkens, der der Dauer der Veranstaltung entspricht. Zahlenmäßig stehen die Tage ja schon im Hauptfeld der Ansicht nach dem Namen des Events drin. Das habe ich unter „Properties“ eingestellt. Da gibt es für jedes Feld in der Tabell einen Schalter: Zeigen oder nicht zeigen. Und zwar jeweils für den linken Tabellenbereich und für die Timeline selbst.
- Schritt: Notion benötigt für die Darstellung der Dauer in der Timeline neben dem Startdatum auch ein Enddatum. Mit einer Angabe der Dauer selbst kann Notion da nichts anfangen. Das ist also wie bei Google Charts. Entweder haben wir also ein Feld „Date_End“ schon vor dem Import nach Notion automatisch errechnet (wie im Kapitel zu Google Charts gezeigt) oder wir machen dies direkt in Notion: So geht’s:
- zurück in die Table-View schalten
- am Ende der Tabelle eine Spalte hinzufügen, dafür den Property type: Formula auswählen
- Und in die neue Spalte die folgende Funktion eingeben: dateAdd(prop(„Date_Start“), prop(„Approx_Days“), „days“). Diese Funktion addiert den in der property „Approx_Days“ gefundenen Wert als Tage auf das in der property „Date_Start“ gefundene Datum und liefert damit das Enddatum ebenfalls als Datum zurück.
- Schritt: Jetzt können wir wieder die Timeline View auswählen, dort auf das „…“ Menü klicken, den untersten Eintrag „Timeline by“ auswählen und im Folgedialog selektieren, dass wir separate Start- und End-Daten benutzen wollen und welche Felder das sind.
Fertig!
Eine weitere Ausgestaltung mit Farbe geht leider nicht, was sehr schade ist. Damit fallen auch alle Hervorhebungsmöglichkeiten flach. Dafür sieht es sehr minimalistisch elegant aus und es sind sowohl für den linken Listenrand wie auch für die Timeline-Balken alle möglichen Felder zur Darstellung ein- und ausschaltbar. Der Maßstab bzw. die Zeitabschnitte sind oben frei zwischen Tagen, Wochen usw. frei wählbar und auch eine Gruppierung oder Filterung ist nach jedem Feld möglich. Man kann sich also z.B. nur Bikepacking- ,Gravel-Events oder Expos einblenden und nach diesen Gruppieren. Das sähe dann z.B. so aus:

Und das ist tatsächlich fast schon Perfektion.
Tableau.public
Kann Tableau als Gewinner aus diesem kleinen Vergleich, der ja eher eine Methodiken-erkundende Lern-Übung mit resultierendem Multi-App-Tutorial ist, hervorgehen? Wir werden dazu heftige 1,5 Gigabyte an App installieren müssen, kommen dann aber buchstäblich mit 8 Klicks zum Ziel. Nicht 8 Schritte, wirklich nur 8 Klicks.
Doch zunächst: was ist Tableau und welche Version brauchen wir? Tableau ist eine Software der Kategorie die mit Business Intelligence, Business Analytics oder auch Visual Analytics bezeichnet wird. Quasi eine Tabellenkalkulation auf Drogen. Wobei der Fokus nicht auf das Erstellen der Daten und Tabellen liegt, sondern im Darstellen, Auswerten und Erkunden. Und zwar mit möglichst mächtigen Werkzeugen, die es Spezialisten und Datenanalysten ermöglichen, tief in Zusammenhänge der verschiedenen Daten einzutauchen und auch visuelle Präsentationen oder ganze Dashboards zu erstellen. Die aber genauso geeignet sind, jedermann und -frau, ob Datenanalyst oder nicht, ob Managementebene oder nicht oder ob Lehrer, Student, Wissenschaftler usw. diese Werkzeuge möglichst einfach benutzbar zur Verfügung zu stellen. Die Daten, die ausgewertet und visualisiert werden sollen, kommen dabei immer aus einer anzubindenden externen Quelle. Ob das Excel-, Text,- PDF-, JSON oder andere Dateien sind oder diverse Datenbanken, Geodatenbanken und Ausgabedateien diverser Statistikpakete. Und sie sind von klein bis riesig groß.
Tableau richtet sich mit seinen Hauptprodukten an professionelle Nutzer und ist entsprechend bepreist. Aber es gibt sowohl eine kostenlose Verwendungsmöglichkeit für akademische Nutzer wie auch das generell für jedermann frei verwendbare Tableau.public. Dessen Nachteil scheint für mich auf den ersten Blick nur darin zu liegen, dass das lokale Speichern eingeschränkt (lese – nicht möglich) ist. Statt dessen kann man (muss) man seine Ergebnisse allerdings auf der tableau.public Seite veröffentlichen, wenn man sie behalten möchte.
Die Applikation selbst wird dabei lokal auf dem eigenen Rechner installiert. Und ist besagte 1,5 Gb groß. Der Downloadlink befindet sich direkt auf der verlinkten Tableau.public Startseite. Von dort aus kann man sich auch einen Eindruck von den vielen Verwendungsmöglichkeiten mit Visualiserungen und Dashboards zu allem Möglichen machen. Von Erdbeben diverser Epochen über Sportstatisitken oder von Census-Daten bis zur Auswertung, welcher Character der Gefolgschaft des Rings über alle 11 Stunden der Herr der Ringe Filme an welcher Position der Reise die längsten Dialoge hatte.
Einerseits beindruckend, andererseits finde ich, dass bei allen diesen Showcases (und zwar nicht nur denen auf der tableau.public Seite, sondern auch direkt auf Tableau selbst – also quasi in vorderster Schaufensterfront) die Performance nicht so auf Zack ist, wie ich mir das wünschen würde und wie man es eigentlich auch von interkativen Charts gewöhnt ist, wenn sie nicht komplett schlecht programmiert sind. Und dies gilt ausnahmslos für alle Auswertungen und Showcases, auf die ich geklickt und mit denen ich herumprobiert habe. Es geht alles und ist „ok“, aber „überzeugend“ ist anders. Die Ergebnisse an sich, was die grafische Qualität und Möglichkeiten angeht – die sind jedoch sehr ansprechend. Und auf dem eigenen Rechner lokal angewendet, kann man mit der Performance auch zufrieden sein.
Ok, jetzt aber zur Anwendung auf unseren Einsatzfall zurück. Tableau.public ist installiert und geöffnet, was jetzt?
- Schritt: Wir müssen die auszuwertende Datenquelle auswählen. In unserem Fall soll das jetzt auch wieder die online in der Google Cloud residierende Google Sheets Tabelle sein. Google Tabellen wird also ausgewählt und wir müssen zunächst Tableau.public für unseren Google Account authentifizieren. Das ist mit einem Klick möglich. Und dann sehen wir die Auswahl-Liste unserer Google-Tabellen:
- Schritt: Unsere Daten sind eingelesen. Wir sehen, dass alles ok ist und könnten jetzt auch weitere Daten hinzuladen und verknüpfen. Brauchen wir in unserem Falle nicht und wählen daher „Zum Arbeits-Blatt“ aus
- Schritt: Da packen wir uns das Feld „Event Name Short“ aus der Liste aller Felder am linken Bildschirmrand und ziehen es mit der Maus in die Mitte des leeren Visualisierungsfelds. Automatisch erscheint die Liste der Namen im Feld und oben drüber finden sich zwei Felder, „Zeilen“ und „Spalten“ benannt. Unser Feld „Event Name Short“ ist als Button in „Zeilen“ abgelegt.
- Schritt: Das Feld „Date_Start“ in die Zeile „Spalten“ ziehen
- Schritt: in der rechten Icon-Galerie („Zeig es mir“ betitelt) klicken wir auf das Gantt-Diagramm:
- Schritt: Wir greifen das Feld „Approx_Days“ aus der Feldliste am linken Bildschirmrand und ziehen es mitten in die Gantt-Fläche hinein – Voilà! Fertige Timeline.
Nun ja, fast. Alle Balken erscheinen noch links angeschlagen und die Reihenfolge der Events ist noch nicht aufsteigend. Das ist aber einfach gelöst.
Mehrfaches Klicken auf das kleine „+“ Symbol des zur Schaltfläche gewordenen Feldnamens „Date_Start“ in der Leiste „Spalten“ rotiert durch zeitliche Skalierungen (Jahr, Quartal, Monat, Woche, Tag). Gleiches funktioniert auch direkt in der Zeitachse unter dem Diagramm. Oder ich klicke auf die Feldschaltfläche und kann direkt „Tag“ oder „genaues Datum“ auswählen.
Und die Sortierung kann auch wie gewünscht erfolgen. In dem Fall klicke ich auf die Überschrift der Event-Spalte am linken Diagramm-Rand und wähle „Feld/Date_Start“ aus:
Jetzt aber. Fertig! :)

Jetzt können wir weiter erkunden. Das mache ich buchstäblich on-the-fly und in der Minute, wo ich auch diesen Abschnitt hier schreibe. Die Kachel „Farbe“ fällt mir links auf. Das Fly-out zeigt, was man machen soll. Ein Feld draufziehen, welches die Informationen enthält, nachdem die Farben ausgewählt werden soll. Ok – ich ziehe das Feld „Kategorie“ von links per Drag und Drop auf diese Kachel und voilà, so sieht das Ergebnis aus:

Über die Legende können nun auch Einzel- und Mehrfach-Selektionen, Hervorhebungen und Ausschlüsse erzeugt werden.
Das Feld „Angemeldet“ per Drag und Drop auf die Kachel „Quickinfo“ gezogen führt dazu, dass unter dem Mauszeiger beim Verweilen auf einem Event-Balken im Flyout nun auch der Anmeldestatus angezeigt wird. Sehr schön.
Jetzt sind der Fantasie kaum Grenzen gesetzt, was man noch visualisieren könnte. Wobei das dann aber unser eigentliches Vorhaben der Visualisierung einer Timeline sprengen würde.
Wenn ich die Ergebnisse meiner Arbeit jetzt allerdings speicher möchte, dann geht dies nur über das Anlegen eines Tableau.public Accounts (kostenlos) und dem Veröffentlichen auf Tableau.public selbst. Jedermann kann diese Visualisierungen dann einsehen. Das ist also nichts für private oder vertraulichen Informationen. Immerhin darf man abwählen (und das ist auch sinnigerweise standardmäßig ausgeschaltet), dass die Auswertungen mit der Datenquelle synchron gehalten und die Anmeldeinformationen eingebettet werden.
Wer also mit meiner Beispielvisualisierung selbst online spielen möchte, kann dies unter diesem Link tun.
Python
Und damit kommen wir zum letzten Abschnitt der wundersamen Erkundungsreise zu diversen Visualisierungs-Lösungen einer Bike-Event-Datenbank bzw. -liste. Zuvor haben wir für die Google Charts ja schon ein paar wenige Code-Zeilen erstellt. Dort mit JavaScript. Das interessiert mich eigentlich weniger bis gar nicht.
Was mich hingegen immer schon mal interessiert hat, war einen Einstieg entweder in R oder in Python zu finden. Beides habe ich auch im Urlaub zwischen Weihnachten und Neujahr nochmal kurz überdacht, was ich eigentlich als interessanter erachte und habe mich dann für Python entschieden. Nun sind Python und R nicht eins zu eins dasselbe: R ist sehr auf statistische Analyse und Daten Visualisierung ausgelegt, während Python dort ebenfalls sehr stark ist und viel für solche Zwecke verwendet wird, aber auch für generelle App-Programmierung, vor allem von Web-Applikationen und anderen Dingen benutzt wird. R und auch Python erfreuen sich hoher Beliebtheit in wissenschaftlichen Anwendungen und die Anzahl an lebenden Dokumenten mit live Python (aber auch R) Code, eingebetteten Daten, Visualisierungen und Erläuterungen wächst und wächst.
Python (wie auch R) ist Open Source und hier ist die erste Anlaufstelle, wo man sich auch Python selbst herunterladen kann: Python.org
Für erste Schritte muss man dies aber gar nicht. Ähnlich wie das JSFiddle.net, das wir schon im Abschnitt zu Google Charts kennengelernt haben, gibt es diverse Online Entwicklungsumgebungen bzw. Compiler. Wie z.B. OneCompiler.
Und sobald man im Web nach Python googlet, trifft man sofort auf Begriffe wie Notebooks und Jupyter.
In diesem Zusammenhang versteht man unter „Notebooks“ sogenannte Computational Notebooks. Das sind Dokumentationsformate, die Text, ausführbahren Code, Daten und Analysen gemeinsam beinhalten. So kann eine Untersuchung oder Auswertung mit einer Einleitung anfangen, dann ein paar Zeilen Code beinhalten, dann direkt eine Diskussion oder Erläuterung im Fließtext darunter aufweisen und dann folgt das nächste Code-Stück usw.
Und Jupyter Notebooks oder Projekt Jupyter ist eine besonders verbreitete Version solcher Notebooks (und mittlerweile noch mehr, nämlich Jupyter Notebooks, JupyterHub und JupyterLab). Wobei Jupyter und seine Produkte nicht nur auf Python beschränkt sind, sondern auch andere Kernels zulassen, u.a. auch R.
Diese Tools kann man lokal installieren aber auch direkt online benutzen. Diese Online-Benutzung kann aber auch mal unterbunden sein, habe ich festgestellt. Und zwar erhält man dann nur die Meldung: „Too many users running https://github.com/jupyterlab/jupyterlab-demo! Try again soon.“
Deswegen bin ich nach den ersten Tutorials direkt in die Vollen gegangen und habe auf meinem System Python selbst wie auch die wohl gebräuchlichste Entwicklungsumgebung, die IDE PyCharm installiert. Die Community-Edition ist kostenlos und bringt alles mit sich, was für die Python-Entwicklung benötigt wird. Den Download für verschiedene Plattformen gibt es hier.
So kann das dann bei euch aussehen, wenn der Editor offen ist. In der Tat ist der Code in der Abbildung schon alles, was wir für die erste Variante der Timeline-Darstellung benötigen. Und das meiste davon ist sogar grauer Text mit dem #- davor. D.h. das meist sind Kommentare:
Erste Variante? Ja, denn natürlich gibt es zahlreiche Bibliotheken und Pakete für Python, die diverse Funktionen bereitstellen. Auch für Datenvisualisierung gibt es mehrere. Häufig benutzt werden wohl Matplotlib und Plotly. Da gibt es aber noch wesentlich mehr, wie z.B. Seaborn und anderes. Wie groß da der Ozean an Möglichkeiten ist, kann ich mit meinen paar Tagen Einstieg noch überhaupt nicht überblicken.
Ich habe mit Matplotlib angefangen und mich dann Plotly zugewendet und damit dann etwas mehr Zeit beim experimentieren verbracht.
Daher in der Folge zwei Unter-Kapitel: Visualisierung mit Matplotlib und mit Plotly. Wie auch schon bei dem Beispiel mit Google Charts und JavaScript werden wir hier weniger programmieren im Wortsinn sondern eher mit damit befasst sein, die nötigen Bibliotheken zu importieren, daraus das richtige Paket bzw. das richtige Visualisierungsobjekt anzusprechen, ihm die nötigen Daten und Darstellungsparameter zu übergeben und zuvor natürlich noch die Anbindung zu den Daten selbst herzustellen bzw. diese zu importieren.
Event-Timeline mit Python und Matplotlib
Ihr könnt diese Schritte auch nahezu eins zu eins online, z.B. im erwähnten OneCompiler, durchführen. Ich gehe in der weiteren Beschreibung von der Verwendung der IDE PyCharm aus. Python und PyCharm sollten also lokal installiert sein.
Bevor ich Matplotlib zum weiteren Experimentieren ausgewählt habe, habe ich natürlich erstmal gestöbert, was diese Bibliothek denn so kann und an Funktionen bietet. Dazu gibt es eine hübsche und vielversprechende Galerie:
Und ja, es gibt einen Plot, der nennt sich Timeline, dieser ist aber nur für eine reine Zeitachse gedacht. Ganz genau so wie das erste Excel-Beispiel mit dem x-y-Diagramm, dass ich gezeigt habe. Einen dedizierten Gantt-Plot gibt es in Matplotlib nicht. Wir müssen uns also wieder mit der horizontalen Balken-Grafik als Basis auseinandersetzen. Das ist der Horizontal Bar Chart mit Beispiel und Beispiel-Code auf Matplotlib.
Da sehen wir schon, dass wir zwei Bibliotheken importieren müssen: Matplotlib.pyplot selbst (klar), aber auch numpy. Es ginge zwar wohl auch ohne, aber eigentlich kommt kaum ein Python Programm ohne den import von numpy daher (Wikipedia weiss, warum).
Als dritte Bibliothek werden wir auch noch Pandas importieren. Das ist die wohl meist verbreitetste Bibliothek in der gesamten Data Science mit Python. Sie dient zur Datenanalyse und Datentransformation und bietet auch Funktionalitäten für Import und Abfrage von Datenquellen.
- Schritt: Wir legen also in PyCharm ein neues Projekt an und nennen es bikeEvents.
- Schritt: in diesem Projekt erzeugen wir ein neues Python file mit dem Namen „bikeEvents.py“
- Schritt: wir geben die ersten Zeilen in Editor ein
# import libraries
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
Ein vorangestelltes # leitet übrigens einen Kommentar ein.
Jetzt kann es sehr wahrscheinlich so sein, dass weder pandas noch die matplotlib bereits auf eurem System installiert ist. Das lässt sich aber gerade mit PyCharm und auf dem Mac super einfach überprüfen und durchdführen. In der Auswahlleiste am unteren Fensterrand befindet sich die Auswahl „Python Packages“. Dort draufgeklickt erscheinen die installierten und nicht installeriten Packages mit den aktuellen Versionsnummern und man kann auch Packages hinzufügen.
Am elegantesten geht das aber, wenn man das Terminal aufruft (ebenfalls unten in der Auswahlleiste von PyCharm) und dort einfach eingibt:
pip install matplotlib
und ggfs.
pip install pandas
Das war es schon. Pip ist übrigens der Standard Package Manager für Python.
Zurück zum eigentlichen Programm-Code. Wie wir sehen, installieren wir Bibliotheken immer als irgendwas. import pandas as pd
.
Überall, wo im Code fortan pd
benutzt wird, ist das also das Synonym für die pandas package. Mit der nächsten Zeile
bike_ev = pd.read_csv('Bikeevents_testexport.csv', sep=';')
rufen wir die Funktion read_csv von Pandas auf, übergeben Parameter und speichern das Ergebnis in der Variablen bike_ev.
CSV sagt es bereits – ich habe mich in diesem Beispiel wieder entschieden, eine lokal abgespeicherte CSV-Datei als Import zu verwenden. Die habe ich der Einfachheit halber in den Projektordner des PyCharm-Projektes kopiert, damit hier nicht ellenlange Pfade stehen müssen.
Und der zweite Parameter sep=';'
ist für wahrscheinlich deutsch regionalisierte Excel-Versionen wichtig. Die speichern eigentlich Comma separated values (csv) nämlich gerne als semicolon separated values ab. Ohne diesen Parameter geht Pandas von Kommas als Trennzeichen aus und wird einen erst mal kryptischen Fehler in ungefähr folgender Form in der Konsole hinterlassen: „pandas.errors.ParserError Error tokenizing data…“
Und mit print(bike_ev)
könnten wir jetzt das kurze Programm schon beenden und schauen, ob das so funktioniert. Denn wenn alles geklappt hat, würde dieser Befehl die übernommenen Daten aus der .csv-Datei in der Run-Konsole von PyCharm ausgeben. Das Run-Command holt man zum ersten Mal wohl am Besten durch das Kontextmenü durch klicken auf den „bikeEvents.py“ Eintrag aus der Projektliste, damit auch bei mehreren .py-Dateien im Projekt die richtige ausgeführt wird. In der Folge geht das aber auch über Shortcut STRG+SHIFT+R oder über den grünen Pfeil direkt am linken Rand der Konsole. So sieht das dann aus:
Erfolg! Weil die Tabelle allerdings so viele Spalten aufweist, werden nicht alle ausgegeben. Wir sehen aber, das [14 rows x 26 columns] eingelesen wurden.
Die brauchen wir ja erst einmal wieder gar nicht alle. Von daher wählen wir nur die nötigsten Spalten aus:
df = pd.DataFrame(bike_ev, columns= ['Event_Name_Short','Date_Start','Approx_Days','Days_from_Jan1st'])
df wird also ein sogenanntes DataFrame Objekt und enthlt nur die aufgeführten Spalten.
Damit erzeugen wir jetzt ein Plotobjekt als Rahmen mit einem einzigen Subplot und definieren für diesen Subplot den Horizontal Bar Chart der Matplotlib:
fig, ax = plt.subplots(1, figsize=(16,6))
ax.barh(df.Event_Name_Short, df.Approx_Days, left=df.Days_from_Jan1st)
Das ist also sehr ähnlich dem Vorgehen, wie schon eingangs bei Excel und bei Google Sheets. Ein horizontales Balkendiagramm wird ausgewählt .barh
, als Beschriftung der Balken bzw. der vertikalen Achse wird das Feld „Event_Name_Short“ übergeben, die Länge des Balkens wird im Feld „Approx_Days“ angegeben und der dritte und letzte Parameter zeigt mit left=
die Position des linken Beginns des Balkens an. Die findet sich in dem Feld „Days_from_Jan1st“ welches wir ja auch schon für die Darstellung in Excel extra erzeugt haben (gerne dort oben nachschauen). Hier müssen wir also keinen ersten Balken erzeugen und dann verstecken oder so formatieren, dass er nur wie eine Hilfslinie aussieht, sondern können direkt angeben, wo der Balken beginnen soll.
Und mit plt.show()
können wir diesen Plot dann auch tatsächlich darstellen.
Wenn wir das Programm jetzt noch einmal ausführen, erscheint wieder die Ausgabe des bike_ev Objektes in der Run-Konsole und zusätzlich öffnet sich ein Fenster mit dem erzeugten Balkendiagramm:
Soweit, so gut. Aber viel mehr passiert da in diesem Diagramm auch erst einmal nicht. In der Statuszeile wird die Position des Mauszeigers im Diagramm ausgegeben, das war es aber auch an Interaktion. Keine Fly-outs oder anderen Dinge, die passieren.
Aber ein wenig aufhübschen, das können wir wenigstens. Z.B. Achsenbeschriftungen vergeben und auch die Einteilung der horizontalen Achse auf ein Datumsformat anpassen. Aber auch hier bleibt es in der Folge bei der unschönen Erscheinung, die uns auch schon in Excel gestört hat: Wir können nur ganzzahlige Tick-Abstände vorgeben und zwar die entsprechenden Zahlen als Datum formatieren, aber es ist ohne eigene Programmier-Arbeit keine Funktion dahinter, die jeweils den Ersten eines Monats als Gitter-Linie oder Tick-Mark setzen würde.
Hierfür kommt jetzt numpy in’s Spiel, aber wir brauchen auch noch die date Funktion aus der datetime Bibliothek, die wir kurzerhand on the fly einbinden:
### Tickmarks ###
from datetime import date
proj_start = date(2022,1,1)
proj_end = date(2022,12,31)
xticks = np.arange(0, 365+1, 30)
xticks_labels = pd.date_range(proj_start, proj_end).strftime("%m/%d")
xticks_minor = np.arange(0, 365+1, 1)
ax.set_xticks(xticks)
ax.set_xticks(xticks_minor, minor=True)
ax.set_xticklabels(xticks_labels[::30])
ax.set_xlabel('Datum')
ax.set_ylabel('Event')
plt.show()
Tadaa! Jetzt haben wir Achsentitel und eine Zeitachseneinteilung nach jeweils 30 Tagen und mit Monat/Tag beschriftet:
Sehr wahrscheinlich kann man das jetzt noch deutlich weiter aufhübschen – aber so wirklich zuversichtlich war ich da jetzt nicht, dass sich weiterer Aufwand auch wirklich in besserer Funktion niederschlagen würde. Deswegen schauen wir uns lieber einmal an, was das Plotly-Paket so zur Verfügung stellt.
Event-Timeline mit Python und Plotly
Plotly ist eine Open Source Graphing Library, die ebenso auch für R, Julia, Javascript und weitere Sprachen/Umgebungen angeboten wird bzw. verwendbar ist. Zeuge meines kurzen Sprungs in’s Learning-by-Doing-Wasser ist, dass ich dies jetzt gerade für das Schreiben dieses Blogs herausfinde. Aber wie ihr aus der Einleitung wisst, geht es ja auch genau darum. Programmieren, um zu Planen – und Bloggen, um zu lernen. Bzw. das Erlernte zu vertiefen oder erst ein mal zu festigen. Und um weiter festzustellen, wie wenig ich weiss, wie wenig ich überhaupt weiss. Eine sehr wichtige Grundhaltung, derer sich viel mehr Menschen befleissigen sollten. Und für euch die Erinnerung, dass ihr hier kein Tutorial eines alten Hasen vor euch habt, sondern mir bei meinen ersten Schritten in den jeweiligen Visualisierungsumgebungen bzw. Programmiersprachen und Bibliotheken folgt.
Alle Plotly-Versionen zusammen wurden wohl schon über 100 Millionen mal herunter geladen, sagt Plotly von sich selbst. Und wenn ich mir diesen Download-Screen mit den Github-Likes anschaue, scheint mir das auch einen interessanten Anhalt über die jeweilige Beliebtheit der entsprechenden Sprachen (und sicher auch deren Bedarf an einer Bibliothek wie Plotly aus ihren jeweiligen Anwendungsschwerpunkten heraus) zu geben:
Auch für Plotly gibt es eine schöne und gut lesbare Dokumentation inklusive „Getting Startet“ und diversen Beispielen.
Browser-Timeline mit Plotly aus .csv-Datei
Wir greifen unseren Beispiel-Code von der Matplotlib wieder auf. Bevor wie dies tun können, müssen wir aber zunächst plotly auf unserem System installieren. Das funktioniert genau wie bei anderen Bibliotheken am einfachsten mit pip.
Also wieder: das Terminal aufrufen (unten in der Auswahlleiste von PyCharm) und dort eingeben:
pip install plotly
- Schritt: Optional, nur wenn noch nicht das Matplotlibbeispiel durchexerziert wurde und noch kein Projekt angelegt wurde: in der IDE PyCharm ein neues Projekt anlegen und es bikeEvents nennen.
- Schritt: in diesem neuen oder in dem schon bestehenden Projekt erzeugen wir ein neues Python file mit dem Namen „bikeEventsPlotly.py“
- Schritt: wir geben die ersten Zeilen im Editor ein
# import libraries
import pandas as pd
import plotly.express as px
import plotly
Wir benötigen also nach wie vor pandas, aber nicht mehr numpy. Und anstelle von Matplotlib importieren wir jetzt plotly. Und zwar nicht nur plotly (ohne as
, das ist kurz genug), sondern explizit auch plotly.express as px
. Über das Kürzel px können wir also auf plotly.express zugreifen, welches in plotly selbst enthalten ist.
Das sagt die Doku: „The plotly.express
module (usually imported as px
) contains functions that can create entire figures at once, and is referred to as Plotly Express or PX. Plotly Express is a built-in part of the plotly
library, and is the recommended starting point for creating most common figures.„
Die nächsten zwei Zeilen sind unverändert vom Matplotlib-Beispiel. Denn wir nutzen ja pandas, um wieder dieselbe .csv-Datei einzulesen und wir brauchen zunächst nur die gleichen drei Spalten, die dem DataFrame Objekt df zugewiesen werden.
bike_ev = pd.read_csv('Bikeevents_testexport.csv', sep=';')`
df = pd.DataFrame(bike_ev, columns= ['Event_Name_Short','Date_Start','Approx_Days','Days_from_Jan1st'])
Plotly bietet dankenswerterweise ein dediziertes Gantt-Diagramm-Objekt. Es heisst Gantt in der Dokumentation, wird aber als .timeline
aufgerufen. Und es benötigt für die Darstellung einen Start- und ein Endzeitpunkt. Wir haben aber ja nur einen Startzeitpunkt und die Dauer (Approx_Days) zur Verfügung und eingeladen.
Hier lässt sich prima einflechten: Wenn man’s weiss (das gilt so ziemlich für jede Zeile dieses Artikels) ist es einfach. Bis es aber läuft, ist doch immer jede Menge googeln, Doku lesen und testen angesagt. Hier war z.B. zunächst nicht klar und in verschiedenen Stellen im Web unterschiedlich dargelegt, wie man die doch hoffentlich einfache Funktion, eine Dauer zu einem Datum (oder allgemeiner, Zeitpunkt) in einer bestimmten Einheit (Tage, Sekunden, was auch immer) erhält und anwendet.
Denn die offensichtliche und schnell gefundene Lösung, timedelta, wollte erst nicht funktionieren. Sie kann z.b. per se nicht auf Listen angewendet werden. Mit dem Standardvorgehen des Einlesens einer Spalte eines dataframes sind diese Spalten bzw. Felder aber zu Listenobjekten geworden. Ich fand dann Tips, dass man mit der apply Funktion hantieren müsste (und zuvor muss natürlich auch noch sichergestellt sein, dass unsere Spalten auch vom Typ Datetime sind). Denn nur Datetime objects und timedeltas können auch addiert werden. Es hätte also noch eines from datetime import timedelta
und weiterer drei Zeilen bedurft.
Glücklicherweise fand ich dann noch den richtigen Hinweis, wie es dank pandas und mit der pandas.to_timedelta
Funktion dann doch so elegant und als Einzeiler geht, wie ich das erwartet habe:
finish = pd.to_datetime(df.Date_Start) + pd.to_timedelta(df.Approx_Days, unit="D")
Wo wir „finish“ dann schon als kurzen Variablennamen haben, erzeugen wir der Einfachheit halber für die weitere Diagramm-Erstellung gleich noch zwei weitere, damit der Code lesbarer wird:
events = df['Event_Name_Short'] start = pd.to_datetime(df['Date_Start'])
Und jetzt können wir schon das Diagramm erzeugen. Dazu müssen wir der Diagrammfunktion mindestens 4 Parameter übergeben: den gesamten Dataframe, start, ende und Y-Achsen-Label. Wir senden gleich noch einen fünften mit – einen Titel:
fig = px.timeline(df, x_start=start, x_end=finish, y=events, title='Bike Events')
Jetzt aktualisieren wir gleich noch dieses erzeugte fig
mit der folgenden Zeile, die dafür sorgt, dass die Events in aufsteigender Reihenfolge sortiert werden:
fig.update_yaxes(autorange='reversed')
Mehr zu Formatierungen im nächsten Abschnitt.
Und das wäre es fast schon. Wir können unser Programm jetzt einmal starten und schauen, was passiert. Und sehen, dass nichts passiert. Aber immerhin und hoffentlich sehen wir in der Run-Konsole „Process finished with exit code 0“. D.h. dass das Programm ohne Fehler durchgelaufen ist.
Dargestellt wurde aber nichts. Wir haben nämlich zunächst nur ein fertiges Diagramm erzeugt, aber noch nichts damit angefangen.
Mit der folgenden Zeile wird das erzeugte Diagramm aber elegant als .html-Datei abgespeichert und praktischerweise beim Ausführen des Programms in PyCharm direkt in eurem Standard-Webbrowser geöffnet.
plotly.offline.plot(fig, filename='plotly_BikeEvents.html')
Und so sieht dann die Ausgabe aus. Beachtet, dass das hilfreiche Top-Menü, das ich im folgenden Screenshot grün unterstrichen habe, nur erscheint, wenn ihr mit der Maus in das Diagramm klickt:
Fertig. Und schon vor jeder weiteren Anpassung in meinen Augen sehr gefällig und funktional!
Die Beschriftung sieht ordentlich aus. Ohne jegliche Aktion von uns ist die horizontale Achse auch eine wahre Zeitachse und monatsgenau unterteilt und beschriftet. Das Feld ist angenehm hinterlegt und das Beste: dieses Diagramm ist responsive und intuitiv interaktiv. Verweilen über einem Balken bringt ein Fly-Out hevor und ich kann sehr einfach hinein- und hinaus zoomen und den Ausschnitt verschieben:
Klasse!
Das macht Lust auf mehr und das machen wir jetzt:
Gruppierte und filterbare Event-Timeline mit Plotly aus einer Excel-Datei
Zur Abwechslung nutze ich jetzt einen Import direkt aus meiner Exceldatei heraus. Um auch das einmal zu testen und weil in meinem Falle die .csv-Datei ja ohnehin nur ein für andere Zwecke nötiger Zwischenschritt war. Meine Original-Datenhaltung ist also derzeit ohnehin in Excel. Und wenn ich diese ohne Extraaufwand direkt verwenden kann – umso besser.
- Schritt: Optional, nur wenn noch nicht das Matplotlib-Beispiel oder das vorhergehende Plotly-Beispiel durchexerziert wurde und noch kein Projekt angelegt wurde: in der IDE PyCharm ein neues Projekt anlegen und es bikeEvents nennen.
- Schritt: in diesem neuen oder in dem schon bestehenden Projekt erzeugen wir ein neues Python file mit dem Namen „bikeEventsPlotlyExcel.py“
Pandas hält auch eine .read_excel
Funktion bereit. Interessanterweise muss man für die folgende Zeile aber zuerst das Modul openpyxl installieren, das zumindest in meiner Python-Version bzw. Installation nicht direkt dabei war. D.h. auch hier hilft uns wieder pip. Im Terminal also eingeben:
pip install openpyxl
Importieren müssen wir das aber nicht. Es muss nur auf dem System installiert sein. Die ersten drei Zeilen lauten also wieder gleich derer im vorhergehenden Plotly-Beispiel und in der vierten Zeile wird anstelle von .read_csv
nun .read_excel
mit dem entsprechenden Dateinamen verwendet. Auch hierfür habe ich die Exceldatei der Einfachheit halber in das Projektverzeichnis kopiert:
# import libraries
import pandas as pd
import plotly.express as px
import plotly
bike_ev = pd.read_excel('Bike_Events_2022.xlsx', 'Bike_Events_2022')
Weil eine Exceldatei mehrere Tabellenblätter beinhalten kann (und meine dies auch tut), wird in der oberen Zeile nach dem Dateinamen noch der Name des Tabellenblattes, welches einzulesen ist, definiert.
Auch die nächsten Zeilen sind wieder (fast) genau gleich wie im vorangehenden Beispiel. Wir wollen jetzt aber auch nach der Event-Kategorie gruppieren und auswählen können. Daher holen wir auch die Spalte „Kategorie“ in unseren DataFrame und weisen der entsprechenden Liste auch einen Variablennamen zu („category“):
df = pd.DataFrame(bike_ev, columns= ['Event_Name_Short','Date_Start','Approx_Days','Kategorie'])
# Um's einfacher zu machen, werden die Spalten zu Variablen zugewiesen
events = df['Event_Name_Short']
category = df['Kategorie']
start = pd.to_datetime(df['Date_Start'])
finish = pd.to_datetime(df.Date_Start) + pd.to_timedelta(df.Approx_Days, unit="D")
Damit können wir wieder das Diagramm mit der .timeline
Funktion von Plotly erzeugen. Als neuen Parameter übergeben wir jetzt auch die Variable (also die Datenliste) „category“ und zwar als Parameter für die Farbe:
fig = px.timeline(df, x_start=start, x_end=finish, y=events, color=category, title='Bike Events')
Und wenn wir jetzt nichts weiter formatieren, sondern unser Programm wieder mit dem Speichern des erzeugten Diagramm-Objekts als .html-Datei abschließen und ausführen…
plotly.offline.plot(fig, filename='plotly_BikeEvents.html')
erhalten wir dieses Ergebnis:
Überraschung! Sehr nett – noch nicht ganz so dargestellt, wie ich mir das wünsche, aber schon mal hilfreich und sehr interessant.
Zum Einen wird euch auffallen, dass in diesem Diagramm plötzlich sehr viel mehr Events enthalten sind. Ich habe natürlich während der Entstehung dieses Artikels meine Datentabelle immer weiter befüllt und für dieses Beispiel macht eine umfangreichere Tabelle auch mehr Sinn.
Zum Zweiten seht ihr, das ohne gesonderte Anweisung eine Legende aufgetaucht ist und dass die Events entsprechend ihrer Kategorie-Einteilung farblich markiert sind. Aber nicht nur das – sie sind auch entsprechend ihrer Kategorie von oben nach unten gruppiert. Was an und für sich eine schöne Sache ist. Ich möchte aber gerne alle Events in ihrer zeitlichen Abfolge sortiert unabhängig von der Kategorie sehen. Also nicht optisch mehr schlecht als recht abschätzen müssen, ob der Balken des Gravel-Events ganz unten im Diagramm ungefähr in der Mitte zwischen Juli und September sich nun mit dem Balken des Wochenend-Camps weiter oben im Daigramm deckt oder nicht. Und natürlich möchte ich wieder, dass die frühesten Events oben und die spätesten dann unten im Diagramm zu finden sind.
Hier jetzt also der nötige Formatierungsblock:
fig.update_layout(
xaxis = dict(
showgrid=True
,rangeslider_visible=False)
,yaxis = dict(
title= "Event Name"
,autorange="reversed"
# ,categoryorder="category ascending" # sortiert nach der Y-Achse, die hier durch die Event-Namen gebildet wird
,categoryorder="array" # sortiert nach dem Array, das per categoryarry ausgewählt wird, umgeht so das
,categoryarray=events # Sortieren nach der gewählten Farbe
,automargin=True
,ticklen=10
,showgrid=False # False: keine horizontalen Gridlines
,showticklabels=True)
,legend=dict(
traceorder="grouped") # tjo - passiert nix, egal ob normal oder grouped
)
Ich habe gleich noch weitere passende Parameter aufgeführt, damit ich mit diesen experimentieren kann. Die funktional wichtigen sind aber das schon bekannte autorange="reversed"
für die y-Achse und vor allem der Parameter categoryorder
. Der hat verschiedene „Schalter“. Eine Möglichkeit davon ist z.B. „category ascending“. Die Zeile ist auskommentiert, weil sie für unseren Fall nicht zum richtigen Ergebnis führt. Aber der Schalter „array“ lässt uns nach einem definierbaren Array sortieren. Das wird mit dem Parameter categoryarray
gesetzt. Und wenn wir unsere Liste „events“ dafür hernehmen, dann erfolgt die Sortierung so, wie ich sie möchte.
Die Parameter zur Legende sind ebenfalls nur der Vollständigkeit enhalten, falls hier Formatierungen erfolgen sollen. Eigentlich sind sie nur Überbleibsel aus vorhergehenen erfolglosen Versuchen, diese Autogruppierung aus dem vorherigen Diagramm-Ergebnis abzuschalten.
Diese Formatierungsblock schieben wir also vor die Zeile zum Abspeichern des Diagramm-Objekts als .html-Datei ein und führen unser Programm erneut aus.
plotly.offline.plot(fig, filename='plotly_BikeEvents.html')
Tadaaa!
Ähnlich nahe an der Perfektion wie viel weiter oben schon das Ergebnis mit Notion. Aber auf eine andere Art und Weise. Und unabhängig direkt für die Darstellung im Web geeignet.
Wir können wieder genauso intuitiv im Diagramm zoomen und schieben und wir können nun zusätzlich über die Legende einzelne oder mehrere Kategorien zur Darstellung ein- und ausschalten (oder über Doppelklick auf eine Kategorie nur diese selektieren).
Einbinden des Plotly Diagramms in ein WordPress Blog
Bis jetzt haben wir vollständige .html-Dateien mit Plotly erzeugt, die als alleinstehende Datei alles mitbringen, um sowohl die Daten in der gewünschten Form anzuzeigen als auch die Interaktion mit ihnen zu gewährleisten. Zoomen, Ausschnitte verschieben, Fly-Outs anzeigen, Selektieren usw. Wie bekommt man diese Diagramme genau mit dieser vollen interaktiven Funktionalität auch in ein Blog eingebunden? In genau so einen Artikel wie diesen? In einem WordPress Blog oder auf den Seiten irgendeines Online-Magazins oder Seiten wie Medium und Co?
Dazu „hostet“ man eine solches Diagramm oder allgemein auch Element (das können ja auch Videos, Tweets, Audio oder Forenbeiträge sein, wenn der Host dafür Code bereitstellt) gerne bei einem Service, der die Darstellung übernimmt und nutzt dafür dann einen „Embed“-Block bzw. einen iframe in seiner Web- bzw. Blog-Seite.
Achtung – hier spricht ein reiner Anwender zu euch, der zwar 1997 seine erste handcodierte Webseite online gestellt hat (und aus historisch-nostalgischen Gründen diese nach wie vor online hat – tfrank.de ), der aber dem meisten an Webtechnologie dazwischen relativ wenig Beachtung geschenkt hat und auch aus gutem Grund heute auf gehostetes WordPress setzt anstelle seinen eigenen Server zu betreiben. Man sollte es bei solch einem Artikel wie diesem hier nicht denken, aber mir geht es eher um das Radfahren, Fotografieren und ganz allgemein um das „Content“ produzieren als um Server-Konfiguration und der Administration und dem Basteln an der eigenen Blog-Präsenz. Zumindest aktuell und die letzten, äh, Dekaden… ;-) ).
Viel technischer als: Wir wählen einen passenden „Embed-Block“ aus, wird es daher im Folgenden nicht. ;-)
Möglichkeit Nr. 1: Das Chart Studio von Plotly
Plotly bietet mit Dash Enterprise und auch mit dem Chart Studio auch kommerzielle Lösungen zur Erstellung von Dashboards und zur direkten Interaktion mit Charts an. Per Code (z.B. mit Python und der Open Source Plotly Python Bibliothek) erstellte Diagramme können auch dort hin importiert werden. Auch direkt aus dem Code heraus. Dazu wird allerdings auch ein Account für z.B. Chart Studio benötigt. Es gibt auch eine kostenlose Version, aber da scheint mir die Anzahl an hostbaren Diagrammen wie auch die benutzte Datenmenge für die Diagramme beschränkt zu sein. Ich habe mich daher noch nicht weiter damit befasst.
Trotzdem hier die Vorgehensweise (übernommen von hier) in aller Kürze:
Damit das hochladen aus dem Python-Code funktioniert, müssen wir die chart studio Bibliothek installerien. Das machen wir wieder mit pip im Terminal (unserer PyCharm IDE): pip install chart_studio
. Dann müssen wir sie auch in unser Python Programm am Anfang importieren: import chart_studio.plotly as py
.
Im Code müssen wir auch unsere Account-Informationen (Nutzername und API-Key) übergeben, mit denen wir uns beim Chart Studio den kostenlosen (oder bezahlten) Zugang geholt haben. You’ll need your username and api key from your plotly account to connect to it from your notebook. Der API Key wird im Chart Studio durch Klicken auf den Nutzernamen im Profil / Settings erzeugt. Diese Informationen schreiben wir dann in den Code des Python-Programms:
username = '' # your username
api_key = '' # your api key - go to profile > settings > regenerate keychart_studio.tools.set_credentials_file(username=username, api_key=api_key)
Und schließlich, anstelle der Zeileplotly.offline.plot(fig, filename='plotly_BikeEvents.html')
schieben wir die erzeugte Timeline auf unseren Chart Studio Account mit dieser Zeilepy.plot(fig, filename = 'plotly_BikeEvents', auto_open=True)
Wenn das alles geklappt hat, sollte sich nach Ausführen des Python-Programms ein Webtab mit der Bikeevents-Timeline innerhalb eures Plotly Chart Studio Accounts öffnen. Und ihr könnt. dort auch direkt den Embed-Link zur Einbindung z.B. in ein Blog kopieren. Der wird vermutlich (ich habe es nicht ausprobiert), wenn ihr ihn als klassische iframe-Anweisung in euerer Seite dann im Quelltext anschaut in etwa so aussehen: //plot.ly/~irgendein-Pfad/Plotname.embed
. Ist also schön kurz und kompakt. Um die Darstellung und alles Weitere kümmert sich das Chart Studio.
Aber wir haben ja schon von unserem vorhergehenden Kapitel die komplette, offline-fähigen HTML-Ausgabe des Diagramms vorliegen. Was kann man denn damit machen? Das führt mich zur Möglichkeit Nr. 2.
Möglichkeit Nr. 2: Direktes Einbinden des vollständigen HTML-Codes
Bei vielen Webseiten oder gehosteten Blogs wird es vermutlich nicht möglich sein, ganze HTML-Abschnitte frei einzubinden. Da ich hier einen bezahlten WordPress.com Plan benutzte (der für mich und Euch diese Seite werbefrei hält und mir mehr Speicher für Medien und auch mehr Optionen in der Nutzung bietet), kann ich aus den angebotenen Design-Elementen aus dem Vollen schöpfen. Und da gibt es auch die Möglichkeit des einbindens von „Individuellem HTML“ als visuell editierbare Vorschau auf beliebigen, einzubindenden HTML Code. Da habe ich einfach einmal den gesamten HTML-Code aus der im vorhergehenden Kapitel erzeugten plotly_BikeEvents.html Datei hineinkopiert und… es funktioniert.
Warnung! Die von Plotly erzeugten HTML-Dateien sind für die Stand-Alone-Darstellung geschaffen. Sprich – sie bringen alles in sich selbst mit, um selbst lokal, ohne jeden weiteren Serverabruf, das erstellte Diagramm als Webseite darzustellen und damit zu interagieren. Alle Daten sind also drin und die komplette Engine zur Darstellung und Interaktion ist drin. Das macht solche Dateien recht umfangreich. Meine plotly_BikeEvents.html Datei ist 3,7 MByte groß. Alleine das Einfügen in den Embed-Block im WordPress.com Editor nimmt ein paar Sekunden in Anspruch (ich öffne die .html Datei mit dem sublime text editor, kopiere den gesamten Inhalt und füge in per Paste in den Embed-Block ein).
Für ein einziges solches Element pro Seite mag das gehen. Mehrere solcher Diagramme auf diese Art in eine Seite einzubinden, ist aber sicher nicht zu empfehlen. Da für jedes einzelne Diagramm der gesamte Code der Engine mehrfach geladen und mehrfach ausgeführt werden würde. Und alleine aufgrund der Menge an HTML-Code die Ladezeiten der Web- bzw. Blogseite negativ beinflusst würden.
Aber – es geht theoretisch. Vielleicht…
Diagramm-Darstellungsfläche maximieren
Für die Darstellung ein einem Blog-Artikel bietet es sich darüber hinaus an, die Ausnutzung der Bildschirmfläche durch das Diagramm zu maximieren. Da Seitenbreiten in Blogs ja gerne einmal in der Breite beschränkt sind und sich überdies auch an unterschiedliche Ausgabe-Geräte (Desktop, Tablets, Smartphones) anpassen sollen. Also weg mit zu großen Randbereichen zwischen eigentlicher Datenfläche und Diagramm-Rand. Weg mit dem y-Achsen-Titel und auch weg mit dem Diagramm-Titel.
Dazu passen wir in unserem Python-Programm den layout-Block wie folgt an:
In der Zeile zur fig-Erstellung lassen wir den Titel-Parameter ganz weg:fig = px.timeline(df, x_start=start, x_end=finish, y=events, color=category)
Und innerhalb des Statemens fig.update_layout()
lassen wir den y-Achsen-Titel nicht nur leer sondern ganz weg und geben damit den entsprechenden Platz auch wirklich frei. Und zwar über den Schalter title = None:
yaxis = dict( title= None # Maximizing screen utilisation by omitting a y-axis title
Und schlussendlich passen wir noch die Plot-Ränder über den Parameter margin
an.
Der gesamte Layout-Block sieht dann so aus:
# Layoutanpassungen
fig.update_layout(
xaxis = dict(
showgrid=True
,rangeslider_visible=False)
,yaxis = dict(
title= None # Maximizing screen utilisation by omitting a y-axis title, else title = "Event Name"
,autorange="reversed"
# ,categoryorder="category ascending" # sortiert nach der Y-Achse, die hier durch die Event-Namen gebildet wird
,categoryorder="array" # sortiert nach dem Array, das per categoryarry ausgewählt wird, umgeht so das
,categoryarray=events # Sortieren nach der gewählten Farbe
,automargin=True
,ticklen=10
,showgrid=False # False: keine horizontalen Gridlines
,showticklabels=True)
,legend=dict(
traceorder="grouped") # tjo - passiert nix, egal ob normal oder grouped
# Maximizing screen utilisation by specifying margins in px
,margin= dict(
l=10, # left
r=10, # right
t=10, # top
b=10, # bottom
),
)
Das entsprechend aktualisierte Python-Progamm führen wir aus, erhalten die Ausgabe-Datei plotly_BikeEvents.html (und sehen sie auch direkt in einem sich öffnenden Browser-Tab – können also kontrollieren, das alles passt), öffnen die Datei mit einem fähigen Text-Editor (z.B. Sublime Text), kopieren den gesamten Inhalt und fügen ihn in den entsprechenden Embed-Block in unserem WordPress-Editor ein. Fertig. In der Theorie.
In der Praxis muss ich feststellen, dass ich sich zwar im visuellen WordPress-Editor alles noch perfekt in der Vorschau präsentiert und bedienbar ist, die Einbindung aber nicht die tatsächliche Veröffentlichung überlebt und sich im publizierten Artikel leider nur noch der gesamte HTML-Code der Plotly-Diagramm-Datei findet. Unschön. Also zurück zum Zeichenbrett. Bzw. doch die 1. Möglichkeit (oder andere Wege) im Nachgang ausprobieren. Ok – das hält dann auch erst mal diesen Artikel schlanker. Sowohl vom Inhalt als auch von den Ladezeiten.
Zusammenfassung
Das waren jetzt jede Menge Möglichkeiten bzw. Werkzeuge, zur ein- und derselben angedachten Ausgabe zu gelangen: Eine interaktiv erkundbare Darstellung von (Radfahr-) Events mit ihren Start-Zeitpunkten und ihrer jeweiligen Dauer, die von einem bis mehreren Tagen reicht. Um sich möglichst schnell einen Überblick zu Überschneidungen und auch Parallel-Veranstaltungen verschaffen zu können.
Also Fragen zu beantworten: Diese Rennserie mit individuell möglichen Einzelversuchen läuft also von z.B. Mitte Juni bis Mitte August – wieviel Luft bleibt mir denn überhaupt für die Verfolgung, wenn ich mir andere interessante Events einblende, an denen ich auch teilnehmen möchte?
Ist zwischen Event A und Event B eigentlich noch genug Zeit? Was allein von deren Startzeitpunkten vielleicht erhofft werden könnte, aber bei der Darstellung der zeitlichen Dauern auf den ersten Blick erkennbar möglicherweise nicht der Fall ist.
Ich habe zwei Wochen Zeit irgendwann im August – welche möglichst langen Events bieten sich da an und passen in mein Zeitfenster?
Und – lüftet sich das Bild etwas, wenn ich mich anstelle von Road- und Offroad-Bikepacking-Events samt Einzelzeitfahren und GranFondos nur noch auf Offroad-Bikepacking-Events konzentriere (also selektiere bzw. filtere)? Möglicherweise auch auf Basis von weiteren Kriterien, wie Dauer, Streckenlänge, persönliches Ranking oder Anmeldestatus?
Dazu brauchen wir zum einen eine passende Datenbasis mit den nötigen Feldern. Das dies kein Hexenwerk ist und sich eigentlich kaum von dem normalen Zusammen-„Hacken“ einer Excel- oder Google-Sheets-Tabelle unterscheidet, sondern nur einem Hauch Struktur bedarf, zeige ich im ersten Abschnitt zu Excel und zu meiner gewählten Daten- bzw. Tabellenstruktur.
Was damit bereits dann alleine in Excel selbst möglich ist – von der Filterung und visuellen Hervorhebung einzelner Events bis zur schon fast perfekten Timeline-Darstellung in Art eines Gantt-Diagramms – zeige ich dort ebenfalls.
Das darüber hinaus Schöne: von da an sind den weiteren Auswerte- und Darstellungsmöglichkeiten mit weiteren, komplett von der Datenquelle unabhängigen Werkzeugen keine Grenzen gesetzt. Wie ich an insgesamt sieben teilweise komplett verschiedenen Methoden, Werkzeugen und ich kann sogar sagen „Anwendungsbranchen“ Schritt für Schritt zeige.
Wie fandet ihr als Stammleser bzw. als Radfahrer diesen Artikel? Vollständig interessant? Hilfreich? Oder war dann doch nur eher die Struktur der Bike-Event-Tabelle samt der Felder-Definition für euch von Interesse? Und natürlich das eigentliche Ergebnis – ein von mir möglichst umfangreich befüllter Bike-Event-Kalendar?
Lasst es mich gerne in den Kommentaren wissen. Auch, ob und welche Anpassungs-Wünsche oder Verbesserungsvorschläge ihr hinsichtlich der Struktur der Datentabelle habt. Und natürlich gerne auch, wenn ihr solche Vorschläge und weitere Tips für jedes der dargestellten Werkzeuge (Notion, Tableau, Plotly per Python usw.) habt.
Den Bike-Event-Kalendar habt ihr ja zumindest schon mal in Form der direkt im letzten Abschnitt eingebundenen interaktiven Plotly-Timeline. Und einen Start der zugrundeliegenden Datentabelle (erst mit wenigen Beispieldaten befüllt) über die bereits anfangs verlinkte und freigegebene Google-Tabelle.
Ich werde aber auch noch einen weiteren Artikel folgen lassen, welche Events für dieses aber auch für die kommenden Jahre mein Interesse gefunden haben, warum da auch Zeitfahr-Events darunter sind und welche interessanten Bike-Event-Übersichten und Kalendarien es sonst so im Internet gibt.
Und was nutze ich nun?
Wie eingangs geschrieben – dieser gesamte Artikel war quasi Mittel zu zwei Zwecken: Einerseits zu einer gefälligen und gut anwendbaren Timeline-Ansicht zu gelangen aber andererseits auch, um praktische Erfahrung in der Nutzung der diversen Möglichkeiten zu sammeln und auch Motivation für den Einstieg in die Programmiersprache Python zu finden.
Ich muss sagen, trotz meiner Vorbehalte gegenüber dem Geschäfts- und Datenmodell von Notion bin ich von dem Ergebnis und wie relativ einfach man es dort erhält überaus angetan.
Insgesamt finde ich aber die Datenvisualisierung über Plotly mit Python am vielseitigsten einsetzbar, auch was weitere Anwendungen in der Datenvisualisierung und -Analyse angeht, wenn es etwas wissenschaftlicher würde oder z.B. auch Trainingsdaten automatisch per API-Call aus z.B. Trainingspeaks, Strava oder aus bzw. auch innerhalb von Golden Cheetah geholt und analysiert werden sollen.
Tableau.public ist elegant und mächtig – für den Zweck einer Timeline-Erzeugung aber völliger Overkill.
Mit den richtigen Kniffen ist aber auch MS Excel sehr cool und letzten Endes für das lokale Arbeiten und planen mein richtiges Werkzeug.
Für die Webdarstellung als fertiges Produkt für andere sehe ich das richtige Werkzeug in Plotly.
Für die Kollaboration in kleinen Teams / im Freundeskreis: Google Sheets (und dann vielleicht Plotly) oder ggfs. auch Notion, sofern in dem Team ohnehin jeder auch für andere Zwecke Notion einsetzt.
Und damit bedanke ich mich für Euer Interesse und bin gespannt, wie sich die Zugriffe auf diesen Artikel entwickeln werden. Wie immer habe ich ihn eigentlich nur für mich geschrieben. Wenn Ihr in interessant oder gar hilfreich findet – um so besser. Ich kann mir gut vorstellen, dass er auch viele Treffer von Suchmaschinen generiert, wenn jemand ganz unabhängig vom Thema Radfahren nach Timeline-Visualisierungs-Tutorials für eine der genannten Methoden sucht. Und auch dass ist sehr willkommen – mehr noch, wenn es zu auch für mich hilfreichen und interessanten Kommentaren, Anmerkungen oder auch Korrektur-Tips führt.
Also – haut gerne in die Tasten. Entweder hier in den Kommentaren unter dem Artikel oder bei euch in Excel oder den diversen Editoren zum Nachvollziehen der Beispiele. Viel Spaß!
Hallo Torsten,
Nur keine Scham. Das Aufzeigen von verschiedenen Möglichkeiten der Visualisierung wird sicherlich vielen hilfreich sein, wobei ich jedoch denke, dass Excel für 90% (oder noch mehr) der Anwender, das Mittel der Wahl sein wird. Einfach klasse, wie tief du in eine Materie einsteigst. Ein Lob auf die Ingenieure.
„Wenn man etwas anfängt, dann soll man es auch richtig machen“, das zeigt dein Artikel in Excellence. Und ein schönes kleines Ziel um sich mit Python zu beschäftigen.
Ein Thema was mich bei dir persönlich auch brennend interessieren würde und worüber ich auch gespannt wäre zu lesen: das perfekte Bike-Storage-System.
Wie lagere ich meine Fahrräder? Welche Werkzeuge werden wie gelagert? Welche Werkzeuge werden überhaupt benötigt? Welche Teile legt man sich aufs Lager für schwere Lieferengpässe? Welche Staumöglichkeiten gibt es oder baut man sich das selbst zusammen?
Ich merke bei mir persönlich, das aus der anfänglichen Basic-Ausrüstung (die in 2-3 Schubladen passte), ein stetig wachsendes Chaos und Platzproblem entsteht, was sich zur einer langsamen Beziehungskrise entwickelt, wenn nicht gegengesteuert wird.
Ich freue mich auf jeden Fall auf weitere spannende Artikel von deinem Blog.
Viele Grüße aus Ostbelgien,
RS
Hallo RS, vielen Dank für deinen Kommentar. Und auch für den Themenvorschlag. Haha – ja, ein paar coole Ideen für Wohnungsgestaltung und Interior Design (wo sollte man seine Schätzchen sonst aufstellen? ;-)) wären sicher einen Artikel wert. Andererseits hielten mich dann viele Leser endgültig für einen hoffnungslosen Fall… 🤣 Aber als Hinweis: eine lange, fensterlose Wand und niedrige Sideboards mit Milchglasscheiben oben drauf ergeben ein tolles Rad-Display in dem man auch viel Werkzeug und Kit wie Schuhe, Helme und Co unterbekommt… ^^
viele Grüße
Torsten