Silverlight Line Graph with Gradient - silverlight

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!

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 path description for a sine curve using bezier curves

I need to draw a sine curve (from x = 0 to 2pi) as part of a DrawingVisual and would like to use WPF's basic path capabilities to get a smooth curve. Probably I need some sort of bezier curve for that. Unfortunately I don't even know how they work. (Just that they can "pull" the line towards a control point somehow.)
Can somebody tell me what coordinates I should use to make it look right?
I could apply a ScaleTransform if I want to stretch it a little, so the normal form would be fine.
A thread in the MSDN forums just brought me in the middle of a formula mess in Wikipedia's scientific depths. I haven't studied maths so that's not much use to me.
Nevermind, I played a while with Kaxaml and found this pretty neat. It's probably a bit stretched already, but it makes the plot more recognisable.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Path Data="M0,100 L50,0 L50,200 L100,100" Stroke="Gray" StrokeThickness="0.5"/>
<Path Data="M0,100 C50,0 50,200 100,100" Stroke="Red" StrokeThickness="3"/>
</Grid>
</Page>
The first Path (grey) shows the control points used and how they are on the same horizontal offset; the second Path (red, bold) shows the final bezier curve.
This is how it looks like:

Recolor a given DrawingImage in WPF (in code)

I have a DrawingImage which I have converted from SVG by the magnificent Svg2Xaml plugin. This way I can let the users easily define the visuals of some elements in my application.
There are some use-cases where I would like to recolor the given DrawingImage. The simplest case would be to make it grayscale.
Is there a way to recursively go through all the elements, get their color and switch it to their grayscale counterparts? Or - for example - use something like a "filter" on the whole image?
I'm not really experienced in WPF, but if this could be done it would make my work a lot easier.
What would be my best choice?
Also it is important that the DrawingImage uses vector graphics, so I wouldn't want to pixellate the image.
Converting my comment to an answer:
for the specific case of making a Visual grayscale, you may want to take a look at the Shader Effect Library
U might need to look at the WPF resource dictionary, and use DynamicResource
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Color x:Key="FrontColor">White</Color>
<SolidColorBrush x:Key="Foreground" Color="{DynamicResource FrontColor}" />
</ResourceDictionary>

Silverlight Toolkit LineSeries connects data points randomly

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.

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