using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using HeuristicLab.Collections; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using ICSharpCode.SharpZipLib.Zip; namespace HeuristicLab.Analysis.FitnessLandscape.BoxCharts { [Item("Box Chart Creator", "Visualizes essential run information by creating an overview chart.")] [StorableClass] public class BoxChartCreator : ParameterizedNamedItem, IRunCollectionModifier { public enum AppendModes { None, Horizontal, Vertical }; #region Parameters public ValueParameter ChartNameParameter { get { return (ValueParameter)Parameters["ChartName"]; } } public ValueParameter> ElementsParameter { get { return (ValueParameter>)Parameters["Elements"]; } } public ValueParameter SizeParameter { get { return (ValueParameter)Parameters["Size"]; } } public ValueParameter PaddingParameter { get { return (ValueParameter)Parameters["Padding"]; } } public ValueParameter ZipFileNameParameter { get { return (ValueParameter)Parameters["ZipFileName"]; } } public IConstrainedValueParameter AppendModeParameter { get { return (IConstrainedValueParameter)Parameters["AppendMode"]; } } #endregion #region Parameter Values protected string ChartName { get { return ChartNameParameter.Value.Value; } } protected string ZipFileName { get { return ZipFileNameParameter.Value.Value; } } protected int Size { get { return SizeParameter.Value.Value; } } protected int Padding { get { return PaddingParameter.Value.Value; } } protected AppendModes AppendMode { get { return (AppendModes)Enum.Parse(typeof(AppendModes), AppendModeParameter.Value.Value); } } protected List Generators { get { return ElementsParameter.Value.CheckedItems.Select(i => i.Value).ToList(); } } #endregion #region Construction & Cloning [StorableConstructor] protected BoxChartCreator(bool deserializing) : base(deserializing) { } protected BoxChartCreator(BoxChartCreator original, Cloner cloner) : base(original, cloner) { RegisterEvents(); } public BoxChartCreator() { Parameters.Add(new ValueParameter("ChartName", "The result name of the chart.", new StringValue("Chart"))); Parameters.Add(new ValueParameter>("Elements", "List of patient chart element generators.", new CheckedItemList())); Parameters.Add(new ValueParameter("Size", "The size of one box in pixels.", new IntValue(50))); Parameters.Add(new ValueParameter("Padding", "The padding inside the boxes", new IntValue(1))); Parameters.Add(new ValueParameter("ZipFileName", "The name of the zip file that will contain all generated charts.", new StringValue(""))); Parameters.Add(new ConstrainedValueParameter("AppendMode", "Determines how coordinates of new elements are calculated.", new ItemSet(Enum.GetNames(typeof(AppendModes)).Select(v => new StringValue(v))))); AppendModeParameter.Value = AppendModeParameter.ValidValues.SingleOrDefault(v => v.Value == AppendModes.Horizontal.ToString()); RegisterEvents(); } public override IDeepCloneable Clone(Cloner cloner) { return new BoxChartCreator(this, cloner); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (!Parameters.ContainsKey("ZipFileName")) Parameters.Add(new ValueParameter("ZipFileName", "The name of the zip file that will contain all generated charts.", new StringValue(""))); if (!Parameters.ContainsKey("AppendMode")) { Parameters.Add(new ConstrainedValueParameter("AppendMode", "Determines how coordinates of new elements are calculated.", new ItemSet(Enum.GetNames(typeof(AppendModes)).Select(v => new StringValue(v))))); AppendModeParameter.Value = AppendModeParameter.ValidValues.SingleOrDefault(v => v.Value == AppendModes.Horizontal.ToString()); } RegisterEvents(); } #endregion private void RegisterEvents() { ElementsParameter.ValueChanged += ElementsParameter_ValueChanged; ElementsParameter.Value.ItemsAdded += ElementsParameter_Value_ItemsAdded; } private void ElementsParameter_ValueChanged(object sender, EventArgs e) { ElementsParameter.Value.ItemsAdded += ElementsParameter_Value_ItemsAdded; } private void ElementsParameter_Value_ItemsAdded(object sender, CollectionItemsChangedEventArgs> e) { if (sender != ElementsParameter.Value) { var oldParameter = sender as ICheckedItemList; if (oldParameter != null) oldParameter.ItemsAdded -= ElementsParameter_Value_ItemsAdded; } else { var generators = Generators; var newItems = e.Items.Select(kvp => kvp.Value).ToList(); switch (AppendMode) { case AppendModes.Horizontal: foreach (var generator in newItems) { generator.Y = generators.Max(g => g.Y + g.RowSpan - 1); generator.X = generators.Where(g => g.Y + g.RowSpan - 1 == generator.Y).Max(g => g.X + g.ColSpan); } break; case AppendModes.Vertical: foreach (var generator in newItems) { generator.X = generators.Max(g => g.X + g.ColSpan - 1); generator.Y = generators.Where(g => g.X + g.ColSpan - 1 == generator.X).Max(g => g.Y + g.RowSpan); } break; } } } #region IRunCollectionModifier Members public void Modify(List runs) { var bitmaps = new Dictionary(); var generators = Generators; var maxX = generators.Max(g => g.X + g.ColSpan); var maxY = generators.Max(g => g.Y + g.RowSpan); for (int i = 0; i < runs.Count; i++) { var run = runs[i]; var b = new Bitmap(maxX * Size, maxY * Size); using (var g = Graphics.FromImage(b)) { g.FillRectangle(SystemBrushes.Control, 0, 0, b.Width, b.Height); foreach (var gen in generators) { g.SetClip(new Rectangle(gen.X * Size + Padding, gen.Y * Size + Padding, gen.ColSpan * Size - 2 * Padding, gen.RowSpan * Size - 2 * Padding)); gen.Draw(run, g); g.ResetClip(); } } run.Results[ChartName] = new BitmapItem(b); bitmaps.Add(string.Format("{0}.png", run.Name), (Bitmap)b.Clone()); } SaveAllBitmaps(bitmaps); } private void SaveAllBitmaps(Dictionary bitmaps) { if (ZipFileNameParameter.Value == null && string.IsNullOrEmpty(ZipFileName)) return; var filename = ZipFileName; if (!filename.ToLowerInvariant().EndsWith("zip")) filename = string.Format("{0}.zip", filename); using (var stream = File.Create(filename)) { using (var zipStream = new ZipOutputStream(stream)) { foreach (var bitmap in bitmaps) { zipStream.PutNextEntry(new ZipEntry(bitmap.Key) { DateTime = DateTime.Now }); using (var s = new MemoryStream()) { bitmap.Value.Save(s, ImageFormat.Png); zipStream.Write(s.ToArray(), 0, (int)s.Length); } } } } } #endregion } }