XY Plot - Custom color per marker/pixel?
bradparks wrote at 2013-08-27 15:57:
I've just found this excellent looking library and have looked at the examples, but don't see anything that matches what I'd like to do:
I need to do a plot of thousands of x,y coordinates, each as a stand alone point with a custom color per pixel. The colors will range over 1000's of colors as well (possibly a custom color for each individual pixel)
What type of plot and marker type would I use to do this?
I saw the custom marker types example, but that only seems to allow one custom market type per series. I also took a look at the mouse move examples, and they got that to work by creating a custom series for each mouse movement, which isn't really what I want (way too many series). My data comes in batches, and will probably be in ~10 batches, and each batch will be a custom series, I expect.
Thanks,
Brad
everytimer wrote at 2013-08-27 22:54:
If you can use the MatrixSeries provided in the examples you can change it partially:
if (this.image == null)
{
var pixels = new OxyColor[m, n];
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
var c = MyColorSelectionMethod(Matrix[m-1-i, j]);
pixels[i, j] = Math.Abs(this.Matrix[m - 1 - i, j]) <= this.ZeroTolerance ? OxyColors.Transparent : c;
//pixels[i, j] = Math.Abs(this.Matrix[m - 1 - i, j]) <= this.ZeroTolerance ? OxyColors.Transparent : this.NotZeroColor;
}
}
this.image = OxyImage.PngFromArgb(pixels);
}
And the custom method could be:
public static OxyColor MyColorSelectionMethod(double num)
{
OxyColor color = new OxyColor();
IList<OxyColor> listColors = new List<OxyColor>();
OxyColor c;
for (double i = 0; i < 1; i += 0.02)
{
c = OxyColor.FromHsv(i, 0.8, 0.8);
listColors.Add(c);
}
if (num > 0.7)
{
color = listColors[Convert.ToInt32(num * 49)];
}
else
{
color = listColors[Convert.ToInt32(num * 49)].ChangeAlpha((byte)(100*num));
}
return color;
}
This method assigns a color from gradient depending on the value of "num". Note that in this example I've set its maximum value to 1.
Result:
bradparks wrote at 2013-08-28 15:09:
Rubber-banding with OxyPlot
mohitvashistha wrote at 2013-05-06 14:35:
I have written an example for the same.
[Example("LineSeries rubberbanding")]
public static PlotModel MouseRubberbandingEvent()
{
var model = new PlotModel("Rubberbanding",
"Left click to add line and press Esc to end.")
{
LegendSymbolLength = 40
};
// Add a line series
var s1 = new LineSeries("LineSeries1")
{
Color = OxyColors.SkyBlue,
MarkerType = MarkerType.Circle,
MarkerSize = 6,
MarkerStroke = OxyColors.White,
MarkerFill = OxyColors.SkyBlue,
MarkerStrokeThickness = 1.5
};
model.Series.Add(s1);
s1.Points.Add(new DataPoint(10,
10));
IDataPoint tempDataPoint = new DataPoint(0,0);
s1.Points.Add(tempDataPoint);
// Remember to refresh/invalidate of the plot
model.RefreshPlot(false);
bool isRubberbanding = false;
// Subscribe to the mouse down event on the line series
model.MouseDown += (s, e) =>
{
// only handle the left mouse button (right button can still be used to pan)
if (e.ChangedButton == OxyMouseButton.Left)
{
s1.Points.Add(s1.InverseTransform(e.Position));
isRubberbanding = true;
// Remember to refresh/invalidate of the plot
model.RefreshPlot(false);
// Set the event arguments to handled - no other handlers will be called.
e.Handled = true;
}
};
// Subscribe to the mouse down event on the line series
s1.MouseDown += (s, e) =>
{
// only handle the left mouse button (right button can still be used to pan)
if (
(e.ChangedButton == OxyMouseButton.Left)
&&
(isRubberbanding)
)
{
s1.Points.Add(s1.InverseTransform(e.Position));
isRubberbanding = true;
// Remember to refresh/invalidate of the plot
model.RefreshPlot(false);
// Set the event arguments to handled - no other handlers will be called.
e.Handled = true;
}
};
model.MouseMove += (s, e) =>
{
if (isRubberbanding)
{
var point = s1.InverseTransform(new ScreenPoint(e.Position.X-8,
e.Position.Y-8));
tempDataPoint.X = point.X;
tempDataPoint.Y = point.Y;
s1.Points.Remove(tempDataPoint);
s1.Points.Add(tempDataPoint);
model.RefreshPlot(false);
}
};
model.MouseUp += (s, e) =>
{
if (isRubberbanding)
{
s1.LineStyle = LineStyle.Solid;
model.RefreshPlot(false);
e.Handled = true;
}
};
return model;
}
It works fine when I offset the mouse cursor by 8 pixel. But when I don't do that the mouse down event doesn't fire up neither for plot model nor for line series.Please suggest why mouse down is not fires while rubber banding.
Also how can i get the ESC key to end the rubberbanding.
Styling the plot
Tech_Junkie wrote at 2012-07-19 13:19:
I am busy implementing a lineseries with two axes to show an overview of frequencies and their intensity. And until now I've used the styling as I've copied it from an example, in the definition of a lineseries:
LineSeries ls = new LineSeries() { Color = OxyColors.Green, StrokeThickness = 2, MarkerType = MarkerType.Square, MarkerSize = 3, MarkerStroke = OxyColors.Black, MarkerStrokeThickness = 1 };I was wondering if (and how) I can take these styling elements out of the code and put it in a styling in a xaml ResourceDictionary? Is this possible?
Tech_Junkie wrote at 2012-07-20 09:38:
I seem to have already solved this by using a vertical LineAnnotation :)
Thank you for providing the functionality!
Tech_Junkie wrote at 2012-07-20 14:03:
An additional question though, is it possible to have a vertical line and a horizontal text-label with it? Or do I have to position a TextAnnotation myself? (which is tricky, because the scaling depends on zooming, and I want a constant distance between the line and the text)
objo wrote at 2012-08-08 23:56:
Yes, the line annotation should have a 'Text' property you could use.You have some control of the position/alignment - see the TextPosition, TextMargin, TextHorizontalAlignment and TextVerticalAlignment properties.
Tech_Junkie wrote at 2012-08-09 09:18:
This is true, but if I render a vertical line, the text will also be vertical and I cannot find how to change this to a horizontal text with my vertical line. Is this possible?
I currently 'solve' this by adding a textannotation below the vertical line and leaving a space at the bottom of the line by giving it a minimumY
objo wrote at 2012-08-10 13:10:
Added a TextOrientation property in the LineAnnotation class.
Tech_Junkie wrote at 2012-08-10 13:31:
Thank you for the quick fix!
Tech_Junkie wrote at 2012-08-13 12:34:
Tech_Junkie wrote:
I am busy implementing a lineseries with two axes to show an overview of frequencies and their intensity. And until now I've used the styling as I've copied it from an example, in the definition of a lineseries:
LineSeries ls = new LineSeries() { Color = OxyColors.Green, StrokeThickness = 2, MarkerType = MarkerType.Square, MarkerSize = 3, MarkerStroke = OxyColors.Black, MarkerStrokeThickness = 1 };I was wondering if (and how) I can take these styling elements out of the code and put it in a styling in a xaml ResourceDictionary? Is this possible?
I see now that my second post apparently did not cover my complete question. Objo, would it be possible to do styling of elements in a plot out of the code, and in xaml?
objo wrote at 2012-08-23 15:59:
If you define your plot in XAML (WPF/SL) it should be possible to use a Style from a ResourceDictionary on the OxyPlot.Wpf.LineSeries. I have no example on this, but believe it should work. Let us know if there is a bug!
aec wrote at 2012-08-23 21:23:
Hi, I have already done this with WPF and it works fine!
aec wrote at 2012-08-23 21:24:
This discussion leads me to an additional question: Is it possible to define a line series (or in my case a plot model) with C# and to change the style afterwards with WPF xaml code? This way, we have a default style defined by the C# code, which can be overwritten later on. This yields more flexibility.
objo wrote at 2012-08-24 08:33:
You could override property metadata
http://msdn.microsoft.com/en-us/library/ms754209.aspx
but I don't think it is possible to mix a PlotModel and a Plot defined by XAML...
aec wrote at 2012-08-24 11:04:
Hi objo, I know this. Okay, it was just an idea but this realization leads to too much effort for me. In addition, I like brief and neat program code.
Binding Confusion with ContextMenus
jstrang3 wrote at 2013-09-04 23:01:
<oxy:Plot Grid.Row="0" x:Name="BalancesByPeriodChart"
LegendPlacement="Outside"
LegendPosition="BottomCenter"
LegendOrientation="Horizontal"
LegendSymbolLength="30"
LegendBorder="#000000"
LegendBorderThickness="1"
LegendFontSize="14"
PlotMargins="54,10,10,50"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
KeyboardPanHorizontalStep="-0.1"
KeyboardPanVerticalStep="-0.1"
Model="{Binding ChartViewModel}"
Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type oxy:Plot}}, Path=Model}"
>
<oxy:Plot.ContextMenu>
<ContextMenu ItemsSource="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self} }">
<MenuItem Command="{Binding Plot.HideGraph1}" Header="Foo"
IsCheckable="True" IsChecked="True"/>
<MenuItem Command="{Binding Plot.HideGraph2}" Header="Foo2"
IsCheckable="True" IsChecked="True"/>
</ContextMenu>
</oxy:Plot.ContextMenu>
With this code I am trying to make a context menu so I can eventually set the visibility of two different graphs to hidden. The context menu shows up but when I click on either option, the command in the modelview is not triggered. Any help with this problem
is greatly appreciated. everytimer wrote at 2013-09-04 23:22:
Plot.HideGraph2
This seems weird for me, where the command is located? Is the datacontext set correctly? First try simple operation when you're starting to wiring the commands, try if your commands are working with a MessegeBox. If your bindings are okey: a common mistake
is to forget to update the plot. Show the actual code in your command so we can help you.jstrang3 wrote at 2013-09-05 14:54:
everytimer wrote at 2013-09-05 15:55:
Create a new static class Mediator:
static public class Mediator
{
static IDictionary<string, List<Action<object>>> pl_dict = new Dictionary<string, List<Action<object>>>();
static public void Register(string token, Action<object> callback)
{
if (!pl_dict.ContainsKey(token))
{
var list = new List<Action<object>>();
list.Add(callback);
pl_dict.Add(token, list);
}
else
{
bool found = false;
foreach (var item in pl_dict[token])
if (item.Method.ToString() == callback.Method.ToString())
found = true;
if (!found)
pl_dict[token].Add(callback);
}
}
static public void Unregister(string token, Action<object> callback)
{
if (pl_dict.ContainsKey(token))
pl_dict[token].Remove(callback);
}
static public void NotifyColleagues(string token, object args)
{
if (pl_dict.ContainsKey(token))
foreach (var callback in pl_dict[token])
callback(args);
}
}
In your MenuItem set the click event: <MenuItem Header="Mediator!" Click="MenuItem_Click_1" />
Code behind notify the message:
private void MenuItem_Click_1(object sender, RoutedEventArgs e)
{
Mediator.NotifyColleagues("menu1", null);
}
Don't forget to register to listen the message in your ViewModel constructor: Mediator.Register("menu1", yourMethod);
void yourMethod(object param)
{
MessageBox.Show("Hey!");
myLineSeries.IsVisible = !myLineSeries.IsVisible;
}
Done!If would be nice if someone could tell us if he can achieve the binding to command in the context menu.
jstrang3 wrote at 2013-09-05 16:26:
everytimer wrote at 2013-09-05 17:37:
objo wrote at 2013-09-06 07:08:
{Binding PresentationTraceSources.TraceLevel=High}
and it seems the data context is not passed to the context menu. I don't know why..
I added
this.ContextMenu.DataContext = this.DataContext;
to the Plot control, just before it shows the context menu.
I am not sure if this is an ok way to solve it, but it seems to work.
DrStrangeLove wrote at 2013-09-06 22:12:
Xamarin.Android LineChart legend items text cut off
Control.Model.LegendOrientation = LegendOrientation.Horizontal;
Control.Model.LegendPosition = LegendPosition.TopCenter;
Control.Model.LegendPlacement = LegendPlacement.Outside;
Control.Model.LegendItemAlignment = HorizontalAlignment.Center;
Control.Model.LegendFontSize = 9;
Control.Model.LegendMaxWidth = 1000;
Control.Model.LegendSymbolLength = 15;
Performance of ColumnSeries
Coffeephile wrote at 2012-07-17 13:31:
Is there any way to increase performance of ColumnSeries bars? With 200+ bars it gets PAINFULLY slow.
objo wrote at 2012-08-08 23:35:
The Bar/ColumnSeries is currently rendering the bars/columns one by one (see BarSeriesBase.RenderItem) as polygons (I think this was necessary to get it pixel-perfect on some platforms...). You could try to override the RenderItem method - add the rectangles to a list, perform the clipping and use IRenderContext.DrawRectangles to render all bars/columns at the end. Can you create a fork and test this? Let us know the results! :)
I want to extend the boxplot item with a new constructor to create a bpi based on a list of values, not the calculated boxplot stats
When using the boxplot series as it is currently, one needs to first calculate the quartiles, the median and the whisker values of the series.
I believe this can be improved by creating a new constructor which takes the original list of datapoints and then calculates the box and whisker boundaries.
This will make the boxplot series more inline with the other series, where the user needs to supply the original values and not the derived statistics.
To give the user more control over the upper and lower whiskers, I'll include an enum with the 5 most common whiskers and make the calculations accordingly:
The 5 different whisker settings being:
IQR: interquartile range : Q3+1.5 * IQR | Q1 - 1.5* IQR
MinMax: Minimum and maximum of datapoints
NinthPercentile: The whiskers are the ninth and ninety first percentile of the dataseries
secondPercentile: The whiskers are the second and ninety eightpercentile of the dataseries
StDev: standard deviation: mean of series + standard deviation / mean of series - standard deviation.
Background color doesn't change from white in WPF
DennisLer wrote at 2014-03-19 10:57:
I have started using OxyPlot for a simple graph, but I have a problem regarding setting the background color. It apparently doesn't seem to work ?
The plotAreaBackground is changed correctly.
Even setting it to red, it continues to be white. What I have done is the below:
plotModel = new PlotModel();
plotModel.PlotAreaBackground = BackgroundBaseColor.ToOxyColor();
plotModel.Background = OxyColors.Red;
DateTimeAxis dateTimeAxis = new DateTimeAxis(AxisPosition.Bottom, "Date", CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern);
dateTimeAxis.Maximum = DateTimeAxis.ToDouble(DateTime.Today);
plotModel.Axes.Add(dateTimeAxis);
OxyPlot.MinWidth = ActualWidth;
OxyPlot.MaxHeight = ActualHeight;
OxyPlot.Model = plotModel;
ContainerPanel.Children.Add(OxyPlot);
I have tried having ContainerPanel both as a stackpanel and grid... Hope somebody can help.
objo wrote at 2014-03-19 23:17:
Annotationperformance
urm3l wrote at 2013-04-11 07:07:
Is there a way to render annotations as fast as the tracker gets rendererd? I need annotations to move through the plot with the mouse and as soon as I get a lot of data (around 5k points) it really starts to lag.
I call refreshPlot(false) because I thought its not updating the data then. Is there a better way to do that?
Kind regards
objo wrote at 2013-04-18 10:02:
Customize the borders of PlotView: PlotAreaBorderThickness is not a Thickness, but a double
Auriou wrote at 2014-05-24 14:55:
But it seems that this is not possible because the PlotAreaBorderThickness PlotView property is a double, not a Thickness. (currently PlotAreaBorderThickness = "1")
Should be able to write
PlotAreaBorderThickness = "1,0,0,1" like BorderThickness = "1,0,0,1"
Thank.
Auriou wrote at 2014-05-24 18:35:
var model = new PlotModel()
{
PlotAreaBorderThickness = 0,
};
var lineAxis = new LinearAxis()
{
AxislineStyle = LineStyle.Solid
};
model.Axes.Add(lineAxis);
....Other axes with AxislineStyle = LineStyle.Solid
model.Axes.Add(dateTimeAxis);
objo wrote at 2014-05-25 13:51:
I agree it is a good idea! But I am not sure who should have the responsibility of drawing those lines - the axes or the plot...
objo wrote at 2014-05-25 15:47:
I am sorry about breaking the build for those who have used
PlotAreaBorderThickness
, but it should be very easy to correct. Simply replace the double value by
new OxyThickness(x)
.Auriou wrote at 2014-05-26 09:09:
PlotAreaBorderThickness = new OxyThickness() { Bottom = 1, Left = 1, Right = 0, Top = 0}
now it works, thank you again.
Служба підтримки клієнтів працює на UserEcho