Skip to content

Commit e6b241c

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into transposablexyseries
2 parents 3e9bcf6 + dbe818f commit e6b241c

File tree

4 files changed

+76
-7
lines changed

4 files changed

+76
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
66
- WindowsForms and Wpf support .NET Core 3.0 (#1331)
77
- Added .NET Core port of PngExporter
88
- New PolarPlot filling the full plot area (#1056)
9+
- Support for three colors in histogram series (#1305)
910
- Command to copy plot to the clipboard in Windows Forms (Ctrl-C) (#1297)
1011
- Added Avalonia based renderer and control library (based off OxyPlot.Wpf).
1112
- New `InterpolationAlgorithm` property in LineSeries and PolylineAnnotation (#494)

Source/Examples/ExampleLibrary/Series/HistogramSeriesExamples.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ public static PlotModel DisconnectedBins()
9090
return CreateDisconnectedBins();
9191
}
9292

93+
[Example("Normal Distribution Three Colors")]
94+
public static PlotModel NormalDistribution()
95+
{
96+
return CreateNormalDistribution();
97+
}
98+
9399
public static PlotModel CreateExponentialDistribution(double mean = 1, int n = 10000)
94100
{
95101
var model = new PlotModel { Title = "Exponential Distribution", Subtitle = "Uniformly distributed bins (" + n + " samples)" };
@@ -128,6 +134,43 @@ public static PlotModel CreateExponentialDistributionCustomBins(double mean = 1,
128134
return model;
129135
}
130136

137+
public static PlotModel CreateNormalDistribution(double mean = 0, double std = 1, int n = 1000000)
138+
{
139+
var model = new PlotModel { Title = $"Normal Distribution (μ={mean}, σ={std})", Subtitle = "95% of the distribution (" + n + " samples)" };
140+
model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Frequency" });
141+
model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "x" });
142+
143+
Random rnd = new Random();
144+
145+
HistogramSeries chs = new HistogramSeries();
146+
var binningOptions = new BinningOptions(BinningOutlierMode.CountOutliers, BinningIntervalType.InclusiveLowerBound, BinningExtremeValueMode.ExcludeExtremeValues);
147+
var binBreaks = HistogramHelpers.CreateUniformBins(-std * 4, std * 4, 100);
148+
chs.Items.AddRange(HistogramHelpers.Collect(SampleNormal(rnd, mean, std, n), binBreaks, binningOptions));
149+
chs.StrokeThickness = 1;
150+
151+
double LimitHi = mean + 1.96 * std;
152+
double LimitLo = mean - 1.96 * std;
153+
OxyColor ColorHi = OxyColors.DarkRed;
154+
OxyColor ColorLo = OxyColors.DarkRed;
155+
156+
chs.ColorMapping = (item) =>
157+
{
158+
if (item.RangeCenter > LimitHi)
159+
{
160+
return ColorHi;
161+
}
162+
else if (item.RangeCenter < LimitLo)
163+
{
164+
return ColorLo;
165+
}
166+
return chs.ActualFillColor;
167+
};
168+
169+
model.Series.Add(chs);
170+
171+
return model;
172+
}
173+
131174
public static PlotModel CreateDisconnectedBins()
132175
{
133176
var model = new PlotModel { Title = "Disconnected Bins" };
@@ -155,5 +198,21 @@ private static double SampleExp(Random rnd, double mean)
155198
{
156199
return Math.Log(1.0 - rnd.NextDouble()) / -mean;
157200
}
201+
202+
private static IEnumerable<double> SampleNormal(Random rnd, double mean, double std, int count)
203+
{
204+
for (int i = 0; i < count; i++)
205+
{
206+
yield return SampleNormal(rnd, mean, std);
207+
}
208+
}
209+
210+
private static double SampleNormal(Random rnd, double mean, double std)
211+
{
212+
// http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
213+
var u1 = rnd.NextDouble();
214+
var u2 = rnd.NextDouble();
215+
return Math.Sqrt(-2 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2);
216+
}
158217
}
159218
}

Source/OxyPlot/Series/HistogramItem.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public HistogramItem(double rangeStart, double rangeEnd, double area, int count)
4848
public double Area { get; set; }
4949

5050
/// <summary>
51+
/// Gets the center of the item.
52+
/// </summary>
53+
public double RangeCenter => this.RangeStart + ((this.RangeEnd - this.RangeStart) / 2);
54+
5155
/// Gets or sets the count.
5256
/// </summary>
5357
/// <value>The count.</value>

Source/OxyPlot/Series/HistogramSeries.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,24 @@ public class HistogramSeries : XYAxisSeries
3838
/// </summary>
3939
private bool ownsActualItems;
4040

41+
/// <summary>
42+
/// The default color mapping.
43+
/// </summary>
44+
private OxyColor defaultColorMapping(HistogramItem item) => ActualFillColor;
45+
4146
/// <summary>
4247
/// Initializes a new instance of the <see cref="HistogramSeries" /> class.
4348
/// </summary>
4449
public HistogramSeries()
4550
{
4651
this.FillColor = OxyColors.Automatic;
47-
this.NegativeFillColor = OxyColors.Undefined;
4852
this.StrokeColor = OxyColors.Black;
4953
this.StrokeThickness = 0;
5054
this.TrackerFormatString = DefaultTrackerFormatString;
5155
this.LabelFormatString = null;
5256
this.LabelFontSize = 0;
5357
this.LabelPlacement = LabelPlacement.Outside;
58+
this.ColorMapping = defaultColorMapping;
5459
}
5560

5661
/// <summary>
@@ -124,6 +129,11 @@ public OxyColor ActualFillColor
124129
/// </summary>
125130
public bool CanTrackerInterpolatePoints { get; set; }
126131

132+
/// <summary>
133+
/// Gets or sets the delegate used to map from histogram item to color.
134+
/// </summary>
135+
public Func<HistogramItem, OxyColor> ColorMapping { get; set; }
136+
127137
/// <summary>
128138
/// Gets or sets the delegate used to map from <see cref="ItemsSeries.ItemsSource" /> to <see cref="HistogramSeries" />. The default is <c>null</c>.
129139
/// </summary>
@@ -344,12 +354,7 @@ protected void RenderBins(IRenderContext rc, OxyRect clippingRect, ICollection<H
344354
{
345355
foreach (var item in items)
346356
{
347-
// Get the color of the item
348-
var actualFillColor = this.ActualFillColor;
349-
if (item.Value < 0 && !this.NegativeFillColor.IsUndefined())
350-
{
351-
actualFillColor = this.NegativeFillColor;
352-
}
357+
var actualFillColor = ColorMapping(item);
353358

354359
// transform the data points to screen points
355360
var p1 = this.Transform(item.RangeStart, 0);

0 commit comments

Comments
 (0)