I am using a OxyPlot to Real time changing data.
I do this using a Dispatcher Timer in a WPF C# app.
plotTimer.Interval = TimeSpan.FromMilliseconds(1000);
plotTimer.Tick += PlotTimer_Tick;
plotTimer.Start();
SensorPlotModel is a class of primarily the OxyPlot plotmodel with some properties to help keep track of which sensors it is for.
<oxy:PlotView Grid.Row="2" Grid.RowSpan="5" Grid.Column="1" Grid.ColumnSpan="4" Model="{Binding graphPlotModel}" MinHeight="250" MinWidth="1200"/>
The plotModel is then bound in this way to the xaml, where graphPlotModel is a property of the dataContext.
The graph works well when the sensor value is changing. When the value is not changing, the graph seems to be updated with the values, however, the zoom is not changing meaning that the past values can be seen but not the new ones.
I suspect Oxyplot is optimising by not zooming to the new values.
Please let me know if there a problem in the code.
FYI, the graphs are initialised as so:
DateTimeAxis dateAxis = new DateTimeAxis();
dateAxis.Position = AxisPosition.Bottom;
dateAxis.StringFormat = "mm:ss";
dateAxis.MajorGridlineStyle = LineStyle.Solid;
dateAxis.MinorGridlineStyle = LineStyle.Dot;
dateAxis.MinimumMajorStep = 1;
dateAxis.IntervalType = DateTimeIntervalType.Minutes;
//dateAxis.MaximumRange = 10;
//dateAxis.IntervalLength = 5;
plotModel.Axes.Add(dateAxis);
LinearAxis valueAxis = new LinearAxis();
valueAxis.Position = AxisPosition.Left;
valueAxis.StartPosition = 0;
valueAxis.MajorGridlineStyle = LineStyle.Solid;
valueAxis.MinorGridlineStyle = LineStyle.Dot;
valueAxis.Maximum = max;
valueAxis.Minimum = min;
plotModel.Axes.Add(valueAxis);
I hope I understand your question here correctly. You could re-adjust the Axis.Minimum and Axis.Maximum as the new data comes in. For example,
var series = SensorPlotModel.Series.OfType<LineSeries>().First();
var dateTimeAxis = SensorPlotModel.Axes.OfType<DateTimeAxis>().First();
// set Initial axis Range
if (!series.Points.Any())
{
dateTimeAxis.Minimum = DateTimeAxis.ToDouble(DateTime.Now);
dateTimeAxis.Maximum = DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(MaxSecondsToShow));
}
foreach (var newItem in newItems)
{
if(newItem is SensorData sensorData)
{
series.Points.Add(new DataPoint(DateTimeAxis.ToDouble(sensorData.TimeStamp), sensorData.Data));
}
}
// Reset the axis range when axis is out of range
if (DateTimeAxis.ToDouble(DateTime.Now) > dateTimeAxis.Maximum)
{
dateTimeAxis.Minimum = DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(-1 * MaxSecondsToShow));
dateTimeAxis.Maximum = DateTimeAxis.ToDouble(DateTime.Now);
dateTimeAxis.Reset();
}
SensorPlotModel.InvalidatePlot(true);
NotifyOfPropertyChange(nameof(SensorPlotModel));
Related
I have this simple graph plotted in a chart. On the X-axis the values are DateTime values.
public partial class Form1 : Form
{
List<double> valuelist = new List<double>();
List<DateTime> timelist = new List<DateTime>();
public Form1()
{
InitializeComponent();
// fill the lists with values
for (int i = 0; i < 2000; i++)
{
double value = Math.Sin(i/20.0);
valuelist.Add(value);
timelist.Add(DateTime.Now.AddMinutes(i + 2));
}
// add the Values to the chart
for (int i = 0; i < valuelist.Count; i++)
{
this.chart1.Series[0].Points.AddXY(timelist[i], valuelist[i]);
}
this.chart1.ChartAreas[0].AxisX.LabelStyle.Format = "dd.MM-hh:mm";
}
private void Form1_Load(object sender, EventArgs e)
{
chart1.Series[0].XValueType = ChartValueType.DateTime;
chart1.ChartAreas[0].AxisX.Maximum = timelist.Max().ToOADate();
chart1.ChartAreas[0].AxisX.Minimum = timelist.Min().ToOADate();
chart1.ChartAreas[0].CursorX.AutoScroll = true;
chart1.ChartAreas[0].CursorY.AutoScroll = true;
chart1.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chart1.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
DateTime intervall = timelist.Min().AddHours(3);
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(chart1.ChartAreas[0].AxisX.Minimum, intervall.ToOADate());
// disable zoom-reset button
chart1.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = intervall.ToOADate();
}
}
My problem is that I cannot get the scrollbar to move smoothly. When I plot only the Y-Values and use just double values for the AxisX.Maximum, AxisX.Minimum, AxisX.ScaleView.Zoom and for AxisX.ScaleView.SmallScrollSize it works like a charm. But as soon as I use DateTime for the X-Values I can only scroll in steps. Does someone know how to surpass this? I have the feeling that this piece of code is the obstacle:
// set scrollbar small change to blockSize (e.g. 100)
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = intervall.ToOADate();
EDIT:
The Interval for the X-Axis is automatic, the range is set by the ZoomLevel of chart1.ChartAreas[0].AxisX.ScaleView.Zoom. Here is a picture:
EDIT 2:
The Values for the X-Axis are DateTime-Values simulating a sampling of 1 value every minute:
timelist.Add(DateTime.Now.AddMinutes(i + 2));
Because it is a lot of values I did not set an interval.
The code is posted this way, so that it can be copied as it is and run right away to try it out.
You scrolling interval is wrong.
It should not be the start of your data but the step you want to go when scrolling.
Looks like you want to scroll by 3 hours?
Here is what you do:
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Hours;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = 3;
If you wanted to use a DateTime.ToOADate double to achieve the same you need it to start at the first day of the DataTime data type (0aka 'dawn of time' aka 1899-12-30) and then add 3 hours:
DateTime interval = DateTime.FromOADate(0).AddHours(3);
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Number;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = interval.ToOADate();
To allow dragging the lift smoothly this may work better than setting the SmallScrollSize:
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollMinSizeType =DateTimeIntervalType.Minutes;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollMinSize = 60;
Use your unit and numbers! This will only work if you don't set the SmallScrollMinSize.
As the title says, I am using TeeChart to draw several boxplots within one chart object. Since, the number of boxplots can be quite big, I want to be able to click on a box and have information pertaining to that series to show up as a tooltip.
I am currently trying to do this with a MarksTip but for some reason, when I try to hover over the box, MarksTip will sometimes open and then immediately close (basically being visible for a split second). I have already tried setting the hide delay but it seems to be ignoring that.
Code snippet below:
seriesIndex = 0;
foreach (var seriesData in seriesDataList)
{
var series = new Box()
series.UseCustomValues = true;
series.Box.HorizSize = 5;
series.Box.Style = PointerStyles.Rectangle;
series.MildOut.Visible = true;
series.MildOut.HorizSize = 2;
series.MildOut.VertSize = 2;
series.ExtrOut.Visible = true;
series.ExtrOut.HorizSize = 2;
series.ExtrOut.VertSize = 2;
series.LinePen.Visible = _isLineVisible;
series.Pointer.Pen.Visible = true;
series.ShowInLegend = false;
series.Add(seriesIndex, seriesData);
series.Title = "tooltip text";
var tooltip = new MarksTip(Chart.Chart)
{
Series = series,
Style = MarksStyles.SeriesTitle,
HideDelay = 31000,
};
Chart.Series.Add(series);
seriesIndex++;
}
Credit to this other question for pointing me in the right direction.
I ended up using the GetSeriesMark event to modify the text of a single chart-bound MarksTip instead of creating multiple series-bound `MarksTip
seriesIndex = 0;
Chart.Tools.Add(new MarksTip());
foreach (var seriesData in seriesDataList)
{
var series = new Box()
series.UseCustomValues = true;
//Other series appearance stuff
series.Add(seriesIndex, seriesData);
series.Title = "tooltip text";
series.GetSeriesMark += (s, args) =>
{
args.MarkText = s.Title;
};
series.Marks.Visible = false;
Chart.Series.Add(series);
seriesIndex++;
}
One note about this method. The tooltip will only appear when hovering over actual datapoints and not the whole box. Not ideal but at least I can read the tooltip now.
I'm implementing some real-time charts in a C# WPF application, but am using WinForms charts as they are generally easy to work with and are surprisingly performant.
Anyway, I've got the charts working just fine except for one major issue which I can't for the life of me figure out:
When I add data to the chart, it sometimes just resizes itself. Sometimes it does that a lot, giving itself the wiggles and making the chart super annoying to read and deal with.
My question is: how can I prevent this damned chart from constantly resizing itself?!
Some additional information:
The chart is included in my XAML as such:
<WindowsFormsHost Grid.Row="1" Grid.ColumnSpan="2" Margin="5">
<winformchart:Chart Dock="Fill" x:Name="Session0Chart">
<winformchart:Chart.ChartAreas>
<winformchart:ChartArea/>
</winformchart:Chart.ChartAreas>
</winformchart:Chart>
</WindowsFormsHost>
Gets initialized via:
// initialize it!
chart.Palette = ChartColorPalette.Bright;
// setup the labels
Font monoSpaceFont = new Font("Consolas", 10);
chart.ChartAreas[0].AxisX.LabelStyle.Font = monoSpaceFont;
chart.ChartAreas[0].AxisY.LabelStyle.Font = monoSpaceFont;
// set the axis limits appropriately
chart.ChartAreas[0].AxisY.Maximum = 600;
chart.ChartAreas[0].AxisY.Minimum = -200;
// set up grid lines and axis styles
chart.ChartAreas[0].AxisX.MinorGrid.Enabled = true;
chart.ChartAreas[0].AxisX.MinorGrid.LineDashStyle = ChartDashStyle.Dash;
chart.ChartAreas[0].AxisX.MinorGrid.LineColor = System.Drawing.Color.Gray;
chart.ChartAreas[0].AxisX.MinorGrid.Interval = 0.04;
chart.ChartAreas[0].AxisX.LabelStyle.Format = "F2";
chart.ChartAreas[0].AxisX.LabelAutoFitStyle = LabelAutoFitStyles.None;
chart.ChartAreas[0].AxisY.MajorGrid.Enabled = true;
chart.ChartAreas[0].AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Solid;
chart.ChartAreas[0].AxisY.MajorGrid.Interval = 200;
chart.ChartAreas[0].AxisY.LabelAutoFitStyle = LabelAutoFitStyles.None;
chart.ChartAreas[0].AxisY.LabelStyle.Format = "F0";
chart.Series.Clear();
Series s = new Series();
s.ChartType = SeriesChartType.FastLine;
chart.Series.Add(s);
chart.Refresh();
And data points get added via:
// if we get too many points, remove the head
if (session.Chart.Series[0].Points.Count >= Properties.Settings.Default.ECGDataPoints)
{
session.Chart.Series[0].Points.RemoveAt(0);
}
// add the points
for (int i = data.samples.Length - 1; i >= 0; i--)
{
session.Chart.Series[0].Points.AddXY(session.ecgT, data.samples[i]);
session.ecgT += session.ECGPeriod / (double)data.samples.Length;
}
// only look at the last few seconds
session.Chart.ChartAreas[0].AxisX.Maximum = session.ecgT;
session.Chart.ChartAreas[0].AxisX.Minimum = session.ecgT - Properties.Settings.Default.ECGTimeWindow;
Any help you can offer would be GREATLY appreciated, this has been driving me crazy for way too long!
You should make your X axis DateTime, not double. It's an ECG anyway....
The wiggle is caused by incrementing your X axis with values such as 0.10000000001234.
// No wiggle
chartNoWiggle.Series[0].Points.AddXY(xdatetime, r.NextDouble());
if (chartNoWiggle.Series[0].Points.Count > 10)
chartNoWiggle.Series[0].Points.RemoveAt(0);
chartNoWiggle.ChartAreas[0].AxisX.Minimum = chartNoWiggle.Series[0].Points[0].XValue;
chartNoWiggle.ChartAreas[0].AxisX.Maximum = xdatetime.ToOADate();
xdatetime = xdatetime.AddMinutes(1);
// Wiggle
chartWiggle.Series[0].Points.AddXY(xdouble, r.NextDouble());
if (chartWiggle.Series[0].Points.Count > 10)
chartWiggle.Series[0].Points.RemoveAt(0);
chartWiggle.ChartAreas[0].AxisX.Minimum = chartWiggle.Series[0].Points[0].XValue;
chartWiggle.ChartAreas[0].AxisX.Maximum = xdouble;
xdouble += 0.10000000001234;
chart.ChartAreas[0].InnerPlotPosition.X = 50;
chart.ChartAreas[0].InnerPlotPosition.Y = 5;
chart.ChartAreas[0].InnerPlotPosition.Width = 80;
chart.ChartAreas[0].InnerPlotPosition.Height = 80;
Read this.
You can set ChartArea Position and InnerPlotPosition to avoid those wiggles.
chrt.ChartAreas[0].Position.Auto = false;
chrt.ChartAreas[0].Position.Height = 70;
chrt.ChartAreas[0].Position.Y = 5;
chrt.ChartAreas[0].InnerPlotPosition.Auto = false;
chrt.ChartAreas[0].InnerPlotPosition.Height = 50;
chrt.ChartAreas[0].InnerPlotPosition.Y = 10;
I apologize for asking so many OxyPlot questions, but I seem to be really struggling with using the OxyPlot chart control.
My project is in WPF format so I was originally using a hosted WINFORMS chart and that worked like a charm and did absolutely everything I needed it to until I needed to overlay a WPF element on top of the hosted winform chart. Due to the "AirSpace" issue, I was not able to see the WPF element that I put on top of the hosted chart no matter what I did. That is when I decided to go with OxyPlot, which is giving me quite a few headaches so far.
Here is my origional question! that I asked over at CodePlex. I don't seem to be getting much help over there so I am trying again here.
My question is:
Does anyone know how to plot MULTIPLE LineSeries onto a Plot??
My approach so far:
I am taking a c# List array and adding a new copy of the LineSeries that holds new data to be plotted. My code:
// Function to plot data
private void plotData(double numWeeks, double startingSS)
{
// Initialize new Salt Split class for acess to data variables
Salt_Split_Builder calcSS = new Salt_Split_Builder();
calcSS.compute(numWeeks, startingSS, maxDegSS);
// Create the OxyPlot graph for Salt Split
OxyPlot.Wpf.PlotView plot = new OxyPlot.Wpf.PlotView();
var model = new PlotModel();
// Add Chart Title
model.Title = "Salt Split Degradation";
// Create new Line Series
LineSeries linePoints = new LineSeries() { StrokeThickness = 1, MarkerSize = 1, Title = numWeeks.ToString() + " weeks" };
// Add each point to the new series
foreach (var point in calcSS.saltSplitCurve)
{
DataPoint XYpoint = new DataPoint();
XYpoint = new DataPoint(point.Key, point.Value * 100);
linePoints.Format("%", XYpoint.Y);
linePoints.Points.Add(XYpoint);
}
listPointAray.Add(linePoints);
// Define X-Axis
var Xaxis = new OxyPlot.Axes.LinearAxis();
Xaxis.Maximum = numWeeks;
Xaxis.Minimum = 0;
Xaxis.Position = OxyPlot.Axes.AxisPosition.Bottom;
Xaxis.Title = "Number of Weeks";
model.Axes.Add(Xaxis);
//Define Y-Axis
var Yaxis = new OxyPlot.Axes.LinearAxis();
Yaxis.MajorStep = 15;
Yaxis.Maximum = calcSS.saltSplitCurve.Last().Value * 100;
Yaxis.MaximumPadding = 0;
Yaxis.Minimum = 0;
Yaxis.MinimumPadding = 0;
Yaxis.MinorStep = 5;
Yaxis.Title = "Percent Degradation";
model.Axes.Add(Yaxis);
// Add Each series to the
foreach (var series in listPointAray)
{
LineSeries newpoints = new LineSeries();
newpoints = linePoints;
model.Series.Add(newpoints);
}
// Add the plot to the window
plot.Model = model;
SaltSplitChartGrid.Children.Add(plot);
}
My code works the first time I press my "Graph Data" button, but fails on consecutive attempts with the following error:
The element cannot be added, it already belongs to a Plot Model
The following plot is the type of plot I would like to produce (it worked fine using WinForms Chart control):
I would like a new line with a new color to be plotted each time I run the method.
This is how I've created multi lines on an OxyPlot chart before, the key is creating a set of DataPoints for each series - called circlePoints & linePoints in the following example code, these are then bound to the CircleSeries and LineSeries:
var xAxis = new DateTimeAxis
{
Position = AxisPosition.Bottom,
StringFormat = Constants.MarketData.DisplayDateFormat,
Title = "End of Day",
IntervalLength = 75,
MinorIntervalType = DateTimeIntervalType.Days,
IntervalType = DateTimeIntervalType.Days,
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.None,
};
var yAxis = new LinearAxis
{
Position = AxisPosition.Left,
Title = "Value",
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.None
};
var plot = new PlotModel();
plot.Axes.Add(xAxis);
plot.Axes.Add(yAxis);
var circlePoints = new[]
{
new ScatterPoint(DateTimeAxis.ToDouble(date1), value1),
new ScatterPoint(DateTimeAxis.ToDouble(date2), value2),
};
var circleSeries = new ScatterSeries
{
MarkerSize = 7,
MarkerType = MarkerType.Circle,
ItemsSource = circlePoints
};
var linePoints = new[]
{
new DataPoint(DateTimeAxis.ToDouble(date1), value1),
new DataPoint(DateTimeAxis.ToDouble(date2), value2),
};
var lineSeries = new LineSeries
{
StrokeThickness = 2,
Color = LineDataPointColor,
ItemsSource = linePoints
};
plot.Series.Add(circleSeries);
plot.Series.Add(lineSeries);
Sucess!!!!
AwkwardCoder, thank you for the help, but I realized my mistake was just me having overlooked some things!
Here is the version of the code that works:
// Make a new plotmodel
private PlotModel model = new PlotModel();
// Create the OxyPlot graph for Salt Split
private OxyPlot.Wpf.PlotView plot = new OxyPlot.Wpf.PlotView();
// Function to plot data
private void plotData(double numWeeks, double startingSS)
{
List<LineSeries> listPointAray = new List<LineSeries>();
// Initialize new Salt Split class for acess to data variables
Salt_Split_Builder calcSS = new Salt_Split_Builder();
calcSS.compute(numWeeks, startingSS, maxDegSS);
// Create new Line Series
LineSeries linePoints = new LineSeries()
{ StrokeThickness = 1, MarkerSize = 1, Title = numWeeks.ToString() + " weeks" };
// Add each point to the new series
foreach (var point in calcSS.saltSplitCurve)
{
DataPoint XYpoint = new DataPoint();
XYpoint = new DataPoint(point.Key, point.Value * 100);
linePoints.Format("%", XYpoint.Y);
linePoints.Points.Add(XYpoint);
}
listPointAray.Add(linePoints);
// Add Chart Title
model.Title = "Salt Split Degradation";
// Add Each series to the
foreach (var series in listPointAray)
{
// Define X-Axis
OxyPlot.Axes.LinearAxis Xaxis = new OxyPlot.Axes.LinearAxis();
Xaxis.Maximum = numWeeks;
Xaxis.Minimum = 0;
Xaxis.Position = OxyPlot.Axes.AxisPosition.Bottom;
Xaxis.Title = "Number of Weeks";
model.Axes.Add(Xaxis);
//Define Y-Axis
OxyPlot.Axes.LinearAxis Yaxis = new OxyPlot.Axes.LinearAxis();
Yaxis.MajorStep = 15;
Yaxis.Maximum = calcSS.saltSplitCurve.Last().Value * 100;
Yaxis.MaximumPadding = 0;
Yaxis.Minimum = 0;
Yaxis.MinimumPadding = 0;
Yaxis.MinorStep = 5;
Yaxis.Title = "Percent Degradation";
//Yaxis.StringFormat = "{0.00} %";
model.Axes.Add(Yaxis);
model.Series.Add(series);
}
// Add the plot to the window
plot.Model = model;
plot.InvalidatePlot(true);
SaltSplitChartGrid.Children.Clear();
SaltSplitChartGrid.Children.Add(plot);
}
Here are the multiple things I did wrong:
In my foreach var series loop, I was adding the original series which had already been added and NOT the next var series in the list! (dumb!)
I was creating a new model each time I ran the method. This means that each time the code ran, I was adding a series that already existed in the previous model. (also dumb!)
I was creating a new plot every time and trying to add a model in the new plot that already belonged to a previous plot. (getting dummer..)
The plot was being added to the grid each time I ran the method, so I had to CLEAR the grid's children first before re-adding the same plot.
I was not refreshing the plot.
That was a lot of mistakes, but I worked through it. Hopefully this helps someone in the future. Also, I know I am not using ordinary data binding techniques, but this, at-least, works.
Final result:
Here is how you can achieve a similar result in XAML especially if you are using the MVVM approach.
ViewModel:
public ObservableCollection<DataPoint> DataPointList1 {get;set;}
public ObservableCollection<DataPoint> DataPointList2 {get;set;}
public ObservableCollection<DataPoint> DataPointList3 {get;set;}
public ObservableCollection<DataPoint> DataPointList4 {get;set;}
Using a for loop like below populates DataPointList1 to DataPointList4 with the appropriate datasets.
for (int i = 0; i < dataList.Count; i++)
{
DataPointList1 .Add(new DataPoint{dataList[i].XValue,dataList[i].YValue });
}
XAML:
xmlns:oxy="http://oxyplot.org/wpf"
<oxy:Plot LegendPlacement="Outside" LegendPosition="RightMiddle" Title="Your Chart Title" >
<oxy:Plot.Axes>
<oxy:LinearAxis Title="Your X-axis Title" Position="Bottom" IsZoomEnabled="True" />
<oxy:LinearAxis Title="Your Y-axis Title" Position="Left" IsZoomEnabled="True" />
</oxy:Plot.Axes>
<oxy:Plot.Series>
<oxy:LineSeries Title="Plot1" Color="Black" ItemsSource="{Binding DataPointList1 }"/>
<oxy:LineSeries Title="Plot2" Color="Green" ItemsSource="{Binding DataPointList2 }"/>
<oxy:LineSeries Title="Plot3" Color="Blue" ItemsSource="{Binding DataPointList3 }"/>
<oxy:LineSeries Title="Plot4" Color="Red" ItemsSource="{Binding DataPointList4 }"/>
</oxy:Plot.Series>
</oxy:Plot>
I have encountered a very odd problem today using WPF. Here is the code I have used to draw 10000 LineGeometry objects.
// Draw 10000 lines
var g = new GeometryGroup();
var x = 0;
var y = 0;
var n = 1;
while (n < 10000)
{
x = x + 20;
if (x > 600)
{
x = 0;
y = y + 20;
}
var l = new LineGeometry
{
StartPoint = new Point(x, y),
EndPoint = new Point(x, y + 15)
};
g.Children.Add(l);
n++;
}
var drawing = new GeometryDrawing {Geometry = g};
var drawingGroup = new DrawingGroup();
drawingGroup.Children.Add(drawing);
var myPen = new Pen {Thickness = 1, Brush = Brushes.Yellow};
drawing.Pen = myPen;
var myImage = new Image {Stretch = Stretch.None, Margin = new Thickness(10)};
var myDrawingImage = new DrawingImage {Drawing = drawingGroup};
myImage.Source = myDrawingImage;
canvas.Children.Add(myImage);
Now as you can see the result is not crisp and I used the code below to achieve better results.
RenderOptions.SetEdgeMode(myImage, EdgeMode.Aliased);
The image gets crisp but has another side effects as you can see in the image below.
Some lines are now shown.
Some extra odd lines are shown.
I have included the full code so you can experiment this for yourself.
Note:
I'm using ZoomBorder class around the Canvas canvas.
Pan & Zoom Image
Have you tried using
RenderOptions.SetBitmapScalingMode(myImage, BitmapScalingMode.HighQuality);
instead?
You can also set it on your Canvas control as well..
<Canvas RenderOptions.BitmapScalingMode="HighQuality"> ...
This is not a real answer but I want add something to that odd behavior of WPF in hope somebody can come up with a real explanation.
I added a single line from (0,0)-(20000,20000). Creating 8000 line objects (n < 8000) produces the expected result like this:
Now, creating 9000 line objects will totally mess it up, but see for yourself:
Without setting EdgeMode.Aliased it looks fine, even with high counts of objects.