mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 16:16:31 +00:00
better view for class distribution
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
<UserControl x:Class="Azaion.Dataset.Controls.ClassDistribution"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:controls="clr-namespace:Azaion.Dataset.Controls"
|
||||
xmlns:dto="clr-namespace:Azaion.Common.DTO;assembly=Azaion.Common"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="400"
|
||||
FontFamily="Segoe UI">
|
||||
<UserControl.Resources>
|
||||
<controls:ProportionToWidthConverter x:Key="ProportionToWidthConverter"/>
|
||||
</UserControl.Resources>
|
||||
<ListView ItemsSource="{Binding Items, RelativeSource={RelativeSource AncestorType=controls:ClassDistribution}}"
|
||||
BorderThickness="0" Background="#FF333333" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style TargetType="ListViewItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Focusable" Value="False"/>
|
||||
<Setter Property="Margin" Value="0,1"/>
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type dto:ClusterDistribution}">
|
||||
<Grid Height="18" x:Name="ItemGrid"> <!-- Give the Grid a name -->
|
||||
<Border HorizontalAlignment="Left" VerticalAlignment="Stretch">
|
||||
<Border.Width>
|
||||
<MultiBinding Converter="{StaticResource ProportionToWidthConverter}">
|
||||
<Binding Path="BarWidth"/>
|
||||
<Binding Path="ActualWidth" ElementName="ItemGrid"/>
|
||||
</MultiBinding>
|
||||
</Border.Width>
|
||||
<Border.Background>
|
||||
<SolidColorBrush Color="{Binding Color}" Opacity="0.5"/>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
<TextBlock Text="{Binding Label}" VerticalAlignment="Center" Margin="5,0,0,0" Foreground="White" FontSize="12"/>
|
||||
<TextBlock Text="{Binding ClassCount}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,5,0" Foreground="White" FontSize="12"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Azaion.Common.DTO;
|
||||
|
||||
namespace Azaion.Dataset.Controls;
|
||||
|
||||
public partial class ClassDistribution : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty ItemsProperty =
|
||||
DependencyProperty.Register(nameof(Items), typeof(IEnumerable<ClusterDistribution>), typeof(ClassDistribution), new PropertyMetadata(null));
|
||||
|
||||
public IEnumerable<ClusterDistribution> Items
|
||||
{
|
||||
get => (IEnumerable<ClusterDistribution>)GetValue(ItemsProperty);
|
||||
set => SetValue(ItemsProperty, value);
|
||||
}
|
||||
|
||||
public ClassDistribution()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Azaion.Dataset.Controls
|
||||
{
|
||||
public class ProportionToWidthConverter : IMultiValueConverter
|
||||
{
|
||||
private const double MinPixelBarWidth = 2.0;
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values == null || values.Length < 2 ||
|
||||
!(values[0] is double proportion) ||
|
||||
!(values[1] is double containerActualWidth))
|
||||
return MinPixelBarWidth; // Default or fallback width
|
||||
|
||||
if (containerActualWidth <= 0 || !double.IsFinite(containerActualWidth) || double.IsNaN(containerActualWidth))
|
||||
return MinPixelBarWidth; // Container not ready or invalid
|
||||
|
||||
double calculatedWidth = proportion * containerActualWidth;
|
||||
|
||||
if (proportion >= 0 && calculatedWidth < MinPixelBarWidth)
|
||||
return MinPixelBarWidth;
|
||||
|
||||
return Math.Max(0, calculatedWidth); // Ensure width is not negative
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:vwp="clr-namespace:WpfToolkit.Controls;assembly=VirtualizingWrapPanel"
|
||||
xmlns:scottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"
|
||||
xmlns:controls="clr-namespace:Azaion.Common.Controls;assembly=Azaion.Common"
|
||||
xmlns:dto="clr-namespace:Azaion.Common.DTO;assembly=Azaion.Common"
|
||||
xmlns:controls1="clr-namespace:Azaion.Dataset.Controls"
|
||||
mc:Ignorable="d"
|
||||
Title="Переглядач анотацій" Height="900" Width="1200"
|
||||
WindowState="Maximized">
|
||||
@@ -104,7 +104,7 @@
|
||||
</controls:CanvasEditor>
|
||||
</TabItem>
|
||||
<TabItem Name="ClassDistributionTab" Header="Розподіл класів">
|
||||
<scottPlot:WpfPlot x:Name="ClassDistribution" />
|
||||
<controls1:ClassDistribution x:Name="ClassDistributionPlot"/>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
<StatusBar
|
||||
|
||||
@@ -6,6 +6,7 @@ using Azaion.Common.Database;
|
||||
using Azaion.Common.DTO;
|
||||
using Azaion.Common.DTO.Config;
|
||||
using Azaion.Common.Events;
|
||||
using Azaion.Common.Extensions;
|
||||
using Azaion.Common.Services;
|
||||
using Azaion.CommonSecurity.DTO;
|
||||
using Azaion.CommonSecurity.Services;
|
||||
@@ -13,8 +14,6 @@ using LinqToDB;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ScottPlot;
|
||||
using Color = ScottPlot.Color;
|
||||
|
||||
namespace Azaion.Dataset;
|
||||
|
||||
@@ -140,7 +139,7 @@ public partial class DatasetExplorer
|
||||
ExplorerEditor.CurrentAnnClass = LvClasses.CurrentDetectionClass ?? _annotationConfig.DetectionClasses.First();
|
||||
|
||||
await ReloadThumbnails();
|
||||
await LoadClassDistribution();
|
||||
LoadClassDistribution();
|
||||
|
||||
DataContext = this;
|
||||
}
|
||||
@@ -152,47 +151,29 @@ public partial class DatasetExplorer
|
||||
_annotationsDict[-1][annotation.Name] = annotation;
|
||||
}
|
||||
|
||||
private async Task LoadClassDistribution()
|
||||
private void LoadClassDistribution()
|
||||
{
|
||||
var data = _annotationsDict
|
||||
.Where(x => x.Key != -1)
|
||||
.Select(gr => new
|
||||
.OrderBy(x => x.Key)
|
||||
.Select(gr => new ClusterDistribution
|
||||
{
|
||||
gr.Key,
|
||||
_annotationConfig.DetectionClassesDict[gr.Key].ShortName,
|
||||
_annotationConfig.DetectionClassesDict[gr.Key].Color,
|
||||
Label = $"{_annotationConfig.DetectionClassesDict[gr.Key].UIName}: {gr.Value.Count}",
|
||||
Color = _annotationConfig.DetectionClassesDict[gr.Key].Color,
|
||||
ClassCount = gr.Value.Count
|
||||
})
|
||||
.Where(x => x.ClassCount > 0)
|
||||
.ToList();
|
||||
|
||||
var foregroundColor = Color.FromColor(System.Drawing.Color.Black);
|
||||
var maxClassCount = Math.Max(1, data.Max(x => x.ClassCount));
|
||||
|
||||
var bars = data.Select(x => new Bar
|
||||
foreach (var cl in data)
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Position = -1.5 * x.Key + 1,
|
||||
Label = x.ClassCount > 200 ? x.ClassCount.ToString() : "",
|
||||
FillColor = new Color(x.Color.R, x.Color.G, x.Color.B, x.Color.A),
|
||||
Value = x.ClassCount,
|
||||
CenterLabel = true,
|
||||
LabelOffset = 10
|
||||
}).ToList();
|
||||
|
||||
ClassDistribution.Plot.Add.Bars(bars);
|
||||
|
||||
foreach (var x in data)
|
||||
{
|
||||
var label = ClassDistribution.Plot.Add.Text(x.ShortName, 50, -1.5 * x.Key + 1.1);
|
||||
label.LabelFontColor = foregroundColor;
|
||||
label.LabelFontSize = 18;
|
||||
cl.Color = cl.Color.CreateTransparent(150);
|
||||
cl.BarWidth = Math.Clamp(cl.ClassCount / (double)maxClassCount, 0, 1);
|
||||
}
|
||||
|
||||
ClassDistribution.Plot.Axes.AutoScale();
|
||||
ClassDistribution.Plot.HideAxesAndGrid();
|
||||
ClassDistribution.Plot.FigureBackground.Color = new("#888888");
|
||||
|
||||
ClassDistribution.Refresh();
|
||||
await Task.CompletedTask;
|
||||
ClassDistributionPlot.Items = data;
|
||||
}
|
||||
|
||||
private async void RefreshThumbnailsBtnClick(object sender, RoutedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user