Add violin plots for reliability

And move custom imraii stuff to imraii2
This commit is contained in:
Asriel Camora
2023-11-13 02:35:26 -08:00
parent f63483c9bd
commit bdce750238
10 changed files with 248 additions and 99 deletions
+71 -31
View File
@@ -2,12 +2,16 @@ using Craftimizer.Utils;
using Dalamud.Interface;
using Dalamud.Interface.Utility.Raii;
using ImGuiNET;
using ImPlotNET;
using MathNet.Numerics.Statistics;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -130,37 +134,6 @@ internal static class ImGuiUtils
ImGui.PopID();
}
private struct EndUnconditionally : ImRaii.IEndObject, IDisposable
{
private Action EndAction { get; }
public bool Success { get; }
public bool Disposed { get; private set; }
public EndUnconditionally(Action endAction, bool success)
{
EndAction = endAction;
Success = success;
Disposed = false;
}
public void Dispose()
{
if (!Disposed)
{
EndAction();
Disposed = true;
}
}
}
public static ImRaii.IEndObject GroupPanel(string name, float width, out float internalWidth)
{
internalWidth = BeginGroupPanel(name, width);
return new EndUnconditionally(EndGroupPanel, true);
}
private static Vector2 UnitCircle(float theta)
{
var (s, c) = MathF.SinCos(theta);
@@ -168,6 +141,7 @@ internal static class ImGuiUtils
return new Vector2(c, -s);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float Lerp(float a, float b, float t) =>
MathF.FusedMultiplyAdd(b - a, t, a);
@@ -251,6 +225,72 @@ internal static class ImGuiUtils
Arc(MathF.PI / 2, MathF.PI / 2 - MathF.Tau * Math.Clamp(value, 0, 1), radiusInner, radiusOuter, backgroundColor, filledColor);
}
public sealed class ViolinData
{
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
public float X, Y, Y2;
public Point(float x, float y, float y2)
{
X = x;
Y = y;
Y2 = y2;
}
}
public ReadOnlySpan<Point> Data => (DataArray ?? Array.Empty<Point>()).AsSpan();
private Point[]? DataArray { get; set; }
public readonly float Min;
public readonly float Max;
public ViolinData(IEnumerable<int> samples, float min, float max, int resolution, double bandwidth)
{
Min = min;
Max = max;
bandwidth *= Max - Min;
var samplesList = samples.AsParallel().Select(s => (double)s).ToArray();
_ = Task.Run(() => {
var s = Stopwatch.StartNew();
var data = ParallelEnumerable.Range(0, resolution)
.Select(n => Lerp(min, max, n / (float)resolution))
.Select(n => (n, (float)KernelDensity.EstimateGaussian(n, bandwidth, samplesList)))
.Select(n => new Point(n.n, n.Item2, -n.Item2));
DataArray = data.ToArray();
s.Stop();
Log.Debug($"Violin plot processing took {s.Elapsed.TotalMilliseconds:0.00}ms");
});
}
}
public static void ViolinPlot(in ViolinData data, Vector2 size)
{
using var padding = ImRaii2.PushStyle(ImPlotStyleVar.PlotPadding, Vector2.Zero);
using var plotBg = ImRaii2.PushColor(ImPlotCol.PlotBg, Vector4.Zero);
using var frameBg = ImRaii2.PushColor(ImPlotCol.FrameBg, Vector4.Zero);
using var fill = ImRaii2.PushColor(ImPlotCol.Fill, Vector4.One.WithAlpha(.5f));
using var plot = ImRaii2.Plot("##violin", size, ImPlotFlags.CanvasOnly);
if (plot)
{
ImPlot.SetupAxes(null, null, ImPlotAxisFlags.NoDecorations, ImPlotAxisFlags.NoDecorations | ImPlotAxisFlags.AutoFit);
ImPlot.SetupAxisLimits(ImAxis.X1, data.Min, data.Max, ImPlotCond.Always);
ImPlot.SetupFinish();
if (data.Data is { } points && !points.IsEmpty)
{
unsafe {
var label_id = stackalloc byte[] { (byte)'\0' };
fixed (ViolinData.Point* p = points)
{
ImPlotNative.ImPlot_PlotShaded_FloatPtrFloatPtrFloatPtr(label_id, &p->X, &p->Y, &p->Y2, points.Length, ImPlotShadedFlags.None, 0, sizeof(ViolinData.Point));
}
}
}
}
}
private sealed class SearchableComboData<T> where T : class
{
public readonly ImmutableArray<T> items;