Silverlight Toolkit LineSeries connects data points randomly - silverlight

I am trying to render a line chart but the LineSeries is connecting the data points randomly each time I make it redraw the graph.
My items source is a typed List of my custom classes that have 2 properties, one for the x-axis and one for the y-axis (both are 'double' values). The values of these properties do not change and are loaded once.
My lines have several straight, vertical line jumps, i.e. the x-axis value is the same for 3 or 4 points, but the y-value changes. It properly connects these dots with a straight, vertical line.
But the odd thing is that it randomly uses any of the data points for the connection from the left and another one for the connection to the right.
I would assume that it uses the first point based on the order of the items source for the connection from the left and the last point for the connection to the right.
The items source is always in the same order, which is also the order in which I want them to be connected.
I tried attaching images, but am not allowed to ... So only a textual description is possible.
LineSeries ser = new LineSeries();
Chart.Series.Add(ser);
ser.DependentValuePath = "YAxis";
ser.IndependentValuePath = "XAxis"
ser.ItemsSource = data.Coordinates;
Does anybody know why this is happening? Thanks for any suggestions.

I had a similar issue in creating a strip style chart. Luckily, one of my co-workers noticed that silverlight charts all run left to right - which effects how it plots the different plots provided.
Simply rotating the chart seemed like the best idea - but it still had a few issues with charting (and my legend was also rotated).
I'm not much of a C# coder, so I created a control template in the Chart's style. I went into the template and rotated the edgepanel of the chart. Below is a very brief and generic example:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="charting:Chart">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
I'm not putting all of the code in here, but the full template for the chart can be found at http://silverlight.codeplex.com/SourceControl/changeset/view/80285#778932
<chartingprimitives:EdgePanel x:Name="ChartArea"
Style="{TemplateBindingChartAreaStyle}"
RenderTransformOrigin="0.5,0.5">
<chartingprimitives:EdgePanel.RenderTransform>
<CompositeTransform Rotation="90"/>
</chartingprimitives:EdgePanel.RenderTransform>
</chartingprimitives:EdgePanel>
<Grid x:Name="PlotArea" Canvas.ZIndex="-1"
RenderTransformOrigin="0.5,0.5" />
<Border Canvas.ZIndex="10" BorderBrush="Gray"
BorderThickness="1"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
This way the entire plotting area of the chart has been flipped, allowing the chart to plot downward instead of forcing the data to plot to the right. (I was having the same issue with the lines not plotting correctly and being erratic on what order it wanted to connect the points in)
It helped with my chart (there was tweaking needed, but this gives the general idea of what I was able to figure out). Hope it is somewhat helpful to you.

Its because the chart is Independent value based not Dependent value based. I had a similar issue with my "strip chart". It's as designed. Think of your chart as an x vs y plot flipped sideways. Now you can see how it plots. Changing the order of the points based on y doesn't do anything.
I don't think Telerik has this limitation.

Related

Making a graph from a file with values in WPF

Is there a way you can plot a graph/chart with WPF, I have a file with values, so I want the output to look like this:
This XAML code:
<Grid>
<ItemsControl ItemsSource="{Binding Lines}" Margin="44,102,40,205" Grid.RowSpan="2">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Line X1="{Binding From.X}" Y1="{Binding From.Y}"
X2="{Binding To.X}" Y2="{Binding To.Y}"
Stroke="DarkGray" StrokeThickness="3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
My ViewModel that should have all of the implementation drawing a graph:
My idea was to have a collection of lines, but I then froze, and couldn't implement a good solution.
I would read values from a txt file, but I do not know how should I pass them so they can be drawn on the graph.
public ObservableCollection<Line> Lines { get; private set; }
Lines = new ObservableCollection<Line>
{
// I would add new lines here
};
I have no experience when it comes to plotting graphs, so every advice would be a huge help to me
I don't think this is possible with just a simple use of the built-in controls in WPF, as you are trying to do. You need a custom control to actually render a usable chart. And take it from someone who has actually written a WPF line chart control from scratch: it's a real project. There are a lot of moving parts and things to consider.
Unless you really needed a super custom or proprietary implementation, you'd be far better off going with one of the libraries that have already been written. A quick google search for "WPF chart library" gives you a number of results. A free option that I've personally used is LiveCharts
That being said, if you really need to make your own, here are some points I had to cover in creating mine:
A function to return a "scale" (what numeric values are represented by the top and bottom of the graph), given the input of all the values that need to be displayed.
A function that, given the scale, returns a physical Y coordinate for a given chart value (e.g. "20" should be displayed 95 pixels above the bottom of the graph)
A Grid or other Panel to lay out separate areas for the title, legend, x axis, y axis (or axes, because you could potentially support more than one) and of course the plot area.
A function that determines the actual physical size of the plot area so you can physically scale (not the same as the scale mentioned earlier) the plot to fit inside the control. Don't forget that the size of the axes and other surrounding elements will have to be considered- even though they might not be drawn yet.
A method (or separate methods, which is how I did it) to draw each of axes and the lines. I used a Canvas, TextBlocks, PolyLines and Polygons (for markers).
(If you want to be professional) a method for calculating the overlap between marker labels and moving them apart so they're readable.

WPF Anti-aliasing edge of turned elements

I need Anti-alias edge of my turned rectangle more than normally.
My code is like this:
<Rectangle Margin="20,20,147,135" Fill="#FFCAD2DE" RenderOptions.EdgeMode="Unspecified">
<Rectangle.Effect>
<DropShadowEffect BlurRadius="4" ShadowDepth="2" Opacity=".5"/>
</Rectangle.Effect>
<Rectangle.RenderTransform>
<RotateTransform CenterX="0" CenterY="0" Angle="6" />
</Rectangle.RenderTransform>
</Rectangle>
I change the angle slowly programmatically...
But the result is aliased in some angles like below image (left side). I want edge of my rectangle be fully smooth in all angles like the below image (right side).
EDIT1:
I use .NET 3.5
The following steps can help
A)
First i moved my project from .NET 3.5 to .Net 4.5 without any changes in it and the result was:
It looks like very smoother
B)
Layout Rounding:
What is Layout Rounding and how to use it in WPF 4
When an object edge falls in the middle of a pixel device, the
DPI-independent graphics system can create rendering artifacts, such
as blurry or semi-transparent edges.
Previous versions of WPF included
pixel snapping to help handle this case. Silverlight 2 introduced
layout rounding, which is another way to move elements so that edges
fall on whole pixel boundaries.
WPF now supports layout rounding with
the UseLayoutRounding attached property on FrameworkElement. Drawing
objects on pixel boundaries eliminates the semi-transparent edges that
are produced by anti-aliasing, when an edge falls in the middle of a
device pixel. When you use layout rounding, the layout system creates
small variations in the column or row measurements to avoid sub-pixel
rendering.
The following code uses UseLayoutRounding attached property set on a single pixel-width line. You can see the difference that layout rounding makes when you resize the window slowly.
<StackPanel Width="150" Margin="7" Orientation="Horizontal">
<!-- Single pixel line with layout rounding turned OFF.-->
<Rectangle UseLayoutRounding="False" Width="45.6" Margin="10" Height="1" Fill="Red"/>
<!-- Single pixel line with layout rounding turned ON.-->
<Rectangle UseLayoutRounding="True" Width="45.6" Margin="10" Height="1" Fill="Red"/>
</StackPanel>
C)
SnapsToDevicePixels
Note
You should set UseLayoutRounding to true on the root
element. The layout system adds child coordinates to the parent
coordinates; therefore, if the parent coordinates are not on a pixel
boundary, the child coordinates are also not on a pixel boundary.
If UseLayoutRounding cannot be set at the root, set
SnapsToDevicePixels on the child to obtain the effect that you want.
It looks as if this isn't possible: RotateTranform causes alias edges on border control or a Rectangle.
From there:
Fortunately, the edge becomes perfectly soomth for 25+ degree rotations on my computer. If you eventually find a way to solve your problem, please share with us. It will be very beneficial for other community members having the similar questions.

WPF Text rendering problem

I created a custom control similar to TabControl. It works nice, except that the text in header items gets blury when I resize the content. It can, for example look like this:
Not only the text, but the box around the text can also get non-vertical. See the blue border around the "General" item:
What is causing this problem? I have set SnapToDevicePixels = True.
Thanks for any ideas!
EDIT:
I'm using .NET 4.0. TextOptions.TextFormattingMode is set to "Display".
The whole problem with fuzzy text and background occurs if I apply a DropShadowEffect effect in the style for ItemsControl which displays the buttons. This is the code for the Effect:
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Direction="0" ShadowDepth="1" BlurRadius="10" Opacity="0.2" Color="Black" />
</Setter.Value>
</Setter>
If this code is not enabled, the the text and the borders get displayed nicely.
I suspect you've said it yourself: SnapToDevicePixels will ruin text rendering if you've resized the text so it displays across pixels. You probably want to keep SnapToDevicePixels="True" on your borders/backgrounds, but turn it off for the text elements.
As for your border... can you post the xaml? I'm guessing that you're not using just a single element with rounded corners - are you drawing the edge of that tab as three separate lines?
There are 2 things to consider:
are you using .NET 3.5 or .NET 4.0? reason why I'm asking is that the text rendering has been changed between the versions. In 4.0 it's a lot better.
Sometime you have to wait a little while until the text get's sharper, so you scroll around, and then after a second the text becomes sharper. That could be as well a reason for you're issue.

Silverlight Line Graph with Gradient

I have a series of points which I will turn into a line on a graph. What I want is to give the area under the graph a gradient fill. It would look somewhat similar to a Bloomberg graph like this;
My question really has three parts;
First, how should I fill only the area under the graph?
Second, how do I fill that with a gradient?
Finally, if I have multiple lines on the same graph any area under more than one line should have a greyscale gradient fill, how would you set this up?
My biggest problem is deciding on the data structures to use, I could use many multiple sided shapes (One for each line/ data series) and then tell the brush to draw;
Transparent if it's not in any shape
The colour of one series if it's in one shape (Alpha relative to height to give grad)
Black if it's in multiple shapes (Alpha relative to height to give grad)
Then I'd draw the shapes' boundaries in white afterwards.
Thanks,
Gav
The gradient effect is possible using the free version of Visiblox Silverlight Charts. See the example application 'Hindsight' to see how Visiblox charts can be applied to an application of this context.
I've attached a crude code snippet of the XAML on how to achieve this effect:
<UserControl x:Class="SilverlightApplication1.MainPage"
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:v="clr-namespace:Visiblox.Charts;assembly=Visiblox.Charts">
<UserControl.Resources>
<LinearGradientBrush x:Key="GradientBrush" StartPoint="1.0, 0.0" EndPoint="1.0, 1.0">
<GradientStop Color="AliceBlue" Offset="0.3" />
<GradientStop Color="DarkBlue" Offset="0.7" />
</LinearGradientBrush>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<v:Chart x:Name="Chart">
<v:Chart.Series>
<v:LineSeries x:Name="Series" ShowArea="True" AreaFill="{StaticResource GradientBrush}"/>
</v:Chart.Series>
</v:Chart>
</Grid>
Personally, I would take the action that Hindsight does, removing the area under lines when there are multiple series on the plot area. I think at that point the gradients get in the way of the data, and as you mentioned above, to do something about this incurs a computational cost. This could also lead to misinterpretations of the data so be wary.
In terms of getting your data to the chart, you can use the Visiblox BindableDataSeries to bind your business objects directly onto the chart. :)
Disclosure: I have previously worked as a developer on Visiblox Charts.
Hope this helps!

Tiling rectangles seamlessly in WPF

I want to seamlessly tile a bunch of different-colored Rectangles in WPF. That is, I want to put a bunch of rectangles edge-to-edge, and not have gaps between them.
If everything is aligned to pixels, this works fine. But I also want to support arbitrary zoom, and ideally, I don't want to use SnapsToDevicePixels (because it would compromise quality when the image is zoomed way out). But that means my Rectangles sometimes render with gaps. For example:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Black">
<Canvas SnapsToDevicePixels="False">
<Canvas.RenderTransform>
<ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
</Canvas.RenderTransform>
<Rectangle Canvas.Left="25" Width="100" Height="100" Fill="#CFC"/>
<Rectangle Canvas.Left="125" Width="100" Height="100" Fill="#CCF"/>
</Canvas>
</Page>
If the ScaleTransform's ScaleX is 1, then the Rectangles fit together seamlessly. When it's 0.5, there's a dark gray streak between them. I understand why -- the combined semi-transparent edge pixels don't combine to be 100% opaque. But I would like a way to fix it.
I could always just make the Rectangles overlap, but I won't always know in advance what patterns they'll be in (this is for a game that will eventually support a map editor). Besides, this would cause artifacts around the overlap area when things were zoomed way in (unless I did bevel-cut angles on the underlapping portion, which is an awful lot of work, and still causes problems at corners).
Is there some way I can combine these Rectangles into a single combined "shape" that does render without internal gaps? I've played around with GeometryDrawing, which does exactly that, but then I don't see a way to paint each RectangleGeometry with a different-colored brush.
Are there any other ways to get shapes to tile seamlessly under an arbitrary transform, without resorting to SnapsToDevicePixels?
You might consider using guidelines (see GuidelineSet on MSDN) and overriding the Rectangles' OnRender methods so that their boundaries line up with the pixel boundaries of the device. WPF uses guidelines to determine whether and where to snap drawings.
Internally, it's exactly what SnapsToDevicePixels is using to ensure that objects line up with the device's pixels, but by placing guidelines manually you'll be able to control when the snapping behaviour is applied and when it is not (so when your image is zoomed all of the way out, you can avoid drawing guidelines, or only draw guidelines where your shapes lie next to other shapes, and rely on WPF's anti-aliasing to take care of the rest). You might be able to do it with an attached property so that you can apply it to any element, though if it's only one type of element (e.g. Rectangle) that you need this behaviour on, it's probably not worth the extra effort.
It seems like Microsoft is aware of this problem, too - WPF 4.0 is expected to feature Layout Rounding, which, like the version in Silverlight, rounds off non-integer values at the Render pass when layout rounding has been enabled.
I guess the gaps are not actual gaps but the stroke that is painted. When you scale it down than you just make the stroke smaller to a point where it is not visible anymore. I tried to paint the stroke in the color of the rectangle wich works just fine on any scale.
&ltPage xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Black"&gt
&ltCanvas SnapsToDevicePixels="False"&gt
&ltCanvas.RenderTransform&gt
&ltScaleTransform ScaleX="0.5" ScaleY="0.5"/&gt
&lt/Canvas.RenderTransform&gt
&ltRectangle Canvas.Left="25" Width="100" Height="100" Fill="#CFC" Stroke="#CFC"/&gt
&ltRectangle Canvas.Left="125" Width="100" Height="100" Fill="#CCF" Stroke="#CCF"/&gt
&lt/Canvas&gt
&lt/Page&gt

Resources