Custom Code

Bereits vor einiger Zeit habe ich dieses Whitepaper von Devin Knight (Pragmatic Works) gefunden. Hier wird an einem einfachen Beispiel die Verwendung von Custom Code für Reports erklärt.

Die dort präsentierte Lösung ist sehr interessant, wenn man z. B. die Farben einiger Objekte immer nach festen Regeln vergeben will. Der Custom Code ist unabhängig von den Bezeichnungen in einem Dataset und kann einfach kopiert und mehrfach eingesetzt werden. Die Informationen in der Online-Doku sind eher spärlich und allgemeiner Natur. Was kann man in der Praxis aber noch so damit anstellen?

Heatmap

Bei der weiteren Suche bin ich dann auch auf ein Beispiel gestoßen, welches die Darstellung noch wesentlich dynamischer macht und habe dann mein Beispiel zur Heatmap daraus generiert.

Das Original stammt von Paul Turley, einem SQL Server MVP, der sich überwiegend mit Reporting beschäftigt.

Interessant fand ich an diesem Beispiel, die dynamische Anpassung der Farbverteilung an den Wertebereich. Wir haben (wie viele andere auch) einige Prozesse laufen, die eigentlich immer gleich sind. Muster oder Auffälligkeiten sind anhand der Zahlen nicht so einfach zu erkennen. Daher kam mir die Idee, falls man nun diese Farbverteilung gleichzeitig mit einer zeitlichen Komponente kombinieren würde, sollte ja eigentlich ein ziemlich eintöniges Muster entstehen. Lediglich die Ausreisser in diesem Prozess (nach oben oder unten) würden durch ihre Farbgebung herausfallen. Wenn man nun auch noch zwei eigentlich korrelierende Größen nebeneinander stellt, die demzufolge das gleiche Muster erzeugen sollten, würde man ausserdem die Abweichungen zwischen diesen beiden Mustern sehen.

Konkret ging es bei mir um die Anzahl von Datensätzen, die ich von einer Maschine auf eine andere transferiere und die Dauer für diesen Transfer. Unter der Vorraussetzung, dass die Menge der Sätze mit den Wochentagen in Verbindung steht, stelle ich nun diese Daten pro Kalenderwochen da. Anbei das Bild, war nur wenige Zahlen aufweist aber trotzdem schwierig in der Interpretation ist.

Erweitern wir nun den Report um die Farbgebung für beide einzelnen Komponenten (Anzahl und Dauer), so tritt plötzlich ein Muster zutage, welches eindeutig von den Wochentagen bestimmt wird.

Gleichzeitig fällt auf, dass es an einigen Tagen deutliche Ausreisser hinsichtlich der Dauer gegeben hat, was durch das isolierte Feld mit der hellgrünen Farbe sofort ins Auge fällt.
Damit sind wir auch wieder bei dem Thema von gestern die "Menschliche Wahrnehmung" und das Hervorspringen von Informationen: Ein "Hervorspringen" erfolgt, wenn das Zielobjekt eine Eigenschaft besitzt, die kein anderes ablenkendes Objekt besitzt.

Hier gilt auch die Einschränkung auf "kein anderes ablenkendes Objekt", denn in unmittelbarer Nähe zu der Auffälligkeit haben wir ja keine weiteren Ausreisser. Ansonsten wären ja diese großen Zahlen auch keine Auffälligkeiten mehr, sondern die Regel.

Was fällt noch auf? Die Zahlen für die Dauer haben eine andere Farbverteilung, als für die Anzahl. Das spricht dafür, dass diese beiden Größen nicht unmittelbar voneinander abhängig sind, sondern eine dritte Größe (Auslastung des Netzwerks) und ggf. zwei weitere Größen (Auslastung der beiden Maschinen) eine Rolle spielen können. Interessant ist auch, dass nach dem Ausreisser für die Dauer am Sonntag auch noch direkt einer am Montag folgte.

Implementierung

Für den Custom Code ist leider kein vernünftiger Editor vorgesehen und auch der Zugang zu der Stelle, wo man ihn hinterlegen kann, ist gut versteckt. Man klickt dafür einfach in der Entwurfsansicht mit der rechten Maustaste in den Bereich neben dem weißen Blatt und wählt "Berichtseigenschaften" aus.

Der eigentliche Code wird dann in diesem sparsam ausgestatteten Fenster untergebracht. In diesem Beispiel ist es der Code von Devin Knight aus dem Whitepaper:

Source Code Heatmap

Hier ist der Source-Code, den ich noch leicht modifiziert habe, da ich bei NULL-Werten immer Fehlermeldungen im BIDS erhalten habe:

‘***********************************************************************
‘ Calculate background color for a heatmap report
‘ Returns variations of red and green with pure red returned for the
‘ lowest value and pure green returned for the highest value
‘ Paul Turley, Oct 9, 2011
‘ Modified by Christoph Muthmann, Sep 15, 2012
‘***********************************************************************
Private LowVal As Decimal, HighVal As Decimal

Function SetHeatMapRange(LowValue As Decimal, HighValue As Decimal) As Object
  
LowVal = LowValue
   HighVal
= HighValue
End
Function

Function
HeatMapColor(ThisValue As Decimal) As String
   Dim
OutR As Byte, OutG As Byte, OutB As Byte
   Dim
dOutR As Decimal, dOutG As Decimal
   OutB
= 0
   dOutR
= 255 - ( ( (ThisValue - LowVal) / (HighVal - LowVal) ) * 255)
  
dOutG = 255 * ( ( (ThisValue - LowVal) / (HighVal - LowVal) ) )
  
If dOutR > 255 Or dOutG > 255 Then
      
OutR = 255
       OutB
= 255
       OutG
= 255
  
Else
      
OutR = dOutR
       OutG
= dOutG
  
End If

  
HeatMapColor = "#" & Right("0" & Hex(OutR), 2) & Right("0" & Hex(OutG), 2) & Right("0" & Hex(OutB), 2)
End Function

Arbeiten im Report

Hier ist vorab eine Textbox notwendig, die einen Ausdruck enthält. In diesem Ausdruck geben wir den Minimalwert und Maximalwert unseres Datasets an die Funktion. Dort werden diese beiden Werte für die späteren Berechnungen in Variablen abgelegt. Zu beachten ist, die Anordnung dieser Textbox, die auf jeden Fall vor den eigentlichen Daten stehen muss, damit diese auch zuerst gerendert wird.

=Code.SetHeatMapRange(Min(Fields!Anzahl.Value, "DataSet1"),Max(Fields!Anzahl.Value, "DataSet1"))

Der zweite Teil ist die Angabe der Farbe (BackgroundColor) in den einzelnen Zellen der Tabelle als benutzerdefinierter Code:

=Code.HeatMapColor(Fields!Anzahl.Value)

Ausgehend vom Minimal- und Maximalwert erhält jetzt jede Zelle ihre entsprechende Farbgebung. Damit dies auch mit zwei Spalten möglich ist, ist der Code entsprechend zu duplizieren und mit alternativen Namen (z. B. LowVal2, HighVal2) zu versehen.