Skip to content

Commit

Permalink
fix(LegendParameter): support legend with None
Browse files Browse the repository at this point in the history
  • Loading branch information
MingboPeng committed Mar 20, 2024
1 parent 020226a commit 4f35e95
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 30 deletions.
3 changes: 2 additions & 1 deletion src/LadybugDisplaySchema/ManualAdded/JsonSetting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ public static JsonSerializerSettings AnyOfConvertSetting

if (_setting == null)
{
_setting = new JsonSerializerSettings
_setting = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
FloatFormatHandling = FloatFormatHandling.Symbol,
//DefaultValueHandling = DefaultValueHandling.,
Converters = new List<JsonConverter>() { new AnyOfJsonConverter() }
};
Expand Down
56 changes: 53 additions & 3 deletions src/LadybugDisplaySchema/ManualAdded/Model/LegendParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public double SegmentHeight2D

public double Width2D => this.Vertical ? this.SegmentWidth2D : this.SegmentWidth2D * this.SegmentCountValue;
public double Height2D => this.Vertical ? this.SegmentHeight2D * this.SegmentCountValue : this.SegmentHeight2D;
public double Height2D_None => this.SegmentHeight2D / 4;
public double Height2D_Full => this.HasNone ? Height2D + this.Height2D_None + 10 : Height2D;

public double MinMaxRange => this.MaxValue.Equals(this.MinValue)? 0 : this.MaxValue - this.MinValue; // use Equals to catch double.NaN case

public double TextHeight2D
{
get
Expand All @@ -61,6 +66,7 @@ public double TextHeight2D
return GetPxValue(this.Properties2d.TextHeight);
}
}
public bool HasNone => this.HasNoneColor(out _);

#endregion

Expand Down Expand Up @@ -133,15 +139,16 @@ public LegendParameters(int x = 50, int y = 100): this()

public LegendParameters(double min, double max, int numSegs, List<Color> colors = default) : this()
{
if (numSegs <= 0)
throw new System.ArgumentException("Segment count cannot be 0");
init2DDefault();
DecimalCount = 2;

Min = min;
Max = max;
SegmentCount = numSegs;

var c = colors ?? _defaultColorSet.ToList();
Colors = numSegs > 1 ? c : new List<Color>() { c[0], c[0] };
Colors = _defaultColorSet.ToList();
}

private Legend2DParameters init2DDefault()
Expand All @@ -161,6 +168,43 @@ private Legend3DParameters init3DDefault()

//public System.Drawing.Rectangle GetBoundary => new System.Drawing.Rectangle(this.X, this.Y, this.Width, this.Height);

public LegendParameters SetNoneColor(Color color)
{
return this.AddUserData("_noneColor", color);
}
public bool HasNoneColor(out Color noneColor)
{
var ud = this.GetUserData();
noneColor = null;
if (ud.TryGetValue("_noneColor", out var color))
{
if (color is Color lbC)
{
noneColor = lbC;
}
try
{
noneColor = Color.FromJson(color?.ToString());
}
catch (System.Exception)
{
}

return noneColor!= null;
}
return false;
}
internal Color GetNoneColorWithDefault()
{
if (this.HasNoneColor(out var c))
return c;
var colorStart = this.ColorsWithDefault.First();
return new Color(
System.Math.Max(0, colorStart.R - 50),
System.Math.Max(0, colorStart.G - 50),
System.Math.Max(0, colorStart.B - 50)
);
}

private List<double> _colorDomains;
private List<double> ColorDomains()
Expand Down Expand Up @@ -195,12 +239,18 @@ public Color CalColor(double value)
var colors = this.ColorsWithDefault.ToList();
var colorStart = colors.First();
var colorEnd = colors.Last();

// check if there is none color for legend
if (double.IsNaN(value))
return GetNoneColorWithDefault();


if (value <= this.MinValue)
return colorStart;
if (value >= this.MaxValue)
return colorEnd;

var range_p = this.MaxValue - this.MinValue;
var range_p = this.MinMaxRange;
var factor = range_p == 0 ? 0 : (value - this.MinValue) / range_p;

var colorDomains = ColorDomains();
Expand Down
115 changes: 89 additions & 26 deletions src/LadybugDisplaySchema/ManualAdded/Model/VisualizationData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ public VisualizationData(List<double> results, LegendParameters legend = default
public VisualizationData(List<string> results, LegendParameters legend = default) : this()
{
this.LegendParameters = legend;
var isNumber = results.All(_ => double.TryParse(_, out var n));
var isNumber = IsNumberList(results, out var nums, out var numBounds); // checks for None case
var values = new List<double>(results.Count);
if (isNumber)
{
values = results.Select(_ => double.Parse(_)).ToList();
this.Values = values;
UpdateLegendWithValues();
this.Values = nums;
UpdateLegendWithValues(numBounds);

}
else
Expand Down Expand Up @@ -63,14 +62,6 @@ public VisualizationData(List<string> results, LegendParameters legend = default
legendPar.OrdinalDictionary = keyMapper;
legendPar.ContinuousLegend = false;

// reset color if there is only one from the existing legend param
if ((legendPar.Colors?.Distinct()?.Count()).GetValueOrDefault() == 1 && steps > 1)
{
legendPar.Colors = null;
}



this.LegendParameters = legendPar;
}

Expand All @@ -84,31 +75,97 @@ public LegendParameters ValidLegendParameters
return this.LegendParameters;
}
}
public void UpdateLegendWithValues()

/// <summary>
/// Checks all values
/// </summary>
/// <param name="results"></param>
/// <param name="values"></param>
/// <returns></returns>
public static bool IsNumberList(List<string> results, out List<double> values, out (double min, double max)? numBounds)
{
var noneKeys = new string[] { "None", string.Empty, null };
var gp = results.GroupBy(_ => noneKeys.Contains(_));
var hasNone = (gp.FirstOrDefault(_ => _.Key)?.Any()).GetValueOrDefault();
// check if all the rest values are numbers. If an empty list found, consider it as true to the rest value is number.
var allRestNums = (gp.FirstOrDefault(_ => !_.Key)?.All(r => double.TryParse(r, out _))).GetValueOrDefault(true);
values = null;
numBounds = null;

if (allRestNums) // all non-None values are numbers
{
var noneReplacement = double.NaN;

// replace all none values with noneReplacement
values = results.Select(r => double.TryParse(r, out var v) ? v : noneReplacement).ToList();

// get bounds
// values.Min() will be NaN if there is any NaN found, Max() will return the max value and ignore the NaN
var nonNaNs = values.Where(_ => !double.IsNaN(_));
numBounds = nonNaNs.Any() ? (nonNaNs.Min(), nonNaNs.Max()): (double.NaN, double.NaN);
return true;
}
else
{
return false;
}


}

public void UpdateLegendWithValues((double min, double max)? numBounds = default)
{
var legend = this.LegendParameters;
var valueMin = this.Values.Min();
var valueMax = this.Values.Max();
var values = this.Values;

// check None case which is set to double.NaN
var hasNone = double.IsNaN(valueMin);
var allNones = double.IsNaN(valueMax);
if (numBounds.HasValue && !allNones)
{
valueMin = numBounds.Value.min;
valueMax = numBounds.Value.max;
}

// update the legend with the real number values except NaNs
if (hasNone && !allNones)
values = values.Where(_ => !double.IsNaN(_)).ToList();

var distinctCounts = values.Distinct().Count();
var steps = distinctCounts > 11 ? 11 : distinctCounts;

if (legend == null)
{
var values = this.Values;
var min = values.Min();
var max = values.Max();
var distinctCounts = values.Distinct().Count();
var steps = distinctCounts > 11 ? 11 : distinctCounts;
legend = new LegendParameters(min, max, steps) { ContinuousLegend = true};
legend = new LegendParameters(valueMin, valueMax, steps) { ContinuousLegend = distinctCounts >1};
}

var lMin = legend.Min?.Obj;
var lMax = legend.Max?.Obj;
if (lMin == null || lMin is Default || lMin is double.NaN)
legend.Min = valueMin;
if (lMax == null || lMax is Default || lMax is double.NaN)
legend.Max = valueMax;

//legend.Min = legend.Min == null || legend.Min.Obj is Default || legend.Min.Obj is double.NaN ? valueMin : legend.Min;
//legend.Max = legend.Max == null || legend.Max.Obj is Default || legend.Max.Obj is double.NaN ? valueMax : legend.Max;

// reset colors, min, max when previous saved legend is only for one value/color
if (legend.MinMaxRange == 0 && valueMax>valueMin)
{
legend.Min = valueMin;
legend.Max = valueMax;
legend.SegmentCount = steps;
legend.Colors = null;
legend.ContinuousLegend = distinctCounts > 1;
}
//legend = legend.DuplicateLegendParameters();
legend.Min = legend.Min == null || legend.Min.Obj is Default ? this.Values.Min() : legend.Min;
legend.Max = legend.Max == null || legend.Max.Obj is Default ? this.Values.Max() : legend.Max;

var isNumber = !legend.HasOrdinalDictionary;
if (isNumber)
{
if (legend.SegmentCount == null || legend.SegmentCount.Obj is Default)
{
var distinctCounts = this.Values.Distinct().Count();
var steps = distinctCounts > 11 ? 11 : distinctCounts;
legend.SegmentCount = steps;
}

legend.OrdinalDictionary = null;
}
Expand All @@ -129,6 +186,12 @@ public void UpdateLegendWithValues()
if (!string.IsNullOrEmpty(this.Unit))
legend = legend.AddUserData("_unit", this.Unit);


if (hasNone && !allNones)
{
legend = legend.SetNoneColor(legend.GetNoneColorWithDefault());
}

this.LegendParameters = legend;

}
Expand Down

0 comments on commit 4f35e95

Please sign in to comment.