Tuesday 10 November 2009

New pricing plan for Silverlight Bing Maps

Great news today, as Microsoft has announced new Terms of Service for Bing Maps and released version 1.0 of the Silverlight control for Bing Maps.

Due to the power of Silverlight to serve up large amounts of tiles to the end user the old commercial model would made it commercial suicide for a small developer (see previous post) to use Bing Maps, as a user session could consume a huge number of tiles resulting in CPM rates in the region $100/CPM.

Well now it’s all change with a session based pricing model, with free access for education/non-profit and free 120K sessions a year for developers.

To see how much you save check out my TileCalc demo (based on CTP Silverlight Control and old pricing model).

image

Monday 18 May 2009

Is Virtual Earth for Silverlight commercial suicide?

Update: Today (10 Nov 2009) Microsoft anounced a change to the Bing Maps Terms of Service which means it's now charged per session rather than tile count, also developers get 125,000 sessions per year for FREE.

Before I start I must state that the Virtual Earth CTP control for Silverlight is a CTP and terms have yet to be announced for commercial use of the control….

Recently I’ve created a couple of visualisations using Virtual Earth CTP control for Silverlight ( see previous entry British Politician’s Expenses ). I’ve been impressed at how easy it is to create web apps with the control. Like most CTPs the commercial model has not been announced for Virtual Earth, but looking at the existing commercial licence fees for Virtual Earth I got a bit alarmed after reading GIS in XML blog entry.

Standard version license is $8000 for 1,000,000/year transactions = 8,000,000/year tile renders. Note: no routing in standard

Advanced version license is $15,000 for 1,500,000/year transactions = 12,000,000/year tiles. Includes routing capability"

"An overage rate (generally $0.01 per transaction) is listed for exceeding the preset number of transactions for use during the term."

The situation is slightly better for Bizspark users costing $2000 for 8,000,000 tiles, though not sure what rate it goes to once 8million rate is exceeded ( $0.01 per 8 tiles seems very high).

To get an understanding of the types of apps I could create using Virtual Earth I needed to know how many tiles a typical user would request on a visit to my site, so I created a simple application which you can try out here.

image

The results are quite alarming, from just going on a simple tour of the world (browser size: 1200x800) London->New York->Sydney->Ipswich I rack up 241 tiles, as a BizSpark customer that would cost me $0.06 or $60.25 per CPM, but even more alarming the overage rate would cost me $0.30 for a single user. If I were to makes use of the mouse wheel to zoom in/out and pan around a few tows I hit 1300 tiles in less than a minute! Clearly running this control on an add funded site is commercial suicide where CPM rates are $0.60 to $1.

image

I know their has been talk of a revised VE commercial licence, as without one this control will remain a niche product. One suggestion I would make would be for the VE team to host Open Street Map data on their servers and offer it free to BizSpak customers, this would be a great way to kick of creativity using MS technology?

As for the app, it makes use of a custom tile server ,shown below, to keep track of the number of tiles consumed. The requests are tracked via a dictionary to ensure we only count unique requests. Once we have a request an event is fired back to the main page and the stats updated to the user.

public class FeedEventArgs : EventArgs

{

public string Msg { get; set; }

public long count { get; set; }

}

public class CounterMapTileSource : Microsoft.VirtualEarth.MapControl.TileSource

{

Dictionary<string, long> d = new Dictionary<string, long>();

long tileCount = 0;

public CounterMapTileSource() : base("http://tile.openstreetmap.org/{2}/{0}/{1}.png") { }

public override Uri GetUri(int x, int y, int zoomLevel)

{

string uri = String.Format(this.UriFormat, x, y, zoomLevel);

string info = String.Format("{0:000#} Zoom x,y: {1:0#} {2} , {3} ", tileCount , x,y,zoomLevel);

if (d.ContainsKey(uri) == false)

{

d.Add(uri, tileCount);

tileCount++;

OnFeedRetrieved(new FeedEventArgs { count = tileCount, Msg = info });

}

return null;

}

public void Reset() { tileCount = 0; d.Clear(); }

public event EventHandler<FeedEventArgs> FeedRetrieved;

protected void OnFeedRetrieved(FeedEventArgs args)

{ if (FeedRetrieved != null)FeedRetrieved(this, args); }

}

Finally a couple of caveats:

If you switch map views then make sure to hit the reset button to clear the custom tile source tile cache, otherwise it may underestimate your usage.

Animation is turned off, as the tile requests for the custom tile map are a lot higher than those for Virtual Earth ( looking at my browser cache and watching Fiddler network traffic.

Thursday 23 April 2009

British MP’s Expenses Data Visualisation via Virtual Earth CTP

 

Following on from my previous blog on US Politicians data visualisation using a listbox, this time I’ve moved across the pond to my homeland and created one for British Politician’s Expenses (a bit of a hot topic in the UK at present) based on the CTP of the Virtual Earth for Silverlight control.

The application enables you to quickly view Members of Parliament (MP) expenses for 2007/08 based on:

  • Location / Political Party (colour of the pin)
  • Travel expenses (opacity of the pin)
  • Second home allowance (size of the pin)

Note: An MP represents ~100k people, so map gives a good indication of population density across Britain.

Using the Search tool you can filter the results  based on MP’s name/constituency Travel expenses and second home allowance. Any changes to the map are reflected in the pages URL making it easy to share custom reports via the share button on Twitter, Digg, Facebook and Email.

E.g. the link blow shows MPs in the South East of England:

http://home.btconnect.com/martibiz/mps.htm#?s=&t=0&h=0&y=51.5417&x=-0.1491&z=12

Sample screen shot 

Tech notes:

The visualisation makes use of Client Technical Preview (CTP). The data is sourced from the Guardian MP expense claims with MP geo data coming from TheyWorkForYou, though some data cleansing was required to link the two sets of data. The data is pulled in as  JSON, to keep things as fast as possible I embedded the JSON in the XAP assembly and loaded it using the following code:

void LoadMPdetails()
   {
       Stream file = Assembly.GetExecutingAssembly().GetManifestResourceStream("mmMPs.Assets.mpDetails.js"); 
       TextReader tr = new StreamReader(file);

       JsonArray jsonArray = (JsonArray)JsonArray.Load(tr);

       mps = new List<MP>();

       foreach (JsonObject jsonItem in jsonArray)
       {
           MP item = new MP();
           item.name = jsonItem["name"];
           item.constituency =  jsonItem["constituency"];
           item.party =  jsonItem["party"];
           mps.Add(item);
       }
   }

Even though this is a Silverlight 2.0 application we support deep linking (added to Silverlight 3.0 beta) so you can create custom views and share the links with your friends. Each time the viewport is changed or a search preformed the pages URL is updated and added to the browsers page history using  JQuery and jquery.history and some C# code provided by nerdplusart.com

The code below shows the logic to display the push pin with the tooltips:

private void AddPin2(Loc con)
        {
            // pushpin image
            Image image = new Image();

            if (con.mp == null)
                image.Source = new BitmapImage(new Uri("/assets/pinMagenta.png", UriKind.Relative));
            else        
            switch (con.mp.party)
            {
                case "Liberal Democrat":
                    image.Source = new BitmapImage(new Uri("/assets/pinYellow.png", UriKind.Relative));
                    break;

                case "Conservative":
                    image.Source = new BitmapImage(new Uri("/assets/pinBlue.png", UriKind.Relative));
                    break;
  
                case "Labour":
                    image.Source = new BitmapImage(new Uri("/assets/pinRed.png", UriKind.Relative));
                    break;

                default:
                    image.Source = new BitmapImage(new Uri("/assets/pinMagenta.png", UriKind.Relative));
                    break;
            }

            int size = 35;
            if (con.expense.Cost_Of_Staying_Away_From_Main_Home > 5000)
                size = (int) Math.Min(( (con.expense.Cost_Of_Staying_Away_From_Main_Home - 5000) / 5000) * 10 + 35,80);
            image.Width = size; image.Height = size;

            if (con.expense.Cost_Of_Staying_Away_From_Main_Home < 500)
                image.Opacity = 0.6;
            else
                image.Opacity = 0.6 + (con.expense.Cost_Of_Staying_Away_From_Main_Home / 23000);
            

            image.MouseEnter += new System.Windows.Input.MouseEventHandler(i_MouseEnter);
            image.MouseLeave += new System.Windows.Input.MouseEventHandler(i_MouseLeave);
            image.MouseLeftButtonDown +=new System.Windows.Input.MouseButtonEventHandler(image_MouseLeftButtonDown); // += new System.Windows.Input.MouseButtonEventHandler(image_MouseLeftButtonUp);


            // Add Tooltip
            var tooltipObject = new StackPanel();

            var title = new TextBlock();
            title.FontWeight = FontWeights.Bold;
            title.Text = con.name;
            tooltipObject.Children.Add(title);
            
            var description = new TextBlock();
            if (con.mp != null)
                description.Text = con.mp.party + " - " + con.mp.name + "\n\n" +getExpenseReport(con.expense); // .Total_Allowances_Claimed_Inc_Travel ; // "Info goes here....."; // "This is an arbitrary description of the \"Huge Square\" to be displayed within the Tooltip.";
            tooltipObject.Children.Add(description);

            image.Tag = con.name;

            ToolTipService.SetToolTip(image, tooltipObject);
            
            //Add the pushpin to the Map 
            myMap.Children.Add(image);

            //Position the pushpin using the attached properties 
            MapLayer.SetMapPosition(image, new Location(con.centre_lat, con.centre_lon));
            MapLayer.SetMapPositionMethod(image, PositionMethod.BottomLeft);

        }

Things I would have liked to do if I had the time:

Better control of the map pins when zooming out, would like some form of clustering and pins to be a bit smaller, 600+ large pins is too much for a place the size of Britain.

Restrict zoom level and panning just to the UK, as things get a bit confusing for the user seeing a small island with los of dots.

Host via Silverlight Streaming, but couldn’t figure out how I could get the deep linking working from an IFRAME hosted on a different domain.

Make the tooltip timeouts longer, but this isn’t a trivial task, though you can find a ToolTipService on codeplex that supports such a feature.

Friday 27 February 2009

Open Street Map to XAML

After playing around with maps in my previous post, Silverlight USA States Visualisation, I decided to check out the maps at OpenStreetMap and see if I could embed them into a simple Silverlight app, for which you can see a live demo here.

app

Step 1 – Grab the data

This is very easy, just zoom into the location you want and then hit the Export tab, select format PDF and download your PDF image and save the file to disk e.g map.pdf.

streetmap

Once downloaded check all is ok (I had to download twice for some reason as first download was corrupted).

Step 2 – Import to Expression Design

To do this create rename the file to map.ai and import the data (File/Import) into Expression Design. At this stage you may want to delete some of the features, e.g. cost lines, borders etc.

For more info on this step check of post by Tim Heuer.

Step 3 – Export to Silverlight XAML

Select the File/Export and select Silverlight option this will then give you a map.xaml.

In my XAML I noticed 4 <image> of the format shown below, which I striped out of the XAML.

<

Image Source="Ipswich - Open Street Map_files/image3.png"/>

Step 4 – Embed in your Silverlight project

I pasted the contents into  and paste contents of map.xaml into your canvas..

code1

In the app I just add a scale factor based on the mouse wheel ( using Pete Blois MouseWheelHelper class), which works ok but doesn’t update the horizontal / vertical bar sizes/ranges.

code2 See online version here.

A note on file Sizes

The PDF I used for a medium sized English town (Ipswich) resulted in a 700K PDF file. Once converted to XAML this grew to 5.9MB (and still 1.7MB zipped). Trying to edit such a large file in VS2008 proved very slow which each edit of the file taking 10 seconds, hope VS2010 is faster.

Deep earth

For most Silverlight mapping tasks you would probably be better off using something like DeepEarth which makes use of DeepZoom, and a custom map source provider to enable Open Street Map data to be displayed within a Silverlight app, though not sure of the terms and conditions of using OpenStreetMap tile server, but you can see a live demo at http://deepzoom.soulclients.com/osm/.

Monday 23 February 2009

Silverlight USA States Visualisation

Tim Heuer challenged his readers to create a Silverlight visualisation application; this is my entry…….

It displays visualisation of the following name value pairs (stored as embedded text files) from Wikipedia of:

  • Average salary per state
  • US elections 2008 votes per state - Wikipeida
  • Population per state - Wikipeidia

Other sources of info are on Wikipedia.

Step 1 - Simple Listbox

Each set of name value pairs are stored in their own embedded text file, which are then are then loaded into a observable type and bound to a list box. A slider bar then allows the user to filter the results. The data binding worked well but looked so 2003, so it was time to jazz it up.

Step 2 - Basic Item Template

I then put a nice border around items, could have added some simple graphics, bound the data to colour and opacity attributes, that would have made it a bit better but still it’s so 2005.

Step 3 - Advanced Item Template with paths

Then I remembering seeing a blog of a WPF app that created a USA map from a list box, so I ported the app to Silverlight, this required me to:

  • Resolve issues of Silverlight not supporting binding of certain types
  • Replacing XML data source with my custom observable type
  • Tweaking animation effects
  • Tweaking labels so they weren’t clipped by the state

The results are a great example of the strength of data binding to a custom list box to totally transform an app from a dull winforms style list box to an advanced visualisation. Using these features in WPF/Silverlight makes it very easy to separate the visualisation from data, and the ZAP file is only 36Kb, smalled than a PNG of the screenshot!

Due to time contains there are still a few rough edges, the animation could be a bit slicker, button designs could be improved any fixing the z-order of the selected state.

Future enhancements could include:

  • More complex data type, e.g. third axis to include time
  • Load your own data via local text file
  • Embeddable widget
  • Extra maps