성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - PLplot 사용 예제</h1> <p> 지난 글에서 설명한,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ML.NET Model Builder - 회귀(Regression), 다중 분류(Multi-class classification) 예제 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11895'>http://www.sysnet.pe.kr/2/0/11895</a> </pre> <br /> Regression_TaxiFarePrediction 예제를 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > dotnet/machinelearning-samples ; <a target='tab' href='https://github.com/dotnet/machinelearning-samples/tree/master/samples/csharp/getting-started/Regression_TaxiFarePrediction'>https://github.com/dotnet/machinelearning-samples/tree/master/samples/csharp/getting-started/Regression_TaxiFarePrediction</a> </pre> <br /> PLplot 라이브러리를 사용하는 <a target='tab' href='https://github.com/dotnet/machinelearning-samples/blob/master/samples/csharp/getting-started/Regression_TaxiFarePrediction/TaxiFarePrediction/TaxiFarePredictionConsoleApp/Program.cs'>코드</a>와 출력 사례를 볼 수 있습니다.<br /> <br /> <img alt='plplot_sample_1.png' src='/SysWebRes/bbs/plplot_sample_1.png' /><br /> <br /> 이참에, ^^ 간단한 사용법을 정리해 보겠습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> PLplot 설치를 하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Install-Package PLplot * 설치 후 csproj에 다음의 항목이 추가됩니다. <PackageReference Include="PLplot" Version="5.13.7" /> </pre> <br /> 간단한 실습으로 예전에 그냥 점(dot)으로만 그려봤던,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 그래프 그리기로 알아보는 뉴턴-랩슨(Newton-Raphson's method)법과 제곱근 구하기 - C# ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/10911'>http://www.sysnet.pe.kr/2/0/10911</a> </pre> <br /> 2차 방정식의 곡선을 PLplot으로 그려 보면 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > static void Main(string[] args) { const int yMin = -30; const int yMax = 100; const int xMin = -20; const int xMax = 20; Func<double, double> quad = (x) => x * x - 10; <span style='color: blue; font-weight: bold'>double [] xData</span> = <a target='tab' href='http://www.sysnet.pe.kr/2/0/11908'>PythonUtils.Range</a>(xMin, xMax, 0.1).ToArray(); <span style='color: blue; font-weight: bold'>double [] yData</span> = (from item in xData select quad(item)).ToArray(); using (var pl = new PLStream()) { pl.sdev("png"); pl.sfnam("test.png"); pl.spal0("cmap0_alternate.pal"); pl.init(); pl.env(xMin, xMax, yMin, yMax, AxesScale.Independent, AxisBox.BoxTicksLabelsAxes); pl.lab("x", "y = x#u2#d - 10", "Simple PLplot demo of a 2D line plot"); <span style='color: blue; font-weight: bold'>pl.line(xData, yData);</span> pl.gver(out var verText); } } </pre> <br /> 보는 바와 같이 x 좌표의 값과 그에 대응하는 인덱스에 y 좌표의 값을 담아 pl.line 함수에 전달하기만 하면 됩니다. 그럼, 다음과 같은 이미지를 담은 PNG 파일이 생성됩니다. ^^<br /> <br /> <img alt='plplot_sample_2.png' src='/SysWebRes/bbs/plplot_sample_2.png' /><br /> <br /> <hr style='width: 50%' /><br /> <br /> 이번엔 데이터의 분포도를 알 수 있도록 line이 아닌 점으로 표시해 보겠습니다. 데이터는 다음의 책에 있는,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 기초 수학으로 이해하는 머신러닝 알고리즘 ; <a target='tab' href='https://wikibook.co.kr/math-for-ml/'>https://wikibook.co.kr/math-for-ml/</a> </pre> <br /> click.csv 파일을 로드해서 pl.line만 pl.poin으로 바꿔주면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Dictionary<string, List<double>> data = PythonUtils.Load<double>("click.csv"); <span style='color: blue; font-weight: bold'>List<double> xData</span> = data["x"]; <span style='color: blue; font-weight: bold'>List<double> yData</span> = data["y"]; double xMin = xData.Min() - 10; double xMax = xData.Max() + 10; double yMin = yData.Min() - 10; double yMax = yData.Max() + 10; string chartFileName = "click.svg"; using (var pl = new PLStream()) { pl.sdev("svg"); pl.sfnam(chartFileName); pl.spal0("cmap0_alternate.pal"); pl.init(); 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", "Click"); //This code is the symbol to paint // http://personalpages.to.infn.it/~zaninett/libri/hershey.html char code = Symbol.Bullet; // == 17; // plot using different colors // see http://plplot.sourceforge.net/examples.php?demo=02 for palette indices //pl.col0(9); //Light Green //pl.col0(4); //Red pl.col0(2); //Blue <span style='color: blue; font-weight: bold'>pl.poin(xData.ToArray(), yData.ToArray(), code);</span> // end page (writes output to disk) pl.eop(); // output version of PLplot pl.gver(out var verText); } </pre> <br /> 다음과 같은 출력의 svg 파일이 생성됩니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='plplot_sample_3.png' src='/SysWebRes/bbs/plplot_sample_3.png' /><br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1454&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> 간단하죠? ^^ 좀 더 알고 싶다면 온라인 도움말을 참고할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > API Reference manual ; <a target='tab' href='https://surban.github.io/PLplotNet/api/PLplot.PLStream.html'>https://surban.github.io/PLplotNet/api/PLplot.PLStream.html</a> </pre> <br /> 그렇긴 해도 역시나 레퍼런스 매뉴얼보다는, 다른 사람들이 작성한 예제 코드와 그것의 출력 결과를 통해 익히는 것이 가장 빠릅니다. ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, 예전에 OxyPlot을 소개한 적이 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# Plotting 라이브러리 OxyPlot ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/10973'>http://www.sysnet.pe.kr/2/0/10973</a> </pre> <br /> 입맛에 맞는 걸로 쓰시면 되겠죠? ^^ 게다가 아예 언어를 바꾸는 것도 고려해볼만합니다. 예를 들어 이 글의 그래프를 그리는 코드를 R 언어로 바꾸면 다음과 같이 아주 간단하게 표현할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > x = seq(from=-20, to=20, by=0.1) y = x * x - 10 plot(x, y, col="gray", type="l") // 숫자 1이 아닌, 소문자 'l' </pre> <br /> <hr style='width: 50%' /><br /> <br /> 마지막으로 PLplot 사용 시 오류 발생 상황을 정리해 보겠습니다. "using (var pl = new PLStream())" 코드 수행 시 다음과 같은 예외가 발생한다면?<br /> <br /> <a name="tag1"></a> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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 C:\projects\plplotnet\PLplotNet\PLStream.cs:line 23 at ConsoleApp1.Program.Main(String[] args) in E:\ConsoleApp1\ConsoleApp1\Program.cs:line 21 Inner Exception 1: InvalidOperationException: Cannot find support PLplot support files in System.String[]. </pre> <br /> 이게 좀 원인이 복잡합니다. 일반적으로 NuGet 패키지를 PackageReference로 참조하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Visual Studio 2017 - NuGet 패키지를 직접 참조하는 PackageReference 지원 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11281'>http://www.sysnet.pe.kr/2/0/11281</a> </pre> <br /> 솔루션 파일이 있는 폴더의 /packages 하위 폴더에 라이브러리가 구성되지 않고 "%USERPROFILE%\.nuget\packages\plplot\5.13.7\runtimes\win-x64\native" 폴더에 놓이게 됩니다. 여기서 문제는, native 구성 요소는 nuget cache 폴더에 있는 반면, managed 구성 요소인 "PLplotNet.dll" 파일이 프로젝트의 출력 폴더(/bin/Debug)에 놓인다는 점입니다. 이 때문에 PLplotNet.dll은 현재 디렉터리에서 네이티브 dll을 찾으려 하고 그것이 없어 저런 식으로 오류가 발생하는 것입니다.<br /> <br /> 따라서 간단하게 문제를 해결하려면 "%USERPROFILE%\.nuget\packages\plplot\5.13.7\runtimes\win-x64\native" 폴더의 모든 파일을 프로젝트의 출력 폴더에 복사해 놓는 것입니다. 단지 그러면 바이너리 폴더의 내용이 너무 많아 귀찮아지므로 privatePath를 이용해,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> </startup> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <span style='color: blue; font-weight: bold'><probing privatePath=".\plplot" /></span> </assemblyBinding> </runtime> </configuration> </pre> <br /> 다음과 같이 선처리를 해주면 됩니다.<br /> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.IO; using System.Reflection; class PLPlotEnv { const string ManagedDllFileName = @"PLplotNet.dll"; public static void SetEnv() { do { if (File.Exists(@".\plplot\plplot.dll") == true) { break; } if (File.Exists(ManagedDllFileName) == false) { break; } Version ver = AssemblyName.GetAssemblyName(ManagedDllFileName).Version; string versionText = $"{ver.Major}.{ver.Minor}.{ver.Build}"; string path = Environment.ExpandEnvironmentVariables($@"%USERPROFILE%\.nuget\packages\plplot\{versionText}\runtimes\win-x64\native"); if (Directory.Exists(path) == false) { break; } string targetPath = Path.GetDirectoryName(typeof(PLPlotEnv).Assembly.Location); targetPath = Path.Combine(targetPath, "plplot"); DirectoryCopy(path, targetPath, true); } while (false); CopyPLplotNetFile(); // Environment.SetEnvironmentVariable("PLPLOT_LIB", ...); } private static void CopyPLplotNetFile() { if (File.Exists(ManagedDllFileName) == false) { return; } if (File.Exists($@".\plplot\{ManagedDllFileName}") == false) { File.Copy(ManagedDllFileName, $@".\plplot\{ManagedDllFileName}"); } File.Delete(ManagedDllFileName); } // https://learn.microsoft.com/ko-kr/dotnet/standard/io/how-to-copy-directories private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs) { // Get the subdirectories for the specified directory. DirectoryInfo dir = new DirectoryInfo(sourceDirName); if (!dir.Exists) { throw new DirectoryNotFoundException( "Source directory does not exist or could not be found: " + sourceDirName); } DirectoryInfo[] dirs = dir.GetDirectories(); // If the destination directory doesn't exist, create it. if (!Directory.Exists(destDirName)) { Directory.CreateDirectory(destDirName); } // Get the files in the directory and copy them to the new location. FileInfo[] files = dir.GetFiles(); foreach (FileInfo file in files) { string temppath = Path.Combine(destDirName, file.Name); file.CopyTo(temppath, false); } // If copying subdirectories, copy them and their contents to new location. if (copySubDirs) { foreach (DirectoryInfo subdir in dirs) { string temppath = Path.Combine(destDirName, subdir.Name); DirectoryCopy(subdir.FullName, temppath, copySubDirs); } } } } </pre> <br /> 참고로, 이 문제가 .NET Core 프로젝트에서 NuGet 참조를 한 경우에는 발생하지 않습니다. 왜냐하면, .NET Core 프로젝트는 빌드 시 Managed DLL인 PLplotNet.dll을 빌드 출력 폴더(/bin/debug)에 복사하지 않고 nuget cache 폴더로부터 직접 로드하기 때문입니다.<br /> <br /> 그건 그렇고, 예제에 보면 PLPLOT_LIB 환경 변수가 나오는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > _putenv_s("PLPLOT_LIB", supPath); </pre> <br /> 이게 통하지 않습니다. (혹시 이에 대해 아시는 분은 덧글 부탁드립니다.)<br /> <br /> <hr style='width: 50%' /><br /> <a name='prefer32bit'></a> <br /> 또는 다음과 같은 오류가 발생한다면?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > System.BadImageFormatException HResult=0x8007000B Message=An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B) Source=PLplotNet StackTrace: at PLplot.Native.mkstrm(Int32& p_strm) at PLplot.PLStream..ctor() in C:\projects\plplotnet\PLplotNet\PLStream.cs:line 23 at ConsoleApp1.Program.Main(String[] args) in E:\ConsoleApp1\ConsoleApp1\Program.cs:line 22 </pre> <br /> 현재 nuget에 올라온 plplot은 네이티브 바이너리가 win-x64와 linux-x64 밖에 없으므로 x86으로 구동하는 응용 프로그램으로는 로드할 수 없습니다. 따라서 자신의 프로젝트에 "Prefer 32-bit" 옵션이 켜져 있거나 "x86" 대상으로 빌드했다면 저렇게 <a target='tab' href='http://www.sysnet.pe.kr/2/0/519'>BadImageFormatException</a>이 발생합니다.<br /> <br /> 만약 x86이 굳이 필요하다면, plplot을 x86으로 빌드해 사용하면 됩니다. <a target='tab' href='http://www.sysnet.pe.kr/2/0/11409'>vcpkg</a>가 이미 제공하므로 어렵지 않게 구성할 수 있을 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > E:\git_clone\vcpkg> <span style='color: blue; font-weight: bold'>vcpkg search plplot</span> plplot 5.13.0-1 PLplot is a cross-platform software package for creating scientific plots whos... plplot[wxwidgets] plplot wxwidgets module </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1041
(왼쪽의 숫자를 입력해야 합니다.)