views:

497

answers:

4

I created a custom color palette for my charts using a technique described on TechNet.

I also have a series of drill-through column charts, where you click on one column and it passes a parameter through to the next chart and so on, giving the appearance of drill-down.

My graphs consist of 3 types of labor, and have three colors on the main chart. When I drill down to the next chart, some of the categories do not have all three types of labor that the main one has. So the first color in the palette is assigned to the series, even though it was the second color on the previous chart. I'd like to avoid this, if possible.

So a data value is green on the first chart (2nd in the color order) and yellow on the next chart (1st in the color order). How do I make the graphs "remember" the total number of series groups that were in the first chart?

This is Reporting Services 2005.

A: 

Unfortunately this is not possible. I've been looking for this for quite some time...

JonH
Your comment makes me very sad. Surely there's gotta be a way with custom code...
Nathan DeWitt
If you find it let me know...I've had to do this in the past and was unable to find any solution.
JonH
I'll let you know if I do.
Nathan DeWitt
JonH - See my answer for my solution. It works!
Nathan DeWitt
A: 

You cannot fix this using custom colour palettes.

What you can do is assign the labour type a colour in the database (using HEX is easiest). Then pass that in in your data set. Then set the color property to you hex value.

jimconstable
ugh. (15 characters)
Nathan DeWitt
Sure. It is not the prettiest, but I don't see how you plan to do this without finding a way to assign a colour to a labour type.
jimconstable
And you have to assign it before it gets to any subreports.
jimconstable
jimconstable, I found a solution using custom code.
Nathan DeWitt
A: 

I was able to solve this because I was using a custom color palette, implemented as a hash table. I basically serialized this information and passed it to a hidden parameter on the subreport and then reinflated the data structure.

It's not perfect, but it works for now.

' Define some globals, including the color palette '
Private colorPalette As String() = _
    {"#FFF8A3", "#A9CC8F", "#B2C8D9", "#BEA37A", "#F3AA79", "#B5B5A9", "#E6A5A4", _
     "#F8D753", "#5C9746", "#3E75A7", "#7A653E", "#E1662A", "#74796F", "#C4384F", _
     "#F0B400", "#1E6C0B", "#00488C", "#332600", "#D84000", "#434C43", "#B30023"}
     ' color palette pulled from SAP guidelines '
     ' http://www.sapdesignguild.org/resources/diagram_guidelines/color_palettes.html '
Private count As Integer = 0
Private colorMapping As New System.Collections.Hashtable()
' Create a custom color palette '
Public Function GetColor(ByVal groupingValue As String) As String
    If colorMapping.ContainsKey(groupingValue) Then
        Return colorMapping(groupingValue)
    End If
    Dim c As String = colorPalette(count Mod colorPalette.Length)
    count = count + 1
    colorMapping.Add(groupingValue, c)
    Return c
End Function

' In custom actions of the data value, set the results of this '
' function to the mapping parameter in the next report '
Public Function PassColorMapping() As String
    If colorMapping.Count = 0 Then
        Return Nothing
    End If
    Try
        ' convert the hashtable to an array so it can be serialized '
        Dim objHash As Object()() = ToJaggedArray(colorMapping)

        ' serialize the colorMapping variable '
        Dim outStream As New System.IO.StringWriter()
        Dim s As New System.Xml.Serialization.XmlSerializer(GetType(Object()()))
        s.Serialize(outStream, objHash)

        ' move on to the next report '
        Return outStream.ToString()
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
End Function

I ran into an issue where I couldn't find the equivalent of the onLoad event for the report. Since I wasn't sure where to put this inflate code, I stuck it in the background color of the plot area. Hence I always return "WhiteSmoke". I'll change this if I can find the right place to put it.

' Call this function when the report loads to get the series groups '
' that have already been loaded into the custom color palette '
' Pass in the parameter used to store the color mapping '
Public Function InflateParamMapping(ByVal paramMapping As Parameter) As String
    Try
        If paramMapping.Value Is Nothing Then
            Return "WhiteSmoke"
        ElseIf colorMapping.Count = 0 Then      
            Dim pXmlized As String = paramMapping.Value
            ' deserialize the mapping parameter '
            Dim s As New System.Xml.Serialization.XmlSerializer(GetType(Object()()))

            ' get the jagged array and convert to hashtable '
            Dim objHash As Object()() = DirectCast(s.Deserialize(New System.IO.StringReader(pXmlized)), Object()())
            ' stick the result in the global colorMapping hashtable '
            colorMapping = ToHashTable(objHash)
            count = colorMapping.Count
        End If
    Catch ex As Exception
'       MsgBox(ex.Message) '
    End Try
    Return "WhiteSmoke"
End Function

ToJaggedArray() and ToHashTable() are helper functions because a HashTable is not serializable since they implement an IDictionary. I was in a hurry so I just converted them to an array right quick. Code comes from the Collection Serialization in ASP.NET Web Services article written by Mark Richman. I converted the code from C# to VB.NET to use in the report.

Public Function ToJaggedArray(ByVal ht As System.Collections.HashTable) As Object()()
    Dim oo As Object()() = New Object(ht.Count - 1)() {}
    Dim i As Integer = 0
    For EAch key As Object in ht.Keys
        oo(i) = New Object() {key, ht(key)}
        i += 1
    Next
    Return oo
End Function

Public Function ToHashTable(ByVal oo As Object()()) As System.Collections.HashTable
    Dim ht As New System.Collections.HashTable(oo.Length)
    For Each pair As Object() In oo
        Dim key As Object = pair(0)
        Dim value As Object = pair(1)
        ht(key) = value
    Next
    Return ht
End Function

Now in the report itself you need to do a couple things.

  • Add a reference to System.Xml in Report Properties in both reports.
  • In the Actions of your parent report, set the Parameter containing your data structure to =Code.PassColorMapping()
  • In the Plot Area section of your report, put this expression for the background: =Code.InflateParamMapping(Parameters!colorMapping)
  • And of course, in the Fill for your data Series Style on both charts put this expression: =Code.GetColor(Fields!Type.Value)

You can continue doing this for as many subreports as you want - I currently have 3 levels of drill-through and it works fine.

Nathan DeWitt
let me just say. ugh :)
jimconstable
ok, I deserved that. Thinking about it now, I suppose I could have just stored the series order in the database, and used that number to look up the color.This definitely still needs to be cleaned up, of course. But is was nice to not touch my database schema and my queries.
Nathan DeWitt
A: 

I solved that extremely easy.

In my parent report I have lets say 12 series fields, each one getting their own color in a chart, on my child report I just keep all series on the chart, for instance going from a column chart to a line chart using drill down, but I control the visibility of them...

So in the child report in Series Properties -> Visibility I just add an expression: =(Fields!ContentType.Value <> Parameters!ContentType.Value)

This way the report only keeps the visibility of the clicked value and hides all the others and the colors remains the same :)

Janus007