Texas and Indiana Shapes disappear after a data refresh on Heat Map

3 posts, 0 answers
  1. Michael
    Michael avatar
    8 posts
    Member since:
    Apr 2011

    Posted 09 Jun 2011 Link to this post

    We have a heat map that has two Information Layers, one that is bound to the world map and another that is bound to the United States map.  We currently default to displaying the United States map and pull down an initial data set that contains sales figures and set up a custom color mapping with that bound data.  We're currently experiencing a bug that after we pull down that initial data set if we pull down another set of data with slightly different figures Texas and Indiana disappear from the map.  

    I'm hoping that there is just something minor that I may be doing wrong that is causing this.  It's weird because depending on the data set that is returned (via the query that populates the data set) it will not always disappear.  Also, Indiana doesn't always disappear, but Texas is that one that we can get to disappear on us a lot.  The following code is contained inside it's own user control with the data source being set on the containing page. 

    Here is the XAML:
    <UserControl x:Class="SilverlightApplication2.Blargh"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
     
        <UserControl.Resources>
            <ShapefileViewModel x:Key="DataContext" Region="world" />
            <ShapefileViewModel x:Key="DataContextUSA" Region="USA/usa_states" />
        </UserControl.Resources>
     
        <Grid x:Name="LayoutRoot" Background="White" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <Grid.Resources>
                <telerik:ExtendedDataConverter x:Key="ExtendedDataConverter" />
     
                <DataTemplate x:Key="CustomToolTipDataTemplate">
                    <StackPanel Margin="10,5">
                        <TextBlock FontWeight="Bold" Text="{Binding Converter={StaticResource ExtendedDataConverter}, ConverterParameter='CNTRY_NAME'}" />
                        <TextBlock Text="{Binding Converter={StaticResource ExtendedDataConverter}, ConverterParameter='sales', StringFormat='Sales: ${0:#,#0.00}'}" />
                    </StackPanel>
                </DataTemplate>
                <DataTemplate x:Key="CustomStateToolTipDataTemplate">
                    <StackPanel Margin="10,5">
                        <TextBlock FontWeight="Bold" Text="{Binding Converter={StaticResource ExtendedDataConverter}, ConverterParameter='STATE_NAME'}" />
                        <TextBlock Text="{Binding Converter={StaticResource ExtendedDataConverter}, ConverterParameter='sales', StringFormat='Sales: ${0:#,#0.00}'}" />
                    </StackPanel>
                </DataTemplate>
            </Grid.Resources>
     
            <telerik:RadMap x:Name="RadMap1" Background="#374F5D" BorderBrush="Transparent" BorderThickness="0" UseDefaultLayout="False" MouseClickMode="None" MouseDoubleClickMode="None" ZoomLevel="1" MinZoomLevel="1"  MaxZoomLevel="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <telerik:RadMap.Provider>
                    <telerik:EmptyProvider />
                </telerik:RadMap.Provider>
                <telerik:InformationLayer x:Name="InformationLayer">
                    <telerik:InformationLayer.Reader>
                        <telerik:MapShapeReader Source="{Binding Source={StaticResource DataContext}, Path=ShapefileSourceUri}"
                                                DataSource="{Binding Source={StaticResource DataContext}, Path=ShapefileDataSourceUri}"
                                                ToolTipTemplate="{StaticResource CustomToolTipDataTemplate}" />
                    </telerik:InformationLayer.Reader>
                    <telerik:InformationLayer.Colorizer>
                        <telerik:ColorMeasureScale x:Name="CountryColorScale" ExtendedPropertyName="total_sales" Mode="Count" TickMarkCount="6">
                            <telerik:ColorMeasureScale.ShapeFillCollection>
                                <telerik:MapShapeFill Fill="#FFFFFF" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#CDCFFD" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#888DF2" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#5159E2" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#2E35C6" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#0B1074" Stroke="#1F287A" StrokeThickness="1" />
                            </telerik:ColorMeasureScale.ShapeFillCollection>
                            <telerik:ColorMeasureScale.HighlightFillCollection>
                                <telerik:MapShapeFill Fill="#FFEEA6" Stroke="#1F287A" StrokeThickness="1" />
                            </telerik:ColorMeasureScale.HighlightFillCollection>
                        </telerik:ColorMeasureScale>
                    </telerik:InformationLayer.Colorizer>
                    <telerik:InformationLayer.ShapeFill>
                        <telerik:MapShapeFill Fill="#FFF7DE" Stroke="#5A636B" StrokeThickness="1" />
                    </telerik:InformationLayer.ShapeFill>
                    <telerik:InformationLayer.HighlightFill>
                        <telerik:MapShapeFill Fill="#F7E7BD" Stroke="#5A636B" StrokeThickness="1" />
                    </telerik:InformationLayer.HighlightFill>
                </telerik:InformationLayer>
                <telerik:InformationLayer x:Name="StateLayer" Visibility="Collapsed">
                    <telerik:InformationLayer.Reader>
                        <telerik:MapShapeReader Source="{Binding Source={StaticResource DataContextUSA}, Path=ShapefileSourceUri}"
                                                DataSource="{Binding Source={StaticResource DataContextUSA}, Path=ShapefileDataSourceUri}"
                                                ToolTipTemplate="{StaticResource CustomStateToolTipDataTemplate}" />
                    </telerik:InformationLayer.Reader>
                    <telerik:InformationLayer.Colorizer>
                        <telerik:ColorMeasureScale x:Name="StateColorScale" ExtendedPropertyName="total_sales" Mode="Count" TickMarkCount="6">
                            <telerik:ColorMeasureScale.ShapeFillCollection>
                                <telerik:MapShapeFill Fill="#FFFFFF" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#CDCFFD" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#888DF2" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#5159E2" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#2E35C6" Stroke="#1F287A" StrokeThickness="1" />
                                <telerik:MapShapeFill Fill="#0B1074" Stroke="#1F287A" StrokeThickness="1" />
                            </telerik:ColorMeasureScale.ShapeFillCollection>
                            <telerik:ColorMeasureScale.HighlightFillCollection>
                                <telerik:MapShapeFill Fill="#FFEEA6" Stroke="#1F287A" StrokeThickness="1" />
                            </telerik:ColorMeasureScale.HighlightFillCollection>
                        </telerik:ColorMeasureScale>
                    </telerik:InformationLayer.Colorizer>
                    <telerik:InformationLayer.ShapeFill>
                        <telerik:MapShapeFill Fill="#FFF7DE" Stroke="#5A636B" StrokeThickness="1" />
                    </telerik:InformationLayer.ShapeFill>
                    <telerik:InformationLayer.HighlightFill>
                        <telerik:MapShapeFill Fill="#F7E7BD" Stroke="#5A636B" StrokeThickness="1" />
                    </telerik:InformationLayer.HighlightFill>
                </telerik:InformationLayer>
            </telerik:RadMap>
     
            <telerik:MapLegend x:Name="InformationLayerLegend" MarkerSize="40,20"
                                VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="0,0,10,10"
                                Format="{}{0:0,,.00}" LabelLayout="Center"
                                Layer="{Binding ElementName=InformationLayer}">
                <telerik:MapLegend.Header>
                    <TextBlock Margin="10,0,0,0">
                        <Run FontSize="16" FontWeight="ExtraBlack">Sales</Run>
                        <Run FontSize="14">(in millions)</Run>
                    </TextBlock>
                </telerik:MapLegend.Header>
            </telerik:MapLegend>
            <telerik:MapLegend x:Name="StateLayerLegend" MarkerSize="40,20" Visibility="Collapsed"
                                VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="0,0,10,10"
                                Format="{}{0:0,,.00}" LabelLayout="Center"
                                Layer="{Binding ElementName=StateLayer}">
                <telerik:MapLegend.Header>
                    <TextBlock Margin="10,0,0,0">
                        <Run FontSize="16" FontWeight="ExtraBlack">Sales</Run>
                        <Run FontSize="14">(in millions)</Run>
                    </TextBlock>
                </telerik:MapLegend.Header>
            </telerik:MapLegend>
        </Grid>
    </UserControl>

    Then we have the C#:
    using Telerik.Windows.Controls.Map;
     
    namespace SilverlightApplication2
    {
        public partial class Blargh : UserControl
        {
            private bool initialized;
            private const string SalesDataField = "sales";
     
            public Blargh()
            {
                InitializeComponent();
                RadMap1.InitializeCompleted += new EventHandler(RadMap1_InitializeCompleted);
            }
     
            public DependencyProperty RegionProperty = DependencyProperty.Register("Region", typeof(string), typeof(Blargh), new PropertyMetadata("All", new PropertyChangedCallback(OnRegionPropertyChanged)));
     
            private static void OnRegionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var current = d as Blargh;
     
                if (current.Region == "All")
                {
                    current.InformationLayer.Visibility = Visibility.Visible;
                    current.InformationLayerLegend.Visibility = Visibility.Visible;
                    current.StateLayer.Visibility = Visibility.Collapsed;
                    current.StateLayerLegend.Visibility = Visibility.Collapsed;
                    current.SetZoom();
                    current.RadMap1.Center = new Location(38.138254674708641, 24.156992308937237);
                }
                else if (current.Region == "USA")
                {
                    current.InformationLayer.Visibility = Visibility.Collapsed;
                    current.InformationLayerLegend.Visibility = Visibility.Collapsed;
                    current.StateLayer.Visibility = Visibility.Visible;
                    current.StateLayerLegend.Visibility = Visibility.Visible;
                    current.SetZoom();
                    current.RadMap1.Center = new Location(38.138254674708683, -95.374257691063036);
                }
            }
     
            public string Region
            {
                get { return (string)GetValue(RegionProperty); }
                set { SetValue(RegionProperty, value); }
            }
     
            private ObservableCollection<Sales> _DataSource = new ObservableCollection<Sales>();
     
            public ObservableCollection<Sales> DataSource
            {
                get { return _DataSource; }
                set
                {
                    _DataSource = value;
                    InformationLayer.Reader.Read();
                    StateLayer.Reader.Read();
                }
            }
     
            void RadMap1_InitializeCompleted(object sender, EventArgs e)
            {
                if (!this.initialized)
                {
                    this.initialized = true;
     
                    if (InformationLayer.Reader.ExtendedPropertySet == null)
                        InformationLayer.Reader.ExtendedPropertySet = new ExtendedPropertySet();
     
                    if (InformationLayer.Reader.ExtendedPropertySet != null)
                    {
                        ExtendedPropertySet propertySet = InformationLayer.Reader.ExtendedPropertySet;
                        propertySet.RegisterProperty("CNTRY_NAME", string.Empty, typeof(string), string.Empty);
                        propertySet.RegisterProperty(SalesDataField, string.Empty, typeof(decimal), (decimal)0);
                    }
                    this.InformationLayer.Reader.PreviewReadCompleted += new PreviewReadShapesCompletedEventHandler(CountryReader_PreviewReadCompleted);
                    this.InformationLayer.Reader.ReadCompleted += new ReadShapesCompletedEventHandler(CountryReader_ReadCompleted);
     
                    if (StateLayer.Reader.ExtendedPropertySet == null)
                        StateLayer.Reader.ExtendedPropertySet = new ExtendedPropertySet();
     
                    if (StateLayer.Reader.ExtendedPropertySet != null)
                    {
                        ExtendedPropertySet propertySet = StateLayer.Reader.ExtendedPropertySet;
                        propertySet.RegisterProperty("STATE_NAME", string.Empty, typeof(string), string.Empty);
                        propertySet.RegisterProperty(SalesDataField, string.Empty, typeof(decimal), (decimal)0);
     
                    }
                    StateLayer.Reader.PreviewReadCompleted += new PreviewReadShapesCompletedEventHandler(StateReader_PreviewReadCompleted);
                    StateLayer.Reader.ReadCompleted += new ReadShapesCompletedEventHandler(StateReader_ReadCompleted);
                }
            }
     
            void StateReader_PreviewReadCompleted(object sender, PreviewReadShapesCompletedEventArgs eventArgs)
            {
                if (eventArgs.Error == null)
                {
                    foreach (MapShape shape in eventArgs.Items)
                    {
                        this.SetAdditionalStateData(shape);
                    }
     
                    var colorizer = this.StateLayer.Colorizer as ColorMeasureScale;
                    colorizer.SetColorByExtendedData(eventArgs.Items, SalesDataField, true);
                }
            }
     
            void StateReader_ReadCompleted(object sender, ReadShapesCompletedEventArgs eventArgs)
            {
                List<double> values = new List<double>();
     
                foreach (var state in DataSource.Select(State).Distinct())
                {
                    var sales = DataSource.Where(State).Sum(sales);
     
                    values.Add(Convert.ToDouble(sales));
                }
     
                if (values.Count > 0 && values.Count >= 4)
                {
                    //Uses Mean and Standard Deiviation to Set Map Legend Ranges -- Omitted for Space
                }
                else
                {
                    StateColorScale.MaxValue = (values.Count > 0 ? values.Max() : 0);
                    StateColorScale.MinValue = 0;
                }
            }
     
            private void SetAdditionalStateData(MapShape shape)
            {
                ExtendedData extendedData = shape.ExtendedData;
                if (extendedData != null)
                {
                    string stateName = (string)shape.ExtendedData.GetValue("STATE_NAME");
                    decimal dValue = GetSalesByState(stateName);
                    if (dValue > 0)
                        shape.ExtendedData.SetValue(SalesDataField, dValue);
                }
            }
     
            private decimal GetSalesByState(string State)
            {
                if (DataSource.Count > 0)
                {
                    return DataSource.Where(State).Sum(sales);
                }
                return (decimal)0;
            }
        }
    }

    I omitted the logic around Country populating sales data and setting the legend values because it is nearly identical to that of the state and it's also not the issue here.  
  2. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 14 Jun 2011 Link to this post

    Hello Michael,

    It is hard say for sure what is wrong without the ability to debug your code using your shape files and data, but there are few potential problems I see in your code.

    1. In most of the cases the shape isn't visible when ColorMeasureScale colorizer can't detect range for this shape. I.e. value of the extended property ("total_sales" in your case) doesn't fall into the any range. So you have to check whether value of the "total_sales" extended property always falls into 1 of the ranges that are used by ColorMeasureScale colorizer.

    2. Your XAML specify "total_sales" extended property for the colorizer. But in your code you set value to the "sales" extended property.

    3. You specify source to the reader in XAML, but setup Reader.PreviewReadCompleted and Reader.ReadCompleted events in the RadMap1.InitializeCompleted event handler. It is late to do it there. In this case reader starts (and actually can finish) reading of the shape file BEFORE you assign event handlers. It occurs when Silverlight processes XAML and sets Source property to reader. As result your application can never come into the event handlers. You should assign event handler in XAML or initialize reader in the code completely. The same is true for the registering of the additional extended properties.

    4. The ReadCompleted is not the right place to setup ColorMeasureScale colorizer. At this moment all items are in the information layer already and colorizer can be called already. You should do it in the PreviewReadCompleted event handler.

    All the best,
    Andrey Murzov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. DevCraft banner
  4. Michael
    Michael avatar
    8 posts
    Member since:
    Apr 2011

    Posted 14 Jun 2011 Link to this post

    Thanks for the reply, I knew it had to be something simple I was doing wrong.

    Number 1 ended up being what it was.  In my code where I set my custom ranges I was calculating a max value for the final range that was lower than what these two states were returning.  It's odd though that this works on the initial load even though the same factors are true (Higher than the max value).

    Number 2 was a matter of setting up the example code and me screwing up some of the fields.  

    I went ahead and set the events handlers in XAML, I tried to find an example on how to do the Extended Data as well, but couldn't find anything or figure it out on my own.  It seems to work the way it is so i'm not going to worry to much about fixing what's not broken.

    Then I went ahead and combined the two events mostly for simplicity sake.  

    Thanks for your assistance.  
Back to Top