surban / PLplotNet

PLplot bindings for .Net
https://surban.github.io/PLplotNet
Other
35 stars 12 forks source link

C# example #2

Open SuperDaveOsbourne opened 6 years ago

SuperDaveOsbourne commented 6 years ago

I see two F# examples, any chance there are any C# examples.

surban commented 6 years ago

Not yet, but I will add one when I find some time. Is there any particular example from http://plplot.sourceforge.net/examples.php that you'd like translated to C#?

SuperDaveOsbourne commented 6 years ago

I have this so far but am confused how to pass the command line parameters in code or if they would even work. With the new .core ML stuff I wanted something in line to test with until there are GUI versions of .net core 3.x. I saw your comment on that blog about using PlplotNet.

Ideally would want to programatically select the output type (SVG) #6 and the file name, ala test.svg without having to manually select them.

using PLplot; using System;

namespace ExampleX00 { internal static class Program { private static void Main(string[] args) {

        var pl = new PLStream();

        const int nSize = 100;
        const int yMax = 100;
        const int xMin = 0;
        const int xMax = 1;
        const int yMin = 0;

        var x = new double[nSize];
        var y = new double[nSize];

        for (var i = 0; i <= nSize - 1; i++)
        {
            x[i] = ((double)i / (double)(nSize - 1));
            y[i] = yMax * x[i] * x[i];
        }

        string[] arg = {""};
        pl.parseopts(ref arg, ParseOpts.Full & ParseOpts.NoProgram);

        // Initialize plplot
        pl.init();

        pl.env( xMin, xMax, yMin, yMax, AxesScale.Independent, AxisBox.BoxTicksLabelsAxes );
        pl.lab( "x", "y=100 x#u2#d", "Simple PLplot demo of a 2D line plot" );

        pl.line( x, y );

        // Plplotnet version info
        pl.gver(out var verText);

        Console.WriteLine("PLplot version = " + verText);
        Console.WriteLine(Environment.NewLine);
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();

    }
}

}

SuperDaveOsbourne commented 6 years ago

Got the SVG device working but that is it. pngcairo generates empty files. wincario just hangs. Not sure if or how that GTK+ drivers are accessed through managed code. Here is my example

using PLplot; using System; using System.Reflection;

namespace ExampleSineWaves { internal static class Program { private static void Main(string[] args) { const double sineFactor = 0.012585; const int exampleCount = 1000; var phaseOffset = 125;

        var x0 = new double[exampleCount];
        var y0 = new double[exampleCount];

        for (var j = 0; j < exampleCount; j++)
        {
            x0[j] = j;
            y0[j] = (double)(System.Math.Sin(sineFactor * (j + phaseOffset)) * 1);
        }

        var x1 = new double[exampleCount];
        var y1 = new double[exampleCount];
        phaseOffset = 250;

        for (var j = 0; j < exampleCount; j++)
        {
            x1[j] = j;
            y1[j] = (double)(System.Math.Sin(sineFactor * (j + phaseOffset)) * 1);
        }

        var x2 = new double[exampleCount];
        var y2 = new double[exampleCount];
        phaseOffset = 375;

        for (var j = 0; j < exampleCount; j++)
        {
            x2[j] = j;
            y2[j] = (double)(System.Math.Sin(sineFactor * (j + phaseOffset)) * 1);
        }

        var x3 = new double[exampleCount];
        var y3 = new double[exampleCount];
        phaseOffset = 500;

        for (var j = 0; j < exampleCount; j++)
        {
            x3[j] = j;
            y3[j] = (double)(System.Math.Sin(sineFactor * (j + phaseOffset)) * 1);
        }

        var pl = new PLStream();

        string[] arg = {""};
        pl.parseopts(ref arg, ParseOpts.Full & ParseOpts.NoProgram);

        // set background color r g b
        pl.scolbg(25, 25, 25);

        // ps         PostScript File (monochrome)
        // psc        PostScript File (color)
        // xfig       Xfig file
        // null       Null device
        // mem        User-supplied memory device
        // svg        Scalable Vector Graphics (SVG 1.1)
        // pdfcairo   Cairo PDF Driver
        // epscairo   Cairo EPS Driver
        // pscairo    Cairo PS Driver
        // svgcairo   Cairo SVG Driver
        // pngcairo   Cairo PNG Driver
        // memcairo   Cairo memory driver
        // extcairo   Cairo external context driver
        // wincairo   Cairo Microsoft Windows driver

        // set the device: I couldn't get any other than the vanilla svg driver to work
        // do you have to install the cairo drivers or do they have to be compiled in plplot.net aready?
        // I don't see any error messages.
        pl.sdev("svg");

        // set the output file name
        pl.sfnam("test.svg");

        // Initialize plplot
        pl.init();

        const int xMin = 0;
        const int xMax = 1000;
        const int yMin = -1;
        const int yMax = 1;

        pl.env(xMin, xMax, yMin, yMax, AxesScale.Independent, AxisBox.BoxTicksLabelsAxes);

        // Set scaling for mail title text 125% size of default
        pl.schr(0,1.25);

        // The main title
        pl.lab("X", "Y", "PLplot demo of four sine waves");

        //0 black (default background)
        //1 red (default foreground)
        //2 yellow
        //3 green
        //4 aquamarine
        //5 pink
        //6 wheat
        //7 grey
        //8 brown
        //9 blue
        //10 BlueViolet
        //11 cyan
        //12 turquoise
        //13 magenta
        //14 salmon
        //15 white

        pl.col0(9);
        pl.line(x0, y0);
        pl.col0(1);
        pl.line(x1, y1);
        pl.col0(2);
        pl.line(x2, y2);
        pl.col0(4);
        pl.line(x3, y3);

        // Plplotnet version info
        pl.gver(out var verText);

        // tested version version = 5.13.0
        Console.WriteLine("PLplot Version Number = " + verText);
        Console.WriteLine(Environment.NewLine);

        // Tested Net Core Version Number = 2.1.0
        Console.WriteLine("Net Core Version Number = " + GetNetCoreVersion());
        Console.WriteLine(Environment.NewLine);
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();

    }

    public static string GetNetCoreVersion()
    {
        //https://github.com/dotnet/BenchmarkDotNet/issues/448
        var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
        var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
        int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
        if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
            return assemblyPath[netCoreAppIndex + 1];
        return null;
    }
}

}

surban commented 6 years ago

I've added an example based on your code at https://github.com/surban/PLplotNet/blob/master/Samples/CSharp/SineWaves/Program.cs.

Your code is working fine on my machine after I've removed the call to parseopts. It is only really necessary when you want to use the PLplot command options parser. I've also added a call to pl.eop in the end to make sure that the resulting SVG is written to disk.

image

Are you working on Linux or Windows? On Windows all drivers are shipped in the NuGet package and you don't need to install anything. On Linux, PLplot and the necessary backend needs to be installed using your distribution's package manger.

Direct output the PNG is also working fine for me. For that I've used the following two lines:

            pl.sdev("pngcairo");
            pl.sfnam("SineWaves.png");

sinewaves

SuperDaveWhite commented 6 years ago

Yes since the SVG worked without pl.eop I wasn't looking for it.

Now on my list:

Now off to work on that stuff and will update demos for those. Still something that will visually show trees in .core on Windows 10.

Thanks for the hard work!

surban commented 6 years ago

For trees you might want to try https://www.nuget.org/packages/GraphViz.NET/. I haven’t used the NET Binding, but I know that GraphViz itself is very popular.

tonyle8 commented 6 years ago

I ran the above example but keep running into this issue on Windows 7 with .NET Framework 4.6.2 VisualStudio2017 Pro:

System.TypeInitializationException HResult=0x80131534 Message=The type initializer for 'PLplot.Native' threw an exception. Source=PLplotNet StackTrace: at PLplot.Native.mkstrm(Int32& p_strm) at PLplot.PLStream..ctor() in PLStream.cs:line 24 at Program.Main(String[] args) in Program.cs:line 68

Inner Exception 1: InvalidOperationException: Cannot find support PLplot support files in System.String[].

tonyle8 commented 6 years ago

More info - I installed using NuGet Package Manager

tonyle8 commented 6 years ago

Fix - Manually copy over \packages\PLplot.5.13.7\runtimes\win-x64\native\ to the debug or release folder.

Strangely, running a console app with .Net core does not have this issue.

capesean commented 5 years ago

Fix - Manually copy over \packages\PLplot.5.13.7\runtimes\win-x64\native\ to the debug or release folder.

I tried this, but then the following line errors:

_putenv_s("PLPLOT_LIB", supPath);

(Not using .net core, fwiw)

gruckion commented 5 years ago

Also having the same issue

dotnet add package PLplot

Microsoft Visual C++ Redistributable 2017 (was already installed, I clicked repair and restarted my machine).

Running via dotnet run

 ---> System.InvalidOperationException: Cannot find support PLplot support files in System.String[].
   at PLplot.Native..cctor() in C:\projects\plplotnet\PLplotNet\NativeHelpers.cs:line 200
   --- End of inner exception stack trace ---
   at PLplot.Native.mkstrm(Int32& p_strm)
   at PLplot.PLStream..ctor() in C:\projects\plplotnet\PLplotNet\PLStream.cs:line 24
   at Program.Main(String[] args) in D:\repos\ML.Net\Program.cs:line 53

Or running in visual studio 2019

image

using System;
using Microsoft.ML;
using Microsoft.ML.Data;
using PLplot;

class Program
{
    public class HouseData
    {
        public float Size { get; set; }
        public float Price { get; set; }
    }

    public class Prediction
    {
        [ColumnName("Score")]
        public float Price { get; set; }
    }

    static void Main(string[] args)
    {
        var mlContext = new MLContext();
        {
            // 1. Import or create training data
            var trainingData = mlContext.Data.LoadFromEnumerable(
                new HouseData[]
                {
                new HouseData() { Size = 1.1F, Price = 1.2F },
                new HouseData() { Size = 1.9F, Price = 2.3F },
                new HouseData() { Size = 2.8F, Price = 3.0F },
                new HouseData() { Size = 3.4F, Price = 3.7F }
                });

            // 2. Specify data preparation and model training pipeline
            var pipeline = mlContext.Transforms.Concatenate("Features", new[] { "Size" })
                .Append(mlContext.Regression.Trainers.Sdca(
                    labelColumnName: "Price",
                    maximumNumberOfIterations: 100));

            // 3. Train model
            var model = pipeline.Fit(trainingData);

            // 4. Make a prediction with test data
            var testingData = new HouseData() { Size = 2.5F };
            var price = mlContext.Model.CreatePredictionEngine<HouseData, Prediction>(model)
                .Predict(testingData);

            Console.WriteLine($"Predicted price for size: {testingData.Size * 1000} sq ft= {price.Price * 100:C}k");

            // Predicted price for size: 2500 sq ft= $261.98k
        }

        // 5. Visualize our data
        var pl = new PLStream();
        pl.sdev("svg");
        pl.sfnam("linear-regression.svg");
        pl.spal0("cmap0_alternate.pal");
        pl.init();

        const int xMin = 0;
        const int xMax = 1000;
        const int yMin = -1;
        const int yMax = 1;
        pl.env(xMin, xMax, yMin, yMax, AxesScale.Independent, AxisBox.BoxTicksLabelsAxes);
        pl.schr(0, 1.25);
        pl.lab(nameof(HouseData.Size), nameof(HouseData.Price), "Linear regression plot of house price for size");
        pl.eop();

    }
}

I am just setting up the plotting of the linear data above, haven't set the data yet. As I cannot even get it to load the PLStream. If your curious of what I am doing, I am doing the Hello ML.Net World example

saskathex commented 5 years ago

Hi,

I had the same issue with Win10 and .NetCore 3.0 today.

---> System.InvalidOperationException: Cannot find support PLplot support files in System.String[]. at PLplot.Native..cctor() in C:\projects\plplotnet\PLplotNet\NativeHelpers.cs:line 200

My solution was to copy the runtimes folder with the dlls 2 directories upward! The init is looking 2 folders upward too.

ggorecki commented 4 years ago

Following up on @saskathex's correct post, here is a concrete example...

Example on my system… Copy the “runtimes” folder up 2 levels into the “bin” folder. FROM ==> M:\ProjectFolder\bin\Debug\netcoreapp3.1\ TO ==> M:\ProjectFolder\bin

See comment (cut/paste below) from this link: https://github.com/surban/PLplotNet/blob/eed9c8796c037c0df539247b9c5bbc63f10afc34/PLplotNet/NativeHelpers.cs You can see there in the NativeHelpers.cs code that it is looking for the plplot directory (via its path), 2 levels up.

// For PLplot to find its support files, the environment variable // PLPLOT_LIB must be set accordingly.
string[] supPaths = { Path.Combine(libDir, "plplot"), Path.Combine(libDir, "..", "..", "runtimes", "win-x64", "native", "plplot") };

Thank you for your research and a solution @saskathex !

MalcolmHannah commented 4 years ago

Adapting the sample as a Windows Forms app and running inside Visual Studio, I also hit the exception about not finding the support files.

The two-folders-up trick didn't work for me (ProcMon didn't show that folder being searched for plplot.dll).

What worked for me was adding this Pre-Build Event to the project:

rem VS runs this in $(OutDir)
rem /E includes sub-dirs
rem /NP avoids progress updates
rem /NFL avoids listing files
Robocopy $(ProjectDir)packages\PLplot.5.13.7\runtimes\win-x64\native . /E /NP /NFL
rem Exit codes 0 to 7 mean success
IF %ERRORLEVEL% LEQ 7 exit /B 0

This copies the contents of the native folder into the same folder where the executable will be produced. Robocopy skips files that are already in the destination.

After getting past this exception I hit another because the PLplot libraries are 64-bit. The fix is to de-select "Prefer 32-bit" in Project, Properties, Build (my Platform target is 'Any CPU').

engineering87 commented 4 years ago

Same issue here with a .NET Core 3.1 console app. Fix copying the native PLPlot directory into bin/debug(release)/netcoreapp3.1

sam-wheat commented 2 years ago

Quick copy/paste fix that works for me:

<Target Name="CopyFiles" AfterTargets="Build">
    <ItemGroup>
        <PlotFiles Include="$(TargetDir)runtimes\win-x64\native\**\*.*" />
    </ItemGroup>
    <Message Text="Executing AfterBuild copy files task" Importance="High" />
    <Copy SourceFiles="@(PlotFiles)" DestinationFolder="$(TargetDir)%(RecursiveDir)" ContinueOnError="true" />
    <Message Text="AfterBuild copy files task completed" Importance="High" />
</Target>

Paste the above into your .csproj directly inside the <Project> tags.

The needed files are in a sub directory of the output folder after build. As others have mentioned, files for the runtime identifier need to be copied up a couple levels into the output folder.

Tested on:

Windows

VS 2019 / net 5

PLplot 5.13.7

bharathwajv commented 1 month ago

Quick copy/paste fix that works for me:

<Target Name="CopyFiles" AfterTargets="Build">
  <ItemGroup>
      <PlotFiles Include="$(TargetDir)runtimes\win-x64\native\**\*.*" />
  </ItemGroup>
  <Message Text="Executing AfterBuild copy files task" Importance="High" />
  <Copy SourceFiles="@(PlotFiles)" DestinationFolder="$(TargetDir)%(RecursiveDir)" ContinueOnError="true" />
  <Message Text="AfterBuild copy files task completed" Importance="High" />
</Target>

Paste the above into your .csproj directly inside the <Project> tags.

The needed files are in a sub directory of the output folder after build. As others have mentioned, files for the runtime identifier need to be copied up a couple levels into the output folder.

Tested on:

Windows

VS 2019 / net 5

PLplot 5.13.7

Works fine for me!