This is the discussion forum for OxyPlot.
For bugs and new features, use the issue tracker located at GitHub.
Also try the chat room!

XY Plot - Custom color per marker/pixel?

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

bradparks wrote at 2013-08-27 15:57:

Hi there;

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:

I don't think it's possible right now. As you said you can create a new ScatterSeries/LineSeries for each group of points with the same color.

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: Image

bradparks wrote at 2013-08-28 15:09:

Hmmm... interesting! thanks for the code and suggestions.... I'll take a look and see what I can make of it.... thanks for your help!

Rubber-banding with OxyPlot

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

mohitvashistha wrote at 2013-05-06 14:35:

I want to rubberband a line series as we rubberband a polyline in any CAD application.

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

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

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

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

jstrang3 wrote at 2013-09-04 23:01:

Trying to bind a data source in MVVM and confused on why the data does not seem to be binding.
<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:

Are you sure that you are binding correctly?
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:

I am trying to make a simple messagebox appear for my command. I am pretty sure that my bindings are incorrect, and that is what I need help with. The binding of a context menu is confusing to me. So helping with the binding would be great.

everytimer wrote at 2013-09-05 15:55:

I don't know why the binding isn't working. If you really need to perform a command in your bound ViewModel you can do the following:

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:

Can not use the code behind, so I have to do all the binding in the xaml. This makes the task a little more difficult. Also, I have been trying different bindings and nothing seems to be working for me. So I am open to suggestions, that do not use code behind.

everytimer wrote at 2013-09-05 17:37:

Then bind the command to a button, that will work.

objo wrote at 2013-09-06 07:08:

I tried to use a {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:

My problem is that I am using the MVVM model, and I do not have any code behind, so the view is only xaml. Which does not allow me to connect directly to the plot or anything in it. So is there a way to do the same thing in the xaml that you suggested in the code behind.
0
Under review

Xamarin.Android LineChart legend items text cut off

Tyron Gower 10 years ago updated by anonymous 10 years ago 1
I have a LineChart with the Legend Above/Outside and it is cutting off the text, when i increase the symbol length it expands but i cant seem to get the text to stop being cut off (after about 1-2 letters)

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

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

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! :)

0

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

Mischa Vreeburg 9 years ago 0

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

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

DennisLer wrote at 2014-03-19 10:57:

Hi

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:

Thanks, I see the background of the WPF control was not set by the Background property of the PlotModel. Should be fixed in build 257.

Annotationperformance

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

urm3l wrote at 2013-04-11 07:07:

Hi,

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:

I think you need to write a custom tracker control to do this with max performance! Then you can update the graphics of the tracker without changing the graphics of the plot.

Customize the borders of PlotView: PlotAreaBorderThickness is not a Thickness, but a double

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

Auriou wrote at 2014-05-24 14:55:

Hi all, I would not have a border at the top and right side of my graphics.

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:

I found the solution:

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:

This should be covered by http://oxyplot.codeplex.com/workitem/10006
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:

This should be fixed now.
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:

Great, thank you! it's true that it's normal that the PlotAreaBorderThickness property that must manage the plot borders and not axes responsibility.

  PlotAreaBorderThickness = new OxyThickness() { Bottom = 1, Left = 1, Right = 0, Top = 0}
now it works, thank you again.