private void plotSeries(Canvas _graph, plotData _plotData, eZoom eZoom, eRescale eRescale)
{
if (isPlotting) return;
isPlotting = true;
if (!mouseScrollX && !mouseScrollY) setEvents(false);
double gw = _graph.ActualWidth - offsetL - offsetR;
double gh = _graph.ActualHeight - offsetT - offsetB;
double _nTickX = _plotData.nTickX > 0 ? _plotData.nTickX : nTickX;
double _nTickY = _plotData.nTickY > 0 ? _plotData.nTickY : nTickY;
_graph.Background = getBrush(borderColour); // Possible user change
/*******************************************************************************
* Axes scaling
******************************************************************************/
if (eZoom == eZoom.TRUE)
{
double minXtemp = _plotData.minX - _plotData.shiftX + posDown.X / gw * (_plotData.maxX - _plotData.minX);
double minYtemp = _plotData.maxY - _plotData.shiftY + posUp.Y / gh * (_plotData.minY - _plotData.maxY);
double maxXtemp = _plotData.minX - _plotData.shiftX + posUp.X / gw * (_plotData.maxX - _plotData.minX);
double maxYtemp = _plotData.maxY - _plotData.shiftY + posDown.Y / gh * (_plotData.minY - _plotData.maxY);
_plotData.minX = System.Math.Min(minXtemp, maxXtemp);
_plotData.minY = System.Math.Min(minYtemp, maxYtemp);
_plotData.maxX = System.Math.Max(minXtemp, maxXtemp);
_plotData.maxY = System.Math.Max(minYtemp, maxYtemp);
_plotData.shiftX = 0.0;
_plotData.shiftY = 0.0;
}
else if (eRescale == eRescale.TRUE)
{
_plotData.minX = 1.0e20;
_plotData.minY = 1.0e20;
_plotData.maxX = -1.0e20;
_plotData.maxY = -1.0e20;
foreach (seriesData _series in _plotData.series)
{
_plotData.minX = System.Math.Min(_plotData.minX, _series.minX);
_plotData.minY = System.Math.Min(_plotData.minY, _series.minY);
_plotData.maxX = System.Math.Max(_plotData.maxX, _series.maxX);
_plotData.maxY = System.Math.Max(_plotData.maxY, _series.maxY);
}
_plotData.shiftX = 0.0;
_plotData.shiftY = 0.0;
if (_plotData.userIntervalX == 0 && _plotData.userMaxX < _plotData.userMinX)
{
if (autoScale)
{
double interval = getInterval((_plotData.maxX - _plotData.minX) / nTickX);
_plotData.minX = interval * (int)(_plotData.minX / interval - 1);
_nTickX = 1 + (int)((_plotData.maxX - _plotData.minX) / interval);
_plotData.maxX = _plotData.minX + _nTickX * interval;
_plotData.nTickX = _nTickX;
}
else
{
round(ref _plotData.minX, ref _plotData.maxX);
_plotData.nTickX = 0;
_nTickX = nTickX;
}
}
else
{
if (_plotData.userMaxX >= _plotData.userMinX) _plotData.minX = _plotData.userMinX;
if (_plotData.userMaxX > _plotData.userMinX) _plotData.maxX = _plotData.userMaxX;
double interval = _plotData.userIntervalX > 0 ? _plotData.userIntervalX : getInterval((_plotData.maxX - _plotData.minX) / nTickX);
if (_plotData.userMaxX < _plotData.userMinX) _plotData.minX = interval * (int)(_plotData.minX / interval - 1);
_nTickX = (int)((_plotData.maxX - _plotData.minX) / interval);
if (_plotData.userMaxX <= _plotData.userMinX || _plotData.userMaxX > _plotData.userMinX + _nTickX * interval) _nTickX++;
_plotData.maxX = _plotData.minX + _nTickX * interval;
_plotData.nTickX = _nTickX;
}
if (_plotData.userIntervalY == 0 && _plotData.userMaxY < _plotData.userMinY)
{
if (autoScale)
{
double interval = getInterval((_plotData.maxY - _plotData.minY) / nTickY);
_plotData.minY = interval * (int)(_plotData.minY / interval - 1);
_nTickY = 1 + (int)((_plotData.maxY - _plotData.minY) / interval);
_plotData.maxY = _plotData.minY + _nTickY * interval;
_plotData.nTickY = _nTickY;
}
else
{
round(ref _plotData.minY, ref _plotData.maxY);
_plotData.nTickY = 0;
_nTickY = nTickY;
}
}
else
{
if (_plotData.userMaxY >= _plotData.userMinY) _plotData.minY = _plotData.userMinY;
if (_plotData.userMaxY > _plotData.userMinY) _plotData.maxY = _plotData.userMaxY;
double interval = _plotData.userIntervalY > 0 ? _plotData.userIntervalY : getInterval((_plotData.maxY - _plotData.minY) / nTickY);
if (_plotData.userMaxY < _plotData.userMinY) _plotData.minY = interval * (int)(_plotData.minY / interval - 1);
_nTickY = (int)((_plotData.maxY - _plotData.minY) / interval);
if (_plotData.userMaxY <= _plotData.userMinY || _plotData.userMaxY > _plotData.userMinY + _nTickY * interval) _nTickY++;
_plotData.maxY = _plotData.minY + _nTickY * interval;
_plotData.nTickY = _nTickY;
}
}
/*******************************************************************************
* Create all children objects
******************************************************************************/
_graph.Children.Clear();
RotateTransform rotate90 = new RotateTransform();
rotate90.Angle = -90;
ScaleTransform bgLayer = new ScaleTransform();
bgLayer.ScaleY = 1.2;
bgLayer.CenterY = 11.0;
/*******************************************************************************
* Axes labeling
******************************************************************************/
TextBlock _title = new TextBlock();
_title.Text = _plotData.title;
_title.Width = gw;
_title.TextAlignment = TextAlignment.Center;
_title.FontSize = 18;
_title.Foreground = getBrush(textColour);
_title.FontWeight = FontWeights.Bold;
_graph.Children.Add(_title);
Canvas.SetLeft(_title, offsetL);
Canvas.SetTop(_title, 2);
TextBlock _titleX = new TextBlock();
_titleX.Text = _plotData.labelX;
_titleX.Width = gw;
_titleX.TextAlignment = TextAlignment.Center;
_titleX.FontSize = 14;
_titleX.Foreground = getBrush(textColour);
_titleX.FontWeight = FontWeights.Bold;
_graph.Children.Add(_titleX);
Canvas.SetLeft(_titleX, offsetL);
Canvas.SetTop(_titleX, _graph.ActualHeight - 20);
TextBlock _titleY = new TextBlock();
_titleY.Text = _plotData.labelY;
_titleY.Width = gh;
_titleY.TextAlignment = TextAlignment.Center;
_titleY.FontSize = 14;
_titleY.Foreground = getBrush(textColour);
_titleY.FontWeight = FontWeights.Bold;
_graph.Children.Add(_titleY);
Canvas.SetLeft(_titleY, 2);
Canvas.SetTop(_titleY, _graph.ActualHeight - offsetB);
_titleY.RenderTransform = rotate90;
/*******************************************************************************
* Plot area
******************************************************************************/
Canvas _plotarea = new Canvas();
_plotData.plotarea = _plotarea;
_plotarea.Width = gw;
_plotarea.Height = gh;
_plotarea.Background = getBrush(interiorColour);
_plotarea.ClipToBounds = true;
_plotarea.Cursor = Cursors.Cross;
_graph.Children.Add(_plotarea);
Canvas.SetLeft(_plotarea, offsetL);
Canvas.SetTop(_plotarea, offsetT);
/*******************************************************************************
* Hover values
******************************************************************************/
_plotData.hoverValBG = new TextBlock();
_plotData.hoverValBG.Text = "";
_plotData.hoverValBG.Foreground = getBrush(interiorColour);
_plotData.hoverValBG.FontWeight = FontWeights.Bold;
_plotData.hoverValBG.RenderTransform = bgLayer;
Canvas.SetZIndex(_plotData.hoverValBG, 1);
_plotarea.Children.Add(_plotData.hoverValBG);
_plotData.hoverVal = new TextBlock();
_plotData.hoverVal.Text = "";
_plotData.hoverVal.Foreground = getBrush(textColour);
_plotData.hoverVal.FontWeight = FontWeights.Bold;
Canvas.SetZIndex(_plotData.hoverVal, 1);
_plotarea.Children.Add(_plotData.hoverVal);
/*******************************************************************************
* Plot area Border
******************************************************************************/
Rectangle _border = new Rectangle();
_border.Width = gw;
_border.Height = gh;
_border.Stroke = getBrush(linesColour);
_border.StrokeThickness = 1.0;
_graph.Children.Add(_border);
Canvas.SetLeft(_border, offsetL);
Canvas.SetTop(_border, offsetT);
/*******************************************************************************
* X axis tick marks and labels
******************************************************************************/
Line _line;
int i, j;
double iTick;
for (i = 0; i < _nTickX + 1; i++)
{
j = i - (int)System.Math.Floor(_plotData.shiftX * _nTickX / (_plotData.maxX - _plotData.minX));
iTick = j + _plotData.shiftX * _nTickX / (_plotData.maxX - _plotData.minX);
if (iTick >= 0 && iTick <= _nTickX)
{
_line = new Line();
_line.X1 = iTick * gw / _nTickX;
_line.Y1 = gh;
_line.X2 = iTick * gw / _nTickX;
_line.Y2 = 0;
_line.Stroke = getBrush(faintlinesColour);
_line.StrokeThickness = 0.5;
_plotarea.Children.Add(_line);
_line = new Line();
_line.X1 = iTick * gw / _nTickX;
_line.Y1 = gh;
_line.X2 = iTick * gw / _nTickX;
_line.Y2 = gh - 10;
_line.Stroke = getBrush(linesColour);
_line.StrokeThickness = 1.0;
_plotarea.Children.Add(_line);
TextBlock _val = new TextBlock();
_val.Text = sigfig((_plotData.minX - _plotData.shiftX + iTick / _nTickX * (_plotData.maxX - _plotData.minX)), 3).ToString();
_val.Foreground = getBrush(textColour);
_graph.Children.Add(_val);
Canvas.SetLeft(_val, offsetL + iTick / _nTickX * gw - 3 * _val.Text.Length);
Canvas.SetTop(_val, offsetT + gh + 2);
}
}
/*******************************************************************************
* Y axis tick marks and labels
******************************************************************************/
for (i = 0; i < _nTickY + 1; i++)
{
j = i - (int)System.Math.Floor(_plotData.shiftY * _nTickY / (_plotData.minY - _plotData.maxY));
iTick = j + _plotData.shiftY * _nTickY / (_plotData.minY - _plotData.maxY);
if (iTick >= 0 && iTick <= _nTickY)
{
_line = new Line();
_line.X1 = 0;
_line.Y1 = iTick * gh / _nTickY;
_line.X2 = gw;
_line.Y2 = iTick * gh / _nTickY;
_line.Stroke = getBrush(faintlinesColour);
_line.StrokeThickness = 0.5;
_plotarea.Children.Add(_line);
_line = new Line();
_line.X1 = 0;
_line.Y1 = iTick * gh / _nTickY;
_line.X2 = 10;
_line.Y2 = iTick * gh / _nTickY;
_line.Stroke = getBrush(linesColour);
_plotarea.Children.Add(_line);
TextBlock _val = new TextBlock();
_val.Text = sigfig((_plotData.maxY - _plotData.shiftY + iTick / _nTickY * (_plotData.minY - _plotData.maxY)), 3).ToString();
_val.Foreground = getBrush(textColour);
_graph.Children.Add(_val);
Canvas.SetLeft(_val, offsetL - 20);
Canvas.SetTop(_val, offsetT + iTick / _nTickY * gh + 3 * _val.Text.Length);
_val.RenderTransform = rotate90;
}
}
/*******************************************************************************
* Axes scroll areas
******************************************************************************/
Canvas _scrollX = new Canvas();
_scrollX.Width = gw;
_scrollX.Height = offsetB;
_scrollX.Background = getBrush("#00ffffff");
_graph.Children.Add(_scrollX);
_plotData.scrollX = _scrollX;
Canvas.SetLeft(_scrollX, offsetL);
Canvas.SetTop(_scrollX, gh + offsetT);
if (doEvents) _scrollX.Cursor = Cursors.Hand;
Canvas _scrollY = new Canvas();
_scrollY.Width = offsetL;
_scrollY.Height = gh;
_scrollY.Background = getBrush("#00ffffff");
_graph.Children.Add(_scrollY);
_plotData.scrollY = _scrollY;
Canvas.SetLeft(_scrollY, 0);
Canvas.SetTop(_scrollY, offsetT);
if (doEvents) _scrollY.Cursor = Cursors.Hand;
/*******************************************************************************
* Legend
******************************************************************************/
if (_plotData.displayLegend)
{
Canvas _legend = new Canvas();
_plotData.legend = _legend;
_legend.Width = 60;
_legend.Height = 20*_plotData.series.Count;
_legend.Background = getBrush("#00ffffff");
if (doEvents) _legend.Cursor = Cursors.Hand;
i = 0;
foreach (seriesData _series in _plotData.series)
{
Brush seriesBrush = getBrush(_series.colour);
_line = new Line();
_line.X1 = 10;
_line.Y1 = 10+20*i;
_line.X2 = 50;
_line.Y2 = 10 + 20 * i;
_line.Stroke = seriesBrush;
_line.StrokeThickness = 2;
_legend.Children.Add(_line);
TextBlock _val = new TextBlock();
_val.Text = _series.name;
_val.Foreground = getBrush(textColour);
_legend.Children.Add(_val);
Canvas.SetLeft(_val, 55);
Canvas.SetTop(_val, 20 * i);
i++;
}
_graph.Children.Add(_legend);
Canvas.SetLeft(_legend, offsetL + _plotData.legendPosition.X);
Canvas.SetTop(_legend, offsetT + _plotData.legendPosition.Y);
}
/*******************************************************************************
* Plot the series data
******************************************************************************/
double dSeries = 0;
int iCount = 0;
foreach (seriesData _series in _plotData.series)
{
for (i = 0; i < _series.dataX.Count; i++)
{
if (_series.dataX[i] > (_plotData.minX - _plotData.shiftX) && _series.dataX[i] < (_plotData.maxX - _plotData.shiftX)) iCount++;
}
if (_series.type == eLineType.HISTOGRAM) dSeries++; // Number of histograms;
}
double dOffest = -(dSeries - 1.0) / 2.0;
dSeries = 0;;
double dWL = 2.0; // Width for line
double dWH = 0.8 * System.Math.Min(50.0, System.Math.Max(2.0, gw / (double) iCount)); // Width for histogram
double dWP = System.Math.Min(12.0, System.Math.Max(6.0, gw / (double)iCount)); // Width for points
foreach (seriesData _series in _plotData.series)
{
Brush seriesBrush = getBrush(_series.colour);
switch (_series.type)
{
case eLineType.LINE: // Line
{
for (i = 1; i < _series.dataX.Count; i++)
{
double X1 = gw * (_series.dataX[i - 1] - (_plotData.minX - _plotData.shiftX)) / (_plotData.maxX - _plotData.minX);
double Y1 = gh * ((_plotData.maxY - _plotData.shiftY) - _series.dataY[i - 1]) / (_plotData.maxY - _plotData.minY);
double X2 = gw * (_series.dataX[i] - (_plotData.minX - _plotData.shiftX)) / (_plotData.maxX - _plotData.minX);
double Y2 = gh * ((_plotData.maxY - _plotData.shiftY) - _series.dataY[i]) / (_plotData.maxY - _plotData.minY);
if (((X2 >= 0 && X1 <= gw) || (X1 >= 0 && X2 <= gw)) && ((Y2 >= 0 && Y1 <= gh) || (Y1 >= 0 && Y2 <= gh)))
{
_line = new Line();
_line.X1 = X1;
_line.Y1 = Y1;
_line.X2 = X2;
_line.Y2 = Y2;
_line.Stroke = seriesBrush;
_line.StrokeThickness = dWL;
_plotarea.Children.Add(_line);
}
}
}
break;
case eLineType.HISTOGRAM: // Histogram
{
Rectangle _rect;
for (i = 0; i < _series.dataX.Count; i++)
{
double X = gw * (_series.dataX[i] - (_plotData.minX - _plotData.shiftX)) / (_plotData.maxX - _plotData.minX);
double Y1 = gh * ((_plotData.maxY - _plotData.shiftY) - System.Math.Max(0.0, _series.dataY[i])) / (_plotData.maxY - _plotData.minY);
double Y2 = gh * ((_plotData.maxY - _plotData.shiftY) - System.Math.Min(0.0, _series.dataY[i])) / (_plotData.maxY - _plotData.minY);
if ((X >= 0 && X <= gw) && (Y1 <= gh && Y2 >= 0))
{
_rect = new Rectangle();
_rect.Width = 0.8 * dWH;
_rect.Height = Y2 - Y1;
_rect.Fill = seriesBrush;
_rect.StrokeThickness = 0;
_plotarea.Children.Add(_rect);
Canvas.SetLeft(_rect, X + dWH * (dOffest + dSeries) - 0.8 * dWH / 2.0);
Canvas.SetTop(_rect, Y1);
}
}
dSeries++;
}
break;
case eLineType.POINTS: // Points
{
Ellipse _ellip;
for (i = 0; i < _series.dataX.Count; i++)
{
double X = gw * (_series.dataX[i] - (_plotData.minX - _plotData.shiftX)) / (_plotData.maxX - _plotData.minX);
double Y = gh * ((_plotData.maxY - _plotData.shiftY) - _series.dataY[i]) / (_plotData.maxY - _plotData.minY);
if ((X >= 0 && X <= gw) && (Y >= 0 && Y <= gh))
{
_ellip = new Ellipse();
_ellip.Width = dWP;
_ellip.Height = dWP;
_ellip.Fill = seriesBrush;
_ellip.StrokeThickness = 0;
_plotarea.Children.Add(_ellip);
Canvas.SetLeft(_ellip, X - dWP / 2.0);
Canvas.SetTop(_ellip, Y - dWP / 2.0);
}
}
}
break;
}
}
setEvents(doEvents);
isPlotting = false;
}