TrackingDiagram

From Catglobe Wiki
Jump to: navigation, search


New Report Design - 2009 => TrackingDiagram

Introduction

This page is detail design for detail implementation of tracking diagram, both on GUI and Business layers.

First feeling:

  1. There are lots of setting on GUI makes us feel that this diagram is not close to cross diagram, however basically the only different is in phase 1 (DataSeries generation), the remaining are nearly the same.
  2. Data cache must have StartDate and EndDate column to be used with tracking diagram
  3. Diagram's XML must be used (it is optional in CrossDiagram)
  4. There are 2 parts: static part (defined in XML - list of branches, list of target group, timeset, etc.), dynamic part (defined on GUI - which brand to draw on, values of target group, trend line, time period, etc.) => dynamic part MUST be saved for future requests
  5. Formulas are PRE-DEFINED by end user
  6. Time periods and target groups in fact are additional filters
  7. Trend line is just another data series to draw

Design decisions

GUI: Tracking Diagram Config Control

  • Split into user controls with MVP implementation => must have some unit test for this
  • Support skin => default skin is just like the default one of CrossDiagram


XML:

  • We focus on the viewer part instead of editing part => reuse the old XML format, however there must be an FORMAT ADAPTOR that is capable of parsing both old and new (might be defined later) format

Business:

  • TrackingDiagramInfo has the same role as CrossDiagramInfo for cross diagram

Detail design

1. Refactor the generalization:

ICaculator:

New method in an externsion class to realize if an input ICaculator is really typed as type of object inheriting from ICaculator

Filter expression feature is appended to apply filter of the inner Interpreter

Refining method is changed so that it can refine other format ("= { return 7; }" or "{ return 7 }" etc.)


Diagram:

New virtual method T ConvertTypeDiagramInfo<T>(DiagramInfo diagramInfo) where T : DiagramInfo

New virtual method Chart Build<T>(T diagramInfo) where T : DiagramInfo

New virtual method void InitializeCalculator<T>(T diagramInfo) where T : DiagramInfo

New abstract method DataSeries[][] BuildData(DiagramInfo diagramInfo) (moved onto from CrossDiagram originally)

New property called Calculator (type ICalculator) will be initialized whenever method BuildData is called

Note:

From now on just implement abstract method BuildData in any chart info inherited from DiagraramInfo, any diagram will be built by a flow template: Validate and convert general diagram info object into needed info object -> initialize calculator -> freeze -> check validity of info object after freezed -> create and return Chart object with data got from self defined BuildData process, layout info is the very ChartLayoutInfo of info object.


CrossDiagram:

New private methods for Expression builders (moved onto from Diagram as it's especially for Cross)


DiagramInfo:

New properties called SelfDefinedCriterias, containing the self-defined criterias (this assures other own criteria of further chart like : Cross, Campaign etc.). The properties should be initialized inside constructors of each chart whenever it needs to be used. In current scenario, it has just supported for Tracking with:

  • Chart is auto-generate initialized or not
  • Chart is initialized with criteria hidden or not
  • Others


ChartLayoutInfo:

New properties called SelfDefinedLayouts, containing the self-defined layouts (this assures other own layout of further chart like : Cross, Campaign etc.). The properties should be initialized inside constructors of each chart whenever it needs to be used. In current scenario, it has just supported for Tracking with:

  • Chart is generated with one more Trend-line or not
  • Chart is generated with style of each series (brand) applied by their order or not
  • Others


AbstractCrossDiagramTester:

Common methods have been moved out to general AbstractDiagramTester, but not erased yet to assure its stability

2. Create new TrackingDiagramInfo:

TrackingDiagramInfo.png


TrackingDiagramInfo contains a DynamicExpressionResolver 2-D array (which each element is a brand item value)


DynamicExpressionResolver :

Apply ICalculator to sef-calculated its filtered value (recognized as resulted value)

Purpose to exist:

  • Not alike Cross diagram, Tracking diagram has expressions of branches exists independently from each other and might be set more complicated than short math-base axis set expressions of Cross diagram. Also for its filters (common filters of Filters node inside Tracking diagram editor).
  • Assure the flexibility of brand item value. Tracking diagram hasn't got concrete Axis object like Cross, just values of brand item as expressions. Expression might be realized as DynamicExpressionResolver in short format (filter format) like : Q1 == [1] or, in full format like : count() where Q1 == [1]
  • Handle validity of brand item value better (might be used in further Tracking/Campaign editor rebuilding)

Support:

  • Short format (Q1==1)
  • Not full format (count() where Q1==1)
  • Full format (=count() where Q1==1;)
  • Complex expression (={  var x=1; var y=1; ...; return (x+y);}) (Not full yet)

Limitation:

DynamicExpressionResolver hasn't support fully for CGScript (refer older engine's and FilterInfo's also). For example, user don't input as usual, but a cgscript function (like in Spreadsheet : = {  var sht... ; return sht; }, then our current filter-appending-in-last bussiness can dive into a rock when generated expression will be : = { var sht... ; return sht } && Q1==[1].

Solution might be use functions alike in Interpreter (where expression is parsed, get condition, math enumarator from AST etc.), or these existing Interpreter's functions would be set public.


3. Unit test

UnitTest.png

  • Templates contains svgs of 2 simplest cases generated:
  1. From an one-levelled branch to one series
  2. From 2 one-levelled branches to 2 series
  • AbstractDiagramTester : Also ready to be used for AbstractCrossDiagramTester
  • AbstractTrackingDiagramTester has virtual initializing function contains data cache data for case "from an one-levelled branch to one series" which may be overriden in other & further cases


Full further implementations

Free labels

  • Process :
  1. Retrieve the raw inline free label collection from the diagram xml (labels as formula such as : "Đây là Base: (Base) nè ông nội")
  2. Merge it with external free label collection from the external stylesheet (merge here means to union 2 collections with each other)
  3. Generate the formulas according to the predefined formulas that had been calculated (such as Base is predefined onto Brand node alike "=count() where Fools != empty" → Base = 100 → All raw formulas is changed correspondingly "Đây là Base: 100 nè ông nội"
  • Rule to parse formula (each the property if needed will be added into the correlative DiagramInfo)

FreeLabel.png

Campaign:

  1. Target group 1
  2. Target group 2
  3. Diagnostic period 1
  4. Diagnostic period 2
  5. Legend 1
  6. Legend 2
  7. Warning low base 1
  8. Warning low base2
  9. Base 1
  10. Base 2
  11. Mean 1
  12. Mean 2
  13. Data cache specification last built time

Tracking:

  1. From week: <StartWeek>/<StartYear>
  2. To week: <EndWeek>/<EndYear>
  3. Time period: Time period : Week <StartWeek>/<StartYear> - Week <EndWeek>/<EndYear>
  4. Average respondents
  5. Warning low base
  6. Target group: Target group
  7. Subtitle
  8. Calculation methods: Calculation methods : <Rolling average> Week(s)
  9. Data cache specification last built time
  • To follow the above process, there should be some modifications:
  1. StyleSheet is now becomes a new property of ChartLayoutInfo (NonSerializable with setter as a method called SetStyleSheet(StyleSheet)).
  2. So whenever it's necessary to build chart control, StyleSheet won't be input as an outer element anymore, it should be setup inside DiagramInfo as a static data from diagram, by method CopyStaticDataFrom(diagram).
  3. Old engine in fact trying to create only one general free label adder object, containing all above cases for both Tracking and Campaign diagram → It be too excessive for each case : Tracking or Campaign. For the new one we create a general abstract FreeLabelHandler, then 2 other inheriting from it called TrackingFreeLabelHandler and CampaignFreeLabelHandler. Steps to retrieve free labels from inline and external stylesheet then analyse them will be : Diagram → FreeLabelHandler initialization → FreeLabelHandler transforming → FreeLabelHandler applying onto particular a FreeLabelCollection.
  4. FreeLabelHandler is initialized inside CopyStaticDataFrom method as a pre-process before building chart. But it be only transformed inside Freeze method of DiagramInfo, as the value of Free Label needs evaluating based on calculated expression of brand items and filters.
  • Other fringe modifications:
  1. Build method omit input parameter StyleSheet to receive StyleSheet directly from ChartLayout of parameter Diagram

Note:

  • Base is an expression, got from Base of root Brand, if this is left as blank, then Base will be the combination of all Base of 1st-levelled brand-node (such as:=count() where Q1=[2] + count() where Q2=[3] + count() where Q2=[4])
  • Average respondents is an expression, got by a messy algorithm ! (Leave as blank for further confirmation)
  • Subtitle is got as Name of the only selected 1st-levelled brand item
  • Target groups is got as expression of the first filter name or All (if the name is empty)
  • Warning low base will be simple "Warning low base" if AverageRespondents < Base, unless be empty.

Target groups / Filters

Initials:

  • Inside DynamicExpressionResolver, filters are splitted into concrete types: Time period filter, common filters and target group filters.

Flows:

  • TrackingDiagramInfo (Filters from DiagramInfo) => DynamicExpressionResolver [][] (CommonFilters appended directly into Calculator of DynamicExpressionResolvers, only TimePeriodFilter is appended as conditions into ouput value as expression).
  • Such as DynamicExpressionResolvers has Value is "=count() where Q1==[1]", TimePeriodFilters is "StartDate >= #2008-1-1# && EndDate <= #2008-2-2#", Filters are "Q2==[2]" and "Q3==[3]", Target groups is "Q4==[4]", then output Value is "=count() where Q1==[1] && StartDate >= #2008-1-1# && EndDate <= #2008-2-2#", its Calculator has Filters including: "Q2==[2]" and "Q3==[3]" and "Q4==[4]".
  • This leads expession result (for table results) will just show Value with TimePeriodFilter. All filters (including Target groups) shown in Filter section only. This will make the long expression table seems easier to review.

Notes:

  • Both Target groups and Filters are recognized as CommonFilters.
  • Target groups and Filters can be distinguished by type of FilterInfo (must be initialized whenever input Target groups/Filters). Filters should have FilterInfoType as Normal, Target groups should have FilterInfoType as Specific (just for further case when it's necessary to pick up particular Filters or Target groups).
  • To apply general filters into filters of each DynamicExpressionResolver:
  • Property Filters of DiagramInfo becomes virtual.
  • Property Filters of TrackingDiagramInfo overrides DiagramInfo's, also immediately update CommonFilters of its Expressions which are set.
  • Property Filters of ICalculator has purpose to handle FilterExpressions of its Interpreter (known as CGScriptEngine)

Such as:

public override FilterInfo[] Filters
      {
         get { return _filters; }
         set
         {
            _filters = value;
            if (Expressions != null)
            {
               for (var r = 0; r < Expressions.Length; r++)
                  for (var c = 0; c < Expressions[r].Length; c++)
                     Expressions[r][c].CommonFilters = _filters;
            }
         }
      }


Target Filters.png


Trendline

Specifications:

  • Trendlines in fact are point series collections, when drawing them in order, it will be nearly a line.
  • Formula : =trend(<record row index>, <beginning column index> : <ending column index>)
  • To get trend from trend formula, it must be arrage data under table format. Such as:
A
B
C
D
E
1
=count() where Q1==[1]
=count() where Q2==[1]
=trend(1, B1 : B3)
=trend(1, C1 : B3)

2
=count() where Q1==[2]
=count() where Q2==[2]
=trend(2, B1 : B3)
=trend(2, C1 : C3)

3
=count() where Q1==[3]
=count() where Q2==[3]
=trend(3, B1 : B3)
=trend(3, C1 : C3)

  • Trend series has the same series style as its calculated origin's. Such as in above example, trend series D must be drawn with the same style with series B's.

Implementation:

Feature
Old
New
Notes
Separation between Trend line and normal data
Trend series are separated from normal series by number of series

TrendExpressionResolver for specific trends

Trend series are appended and evaluated right after normal series


Style of Trend lines

Stylesheet stays directly on viewer page, initialized & interfered when it's called on the first time by object StyleSheetFactory, by so that the line styles of Trends can be modified with the same of corresponding main series

Stylesheet, as one part of ChartLayoutInfo, stays on domain object (interfered staticly due to chart type - in method Freeze() => SetStyleSheet() - by TrackingTrendHandler

  • Trend lines styles copied from corresponding main series line style including:
  1. Line color
  2. Line pattern (Dash dot line etc...)
  • Line width = 2 (fixed)


Flow of Trend data:

  • TrendExpressionResolver inherits from DynamicExpressionResolver, the purpose is:
  1. Trimming unneeded properties (such as Condition, ValueFiltered etc.) because Trend function has the only one formula and structure
  2. Override to get resulted value through property ValueResulted. ValueResulted of DynamicExpressionResolver is only calculated by its inner Calculator and its ValueFiltered. ValueFiltered of TrendExpressionResolver is calculated by an outer DataTable joining the Value of itself (trace the Specification section).
  3. ICalculator, PseudoCalculator, CGScriptCalculator also get one new method named Execute(DataTable) and Execute(DataTable, Converter<object, object>) to evaluate the whole input data table with formulas related to other result inside data table (trace the Specification section)
  • TrendHandler and TrackingDiagramTrendHandler (for specific trends of Tracking, inehrits from TrendHandler) :
  1. TrendHandler object is one property of DiagramInfo.
  2. TrendHanlder would be initialized inside method Freeze of DiagramInfo, if Trend feature has been marked as activated, right after original Expressions (having role to create the original expressions, trace up Specification section, expressions in column B and C).
  3. TrendHanlder would wait untill being called when a framework Diagram builds its data series array : Firstly its method Freeze is called to retrieve its TrendExpressionResolver, known as Trends. Secondly each trend data series and trend data item (trace up Specification section, expressions in column D and E) will be created based on Trends.Thirdly normal data series and trend series become an union.

Flow of Trend style:

  • SetPredefinedLayout, SetPredefinedCriteria, SetStyleSheet methods won't be inside Freeze method of DiagramInfo anymore.
  • Styles of trend lines are series styles next to the series styles of normal series, customized (having the same color to corresponding series such as column B and D in Specification section example, line width = 2, etc.) by modifying the style sheet of input diagram, through calling TrendStyleApplier of TrendHandler of DiagramInfo, inside method CopyStaticDataFrom(diagram) then SetStyleSheet(diagram).
  • SetPredefinedCriteria(diagram) and SetPredifinedLayout(diagram) methods are also move into CopyStaticDataFrom

Note:

  • SelfDefinedLayoutType.Tracking_TrendApplied would be inserted info dictionary ChartLayoutInfo.SelfDefinedLayouts<SelfDefinedLayouts, object> by AJAX serializing on client side, which means SelfDefinedLayoutType (also SelfDefinedCriteriaType) converted is in DiagramInfoScriptConverter, through converting class named EnumerableKeyedDictionaryConverter<T> with T is an enum parameter.
  • In TrendHandler, data of trend is solved by TrendDataApplier, style of trend is solved by TrendStyleApplier
  • Further feature request can be found here

Trend.png

Unit Test

TrackingDiagram FullImplementation UnitTest.png

Document revisions

Version No. Date Changed By Description Svn revision
0.1 31.12.2009 Nguyen Trung Chinh Create the first version 59167
0.1.1 15.01.2010 Nguyễn Điển Nghĩa Initialize basic class
0.1.2 01.02.2010 Nguyễn Điển Nghĩa Simplest case : Finished TD, coding and wiki report 59899
0.1.3 16.04.2010 Nguyễn Điển Nghĩa Full implementation : TD for Trendline, Target groups/Filters,...