Select to view content in your preferred language

Graphs and Charts

7015
36
03-31-2011 04:10 PM
NathalieNeagle
Regular Contributor
I have a simple police application that allows officers to spatial select and query some points (police calls).  I using esri FeatureDataGrid.  I wanted to create a few simple charts and graphs and send the queried data (that is in the featuredatagrid) into these grids and charts. 

Currently I'm trying to send the selected GraphicLayer
<esri:GraphicsLayer ID="MySelectionGraphicsLayer" />

here's a small snip of my code behind to select the graphiclayer
 GraphicsLayer selectionGraphicslayer = Map.Layers["MySelectionGraphicsLayer"] as GraphicsLayer;
            selectionGraphicslayer.ClearGraphics();


I'm wondering if I'm binding it right

Here's my Pie Chart




 <Grid Style="{StaticResource WrapperStyle}">
            <chartingToolkit:Chart Title="AnimationSequence = FirstToLast" Palette="{StaticResource GrowPieDataPointPalette}" Style="{StaticResource ChartStyle}" MouseLeftButtonDown="OnMouseLeftButtonDown" Margin="1,4,-1,-4">
                <chartingToolkit:Chart.Series>
                    <chartingToolkit:PieSeries ItemsSource="{Binding ElementName=Map, Path=Layers[MySelectionGraphicsLayer].Graphics}" DependentValueBinding="{Binding Attributes[DISPDESC]}" AnimationSequence="FirstToLast"/>
                 </chartingToolkit:Chart.Series>
            </chartingToolkit:Chart>
        </Grid>




My table works and here's how I'm binding that:

 <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="15" />
                                <RowDefinition Height="*" />
                            </Grid.RowDefinitions>
                            <TextBlock x:Name="DataDisplayTitle" Text="Search Results" FontSize="9" Grid.Row="0" FontWeight="Bold" FontFamily="Arial" Foreground="#FFFFFFFF" />



                            <esriWidgets:FeatureDataGrid Grid.Row="1" x:Name="QueryDetailsDataGrid" Height="170" 
                                      Map="{Binding ElementName=Map}" 
                                      GraphicsLayer="{Binding Layers[MySelectionGraphicsLayer], ElementName=Map}" />

                        </Grid>




Does it seem like I'm binding the Pie Graph correctly because now app is not completely firing and its not really working; it is only selecting or creating one graphic.  If I try to select 20 points only one gets selected and the featuredatagrid is not firing and showing up (ResultsDisplay.Visibility = Visibility.Visibility).  Everything was working before so I'm wondering/thinking it is something with my pie chart.



Thanks
Nat
0 Kudos
36 Replies
JenniferNery
Esri Regular Contributor
Your binding looks fine to me. But have you looked at this sample? http://www.silverlight.net/content/samples/sl4/toolkitcontrolsamples/run/default.html I'm not sure which Silverlight toolkit you are using but it seems you have to specify both IndependentValueBinding and DependentValueBinding properties.
0 Kudos
NathalieNeagle
Regular Contributor
Jennifer,
Thanks for the reply. 


Your binding looks fine to me. But have you looked at this sample? http://www.silverlight.net/content/s...n/default.html I'm not sure which Silverlight toolkit you are using but it seems you have to specify both IndependentValueBinding and DependentValueBinding properties.


The link you provided takes me to the main page (MS Silverlight toolkit).  I am basing my work/code straight from the Pie Chart example.  Did you want me to look at a different chart example?  For the Pie Chart they are not using  IndependentValueBinding or at least I didn't see one.  I just assumed the  IndependentValueBinding and DependentValueBinding were basically the X and Y axis for the charts so the Pie Chart only uses the Dependent and the others (Line, graph, bubbles, Bar, etc) use both variables.  Is this the wrong assumption?  Do I need to assign the  IndependentValueBinding for the PIE.  Here's the xaml straght from MS site:

 <Grid Style="{StaticResource WrapperStyle}">
                <chartingToolkit:Chart Title="AnimationSequence = FirstToLast" Palette="{StaticResource GrowPieDataPointPalette}" Style="{StaticResource ChartStyle}" MouseLeftButtonDown="OnMouseLeftButtonDown">
                    <chartingToolkit:Chart.Series>
                        <chartingToolkit:PieSeries ItemsSource="{Binding LevelsInRainfall, Source={StaticResource ParticulateLevel}}" DependentValueBinding="{Binding Particulate}" AnimationSequence="FirstToLast"/>
                    </chartingToolkit:Chart.Series>
                </chartingToolkit:Chart>
            </Grid>




Here's my code behind, which I didn't change at all.

 # region Pie Chart
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Attached to event handler in XAML.")]
        private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Chart chart = sender as Chart;

            if (null != chart)
            {
                // Toggle each Series ItemsSource so the reveal/hide animations can be seen
                foreach (DataPointSeries series in chart.Series)
                {
                    if (null == series.Tag)
                    {
                        series.Tag = series.ItemsSource;
                        series.ItemsSource = null;
                    }
                    else
                    {
                        series.ItemsSource = series.Tag as IEnumerable;
                        series.Tag = null;
                    }
                }
            }
        }

        #endregion



Here's my xaml, which I also posted in my first post but thought I would post it againg (here) for easier reading

 <Grid Style="{StaticResource WrapperStyle}">
            <chartingToolkit:Chart Title="AnimationSequence = FirstToLast" Palette="{StaticResource GrowPieDataPointPalette}" Style="{StaticResource ChartStyle}" MouseLeftButtonDown="OnMouseLeftButtonDown" Margin="1,4,-1,-4">
                <chartingToolkit:Chart.Series>
                    <chartingToolkit:PieSeries ItemsSource="{Binding ElementName=Map, Path=Layers[MySelectionGraphicsLayer].Graphics}" DependentValueBinding="{Binding Attributes[DISPDESC]}" AnimationSequence="FirstToLast"/>
                 </chartingToolkit:Chart.Series>
            </chartingToolkit:Chart>
        </Grid>


I just threw the code in my app; oh ya and I add the snippets xaml for the visual state / style under my resouces (I'll post that below).  Basically if I comment out my code behind and my xaml above (for my grid, which contains my Pie Chart) the app. runs nice and smooth.  I can select muiliple police points and my featuretablegrid is always populated and shows up visible but once I uncomment my pie chart grid and code behind the spatial select tool stops firing correctly, only one point will get select no matter how many I try to select and my featuretablegrid visibility(ResultsDisplay.IsExpanded = true) never happens.

I'm thinking of maybe it is the order of what is trying to happen.  How can I control my Pie Chart not to try and populate until after a selection has been made and after my tablegrid is finished populating?

            <Style x:Key="ChartStyle" TargetType="chartingToolkit:Chart">
                <Setter Property="Background" Value="Transparent"/>
            </Style>

        <ControlTemplate x:Key="GrowPieDataPoint" TargetType="chartingToolkit:PieDataPoint">
            <Path Data="{TemplateBinding Geometry}" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" RenderTransformOrigin="0.5,0.5">
                <Path.RenderTransform>
                    <ScaleTransform x:Name="Scale" ScaleX="0" ScaleY="0"/>
                </Path.RenderTransform>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="RevealStates">
                        <VisualStateGroup.Transitions>
                            <VisualTransition GeneratedDuration="0:0:0.5"/>
                        </VisualStateGroup.Transitions>
                        <VisualState x:Name="Shown">
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetName="Scale" Storyboard.TargetProperty="ScaleX" To="1" Duration="0"/>
                                <DoubleAnimation Storyboard.TargetName="Scale" Storyboard.TargetProperty="ScaleY" To="1" Duration="0"/>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Hidden">
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetName="Scale" Storyboard.TargetProperty="ScaleX" To="0" Duration="0"/>
                                <DoubleAnimation Storyboard.TargetName="Scale" Storyboard.TargetProperty="ScaleY" To="0" Duration="0"/>
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <ToolTipService.ToolTip>
                    <ContentControl Content="{TemplateBinding DependentValue}"/>
                </ToolTipService.ToolTip>
            </Path>
        </ControlTemplate>

     <visualizationToolkit:ResourceDictionaryCollection x:Key="GrowPieDataPointPalette">
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="Gray"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="DarkBlue"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="DarkRed"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="Yellow"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="Blue"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="Red"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="Green"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="Pink"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="chartingToolkit:PieDataPoint">
                    <Setter Property="Template" Value="{StaticResource GrowPieDataPoint}"/>
                    <Setter Property="Background" Value="Cyan"/>
                </Style>
            </ResourceDictionary>
        </visualizationToolkit:ResourceDictionaryCollection>



Sorry for the long post.

Thanks
Nathalie
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Your code looks fine to me.

From your description, something wrong happens when adding the first graphic object in the graphicslayer.

Likely the PieChart doesn't like the value of your attribute DISPDESC.
This attribute has to be numeric. Is it the case?

Also, I am not sure that it's supporting null value or string value (even if convertible to numeric). In this case you may need a converter.
0 Kudos
NathalieNeagle
Regular Contributor
Thanks Dominique,

Likely the PieChart doesn't like the value of your attribute DISPDESC.
This attribute has to be numeric. Is it the case?


THIS MUST BE MY PROBLEM!  My field is a string field and it does not have null values.

So do all the charts require the attributes to be numeric?

I looked into convertors but I'm not sure I can convert a field to numeric that has values like KTP, TS, ILPARK, 488R, W911, etc.  Sometimes there are numbers mixed in the Call Type Codes but other times they are all letters.   Can a Converter handle this?

I tried to write one based of this MS exmaple http://msdn.microsoft.com/en-us/library/d7e175yd(v=vs.95).aspx but had no luck.  I'm confused :confused:

I was just trying to get the pie chart to work because it seemed like the easiest but I would really like to do some bar and line charts; do they only accept attributes that are numeric?

Thanks
Nathalie
0 Kudos
NathalieNeagle
Regular Contributor
O.K.  I went back and check out the basic Pie charts and they are expecting IndependentValueBinding and DependentValueBinding attributes (I was trying to figure out the animation pie charts and they only had the  DependentValueBinding ).

For the Basic ones the IndependentValueBinding attribute seems like it can be a string but the DependentValueBinding attributes seems like it is always a number (int) value.  In my case I really want to set IndependentValueBinding to the Cad Call Type field and the DependentValueBinding to just count and sum the  IndependentValueBinding (Cad Call Type field).  So is there a simple way to do this like

DependentValueBinding="{Binding Attributes[TYPECODE].SUM}
or
DependentValueBinding="{Binding Attributes[TYPECODE].COUNT}

Or do I have to handle this in code behind somehow?

THanks
Nat.
0 Kudos
DominiqueBroux
Esri Frequent Contributor

So do all the charts require the attributes to be numeric?

The DependentValue must be numeric since this will define the size of the pie.

If you bind to a constant you will get the same size for all pies (e.g. you can test with {Binding Attributes.Count}).


I looked into convertors but I'm not sure I can convert a field to numeric that has values like KTP, TS, ILPARK, 488R, W911, etc.

Here, I can't help here since it's depending on the meaning of your data and how you want to represent them.
You have to write a converter taking one attribute value as input and returning the relative size of the corresponding pie.
0 Kudos
NathalieNeagle
Regular Contributor
Dominique,

VERY COOL....THANKS FOR ALL THE HELP!:)

I was hoping to ask one more simple question.  So I have it working; well sort of:eek:

The chart is populating and the site is functioning.  But if the crime code repeats (if there is more than one selected) both or all of the same crime codes get there own piece of the pie.  Also the count is always working out to 22 no matter what (if 1,2,3,4, or 5 of the same crime codes are selected) they each get a sliver of the pie and the count for each is 22.

Here's my xaml --- does it look like I'm doing the count correctly.  Counting is exactly what fits my needs for the pie chart.

<Grid Style="{StaticResource WrapperStyle}" >
            <Border BorderBrush="Black" BorderThickness="1">
                <controlsToolkit:DockPanel>
                    <visualizationToolkit:Title Content="Drill-Down" FontWeight="Bold" FontSize="14" HorizontalAlignment="Center" controlsToolkit:DockPanel.Dock="Top"/>
                    <controlsToolkit:DockPanel LastChildFill="False" controlsToolkit:DockPanel.Dock="Right">
                        <StackPanel x:Name="InformationPanel" controlsToolkit:DockPanel.Dock="Top" Margin="5">
                            <TextBlock Text="Selected Call Type Details" FontWeight="Bold"/>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="TYPE CODE: "/>
                                <TextBlock Text="{Binding  Attributes[TYPECODE]}"/>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="COUNT: "/>
                                <TextBlock Text="{Binding Attributes.Count}"/>
                            </StackPanel>
                        </StackPanel>
                        <Button Content="Unselect" Click="Unselect_Click" Margin="5" controlsToolkit:DockPanel.Dock="Bottom"/>
                    </controlsToolkit:DockPanel>
                    <chartingToolkit:Chart x:Name="DrillDownChart" BorderBrush="Gray" Margin="5">
                        <chartingToolkit:Chart.Series>
                            <chartingToolkit:PieSeries ItemsSource="{Binding ElementName=Map, Path=Layers[MySelectionGraphicsLayer].Graphics}" IndependentValueBinding="{Binding  Attributes[TYPECODE]}" DependentValueBinding="{Binding Attributes.Count}" IsSelectionEnabled="True" SelectionChanged="DrillDown_SelectionChanged"/>
                        </chartingToolkit:Chart.Series>
                    </chartingToolkit:Chart>
                </controlsToolkit:DockPanel>
            </Border>
        </Grid>



Thanks again for all the help and thanks to Jennifer too:D

Nathalie
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Hi Nathalie,

Looks like you don't need a piece of pie by graphic but by group of graphics.
In this case, the following binding can't do the trick:
ItemsSource="{Binding ElementName=Map, Path=Layers[MySelectionGraphicsLayer].Graphics}" 


You need to create by code your groups of graphics and to bind the chart to these groups.

For demo purpose, I did it starting from this sample : http://help.arcgis.com/en/webapi/silverlight/samples/start.htm#SpatialQuery.
Let's suppose that you want to show the population by region.

The steps are:

1) As it's not easy to use anonymous type in SL, you need to create a public class to store the result of your grouping :
public class AttributeGroup
{
    public string Key { get; set; }
    public int Sum { get; set; }
    public int Count { get; set; }
    public IEnumerable<Graphic> Graphics {get; set;} // only useful for graphics selection from sliver selection
}
2) You need to create an enumeration of AttributeGroup from the graphics in your layer:

At the end of QueryExecuted_Completed, add:
DataContext = graphicsLayer.Graphics.GroupBy(graphic => (string)graphic.Attributes["SUB_REGION"],
                            (subregion, graphics) => new AttributeGroup
                            {
                                Key = subregion,
                                Count = graphics.Count(),
                                Sum = graphics.Select(g => (int)g.Attributes["POP2000"]).Sum(),
                                Graphics = graphics
                            }).ToArray();

Note : a cleaner approach would have been to create a new Dependency property (or a new property with change notification) and to use it instead of the DataContext.

3) Bind the chart ItemsSource to this enum
<Grid Width="400" Height="300" HorizontalAlignment="Left" VerticalAlignment="Top">
<chartingToolkit:Chart Title="Population by Region" >
<chartingToolkit:PieSeries IsSelectionEnabled="True" SelectionChanged="PieSeries_SelectionChanged" 
                                   ItemsSource="{Binding}" 
                                   IndependentValuePath="Key"
                                   DependentValuePath="Sum" AnimationSequence="FirstToLast"/>
</chartingToolkit:Chart>
</Grid>

Note : or ItemsSource="{Binding MyGroups}" if you had created a new property called MyGroups.

4) Cherry on the pie : select the corresponding graphics when one selects a piece of pie:
private void PieSeries_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var dataPointSeries = sender as DataPointSeries;
    var attributeGroup = dataPointSeries.SelectedItem as AttributeGroup;
    if (attributeGroup == null)
        return;
 
    GraphicsLayer selectionGraphicslayer = MyMap.Layers["MySelectionGraphicsLayer"] as GraphicsLayer;
    foreach (Graphic item in selectionGraphicslayer.Graphics)
        item.Selected = false;
 
    QueryDetailsDataGrid.SelectedItem = null;
    foreach (var graphic in attributeGroup.Graphics)
    {
        QueryDetailsDataGrid.SelectedItems.Add(graphic);
        graphic.Select();
    }
}
And that's it (see attached result)


0 Kudos
NathalieNeagle
Regular Contributor
Dominique,

O.K. I can't stop giggling or more appropiately stop laughing about your play on words " Cherry on the pie" 😄


And of course strange enough those four words �??Cherry on the pie�?� have been making me laugh all day but it is this section of the code that I can�??t get working.  It is weird when I select a row (attribute in the feature grid table) and then click on the pie map it unselects my selected row but when I click on a slice of the pie it doesn�??t select the rows in the table and it doesn�??t select the features on the map. 

I basically started with the spatial select tools just like you so I think everything is the same:


My featuredatagrid is named the same

                            <esriWidgets:FeatureDataGrid Grid.Row="1" x:Name="QueryDetailsDataGrid" Height="170" 
                                      Map="{Binding ElementName=Map}" 
                                      GraphicsLayer="{Binding Layers[MySelectionGraphicsLayer], ElementName=Map}" Style="{StaticResource FeatureDataGridStyle1}" />



I think my spatial query task is basically the same I did add a little but the key elements are there:

  private void MyDrawSurface_DrawComplete(object sender, ESRI.ArcGIS.Client.DrawEventArgs args)
        {


            GraphicsLayer selectionGraphicslayer = Map.Layers["MySelectionGraphicsLayer"] as GraphicsLayer;
            selectionGraphicslayer.ClearGraphics();


            QueryTask queryTask = new QueryTask((Layers.SelectedItem as FeatureLayer).Url);
 
            queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted;
            queryTask.Failed += QueryTask_Failed;

            Query query = new ESRI.ArcGIS.Client.Tasks.Query();

            query.OutFields.Add("*");

            query.Geometry = args.Geometry;



            // Return geometry with result features
            query.ReturnGeometry = true;

            queryTask.ExecuteAsync(query);



        }

        private void QueryTask_ExecuteCompleted(object sender, ESRI.ArcGIS.Client.Tasks.QueryEventArgs args)
        {
            FeatureSet featureSet = args.FeatureSet;

            if (featureSet == null || featureSet.Features.Count < 1)
            {
                MessageBox.Show("No features retured from query");
                return;
            }

            GraphicsLayer graphicsLayer = Map.Layers["MySelectionGraphicsLayer"] as GraphicsLayer;


            if (featureSet != null && featureSet.Features.Count > 0)

               // ResultsDisplay.Visibility = Visibility.Visible;

            {
                foreach (Graphic feature in featureSet.Features)
                {

                    switch (featureSet.GeometryType.ToString())
                    {
                        case "Polygon":
                            feature.Symbol = LayoutRoot.Resources["ResultsFillSymbol"] as FillSymbol;
                            break;
                        case "Polyline":
                            feature.Symbol = LayoutRoot.Resources["CustomGrowLineSymbol"] as LineSymbol;
                            break;
                        case "Point":
                            feature.Symbol = LayoutRoot.Resources["ResultsMarkerSymbol"] as SimpleMarkerSymbol;
                            break;
                    }

                    graphicsLayer.Graphics.Insert(0, feature);

                }
                //ResultsDisplay.Visibility = Visibility.Visible;
                ResultsDisplay.IsExpanded = true;
            }
            MyDrawSurface.IsEnabled = false;






            // PIE CHART -  create an enumeration of AttributeGroup from the graphics in your layer

            DataContext = graphicsLayer.Graphics.GroupBy(graphic => (string)graphic.Attributes["TYPECODE"],
                            (typecode, graphics) => new AttributeGroup
                            {
                                Key = typecode,
                                Count = graphics.Count(),
                                Sum = graphics.Select(g => (int)g.Attributes["DOW"]).Count(),
                               //Sum = graphics.Select(g => (int)g.Attributes["DOW"]).Sum),
                                Graphics = graphics
                            }).ToArray();

            //END PIE CHART



So does it matter where I add the Cherry! lol.  I don't think it should right?  Just somewhere in the code behind?

Do you see anything that is off?


Oh ya how do you copy your code and retain the easy to read feel (the colors)  like it is still in V.S.?

Thanks again

Nathalie "Cherry Bomb" Neagle --- just kinding:o
0 Kudos