using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Web.UI.DataVisualization.Charting; using System.Web.UI.WebControls; using LeafWeb.Core.Charter; using LeafWeb.Core.Utility; namespace LeafWeb.WebCms.Services { public static class LeafGasCharter { private struct Fonts { public Font Regular { get; } public Font Title { get; } public Font Axis { get; } public Fonts(double multiplier) { var regSize = CeilingMultiply(9, multiplier); var titleSize = CeilingMultiply(10, multiplier); Regular = new Font(new FontFamily("Trebuchet MS"), regSize, FontStyle.Bold); Title = new Font(new FontFamily("Times New Roman"), titleSize, FontStyle.Bold); Axis = new Font(new FontFamily("Times New Roman"), titleSize, FontStyle.Bold); } } private struct ChartSizes { public int Width { get; } public int Height { get; } public int BorderlineWidth { get; } public int RubiscoLimitedMarkerSize { get; } public int RubiscoLimitedBorderWidth { get; } public int RuBPMarkerSize { get; } public int RuBPBorderWidth { get; } public int TpuLimitedMarkerSize { get; } public int TpuLimitedBorderWidth { get; } public int aCurveMarkerSize { get; } public int aCurveBorderWidth { get; } public ChartSizes(double multiplier) { Width = CeilingMultiply(550, multiplier); Height = CeilingMultiply(400, multiplier); BorderlineWidth = CeilingMultiply(1, multiplier); RubiscoLimitedMarkerSize = CeilingMultiply(8, multiplier); RubiscoLimitedBorderWidth = CeilingMultiply(3, multiplier); RuBPMarkerSize = CeilingMultiply(9, multiplier); RuBPBorderWidth = CeilingMultiply(3, multiplier); TpuLimitedMarkerSize = CeilingMultiply(9, multiplier); TpuLimitedBorderWidth = CeilingMultiply(3, multiplier); aCurveMarkerSize = CeilingMultiply(2, multiplier); aCurveBorderWidth = CeilingMultiply(1, multiplier); } } private static int CeilingMultiply(int num, double multiplier) { return Convert.ToInt32(Math.Ceiling(num * multiplier)); } // cntrlcomparison public static IEnumerable ProduceCharts(CurveData curve, double multiplier = 1d) { var curveId = curve.CurveId; var fonts = new Fonts(multiplier); var sizes = new ChartSizes(multiplier); return curve.ParamSets.SelectMany(item => CurveSeries(curveId, item, item.CurveType.GetDescription(), sizes, fonts)); } private static IEnumerable CurveSeries(string curveId, CurveParamSet paramSet, string chartTitle, ChartSizes sizes, Fonts fonts) { var chloroChart = CreateEmptyChart("Chloroplastic CO2 partial pressure (Pa)", sizes, fonts); var interChart = CreateEmptyChart("Intercellular CO2 partial pressure (Pa)", sizes, fonts); // Set the points for the symbol series for paramater set 1, chloroplastic AddAnetMeasPoints(paramSet.AnetMeasChloro1Data, chloroChart.Series["Rubisco-limited"]); AddAnetMeasPoints(paramSet.AnetMeasChloro2Data, chloroChart.Series["RuBP regeneration-limited"]); var tpuSeries = NewTpuSeries(paramSet.AnetMeasChloro3Data, sizes); AddAnetMeasPoints(paramSet.AnetMeasChloro3Data, tpuSeries); chloroChart.Series.Add(tpuSeries); // Set the points for the symbol series for paramater set 1, intercellular AddAnetMeasPoints(paramSet.AnetMeasInter1Data, interChart.Series["Rubisco-limited"]); AddAnetMeasPoints(paramSet.AnetMeasInter2Data, interChart.Series["RuBP regeneration-limited"]); tpuSeries = NewTpuSeries(paramSet.AnetMeasInter3Data, sizes); AddAnetMeasPoints(paramSet.AnetMeasInter3Data, tpuSeries); interChart.Series.Add(tpuSeries); // Set the points on the asymptote curve for parameter set 1, chloroplast AddAsymptotePoints(paramSet.AcChloroData, chloroChart.Series["acCurve"]); AddAsymptotePoints(paramSet.AjChloroData, chloroChart.Series["ajCurve"]); AddAsymptotePoints(paramSet.AtChloroData, chloroChart.Series["atCurve"]); // Set the points on the asymptote curve for parameter set 1, intercellular AddAsymptotePoints(paramSet.AcInterData, interChart.Series["acCurve"]); AddAsymptotePoints(paramSet.AjInterData, interChart.Series["ajCurve"]); AddAsymptotePoints(paramSet.AtInterData, interChart.Series["atCurve"]); var title = new Title($"LeafWeb curveID = {curveId}\n{chartTitle}"){Font = fonts.Title}; chloroChart.Titles.Add(title); interChart.Titles.Add(title); chloroChart.ChartAreas["ChartArea"].AxisX.TitleFont = fonts.Axis; chloroChart.ChartAreas["ChartArea"].AxisY.TitleFont = fonts.Axis; interChart.ChartAreas["ChartArea"].AxisX.TitleFont = fonts.Axis; interChart.ChartAreas["ChartArea"].AxisY.TitleFont = fonts.Axis; yield return chloroChart; yield return interChart; } private static Series NewTpuSeries(IReadOnlyCollection data, ChartSizes sizes) { var seriesName = "TPU-limited"; if (data.Count == 0) seriesName = "Curve Asymptote"; var series3 = new Series(seriesName) { MarkerSize = sizes.TpuLimitedMarkerSize, BorderWidth = sizes.TpuLimitedBorderWidth, XValueType = ChartValueType.Double, ChartType = SeriesChartType.Point, MarkerStyle = MarkerStyle.Square, ShadowColor = Color.Black, BorderColor = Color.Black, Color = Color.Orange, ShadowOffset = 0, YValueType = ChartValueType.Double }; return series3; } private static void AddAnetMeasPoints(IEnumerable data, Series series) { // Set the points for the series from the ArrayList foreach (var xy in data) { series.Points.AddXY(xy.X, xy.Y); } } private static void AddAsymptotePoints(IEnumerable data, Series series) { // Set the points for the series from the ArrayList foreach (var xy in data.Where(xy => (xy.X != -9999) && (xy.Y != -9999))) { series.Points.AddXY(xy.X, xy.Y); } } private static Chart CreateEmptyChart(string axisXTitle, ChartSizes sizes, Fonts fonts) { var borderColor = Color.FromArgb(180, 26, 59, 105); var chart = new Chart { BackColor = Color.White, Width = Unit.Pixel(sizes.Width), Height = Unit.Pixel(sizes.Height), //BorderSkin = {SkinStyle = BorderSkinStyle.None}, BorderColor = borderColor, BorderlineColor = borderColor, BorderlineWidth = sizes.BorderlineWidth, BorderlineDashStyle = ChartDashStyle.Solid }; chart.Legends.Add(new Legend { Enabled = true, IsTextAutoFit = false, Name = "Default", Docking = Docking.Bottom, BackColor = Color.Transparent, Font = fonts.Regular }); chart.ChartAreas.Add(new ChartArea { Name = "ChartArea", BorderColor = Color.FromArgb(64, 64, 64, 64), BorderDashStyle = ChartDashStyle.Solid, BackSecondaryColor = Color.White, BackColor = Color.OldLace, ShadowColor = Color.Transparent, BackGradientStyle = GradientStyle.TopBottom, AxisY = new Axis { LineColor = Color.FromArgb(64, 64, 64, 64), Title = "Net assimilation rate (umol/m2/s)", LabelStyle = { Font = fonts.Regular }, MajorGrid = new Grid { LineColor = Color.FromArgb(64, 64, 64, 64)} }, AxisX = new Axis { LineColor = Color.FromArgb(64, 64, 64, 64), Minimum = 0, Title = axisXTitle, LabelStyle = { Font = fonts.Regular }, MajorGrid = new Grid { LineColor = Color.FromArgb(64, 64, 64, 64)} } }); chart.Series.Add(new Series { MarkerSize = sizes.RubiscoLimitedMarkerSize, BorderWidth = sizes.RubiscoLimitedBorderWidth, XValueType = ChartValueType.Double, Name = "Rubisco-limited", ChartType = SeriesChartType.Point, MarkerStyle = MarkerStyle.Diamond, ShadowColor = Color.Black, BorderColor = borderColor, Color = Color.Red, ShadowOffset = 0, YValueType = ChartValueType.Double }); chart.Series.Add(new Series { MarkerSize = sizes.RuBPMarkerSize, BorderWidth = sizes.RuBPBorderWidth, XValueType = ChartValueType.Double, Name = "RuBP regeneration-limited", ChartType = SeriesChartType.Point, MarkerStyle = MarkerStyle.Circle, ShadowColor = Color.Black, BorderColor = borderColor, Color = Color.Blue, ShadowOffset = 0, YValueType = ChartValueType.Double }); chart.Series.Add(new Series { MarkerSize = sizes.aCurveMarkerSize, BorderWidth = sizes.aCurveBorderWidth, XValueType = ChartValueType.Double, Name = "acCurve", ChartType = SeriesChartType.Line, MarkerStyle = MarkerStyle.None, ShadowColor = Color.Black, BorderColor = borderColor, Color = Color.Red, ShadowOffset = 0, YValueType = ChartValueType.Double, IsVisibleInLegend = false }); chart.Series.Add(new Series { MarkerSize = sizes.aCurveMarkerSize, BorderWidth = sizes.aCurveBorderWidth, XValueType = ChartValueType.Double, Name = "ajCurve", ChartType = SeriesChartType.Line, MarkerStyle = MarkerStyle.None, ShadowColor = Color.Black, BorderColor = borderColor, Color = Color.Blue, ShadowOffset = 0, YValueType = ChartValueType.Double, IsVisibleInLegend = false }); chart.Series.Add(new Series { MarkerSize = sizes.aCurveMarkerSize, BorderWidth = sizes.aCurveBorderWidth, XValueType = ChartValueType.Double, Name = "atCurve", ChartType = SeriesChartType.Line, MarkerStyle = MarkerStyle.None, ShadowColor = Color.Black, BorderColor = borderColor, Color = Color.Orange, ShadowOffset = 0, YValueType = ChartValueType.Double, IsVisibleInLegend = false }); return chart; } } }