Oxyplot : Using Datagrid for tooltip

Oxyplot uses Tracker Controls for displaying tooltip. You could extend the display by Customizing the Default Tracker control. In this article, we will look deeper into that Tracker Control and aim to display a Grid in the Tracker Control.

For sake of example, let us assume a Fruit Seller, who wants to plot his sales per day on a Line Series. To begin with, let us create some random data to emulate the sales.

private enum eFruits
{
Apple,
Banana,
Mango,
Jackfruit
}
public IEnumerable<Fruit> Generate()
{
var random = new Random();
return Enumerable.Range(1, 10)
.SelectMany(x =>
{
return ((eFruits[])Enum.GetValues(typeof(eFruits))).Select(f =>
new Fruit
{
Name = f.ToString(),
ItemsSold = random.Next(0, 100),
Date = DateTime.Now.AddDays(x)
});
});
}

In his first attempt, he plots the Line Series, grouping the data by Date on which items where sold.

private void CreatePlotModel(IEnumerable<Fruit> totalSalesDetails)
{
var salesGrouping = totalSalesDetails.GroupBy(x => x.Date);
var yAxis = new LinearAxis
{
Position = AxisPosition.Left
};
var xAxis = new DateTimeAxis
{
Position = AxisPosition.Bottom,
Minimum = DateTimeAxis.ToDouble(salesGrouping.Min(x => x.Key)),
Maximum = DateTimeAxis.ToDouble(salesGrouping.Max(x => x.Key)),
};
DataPlotModel.Axes.Add(yAxis);
DataPlotModel.Axes.Add(xAxis);

var lineSeries = new LineSeries
{
MarkerFill = OxyColors.Blue,
MarkerType = MarkerType.Circle,
TrackerFormatString = "{0}\n{1}: {2:dd.MM.yy}\n{3}: {4:0.###}"
};
lineSeries.Points.AddRange(salesGrouping.Select(x => new DataPoint(DateTimeAxis.ToDouble(x.Key), x.Sum(c => c.ItemsSold))));
DataPlotModel.Series.Add(lineSeries);
}

XAML Part

<oxy:PlotView Model="{Binding DataPlotModel}"/>

This gave him his desired out as the following.

Initial Design

However, this left a lot to be desired. Currently the tooltip would display total sales per day. He knew he could decifer that from the chart itself and hence wanted to make use of tooltip for something more useful. He decided to display the details of sales, ie, number of each fruit sold during the day in the tooltip. This would give him a better insight into the sales.

Grid inside the Tooltip

While he knew the Oxyplot’s default Tracker control could be customized, he soon realized this wasn’t as straightward as he assumed it to be. As always, the problem lies in the details.

<oxy:PlotView Model="{Binding DataPlotModel}">
<oxy:PlotView.DefaultTrackerTemplate>
<ControlTemplate>
<oxy:TrackerControl>
<DataGrid ItemsSource="{Binding}"/>
</oxy:TrackerControl>
</ControlTemplate>
</oxy:PlotView.DefaultTrackerTemplate>
</oxy:PlotView>

The TrackerControl accepted a TrackerHitResult as its DataContext, displaying the TrackerHitResult.Text as tooltip, and there seemed no direct way for him to bind a collection of items to the TrackerControl if he was to customize it to include a DataGrid.

A bit of googling and with a tip from his mentor, he soon realized that there was a way instead. What if he can write a Converter that reads the required information from TrackerHitResult and returns a collection for DataGrid to bind to.

For this, he needs to extend the DataPoint so that it would contain the sub-collection information. This would ensure that the same would be available in the DataContext (TrackerHitResult)

public class ExtendedDataPoint : IDataPointProvider
{
public DateTime Date { get; set; }
public IEnumerable<Fruit> ItemsSold { get; set; }

public DataPoint GetDataPoint()
{
return new DataPoint(DateTimeAxis.ToDouble(Date), ItemsSold.Sum(x=>x.ItemsSold));
}
}

He can now rewrite his CreatePlotModel method to use the ExtendedDataPoint for adding points to the Line Series.

var lineSeries = new LineSeries
{
MarkerFill = OxyColors.Blue,
MarkerType = MarkerType.Circle,
};

lineSeries.ItemsSource = salesGrouping.Select(x => new ExtendedDataPoint
{
Date = x.Key.Date,
ItemsSold = x.ToList()
});

As you can notice, he has removed the TrackerFormatString as well, as he would not require it any longer. The next step would be to write the Converter required for transforming the TrackerHitResult to IEnumerable<Fruit>.

public class TrackerHitResultConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is TrackerHitResult data)
{
return (data.Item as ExtendedDataPoint).ItemsSold;
}
return null;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Since he had already defined his required sub-collection as a part of ExtendedDataPoint, the role of TrackerHitResultConverter became a lot easier. The last piece in the puzzle was to modify the Xaml to use the Converter.

<oxy:PlotView Model="{Binding DataPlotModel}">
<oxy:PlotView.DefaultTrackerTemplate>
<ControlTemplate>
<oxy:TrackerControl Position="{Binding Position}" Background="Transparent" BorderBrush="Transparent">
<DataGrid HeadersVisibility="None" ItemsSource="{Binding Converter={StaticResource TrackerHitResultConverter}}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Date,StringFormat=d}" Header="Date" />
<DataGridTextColumn Binding="{Binding Name}" Header="Fruit"/>
<DataGridTextColumn Binding="{Binding ItemsSold}" Header="Items Sold" />
</DataGrid.Columns>
</DataGrid>
</oxy:TrackerControl>
</ControlTemplate>
</oxy:PlotView.DefaultTrackerTemplate>
</oxy:PlotView>

With that in place, he was ready to Hit F5 and vola, his tooltip was ready.

Final output

Entire source code discussed in this article is available in my Github.

Law Of Demeter

If you ask any Software Developer, he would vouch that separation of concerns is the fundamental principles for maintaining any complex system and one of the vital links for achieving Separation of Concerns is decoupling.

Law of Demeter (LoD), also known as Principle of least knowledge, intends to reduce coupling between objects as proposed by Ian Holland.

Definition

The original version is outlined as follows.

Each unit should have only limited knowledge about other units: only units “closely” related to the current unit. Or: Each unit should only talk to its friends; Don’t talk to strangers.

The gist of the definition lies in the simple fact that the class should speak only to objects that it directly knows, or in other words, do not talk to strangers.

Let’s examine a real life scenario. You are out to stroll with your favourite pet. You do not order your pet’s legs to walk. Instead, you order your pet, which inturns commands its legs to move.

If we were to examine the rule from the perspective of an Object Oriented Programming Language,

A Method M, of an Object of Type C, may only call methods of
a) Class C
b) Parameters of method M
c) Instance variables of C
d) Objects created by M
e) Global Variables

Let’s write some code to replicate the Pet Scenario we discussed earlier.

public class Owner:IHuman,IHasPet
{
public string Name{get;set;}
public Pet Pet{get;set;}
public void MovePet()
{
Pet.GetLegs().Move();
}
}

public class Pet
{
private Legs _legs;
public Legs GetLegs ( )=>_legs;
}

public class Legs
{
public void Move()
{

}
}

As observed, the Owner Class uses instance of Pet to retrieve instance of Legs, and then request them to move.But, there is no reason the owner needs to be have access or knowledge of the legs or how the Pet commands the legs to move. This is the responsibility of the Pet class and should not be exposed the owner class.

In the above scenario, the Owner class has knowledge of something, which it doesn’t instantiate or should knowledge of and is a clear violation of Law of Demeter.

We can rewrite the classes to overcome the problem.

public class Owner:IHuman,IHasPets
{
public string Name{get;set;}
public Pet Pet{get;set;}
public void MovePet()
{
Pets.Move();
}
}

public class Pet
{
private Legs _legs;
public void Move()
{
_legs.Move();
}
}

In fact, if you look back at Gang Of Four patterns, many of the patterns discretely follows the Law Of Demeter.

A Word of Caution.

While the benefits of following the rule is evident, one also needs to be beware of focusing way too much on adherence to the rule, rather than fulfilling the purpose of the rule, which is to reduce coupling.

Json Custom Filtering : Remove Properties of a Type T

One of the recent questions that came up in SO which fascinated me was how do one filter a Json string by removing properties from Json, which is of a particular Type. For example, consider the following Json.

{
'widget':
{
'debug': 'on',
'window': {
'title': 'Sample Widget',
'name': 'main_window',
'width': 500,
'height': 500
},
'image': {
'src': 'Images/Sun.png',
'name': 'sun1',
'hOffset': 250,
'vOffset': 250,
'alignment': 'center'
},
'text': {
'data': 'Click Here',
'size': 36,
'style': 'bold',
'name': 'text1',
'hOffset': 250,
'vOffset': 100,
'alignment': 'center',

}
}}

What if you want to remove all Json Properties that has a value of Integer Type. What would be a good way to achieve it if the format of Json is unknown ?

I ended up writing an extension method.

public static class Extensions
{
public static JToken RemoveFieldTypes(this JToken token,params JTokenType []fieldTypes)
{
JContainer container = token as JContainer;
if (container == null) return token;

var tokensToRemove = new List<JToken>();
foreach (JToken el in container.Children())
{
JProperty p = el as JProperty;
if(p!=null && fieldTypes.Contains(p.Value.Type))
{
tokensToRemove.Add(el);
}
el.RemoveFieldTypes(fieldTypes);
}
foreach (JToken el in tokensToRemove)
{
el.Remove();
}
return token;
}
}

Client Code Sample

JToken nodeList = JToken.Parse(strJson);
nodeList.RemoveFieldTypes(JTokenType.Integer);

Sample Ouput

{
"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window"
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"alignment": "center"
},
"text": {
"data": "Click Here",
"style": "bold",
"name": "text1",
"alignment": "center"
}
}
}

External Tracker for OxyPlot

Back with another hack with Oxyplot. This time around what I would like to achieve is to actively update a TextBlock with Tracker values as the user moves around the graph. This could be useful when you want to have an external mini-dashboard which would the tracker values as User works on the graph after turning off your original tracker.

For sake of demo, we would leave the OxyPlot Tracker on, so that the results could be verified with our external tracker.

Let’s set up the View first.

<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>

<oxy:PlotView Model="{Binding DemoPlotModel}"/>
<TextBlock Grid.Row="1" Text="{Binding CurrentTrackerValue}"/>
</Grid>

We will now define our PlotModel and define our Series.

DemoPlotModel = new PlotModel();
var xAxis = new LinearAxis
{
Position = AxisPosition.Left,
Maximum = 100,
Minimum = 0
};

var yAxis = new LinearAxis
{
Position = AxisPosition.Bottom,
Maximum = 100,
Minimum = 0
};

DemoPlotModel.Axes.Add(xAxis);
DemoPlotModel.Axes.Add(yAxis);

var listOfDataPoints = new DataPoint[]
{
new DataPoint(10,5),
new DataPoint(20,15),
new DataPoint(30,20),
new DataPoint(40,28),
new DataPoint(50,39),
new DataPoint(60,55),
new DataPoint(70,60),
new DataPoint(80,73),
new DataPoint(90,90),
};
var series = new LineSeries
{
ItemsSource = listOfDataPoints,
Color = OxyColors.Green,
MarkerType = MarkerType.Square,
MarkerSize = 5,
MarkerFill = OxyColors.DarkGreen
};

DemoPlotModel.Series.Add(series);

And now it is time our adding our little hack to update the Label’s bound property – CurrentTrackerValue.

DemoPlotModel.TrackerChanged += (sender, eventArgs) =>
{
CurrentTrackerValue = eventArgs.HitResult != null ? eventArgs.HitResult.Text : CurrentTrackerValue;
NotifyOfPropertyChange(nameof(CurrentTrackerValue));
};

public string CurrentTrackerValue { get; set; }

That’s it, now you have your external live tracker.

Json : Fetch all keys using Linq

Given a Json, how do we get all the keys in it ? Just the keys. For example, Consider the Json below.

{
Person:['Jia Anu', 'Anu Viswan','Sreena Anu'],
Details:[
{
Name: 'Jia Anu',
Age:3,
},
{
Name: 'Anu Viswan',
Age:35,
},
{
Name: 'Sreena Anu',
Age:34,
}
],
Address : 'Address here',
State : 'Kerala',
Country : 'India'
}

Given the above Json, you would like to get all the keys. You might be later interested to show this as a Menu or Dropdown, that’s down to the requirements. But, how do we get the keys in first place ? May be a Linq One liner would be great ?

Person
Details
Details.Name
Details.Age
Address
State
Country

Of course, you do have the option to loop through the JTokens, but the easiest way out would be using Linq.

var data = JObject.Parse(jsonString);
var result = data.Descendants()
.OfType<JProperty>()
.Select(f=>Regex.Replace(f.Path,@"\[[0-9]\]",string.Empty))
.Distinct();

The Regex involed is to ensure the arrays indices are removed and keys in arrays aren’t duplicated. The output of above Linq would give you collection of all keys in the Json as expected.

Enumerable.Empty vs new T[0]

The need for creating an Empty array/collection rises quite often in most applications. This, normally presents us with two options.

  • Using the Constructor, new T[0];
  • Using the extension method, Enumerable.Empty

Let’s dive a bit deeper into both and examine how both these options work and differ.

Using new T[0]

Creating an empty array with Array Construction syntax is as follows.

var collection = new T[0];

What exactly happens behind the scenes. Let’s examine the following code.

var collection1 = new string[0];
var collection2 = new string[0];
object.ReferenceEquals(collection1,collection2).Dump();

Output of above code would be

False

The reason for this is self-explanatory. Each call to ‘new T[0]’ create a new Empty array in the memory. Both these, are as noticable, separate instances. What happens with Enumerable.Empty then ? Let’s examine that next.

Using Enumerable.Empty

Consider the complimentary code using Enumerable.Empty approach.

var collection1 = Enumerable.Empty<string>();
var collection2 = Enumerable.Empty<string>();
var result = object.ReferenceEquals(collection1,collection2);

What would be output of code in above scenario ? As you might have guessed, the output would be true.

Output

True

Enumerable.Empty caches the result for calls and reuses it later on. As MSDN states it

The Empty<TResult>() method caches an empty sequence of type TResult. When the object it returns is enumerated, it yields no elements.

This can be further verified by checking out the source code of Enumerable.Empty.

public static IEnumerable<TResult> Empty<TResult>()
{
return EmptyEnumerable<TResult>.Instance;
}
internal class EmptyEnumerable<TElement>
{
public static readonly TElement[] Instance = new TElement[0];
}

This difference might be of less significance in applications where memory constraints aren’t too critical, but when your applications requires to ensure memory allocations are used well, then Enumerable.Empty is your friend. Personally, I felt Enumerable.Empty should be the “go to” under all circumstances for not only for the reasons described above, but it also is more verbose in declaration and increases code readability manifold.

Evil Code #008: Property Instance

It has been long since I blogged on Evil Code series. Time to check one again now. Consider two samples of code.

Sample 1

public class AnotherClass
{
public MyClass ClassInstance{get;set;}
}

public class TestClass1
{
public AnotherClass AnotherClass{get;set;}
public int Id
{
get=> AnotherClass.ClassInstance.Id;
set=> AnotherClass.ClassInstance.Id=value;
}
}

public class MyClass
{
public int Id{get;set;}
}

Sample 2

public class AnotherClass
{
public MyStruct StructInstance{get;set;}
}

public class TestClass2
{
public AnotherClass AnotherClass{get;set;}
public int Id
{
get=> AnotherClass.StructInstance.Id;
set=> AnotherClass.StructInstance.Id=value;
}
}
public struct MyStruct
{
public int Id{get;set;}
}

How differently would two of the code samples given below behave ?

Well, Sample 1 compiles and Sample 2 doesn’t. Why ?? Sample 2, in fact raises following error.

Cannot modify the return value of 'AnotherClass.StructInstance' because it is not a variable

Could you reason why ?

If you look into the two Sample codes, there is a significant difference. MyStruct, used by Sample 2 is a value type. This means that when you are are in fact accessing a copy of StructInstance and not the valeu itself ( as you would have had it been a class – reference type).
Any change made in the property is made on the Copy instance, and then disregarded, leaving the original value unchanged.

This is the reason compiler warns you against.