Skip to content

Commit

Permalink
Improvements to LogScale in bar graphs (#3284)
Browse files Browse the repository at this point in the history
Fixed so that log scale can be used with "Ratio to Standard" normalization methods on Peak Area Replicate Comparison bar graph.
  • Loading branch information
nickshulman authored Dec 28, 2024
1 parent 30b9a51 commit 9d35570
Show file tree
Hide file tree
Showing 11 changed files with 339 additions and 57 deletions.
4 changes: 2 additions & 2 deletions pwiz_tools/Shared/zedgraph/ZedGraph/CurveList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ public void GetRange( bool bIgnoreInitial, bool isBoundedRanges, GraphPane pane
pane._barSettings.Base == BarBase.X2 )
{
// Only force z=0 for BarItems, not HiLowBarItems
if ( ! (curve is HiLowBarItem) )
if (!yScale.IsLog && !(curve is HiLowBarItem))
{
if ( tYMinVal > 0 )
tYMinVal = 0;
Expand All @@ -496,7 +496,7 @@ public void GetRange( bool bIgnoreInitial, bool isBoundedRanges, GraphPane pane
else
{
// Only force z=0 for BarItems, not HiLowBarItems
if ( !( curve is HiLowBarItem ) )
if (!xScale.IsLog && !(curve is HiLowBarItem ))
{
if ( tXMinVal > 0 )
tXMinVal = 0;
Expand Down
10 changes: 9 additions & 1 deletion pwiz_tools/Skyline/Controls/Graphs/AreaPeptideGraphPane.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ protected override void UpdateAxes()
var maxY = GraphHelper.GetMaxY(CurveList, this);
GraphHelper.ReformatYAxis(this, maxY);

FixedYMin = YAxis.Scale.Min = Settings.Default.AreaLogScale ? 1 : 0;
if (Settings.Default.AreaLogScale)
{
YAxis.Scale.MinAuto = true;
FixedYMin = null;
}
else
{
FixedYMin = 0;
}
}

internal class AreaGraphData : GraphData
Expand Down
42 changes: 22 additions & 20 deletions pwiz_tools/Skyline/Controls/Graphs/AreaReplicateGraphPane.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ private static BarType BarType
return BarType.PercentStack;
}

if (Settings.Default.AreaLogScale && AreaGraphController.AreaNormalizeOption.AllowLogScale)
{
return BarType.Cluster;
}

return BarType.Stack;
}
}
Expand Down Expand Up @@ -653,11 +658,6 @@ public override void UpdateGraph(bool selectionChanged)
ParentGroupNode = parentGroupNode;
SumAreas = sumAreas;

// Draw a box around the currently selected replicate
if (ShowSelection && maxArea > -double.MaxValue)
{
AddSelection(normalizeOption, selectedReplicateIndex, sumArea, maxArea);
}
// Reset the scale when the parent node changes
bool resetAxes = (_parentNode == null || !ReferenceEquals(_parentNode.Id, parentNode.Id));
_parentNode = parentNode;
Expand Down Expand Up @@ -692,6 +692,11 @@ public override void UpdateGraph(bool selectionChanged)
AddDotProductLine(graphData);

UpdateAxes(resetAxes, aggregateOp, dataScalingOption, normalizeOption);
// Draw a box around the currently selected replicate
if (ShowSelection && maxArea > -double.MaxValue)
{
AddSelection(normalizeOption, selectedReplicateIndex, sumArea, maxArea);
}
}

private void AddDotProductLine(AreaGraphData graphData)
Expand Down Expand Up @@ -832,12 +837,7 @@ private void AddSelection(NormalizeOption areaView, int selectedReplicateIndex,
}
else
{
GraphObjList.Add(new BoxObj(selectedReplicateIndex + .5, yValue, 0.99,
-yValue, Color.Black, Color.Empty)
// Just passing in yValue here doesn't work when log scale is enabled, -yValue works with and without log scale enabled
{
IsClippedToChartRect = true,
});
DrawSelectionBox(selectedReplicateIndex, yValue, 0);
}
}

Expand Down Expand Up @@ -923,11 +923,9 @@ private void UpdateAxes(bool resetAxes, GraphValues.AggregateOp aggregateOp, Dat
YAxis.Scale.MinAuto = false;
FixedYMin = YAxis.Scale.Min = 0;
}
else if (Settings.Default.AreaLogScale)
else if (Settings.Default.AreaLogScale && BarSettings.Type == BarType.Cluster)
{
// If currently not log scale, reset the y-axis max
if (YAxis.Type != AxisType.Log)
YAxis.Scale.MaxAuto = true;
YAxis.Scale.MaxAuto = true;
if (Settings.Default.PeakAreaMaxArea != 0)
{
YAxis.Scale.MaxAuto = false;
Expand All @@ -936,8 +934,8 @@ private void UpdateAxes(bool resetAxes, GraphValues.AggregateOp aggregateOp, Dat

YAxis.Type = AxisType.Log;
YAxis.Title.Text = GraphValues.AnnotateLogAxisTitle(GetYAxisTitle(aggregateOp, normalizeOption));
YAxis.Scale.MinAuto = false;
FixedYMin = YAxis.Scale.Min = 1;
YAxis.Scale.MinAuto = true;
FixedYMin = null;
}
else
{
Expand All @@ -964,16 +962,20 @@ private void UpdateAxes(bool resetAxes, GraphValues.AggregateOp aggregateOp, Dat
YAxis.Scale.MaxAuto = true;
}
Legend.IsVisible = !IsMultiSelect && Settings.Default.ShowPeakAreaLegend;
RemoveInvalidPointValues();
AxisChange();

// Reformat Y-Axis for labels and whiskers
var maxY = GraphHelper.GetMaxY(CurveList,this);
if (DotProductLabelsVisible || DotProductLineVisible)
if ((DotProductLabelsVisible || DotProductLineVisible) && !YAxis.Scale.IsLog)
{
var reservedSpace = _labelHeight * 2;
var unitsPerPixel = maxY / (Chart.Rect.Height - reservedSpace);
var extraSpace = reservedSpace*unitsPerPixel;
maxY += extraSpace;
if (unitsPerPixel > 0)
{
var extraSpace = reservedSpace * unitsPerPixel;
maxY += extraSpace;
}
}

GraphHelper.ReformatYAxis(this, maxY > 0 ? maxY : 0.1); // Avoid same min and max, since it blanks the entire graph pane
Expand Down
36 changes: 26 additions & 10 deletions pwiz_tools/Skyline/Controls/Graphs/GraphHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -579,18 +579,34 @@ public static void FormatFontSize(GraphPane g, float fontSize)
g.Legend.FontSpec.Size = fontSize;
}

/// <summary>
/// Ensure that the maximum value displayed on the Y-axis is greater than <paramref name="myMaxY"/>.
/// This is used when the maximum value is different from what ZedGraph thinks it should be, such as because
/// of the extra space for <see cref="MeanErrorBarItem"/> in <see cref="GetMaxY"/> or the space required
/// for the dot product lines and labels.
/// </summary>
public static void ReformatYAxis(GraphPane g, double myMaxY)
{
var _max = MyMod(myMaxY, g.YAxis.Scale.MajorStep) == 0.0 ? myMaxY :
myMaxY + g.YAxis.Scale.MajorStep - MyMod(myMaxY, g.YAxis.Scale.MajorStep);
g.YAxis.Scale.Max = _max;
}
protected static double MyMod(double x, double y)
{
if (y == 0)
return 0;
var temp = x / y;
return y * (temp - Math.Floor(temp));
var yAxisScale = g.YAxis.Scale;
double newMax;
if (yAxisScale.IsLog)
{
newMax = Math.Pow(10.0, Math.Ceiling(Math.Log10(myMaxY)));
}
else
{
var majorStep = yAxisScale.MajorStep;
if (majorStep <= 0)
{
return;
}
newMax = Math.Ceiling(myMaxY / majorStep) * majorStep;
}

if (newMax != yAxisScale.Max && newMax > yAxisScale.Min)
{
yAxisScale.Max = newMax;
}
}

// Find maximum value for bar graph including whiskers
Expand Down
96 changes: 96 additions & 0 deletions pwiz_tools/Skyline/Controls/Graphs/SummaryBarGraphPaneBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,102 @@ protected bool IsRepeatRemovalAllowed
set { _axisLabelScaler.IsRepeatRemovalAllowed = value; }
}

protected void RemoveInvalidPointValues()
{
if (!YAxis.Scale.IsLog)
{
return;
}

foreach (var curve in CurveList)
{
if (curve.IsY2Axis)
{
continue;
}

curve.Points = NonPositiveToMissing(curve.Points);
}
}

/// <summary>
/// Replace with PointPairBase.Missing all points which do not have a positive y coordinate
/// and cannot be correctly displayed on a log scale.
/// </summary>
protected static IPointList NonPositiveToMissing(IPointList pointList)
{
int nPts = pointList.Count;
if (!Enumerable.Range(0, nPts).Any(i => pointList[i].Y <= 0))
{
return pointList;
}

var newPoints = new List<PointPair>(pointList.Count);
for (int i = 0; i < nPts; i++)
{
var pt = pointList[i];
if (pt.Y <= 0)
{
newPoints.Add(new PointPair(pt.X, PointPairBase.Missing));
}
else
{
newPoints.Add(pt);
}
}

return new PointPairList(newPoints);
}

protected void DrawSelectionBox(int xValue, double yMax, double yMin)
{
if (YAxis.Scale.IsLog)
{
// If it's a log scale, the bottom should be controlled by the lowest value displayed
var minPositiveYValue = GetMinPositiveYValue();
if (!minPositiveYValue.HasValue)
{
return;
}

// The Y-axis is usually zoomed to Math.Pow(10.0, Math.Floor(Math.Log10(minPositiveYValue.Value)))
// Make the selection box extend 3 orders of magnitude below the lowest value so that it goes all the way
// even if the user zooms out a bit.
yMin = minPositiveYValue.Value / 1000;
}
GraphObjList.Add(new BoxObj(xValue + .5, yMax, 0.99,
yMin - yMax, Color.Black, Color.Empty)
{
IsClippedToChartRect = true,
});
}

protected double? GetMinPositiveYValue()
{
double? minValue = null;
foreach (var curve in CurveList)
{
if (curve.IsY2Axis)
{
continue;
}

for (int i = 0; i < curve.NPts; i++)
{
var pt = curve.Points[i];
if (pt.Y > 0)
{
if (!minValue.HasValue || minValue.Value > pt.Y)
{
minValue = pt.Y;
}
}
}
}

return minValue;
}

#region Test Support Methods
public string[] GetOriginalXAxisLabels()
{
Expand Down
18 changes: 5 additions & 13 deletions pwiz_tools/Skyline/Controls/Graphs/SummaryPeptideGraphPane.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,19 +141,11 @@ public override void UpdateGraph(bool selectionChanged)
CurveList.Add(curveItem);
}

UpdateAxes();
if (ShowSelection && SelectedIndex != -1)
{
double yValue = _graphData.SelectedMaxY;
double yMin = _graphData.SelectedMinY;
double height = yValue - yMin;
GraphObjList.Add(new BoxObj(SelectedIndex + .5, yValue, 0.99,
height, Color.Black, Color.Empty)
{
IsClippedToChartRect = true,
});
DrawSelectionBox(SelectedIndex, _graphData.SelectedMaxY, _graphData.SelectedMinY);
}

UpdateAxes();
}

protected abstract GraphData CreateGraphData(SrmDocument document, PeptideGroupDocNode selectedProtein,
Expand All @@ -170,8 +162,8 @@ protected void UpdateAxes(bool allowLogScale)
{
YAxis.Title.Text = TextUtil.SpaceSeparate(GraphsResources.SummaryPeptideGraphPane_UpdateAxes_Log, YAxis.Title.Text);
YAxis.Type = AxisType.Log;
YAxis.Scale.MinAuto = false;
FixedYMin = YAxis.Scale.Min = 1;
YAxis.Scale.MinAuto = true;
FixedYMin = null;
YAxis.Scale.Max = _graphData.MaxY * 10;
}
else
Expand Down Expand Up @@ -227,7 +219,7 @@ protected void UpdateAxes(bool allowLogScale)

XAxis.Scale.TextLabels = _graphData.Labels;
ScaleAxisLabels();

RemoveInvalidPointValues();
AxisChange();
}

Expand Down
13 changes: 13 additions & 0 deletions pwiz_tools/Skyline/Model/Results/NormalizeOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ public bool IsRatioToLabel
get { return NormalizationMethod is NormalizationMethod.RatioToLabel; }
}

/// <summary>
/// Returns true if this normalization method can be displayed on an axis with a log scale.
/// </summary>
public bool AllowLogScale
{
get
{
// "MAXIMUM" and "TOTAL" cannot be displayed on a log scale because they always have to be displayed on a stacked bar plot
// and stacked bar plots do not make sense in a log scale.
return this != MAXIMUM && this != TOTAL;
}
}

public override string ToString()
{
return Caption;
Expand Down
14 changes: 3 additions & 11 deletions pwiz_tools/Skyline/SkylineGraphs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4455,16 +4455,6 @@ public void SetNormalizationMethod(NormalizeOption normalizeOption)
{
Settings.Default.AreaNormalizeOption = normalizeOption;
SequenceTree.NormalizeOption = normalizeOption;
if (AreaNormalizeOption == NormalizeOption.TOTAL ||
AreaNormalizeOption == NormalizeOption.MAXIMUM ||
AreaNormalizeOption == NormalizeOption.GLOBAL_STANDARDS ||
AreaNormalizeOption.IsRatioToLabel)
{
// Do not let the user combine Log with Ratios because
// the log scale does not work well with numbers that are less than 1.
// (this should be fixed)
Settings.Default.AreaLogScale = false;
}
UpdatePeakAreaGraph();
}

Expand Down Expand Up @@ -4646,8 +4636,10 @@ private void peptideLogScaleContextMenuItem_Click(object sender, EventArgs e)
public void ShowPeptideLogScale(bool isChecked)
{
Settings.Default.AreaLogScale = isChecked ;
if (isChecked)
if (isChecked && !AreaNormalizeOption.AllowLogScale)
{
AreaNormalizeOption = NormalizeOption.NONE;
}
UpdateSummaryGraphs();
}

Expand Down
Loading

0 comments on commit 9d35570

Please sign in to comment.