Select to view content in your preferred language

Graphs and Charts

7017
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
NathalieNeagle
Regular Contributor
Dominique,

Thanks so much for tending to all my needs; I really owe you...UC 2011 Beers;)


So I'm having a little trouble with everything it seems.  As far as the two new dependency properties
dbroux;97173 wrote:
In your control (or your view model), you have to create two dependency properties (or 2 properties) of type IEnumerable<AttributeGroup>.

QUOTE]

Not really sure if this is correct but after reading the Dependency Properties Overview
on the msdn over and over again this is what I came up with...Sorry I'm learning and hacking my way through
  public class AttributeGroup
        {
            public static DependencyProperty PieGraphListProperty = DependencyProperty.Register(
                "PieGraphList", 
                typeof(IEnumerable<object>),
                typeof(AttributeGroup),
                 null); 
        
            public class PieGraphList
            {
                public string Key { get; set; }
                public int Key2 { get; set; }
                public int Sum { get; set; }
                public int Count { get; set; }
                public DateTime GISDATE { get; set; }
                public int GISDOW { get; set; }
                public int GISTIME { get; set; }
                public int RESPONSETIME { get; set; }
                public IEnumerable<Graphic> Graphics { get; set; } // only useful for graphics selection from sliver selection
            
            }


             public static DependencyProperty LineGraphListProperty = DependencyProperty.Register(
                "LineGraphList", 
                typeof(IEnumerable<object>),
                typeof(AttributeGroup),
                 null); 

            public class LineGraphList
            {
                public string Key { get; set; }
                public int Key2 { get; set; }
                public int Sum { get; set; }
                public int Count { get; set; }
                public DateTime GISDATE { get; set; }
                public int GISDOW { get; set; }
                public int GISTIME { get; set; }
                public int RESPONSETIME { get; set; }
                public IEnumerable<Graphic> Graphics { get; set; } // only useful for graphics selection from sliver selection
            
            }
        
        
        }




I really can't figure this one out and I don't know what I should do when you say:
You initialize the first one with the group by TYPECODE, the second one with the group by CALL (instead of initializing the datacontext).



I'm initializing the datacontext at the end of the spatial select complete (private void QueryTask_ExecuteCompleted)

Here's that code...I can't seem to not use datacontext:


 //LINE CHART
             DataContext = graphicsLayer.Graphics.GroupBy(graphic => (int)graphic.Attributes["CALL"],
                            (call, graphics) => new AttributeGroup.LineGraphList
                            {
                              
                               Key2 = call, 
// GISDATE = DateTime.ParseExact(gisdate.ToString(), "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture),
                               
                               Count = graphics.Count(),
                             //  Sum = graphics.Select(g => (int)g.Attributes["DOW"]).Sum(),
                            
                                Graphics = graphics
                            }).ToArray();

          //END LINE CHART

             // 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.PieGraphList
                             {
                                 Key = typecode,

                                 Count = graphics.Count(),
                                 Sum = graphics.Select(g => (int)g.Attributes["DOW"]).Sum(),
                                 Graphics = graphics

                             }).ToArray();

            //END PIE CHART




Then in XAML you bind the ItemsSource of yours charts to these properties (instead of ItemsSource="{Binding}").


I haven't tried to switch the binding because I can't seem to shake the DataContext


Note : you don't need the new Key2 property, you can use the same Key property for both groups of graphics.

I think I know what you are saying here but for now I'm still using the Key2 but I will lose it soon.



So since I created or tried to create the two dependency (PieGraphList and LineGraphList) I had to change some of my code where it use to be AttributeGroup now it is AttributeGroup.PieGraphList or AttributeGroup.LineGraphList
Like in my Selection_Change Line

     
  private void LineSeries_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var dataPointSeries = sender as DataPointSeries;
            var attributeGroup = dataPointSeries.SelectedItem as AttributeGroup.LineGraphList;
            if (attributeGroup == null)
                return;

            GraphicsLayer selectionGraphicslayer = Map.Layers["MySelectionGraphicsLayer"] as GraphicsLayer;
            foreach (Graphic item in selectionGraphicslayer.Graphics)
                item.Selected = false;

            foreach (var graphic in attributeGroup.Graphics)
            {
                graphic.Select();
            }
        }


Thanks again for all the time and help
Nathalie.
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Hi Nathalie,

As it's easier with a sample than explaining, I updated the sample to display 2 charts, one pie chart with the population 2007 grouped by region and one column serie with the population 2007 grouped by the first letter of the state name.

The steps are these:
1) create 2 DP (one by chart) of type IEnumerable<AttributeGroup> in the user control
 
        public IEnumerable<AttributeGroup> Groups1
        {
            get { return (IEnumerable<AttributeGroup>)GetValue(Groups1Property); }
            set { SetValue(Groups1Property, value); }
        }
        // Using a DependencyProperty as the backing store for Groups1.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Groups1Property =
            DependencyProperty.Register("Groups1", typeof(IEnumerable<AttributeGroup>), typeof(SpatialQuery), null);
        public IEnumerable<AttributeGroup> Groups2
        {
            get { return (IEnumerable<AttributeGroup>)GetValue(Groups2Property); }
            set { SetValue(Groups2Property, value); }
        }
        // Using a DependencyProperty as the backing store for Groups2.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Groups2Property =
            DependencyProperty.Register("Groups2", typeof(IEnumerable<AttributeGroup>), typeof(SpatialQuery), null);
 
 


2) Initialize these DP when the graphics are known:
             // Group by sub region
            Groups1  = graphicsLayer.Graphics.GroupBy(graphic => (string)graphic.Attributes["SUB_REGION"],
                            (key, graphics) => new AttributeGroup
                            {
                                Key      = key,
                                Count    = graphics.Count(),
                                Sum      = graphics.Select(g => (int)g.Attributes["POP2000"]).Sum(),
                                Graphics = graphics
                            }).ToArray();
            // Group by first letter of the state name
            Groups2 = graphicsLayer.Graphics.GroupBy(graphic => ((string)graphic.Attributes["STATE_NAME"]).FirstOrDefault().ToString(),
                            (key, graphics) => new AttributeGroup
                            {
                                Key = key,
                                Count = graphics.Count(),
                                Sum = graphics.Select(g => (int)g.Attributes["POP2007"]).Sum(),
                                Graphics = graphics
                            }).OrderBy(group => group.Key).ToArray();


3) Give a name to the user control
<UserControl x:Name="MyUserControl"


4) Bind the ItemsSource of the charts to the DPs of that user control

<        <StackPanel x:Name="ChartDisplay" Visibility="Collapsed">
          <Grid Width="400" Height="300" HorizontalAlignment="Left" VerticalAlignment="Top" >
              <chartingToolkit:Chart Title="Population 2000 by Region" BorderBrush="Transparent">
                  <chartingToolkit:PieSeries IsSelectionEnabled="True" SelectionChanged="ChartSeries_SelectionChanged" 
ItemsSource="{Binding Groups1, ElementName=MyUserControl}" 
                                              IndependentValuePath="Key"
                                              DependentValuePath="Sum" AnimationSequence="FirstToLast"/>
              </chartingToolkit:Chart>
          </Grid>
          <Grid Width="400" Height="300" HorizontalAlignment="Left" VerticalAlignment="Top">
              <chartingToolkit:Chart Title="Population 2007" BorderBrush="Transparent">
                  <chartingToolkit:ColumnSeries  Title="State First Letter" IsSelectionEnabled="True" SelectionChanged="ChartSeries_SelectionChanged" 
ItemsSource="{Binding Groups2, ElementName=MyUserControl}" 
                                              IndependentValuePath="Key"
                                              DependentValuePath="Sum" AnimationSequence="FirstToLast"/>
              </chartingToolkit:Chart>
          </Grid>
      </StackPanel>

I attached the code and the result to this post.

Looking forward to drinking that beer:)
0 Kudos
NathalieNeagle
Regular Contributor
Dominique,

Thank You!  The conference and Beer are right around the corner...see you there!

Nathalie
0 Kudos
FabienNAPPA
Regular Contributor
Hello,

I would like to use this code but I don't know how to display in another datagrid all the information of MySelectionGraphicsLayer when I select.

Could you help me please ?

Thank you very much,
Fabien (fr)
0 Kudos
NathalieNeagle
Regular Contributor
Hello,

I would like to use this code but I don't know how to display in another datagrid all the information of MySelectionGraphicsLayer when I select.

Could you help me please ?

Thank you very much,
Fabien (fr)


Fabien,
I just noticed you posted and wanted the code are you still in need of help?

Nathalie
0 Kudos
AbdulrahmanTaher
Emerging Contributor
:)Thank you very very much for both Nathalie and Dominique. It's great  topic.
And i was wondered if i can show the chart at the same place of the selected polygon .

Another, if you can explain this object:

DataContext = graphicsLayer.Graphics.GroupBy(graphic => (string)graphic.Attributes["NAME"],
                            (subregion, graphics) => new AttributeGroup
                            {
                                Key = subregion,
                                Count = graphics.Count(),
                                Sum = graphics.Select(g => (int)g.Attributes["ELEVATION"]).Sum(),
                                Graphics = graphics
                            }).ToArray();
0 Kudos
DominiqueBroux
Esri Frequent Contributor
:)Thank you very very much for both Nathalie and Dominique. It's great topic.
And i was wondered if i can show the chart at the same place of the selected polygon .


If you need one chart by polygon we might look at that sample that may be closer of your need.

Here we display only one chart showing all graphics or group of graphics in the same chart.
I am not sure it makes sense that this chart overrides the selected graphics.
But anyway it could be done by setting the position of the chart by code instead of using a fixed position (to do each time the selection changes).


Another, if you can explain this object:

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


NAME being an unique identifier, a group by NAME is not the best sample since it's just returning the complete list of graphics.

The initial sample was:

// Group by sub region
            Groups1  = graphicsLayer.Graphics.GroupBy(graphic => (string)graphic.Attributes["SUB_REGION"],
                            (key, graphics) => new AttributeGroup
                            {
                                Key      = key,
                                Count    = graphics.Count(),
                                Sum      = graphics.Select(g => (int)g.Attributes["POP2000"]).Sum(),
                                Graphics = graphics
                            }).ToArray();


Here we group the graphics by SUB_REGION (by using the keySelector : (string)graphic.Attributes["SUB_REGION"])
and for each SUB_REGION we return an AttributeGroup containing mainly the SubRegion (Key) and the population of the subregion (Sum).
This list of AttributGroup is used as ItemsSource for the chart with the SubRegion as independent value and the population as dependent value. So we get a chart showing the population by subregion.

Hope this helps.
0 Kudos