1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-13 19:54:15 +08:00

Improve ranked play rating graph's x-axis divisions (#37534)

the x axis division was set to a fixed number of steps rather than
picking a neat step size, which created uneven numbers. this pr changes
this so an appropriate factor is determined, the x-axis min/max is
floor'd/ceil'd to that factor and the divisions are created based on
that factor. the cumulative rating line also extends to the new end of
the graph.

in addition, the bars of the bar chart are now aligned using the left
edge of the bar rather than the center. in the after-image, note how the
left edge of the bar for 1600 rating aligns with the division. (this is
based on the assumption that a rating bucket, say "1500", spans the
interval [1500, 1600]. if the bucket spans [1450, 1550] instead, i will
revert the change)

before
<img width="632" height="217" alt="image"
src="https://github.com/user-attachments/assets/b7053d43-99bb-4e5b-87a4-dcec37d56b50"
/>

after
<img width="608" height="230" alt="image"
src="https://github.com/user-attachments/assets/3f9e4284-f1b1-4bcb-8f70-f75f4e242b19"
/>

could optimize the while loop into a single mathematical expression, but
this is easier to read imo. lmk if you'd prefer the expression instead
This commit is contained in:
IceDynamix
2026-05-11 11:31:26 +02:00
committed by GitHub
Unverified
parent 25df5cc602
commit c84777d7bf
@@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
public partial class RatingDistributionGraph : CompositeDrawable, IHasCustomTooltip<RatingDistributionGraph.RatingDistributionGraphTooltipData>
{
private const int y_divisions = 4;
private const int x_divisions = 16;
private const int x_max_divisions = 16;
[Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!;
@@ -50,6 +50,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
private int? userRating;
private (int min, int max, int step) xRange;
private (int min, int max) yRange;
private int xDivisionStep = 1;
[BackgroundDependencyLoader]
private void load()
@@ -237,6 +238,17 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
data.Zip(data.Skip(1), (a, b) => Math.Abs(b.x - a.x)).DefaultIfEmpty().Min()
);
xDivisionStep = Math.Max(xRange.step, 50); // avoid division by zero
// Keep increasing the division until number of lines is appropriately low
while ((xRange.max - xRange.min) / xDivisionStep > x_max_divisions)
{
xDivisionStep *= 2;
}
xRange.min = (int)floorWithFactor(xRange.min, xDivisionStep);
xRange.max = (int)ceilingWithFactor(xRange.max, xDivisionStep);
if (userRating < xRange.min)
{
this.data = this.data.Prepend((userRating.Value, 1)).ToArray();
@@ -249,9 +261,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
xRange.max = userRating.Value;
}
int yMax = this.data.Select(d => d.y).DefaultIfEmpty().Max();
yRange = (
0,
(int)roundToSignificant(this.data.Select(d => d.y).DefaultIfEmpty().Max())
(int)ceilingWithFactor(yMax, significantOfNumber(yMax))
);
updateGraph();
@@ -274,13 +288,15 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
barsContainer.Clear();
userRatingContainer.Clear();
for (int step = 0; step <= x_divisions; step++)
int xDivisions = Math.Max(1, (xRange.max - xRange.min) / xDivisionStep);
for (int step = 0; step <= xDivisions; step++)
{
gridContainer.Add(new VerticalLine
{
RelativeSizeAxes = Axes.Y,
RelativePositionAxes = Axes.X,
X = (float)step / x_divisions,
X = (float)step / xDivisions,
Colour = colourProvider.Background1
});
@@ -289,10 +305,10 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
Anchor = Anchor.TopLeft,
Origin = Anchor.CentreRight,
RelativePositionAxes = Axes.X,
X = (float)step / x_divisions,
X = (float)step / xDivisions,
Margin = new MarginPadding { Right = -2 },
Rotation = -40,
Text = (xRange.min + (xRange.max - xRange.min) / x_divisions * step).ToString(),
Text = (xRange.min + xDivisionStep * step).ToString(),
UseFullGlyphHeight = false,
Font = OsuFont.Default.With(size: 12),
Colour = colourProvider.Foreground1
@@ -337,7 +353,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
{
barsContainer.Add(new Container
{
Origin = Anchor.BottomCentre,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
RelativePositionAxes = Axes.X,
RelativeSizeAxes = Axes.Both,
@@ -393,7 +409,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
currentCount += d.y;
float p = (float)currentCount / totalCount;
return new Vector2(pointOnGraph(d.x, 0).X, 1 - p);
}).ToArray();
}).Append(new Vector2(1, 0)).ToArray();
});
private Vector2 pointOnGraph(int x, int y)
@@ -403,13 +419,25 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
return new Vector2(xPos, yPos);
}
private static double roundToSignificant(double value)
private static double significantOfNumber(double value)
{
if (value == 0)
return Math.Pow(10, Math.Floor(Math.Log10(value)));
}
private static double floorWithFactor(double value, double factor)
{
if (value == 0 || factor == 0)
return 0;
double scale = Math.Pow(10, Math.Floor(Math.Log10(value)));
return Math.Ceiling(value / scale) * scale;
return Math.Floor(value / factor) * factor;
}
private static double ceilingWithFactor(double value, double factor)
{
if (value == 0 || factor == 0)
return 0;
return Math.Ceiling(value / factor) * factor;
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
@@ -474,7 +502,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
int currentCount = 0;
int totalCount = data.Sum(p => p.y);
for (int i = 0; i < cumulativePath.Vertices.Count; i++)
for (int i = 0; i < data.Length; i++)
{
currentCount += data[i].y;