Add violin plots for reliability
And move custom imraii stuff to imraii2
This commit is contained in:
+71
-31
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user