Temat: Nowy interfejs R -> .NET

Pozwolę sobie na mały spam na dwóch grupach, ponieważ i tam i tutaj mogą być osoby zainteresowane tym tematem.

W skrócie:
Dobre wieści dla programistów .NET, którzy chcą wykorzystać w swoich projektach analitycznych potencjał pakietu statystycznego R

Pojawił się nowy interface do .NET - R.NET

Z tego, co widzę, nie opiera się (nareszcie) o (D)COM, ale o interop regularnej DLLki. Niestety, jest jeszcze trochę bugów, a to głównie z uwagi na fakt, że pracujemy z kodem niezarządzanym (R.DLL). Ale, jak widać na stronie, testerzy mają "oko i ucho na pulsie".

Co ważne, można wprost wskazać wersję, z której chcemy korzystać, a to poprzez podanie ścieżki do katalogu R.

Interface oferuje także nazwane sesje, więc różni użytkownicy nie będą sobie "wchodzić w obliczenia". Oczywiście nadal można stosować trick z jedną sesją i prefiksowanymi zmiennymi plus kolejkowanie zapytań.

Wystawienie eRa jako webservice nie stanowi żadnego problemu. Dodatkowo, dzięki CLR możemy się do eRa odwoływać wprost z Excela bądź zapytań SQLowych (oczywiście tylko SQL Server).

Więcej informacji i przydatne linki do artykułów i prezentacji w w odpowiednim temacie w grupie użytkowników pakietu R.


Obrazek

Temat: Nowy interfejs R -> .NET

No i się trochę pośpieszyłem z tymi peanami.

Działać działa. I to jak błyskawica (czego nie mogłem powiedzieć o DCOMie), czasy rzędu pojedynczych ms. I to jest piękne.

Obrazek


Cóż z tego, skoro po równo 18 wywołaniu metody "leniwego wykonania" (9 kliknięć) leci wyjątek i to poważny. Nie wiem, co robi "zwykłe" Evaluate (zwraca coś innego niż EagerEvaluate), ale to już zostawiam na popołudnie. Może rozwiąże problem, bo na razie nie sposób z tym pracować na poważnie. Może jest jakaś dyskusja na ten temat na forum projektu.

Obrazek

Temat: Nowy interfejs R -> .NET

Już wszystko gra :)

Problem został rozwiązany w najnowszych źródłach, ale binarka nie została jeszcze opublikowana. Pobrałem najnowsze źródła, zbudowałem DLLkę i działa jak marzenie.

http://rdotnet.codeplex.com/SourceControl/list/changesets

----------------

Jeśli chodzi o osadzanie wykresów, zgodnie z tym wątkiem, to działa, ale "tylko raz" :) Potem leci exception. Sprawdzone na świeżo skompilowanej DLLce.

Obrazek

Tak, że albo trzeba wyświetlać wykresy w oknie eRa, albo zastosować to podejście, a konkretnie - użyć EagerEvaluate do wygenerowania wykresu, zapisania go do pliku na dysku do wskazanego katalogu, a potem wczytania go do PictureBoxa:

     engine.EagerEvaluate("library(Cairo)");
engine.EagerEvaluate(@"CairoPNG('c:\\tmp\\R.png')");
engine.EagerEvaluate("plot(1:100,col=\"red\")");
engine.EagerEvaluate ("dev.off()");

this.pictureBox1.Image = new Bitmap("c:\\tmp\\R.png");
this.pictureBox1.Invalidate();


Ładnie działa :)

Obrazek
Adrian Olszewski edytował(a) ten post dnia 09.07.11 o godzinie 17:15

konto usunięte

Temat: Nowy interfejs R -> .NET

Super. Swego czasu szukałem czegoś takiego bo interfejs (D)COM do R'a odrzucił mnie błyskawicznie.

Szkoda, że tak rzadko jest okazja do używania tego typu narzędzi.

Temat: Nowy interfejs R -> .NET

Dziś bawiłem się w skalowanie obrazków.

Najpierw tworzymy metodę, która wyśle do R skrypt generujący potrzebny wykres i zapisujący go do pliku we wskazanym katalogu. Ponieważ zapisujemy go do PNG, można ustawić przezroczyste tło, co pozwoli lepiej dopasować wykres do naszych schematów kolorystycznych.

Z racji tego, że generujemy skrypt tekstowy, możemy go dowolnie parametryzować sklejając po prostu literały. Niestety, w pewnym momencie możemy "stracić kontrolę" nad tymi wszystkimi sklejeniami i całość będzie trudna do ogarnięcia, nie mówiąc o późniejszych poprawkach (widać to już w kodzie przykładowym poniżej). Należy zdefiniować klasę, która będzie wystawiać właściwości (panujemy nad typami), enumeracje (kolory, grubości linii, wzorki, nazwy czcionek, etc.), a w gdzieś w środku będzie metoda generateScript składająca całość w skrypt R. I warto robić to krok po kroku, wykorzystując zasadę "jedno zadanie jedna metoda". Innymi słowy metoda appendAndFormatTitle(string title, FontNames fontName, ColorNames colorName) zajmuje się tytułem i niczym więcej.

Polecenia powinny być od siebie oddzielone średnikami bądź znakami nowej linii (i lepiej niech to będzie System.Environment.NewLine).

Pamiętamy, że przekazując ścieżki do R musimy użyć konstrukcji @"c:\\", a nie "c:\\, bądź @"c:\".

Po wykonaniu kodu R, we wskazanym katalogu pojawi się bitmapka, którą trzeba załadować i podać jako źródło do własności "Image" jakiejś kontrolki (w przykładzie - PictureBox).

Tu pojawia się problem. Otóż aplikacja, poprzez klasę Bitmap, trzyma własność pliku i R nie da rady go nadpisać przy kolejnym wykonaniu skryptu. Nie wyrzuci jednak błędu, pozornie wszystko będzie działać, a obrazek nie będzie odświeżany. Radzimy sobie z tym najpierw wczytując bitmapkę do strumienia, którym następnie zasilamy obiekt klasy Bitmap a na koniec strumień zamykamy. Dzięki temu dostęp do pliku zostaje zwolniony i wszystko gra.

void drawChart(REngine engine)
{
StringBuilder plotCommmand = new StringBuilder();

plotCommmand.Append(@"CairoPNG('c:\\tmp\\r.png', width=" + this.pictureBox1.Width.ToString() + ", height=" + this.pictureBox1.Height.ToString() + ", bg='transparent');");
plotCommmand.Append("plot(1:" + (this.pictureBox1.Width / 10).ToString() + ",col='blue', main='Rozmiary wykresu: "+ this.pictureBox1.Width.ToString() + " x " + this.pictureBox1.Height.ToString() + "');");
plotCommmand.Append("graphics.off();");
Console.WriteLine(plotCommmand.ToString());
engine.EagerEvaluate(plotCommmand.ToString());

using (System.IO.StreamReader str = new System.IO.StreamReader("c:\\tmp\\r.png"))
{
this.pictureBox1.Image = new Bitmap(str.BaseStream);
str.Close();
}
this.pictureBox1.Invalidate();
}


Teraz zajmujemy się zmianą rozmiaru kontrolki. Kontrolka powinna być zadokowana, albo mieć odpowiednio zakotwiczona. Można iść na łatwiznę i napisać od razu:
private void Form1_Resize(object sender, EventArgs e)
{
drawChart(this.rEngine);
}


i nawet będzie to działać. Po co jednak zarzynać procesor generowaniem obrazków i tworzeniem obiektów co kilka pikseli? Filmik pokazuje, ile bezsensownej roboty się dzieje (okno konsoli na dole ekranu). Jest to jednak niezły test wydajnościowy ;) Przy StatConnector możemy o zapomnieć o takiej szybkości reakcji. W rzeczywistości wszystko działa szybciej, nie mogłem ustawić framerate w kompresorze video...
http://www.youtube.com/watch?v=Rta2lw-Y53s

Zamiast tego, do rozmiarów okna wykorzystujemy zdarzenie ResizeEnd. Pojawia się jednak kolejny problem- maksymalizacja i minimalizacja okna.

Zdarzenie ResizeEnd, nie wiedzieć czemu, nie jest odpalane po zakończeniu mini-/maksymalizacji okna. Reaguje zaś na to właśnie Resize. Stąd, do obsługi "krąwędziowej zmiany rozmiarów okna" stosujemy ResizeEnd, a do min/max okna - Resize z odrobiną logiki.

FormWindowState oldFormWindowState;

private void Form1_Resize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Maximized)
{
this.OnResizeEnd(null);
this.oldFormWindowState = FormWindowState.Maximized;
}

if (this.WindowState == FormWindowState.Normal && this.oldFormWindowState == FormWindowState.Maximized)
{
this.oldFormWindowState = FormWindowState.Normal;
this.OnResizeEnd(null);
}
}

private void Form1_ResizeEnd(object sender, EventArgs e)
{
drawChart(this.rEngine);
}


I to wreszcie działa, jak należy, tj. płynnie i bez zarzynania komputera, co prezentuje poniższy filmik (od razu na fulscreen):
http://www.youtube.com/watch?v=K2h-wfR5txY

Przy okazji, pod koniec filmiku, widać także paskudną obsługę wyjątków R. Leci wyjątek ogólny ParseException, bez żadnego opisu, nawet bez treści wyjątku. Jest ona wyrzucana dopiero na konsolę: Error in plot.new() : figure margins too large.

Wyjątki w R rzuca funkcja stop(...):
> funkcja_z_bledem <- function() {
+ stop("Błąd!");
+ }

> funkcja_z_bledem()
Error in funkcja_z_bledem() : Błąd!
>


Na koniec - eRowy smaczek :)

Przypominam, że w R świetnie współpracuje z Latexem (pakiet sweave) i potrafi tworzyć PDF oraz DVI. Można zatem generować PDFy (i DVI) i wczytywać je do osadzonej w aplikacji kontrolki przeglądarki*

Obrazek


----------
* .NET posiada wrapper do IE, ale jest też dostępny silnik Gecko, a więc Mozilla (i działa pod MONO). Testowałem to jeszcze w 2010 i działało OK. Niestety, w tym roku Mozilla ogłosiła, że prace nad osadzalną kontrolką zostają wstrzymane: http://lwn.net/Articles/436412/

Temat: Nowy interfejs R -> .NET

I chyba już końcówka eksperymentów - przechwytywanie wielu wykresów na raz na przykładzie modelu liniowego.

Tym razem, wyniku działania komend R, generowanych jest kilka wykresów o kolejnych numerach. Próbowałem z zapisem do jednego "multipage PNG/TIFF", ale jakoś nie znalazłem, jak to zrobić. Zamiast tego korzystam, jak poprzednio, z systemu plików.

Oczywiście poniższy kod należy ubrać w jakąś zgrabną klasę. Tutaj jest jedynie wycinek z dialog-based aplikacji testowej.

1. Generujemy wykresy i tworzymy kolekcję ścieżek do plików z nimi. Istotny jest zapis "%02d" w nazwie pliku, który oznacza inkrementowany z każdym plikiem licznik:
List<string> multipageImage = new List<string>();
int currIndex = 0;
void createDrawMultipageChart(REngine engine)
{
StringBuilder plotCommmand = new StringBuilder();

plotCommmand.Append(@"a <- c(1,3,5,7,9,11,14,15);");
plotCommmand.Append(@"b <- 20-a;");
plotCommmand.Append(@"png('c:\\tmp\\r.net.%02d.png', width=" + this.pictureBox1.Width.ToString() + ", height=" + this.pictureBox1.Height.ToString() + ", bg='transparent');");
plotCommmand.Append(@"plot(lm(a~b));");
plotCommmand.Append("graphics.off();");
Console.WriteLine(plotCommmand.ToString());
engine.EagerEvaluate(plotCommmand.ToString());

multipageImage.Clear();
multipageImage.AddRange( Directory.GetFiles("c:\\tmp\\", "r.net*.png"));

this.currIndex = 0;
this.drawCurrentChart();
}


2. Rysujemy wybrany wykres:
void drawCurrentChart()
{
if (this.multipageImage.Count > 0)
{
using (StreamReader str = new StreamReader(this.multipageImage[this.currIndex]))
{
this.pictureBox1.Image = new Bitmap(str.BaseStream);
str.Close();
}
this.pictureBox1.Invalidate();
}
}


3. i nawigujemy sobie po nich
bool drawPrevChart()
{
if (this.currIndex > 0)
{
this.currIndex--;
this.drawCurrentChart();
}

return !(this.currIndex == 0);
}

bool drawNextChart()
{
if (this.currIndex < this.multipageImage.Count - 1)
{
this.currIndex++;
this.drawCurrentChart();
}

return !(this.currIndex == this.multipageImage.Count - 1);
}

private void btnPreviousImg_Click(object sender, EventArgs e)
{
this.btnPreviousImg.Enabled = this.drawPrevChart();
this.btnNextImg.Enabled = true;
}

private void btnNextImg_Click(object sender, EventArgs e)
{
this.btnNextImg.Enabled = this.drawNextChart();
this.btnPreviousImg.Enabled = true;
}

http://www.youtube.com/watch?v=HIaojtiQXro

Pozostaje pytanie, co w przypadku, gdy mamy kilku userów równolegle korzystających z osobnych instancji R? Można wykorzystać nazwę usera do utworzenia prefiksów plików i trzymać je w jednym katalogu, albo dla każdego usera tworzyć osobny, nazwany jego loginem katalog i tam trzymać pliki.

Dodatkowo, biorąc pod uwagę, że w R można zapisać bieżącą sesję (wszystkie zmienne, funkcje, etc.), można do tego "dograć" ZIPa z obrazkami i "zamrażać" userowi sesję na później.Adrian Olszewski edytował(a) ten post dnia 24.07.11 o godzinie 03:10
Sławomir Orłowski

Sławomir Orłowski PhD, physicist,
software
developer/architect
team leader...

Temat: Nowy interfejs R -> .NET

Witaj
Nie wiem, czy pytanie jest do końca na temat:
A czy miałeś możliwość porównania rysowania wykresów R.NET z ZedGraph'em? Osobiście używam ZedGraph'a. Jest szybki i stabilny. Nie mieliśmy do tej pory z nim problemu.
Pzdr

Temat: Nowy interfejs R -> .NET

Rozumiem, że chodzi o opensource'owego ZedGrapha? Korzystałem, jeszcze od czasu jego premiery na CodeProject w 2003 :)

Myślę, że nie sposób porównać tych dwóch rozwiązań.

Weźmy kilka kryteriów:

Estetyka:
Wykresy eRowe są "specyficzne dla nauki". Ascetyczne, proste, ale czytelne. Idealne do umieszczania w artykułach naukowych. Na Zachodzie traktuje się je jak wzór dobrze wykonanego wykresu naukowego (zaś wykresy Excelopodobne uchodzą często za "antywzorzec"*). Z drugiej strony ciężko wstawić je do jakiejś "fajerwerwkowej" prezentacji marketingowej, gdzie musi być 3D, cieniowanie, gradienty, itd. Wykonanie tych wodotrysków jest oczywiście możliwe w R, ale to sporo klepania kodu. Trudno także wstawić eRowe wykresy do atrakcyjnej graficznie aplikacji, np. jako wykres np. obciążenia sieci (pomijam kwestie techniczne, o czym dalej).

Możliwości:
Wykresy eRowe to nie tylko klasyczne scatterplot, pie/bar/line-chart. W pakietach R można często znaleźć specjalistyczne, charakterystyczne dla statystyki i data miningu wykresy, które trudno byłoby uzyskać w innych narzędziach: http://addictedtor.free.fr/graphiques/thumbs.php
Narysowanie skomplikowanego wykresu z histogramami, drzewami, wektorami własnymi, krzywymi gęstości, płaszczyznami dopasowania, formułami i innymi cudami jest w R stosunkowo proste, a w klasycznych bibliotekach do wykresów często praktycznie niewykonalne. Z kolei narysowanie prostego barcharta w barwnej szacie graficznej, z gradientami, obrazkami w tle, cieniowaniem, "wypłukościami", co w takim Zedzie zajmie parę chwil, w R stanowi poważny wyczyn.

Kwestie techniczne:
Nie wyobrażam sobie instalowania kilkudziesięciu megabajtów środowiska R (kod niezarządzany!) tylko po to, żeby wygenerować "barchart". To tak, jak by instalować .NETa czy Javę tylko po to, aby napisać program poszukujący miejsc zerowych równania kwadratowego, gdzie wystarczy do tego zwykły, konsolowy Turbo C. W dodatku nie uzyska się łatwo takich efektów graficznych, jak chociażby w ZedGraphie. W przypadku biblioteki do wykresów przeciągnie się kontrolkę na formatkę, wybierze odpowiedni typ wykresu, poustawia kilka właściwości, poda tablicę liczb - i gotowe. W przypadku eRa trzeba go zainstalować (można wykorzystać wersję "portable", ale to nadal kolubryna), skompilować i dodać do projektu bibliotekę R.DLL, względnie zainstalować (na prawach admina) StatConnectora, wygenerować mu klasy proxy, wklepać kilka akapitów kodu eRowego, który nam narysuje to, co chcemy (o ile umiemy to uzyskać), a potem jeszcze generować w locie pliki, przechwytywać je i osadzać w jakiejś kontrolce.

Kwestie wydajnościowe:
Załóżmy, że chcemy bardzo szybko odświeżać wykres, np. obciążenia sieci, albo na bieżąco rysować historię zmian jakiegoś parametru, np. temperatury. Dla biblioteki graficznej jest to pestka, może rysować kolejne wykresy tak szybko, że dostaniemy zawrotu głowy. A w przypadku eRa i opisanego rozwiązania będzie to o wiele wolniejsze. Trzeba wygenerować potrzebny kod, przesłać do R (to są milisekundy), R wygeneruje pliki, który trzeba wczytać do strumienia, a następnie przekazać do kontrolki (kolejne milisekundy). Na jednym z powyższych filmików widać, jak szybko odświeżany jest wykres w reakcji na zmianę rozmiarów okna (generowanie obrazka co kilka pikseli). Jak widać - jest to nawet szybkie, ale niepotrzebnie "zarzyna" procesor. http://www.youtube.com/watch?v=Rta2lw-Y53s

Podsumowując - to są różne narzędzia służące do realizacji odmiennych zadań.

------------
* "If anything, there should be a Law: Thou Shalt Not Even Think Of Producing A Graph That Looks Like Anything From A Spreadsheet" - Ted Harding
Sławomir Orłowski

Sławomir Orłowski PhD, physicist,
software
developer/architect
team leader...

Temat: Nowy interfejs R -> .NET

No i teraz wiem wszystko :) Bardzo pomocna odpowiedź. Dziękuję. Porównywaliśmy jakiś czas temu ZedGraph'a do MS Chart. W kwestii wydajności ZedGraph bije na głowę MS Charta. Używałeś może MS Charta?

BTW. Ja w moich publikacjach naukowych używałem OrignLab.

Temat: Nowy interfejs R -> .NET

Tak, używałem, wymiennie do Reporting Services. Typowo "biznesowe" raportowanie, a tam zwykle przedkłada się "look'n'feel" nad szybkość renderowania wykresu :) I do takich właśnie celów, typowo biznesowych, marketingowych, przeznaczona jest większość rozwiązań MS. W systemach analitycznych wykorzystywałem właśnie R, ale tam też wykresy są raczej statyczne, natomiast bardziej egzotyczne. Jeśli zaś zachodziła potrzeba wygenerowania bardziej "kolorowego" a schludnego wykresu, korzystałem ze Statistiki.

Temat: Nowy interfejs R -> .NET

Gdyby ktoś potrzebował przechwycić konsolę R w swoim programie, przedstawiam dwa rozwiązania. Jest to przydatne, gdy ktoś nie potrzebuje wykonywać programowo obliczeń na wynikach EagerEvaluate, a jedynie zrobić coś na kształt "GUI do R".

Wątek na CodePlex: http://rdotnet.codeplex.com/discussions/261917

1. Można napisać klasę implementującą interfejs ICharacterDevice, a następnie przekazać w konstruktorze tej klasy referencję do jakiegoś TexBoxa, RTF boxa czy czegoś podobnego, a najlepiej do delegaty, która wskazywać będzie na funkcję drukującą wyjście/błędy. Niestety, jest tutaj pewien problem - wyświetlone zostaną jedynie komendy "opatrzone" funkcją "print()". Jeśli się o tym zapomni - nic nie zostanie wyświetlone.

Tutaj najprostsza wersja ze zwykłym Console.Write(). Wyniki przechwycone przez VS2010 i wyświetlone w oknie "Output":

Obrazek


Poniżej przykład jak korzystać z ICharacterDevice. W przykładzie, zamiast treści wyników, przechwytuję jedynie teksty błędów. Zamiast Console.Write() wykorzystuję delegatę do metody dopisującej do RTF boxa. Przy okazji - jest to na razie jedyna metoda przechwytywania błędów z R, gdyż, niestety, ich treść NIE JEST przekazywana w wyjątku ParseException:
delegate void ErrorPrinter(string message);

class MyCharacterDevice : RDotNet.Devices.ICharacterDevice
{
ErrorPrinter printer;
public MyCharacterDevice(ErrorPrinter printer)
{
this.printer = printer;
}
.....

public void WriteConsole(string output, int length, RDotNet.Internals.ConsoleOutputType outputType)
{
if (output.StartsWith("Error"))
{
if (this.printer != null) printer(output);
}
}
}


Wykorzystanie w kodzie:
private void SetupR()
{
REngine.SetDllDirectory(this.RPath);
MyCharacterDevice dev = new MyCharacterDevice(PrintError);
this.rEngine = REngine.CreateInstance("instancja", new[] { "-q" }, dev);
}


2. Jest jednak lepszy IMHO sposób, który świetnie się sprawdza. Należy wykorzystać "sink()" i "source()". Przykładowa metoda wykonująca skrypt:
private void RunScript(ref string script)
{
this.rEngine = REngine.GetInstanceFromID("instancja");

string tmpFileNameForScript = Path.GetTempFileName();
string tmpFileNameForSink = Path.GetTempFileName();

this.temporaryFilesCollector.Add(tmpFileNameForScript);
this.temporaryFilesCollector.Add(tmpFileNameForScript);

string tmpFileNameForScript_RFormat = tmpFileNameForScript.Replace(@"\", "/");
string tmpFileNameForSink_RFormat = tmpFileNameForSink.Replace(@"\", "/");

string header = "sinkConnection <- file(\"" + tmpFileNameForSink_RFormat + "\");" + System.Environment.NewLine
+ "sink(sinkConnection, append=TRUE);" + System.Environment.NewLine
+ "sink(sinkConnection, append=TRUE, type=\"message\");";

string footer = "sink();";

File.WriteAllText(tmpFileNameForScript, header + System.Environment.NewLine + script + System.Environment.NewLine + footer);

try
{
this.rEngine.EagerEvaluate("source(\"" + tmpFileNameForScript_RFormat + " \", echo=TRUE);");

string[] outputLines = File.ReadAllLines(tmpFileNameForSink);
foreach (string line in outputLines)
{
if (!line.Contains("sink(")) // zbędne w wynikach
{
this.rtfOutput.SelectionColor = (line.StartsWith(">") || line.StartsWith("+")) ? Color.Maroon : Color.Blue;
this.rtfOutput.AppendText(line);
this.rtfOutput.AppendText(System.Environment.NewLine);
}
}

this.rtfOutput.ScrollToCaret();
File.Delete(tmpFileNameForScript);
File.Delete(tmpFileNameForSink);
}
catch (ParseException pe)
{
}
}


I mały "garbage collector" dla plików tymczasowych:
.....
Application.ApplicationExit += delegate (object s, EventArgs e)
{
this.rEngine.Close();

foreach (string temp in this.temporaryFilesCollector)
{
if (File.Exists(temp)) File.Delete(temp);
}
};

Uwaga: mogłoby się wydawać, że taki "garbage collector" dla plików tymczasowych to przerost formy nad treścią, skoro można pliki usuwać w bloku finally. Niestety, skończy się to wyjątkiem "Proces nie może uzyskać dostępu do pliku „C:\Users\XXXXX\AppData\Local\Temp\tmp2BEC.tmp”, ponieważ jest on używany przez inny proces."
Dlatego kolekcjonuję nazwy plików, a przy zamknięciu aplikacji je usuwam.

I wyniki:
Obrazek


Przykład zgłoszenia błędu:
Obrazek
Adrian Olszewski edytował(a) ten post dnia 20.10.11 o godzinie 03:33

Temat: Nowy interfejs R -> .NET

Nieco po czasie, ale lepiej późno niż wcale :]

Interfejs .NETowy do eRowego serwera TCP/IP znanego jako Rserve. Początkowo klienci byli napisani jedynie w C++ i Javie, teraz doszedł .NET.

Projekt nazywa się RserveCLI. Jest o tyle wygodny, że nie trzeba, jak w przypadku bibliotek korzystających z COM, niczego (poza RServe) instalować ani rejestrować.

Krótka prezentacja: http://www.rinfinance.com/agenda/2011/OliverHaynold.pdf

Mamy zatem już następujące metody połączenia się z R:
1. TCP/IP (RServe, RserveCLI)
2. OLE COM (StatConnector, RCOM). Niestety, StatConnector nie jest już darmowy do komercyjnych zastosowań, a wersja komercyjna niemało kosztuje. Z drugiej strony jest dobrze dopracowany. "Cały internet zna" IStatConnector :]
3. DDE (NDDE + Tcl/Tk)
4. Bezpośrednie wywołania biblioteki R.DLL (R.NET)

Zalety
1. Nareszcie zaimplementowana wielosesyjność bez potrzeby uruchamiania biblioteki w osobnych przestrzeniach adresowych (procesy potomne). Na poniższej ilustracji dwa okna aplikacji, każda z innym GUIDem użytkownika. GUID potrzebny był mi tylko do rysowania wykresu (plik wykresu trzeba "pobrać" z serwera, więc żeby się nie nadpisywał, dodawałem mu GUID do nazwy). Każda nowa instancja aplikacji dostaje swoje środowisko, podobnie, jak w COM (np. StatConnector), ale bez problemów z tym związanych.

2. Szybkość działania. Od momentu wystartowania serwera (Rserve() albo jako exeka) połączenie trwa dosłownie chwilę, zauważalnie szybciej niż w przypadku StatConnectora. Trzeba uważać na wyjątki, które mogą zamknąć serwer, dobrze mieć watchdoga. Inaczej dostaniemy znane zabawne komunikaty o "gwałtownym zakończeniu" i "aktywnej odmowie serwera" :D

3. Możliwość współpracy z serwerem po localhoście i po sieci. Podobnie, jak w DCOM, ale bez problemu z rejestracją komponentów i uprawnieniami. Trzeba tylko uważać na firewall.

4. Łatwa integracja z kodem w C#

Wady
1. Brak urządzenia graficznego, brak konsoli tekstowej. Można zapomnieć o przechwytywaniu komunikatów konsoli (błędy, ostrzeżenia) czy sformatowanych wynikach (np. summary()). Ale tak jest ze wszystkimi tego rodzaju bibliotekami (R.NET, StatConnector). Rozwiązaniem jest sink().

2. W zwiazku z p1. - wykresy trzeba zapisywać do pliku (png, CairoPNG, PDF) i wyświetlać w kontrolce wyświetlającej obrazki albo osadzonej przeglądarce PDF (np. MSIE, Acrobat). Tak właśnie robię w aplikacji testowej.

3. Trzeba pamiętać o podnoszeniu "upadłego serwera". Problemu tego nie było w przypadku COM ani R.DLL (R był zawsze podnoszony od zera). Watchdog obowiązkowy.

4. Brak informacji o błędzie zgłoszonym przez R. Dostajemy wyjątek, że R ma problem i to wszystko. Trzeba kombinować z własną procedurą, która wyświetli ostatni napotkany error/warning. Błędy R można olać (albo try/catch, albo ustawić R tak, by nie zamykał się przy wyjątku), ale błędy transmisji danych najpewniej wywalą serwer. Info o błędach można odczytać także przez sink() ale to wymaga dodatkowej pracy.

5. Po zakończeniu pracy warto zamykać RServe, żeby nie zabierał pamięci.

6. Instancje mogą się wzajemnie blokować. Jeśli RServe czeka na odpowiedź od instancji A, a ona się powiesiła albo czeka na reakcję użytkownika, to pozostałe instancje też wiszą.

-----------------
Wielosesyjność:

Obrazek


Przykładowa struktura zwracanych danych:

Obrazek

Temat: Nowy interfejs R -> .NET

Pojawił się .netowy odpowiednik pakietu rJava, czyli rClr. Pakiet umożliwia odwoływanie się do bibliotek .netowych / Mono z poziomu R.

Strona projektu (w trakcie przenoszenia pod nowy adres): https://r2clr.codeplex.com/
Opis instalacji: http://r2clr.codeplex.com/wikipage?title=Installing%20...

Co prawda repozytorium CRAN zawiera pakiety do zrealizowania praktycznie dowolnego zadania programistycznego (w tym dostęp do baz danych i plikowych źródeł danych w wielu formatach, komunikacja sieciowa od gniazd po webserwisy, tworzenie i odwoływanie się do obiektów COM, kilka bibliotek interfejsu graficznego, funkcje plikowe, dostęp do funkcji systemu operacyjnego, generowanie dokumentów w wielu formatach, itd), ale teraz wystarczy zainstalować jedynie "bridge" i skupić się na wygodnym wykonaniu zadania w .NET/Mono, udostępniając "na zewnątrz" jedynie fasadę kilku funkcji.

Obecnie możemy użyć następujących interfejsów do komunikacji z R:

Obrazek
Ten post został edytowany przez Autora dnia 26.08.14 o godzinie 23:13

Następna dyskusja:

Nowy interfejs R -> .NET




Wyślij zaproszenie do