JMP 19 erweitert die in JMP 18 eingeführte Datenkonnektor-Funktion und ermöglicht so den einheitlichen Zugriff auf mehr Datenquellen. Neben zusätzlichen integrierten Verbindungstypen können Benutzer in JMP 19 mithilfe einer bereitgestellten Python-API auch eigene Verbindungstypen definieren. Wie die integrierten Typen profitieren auch diese von den Vorteilen des Datenkonnektors, einschließlich Konfigurationsverwaltung und Integration in den Abfrage-Generator. Da sie in Python implementiert sind, können sie bestehende Python-Bibliotheken nutzen. In dieser Präsentation beschreiben wir die API, erläutern die zugrunde liegenden Konzepte und demonstrieren sie in der Praxis.
Hallo. Ich möchte Ihnen heute das Data-Connector-Framework von JMP vorstellen, insbesondere wie es in JMP 19 mit Python erweitert werden kann. In JMP 18 haben wir das Data-Connector-Framework eingeführt und damit die ODBC-Konnektivität verbessert. In JMP 19 bauen wir diese Funktionalität weiter aus.
Sie haben vielleicht schon an anderer Stelle davon gehört, wie wir es nutzen, um die Verbindung zu SaaS wiederherzustellen und native Konnektivität zu Snowflake bereitzustellen. Wir verwenden genau dieses Framework, über das ich sprechen werde – diese Python-API –, um Konnektivität zu Amazon S3 und Microsoft SharePoint zu implementieren. Diese wird nicht in JMP integriert sein, sondern über den JMP Marketplace vertrieben.
In diesem Vortrag möchte ich einige Punkte ansprechen. Zunächst möchte ich kurz erläutern, warum es sinnvoll sein kann, eine eigene Datenquelle in JMP zu integrieren. Wenn Sie dies tun möchten, sollten Sie wissen, wo die Integration erfolgt, was JMP für die Kommunikation mit Ihrer Datenquelle benötigt und welche Informationen Sie bereitstellen müssen, um dies zu ermöglichen. Insbesondere: Welchen Code müssen Sie schreiben?
Abschließend sprechen wir darüber, wie Sie Ihren Code teilen können. Ihr geschriebener Code funktioniert zwar für Sie, aber andere in Ihrem Unternehmen möchten ihn vielleicht auch nutzen. Möglicherweise möchten Sie ihn mit anderen JMP-Nutzern weltweit teilen. Um dies zu vereinfachen, haben wir uns für Python entschieden, unter anderem aufgrund der bereits verfügbaren Bibliotheken und des Codes, den Sie möglicherweise selbst geschrieben haben. So haben wir beispielsweise die Verbindungen zu Amazon S3 und Microsoft SharePoint realisiert. Wir können bestehende Python-Bibliotheken einbinden und hoffen, dass es Ihnen dadurch ebenfalls leichter fällt.
Ein weiterer Grund für die Integration, neben unserer einfachen Bedienung, ist die Möglichkeit, Ihre Konfigurationen zu verwalten. Benutzer können die Verbindungskonfigurationen mithilfe des Connector-Editors und des Abfrage-Generators erstellen und bearbeiten. So lassen sich Abfragen grafisch erstellen, Daten filtern, Spalten auswählen und vieles mehr. Außerdem ist die Zusammenarbeit möglich. Die erstellten Verbindungen und Konfigurationen können exportiert und über Add-Ins geteilt werden.
Falls Sie diese Funktionalität noch nicht kennen, werden Sie sie gleich genauer kennenlernen, wenn ich Ihnen alles in Aktion zeige. Zuvor möchte ich Ihnen aber erklären, wie alles zusammenhängt. Am Anfang steht Ihre Datenquelle, die Sie mit JMP verbinden möchten.
Wenn wir in JMP von Daten sprechen, meinen wir Datentabellen. Diese Tabellen lassen sich unter Umständen sehr einfach aus Ihrer Datenquelle bereitstellen. Möglicherweise ist aber auch etwas Aufwand nötig. Beispielsweise könnte ein Web-Endpunkt hierarchisch strukturierte JSON-Daten zurückgeben. In diesem Fall ist eine gewisse Verarbeitung erforderlich. Solange die Daten jedoch als Datentabelle für JMP verfügbar gemacht werden können, sind sie grundsätzlich nutzbar.
Der Abfrage-Generator behandelt diese Daten wie eine herkömmliche Datenbank, beispielsweise MySQL oder SQL Server. Er geht davon aus, dass die Daten in benannten Tabellen und diese Tabellen wiederum in benannten Schemas organisiert sind.
Sie verfügen wahrscheinlich über mehr als eine Datenquelle. Falls nicht, gibt es zumindest mehrere Zugriffsmöglichkeiten. Benutzer haben möglicherweise unterschiedliche Zugangsdaten. Oder Sie möchten die Adresse Ihrer Daten einfach nicht fest codieren. In jedem Fall stehen Ihnen verschiedene Optionen zur Verfügung. Durch die Angabe spezifischer Werte für diese Optionen erhalten Sie eine Konfiguration. Mit dieser Konfiguration können Sie dann eine Datenquelle erstellen. Diese Konfigurationen lassen sich mit dem Datenkonnektor-Editor erstellen.
Das ist das Gesamtbild in Kürze. Aber wie wird daraus Code? Schauen wir uns das an. Ich bin hier in JMP. Wir schließen das Fenster und fangen von vorne an. Links sehen wir Code, der einige Datenkonnektor-Typen implementiert. Ein Typ ist beispielsweise ODBC, das in JMP integriert ist. Es könnte sich um einen der SaaS-Typen handeln, also lokal, remote oder über eine Verbindung. Es könnte auch Snowflake sein. Aber unabhängig davon ist Python für jeden von Ihnen implementierten Typ eine Option.
Ganz oben sehen wir einige Importe. Insbesondere importieren wir das integrierte JMP-Modul. Hier haben wir eine Hilfsfunktion, mit der wir überprüfen können, wann eine Funktion aufgerufen wird. Das ist in dieser Demo wichtig, da JMP den Code aufruft. Wir werden den Code selbst nicht so oft aufrufen. Um den Ablauf zu verstehen, ist es aber wichtig, dass wir die Aufrufe nachverfolgen können.
Der folgende Code implementiert den Typ. Bevor ich näher darauf eingehe, sehen wir uns diese Referenz an. Die verschiedenen Elemente in dieser Liste entsprechen in vielerlei Hinsicht dem Diagramm, das ich Ihnen gerade gezeigt habe. Wir benötigen Optionen. Dazu erstellen wir eine Unterklasse von `jmp.DataConnectorType` und definieren ein Feldattribut, das diese Optionen festlegt. Wir haben eine Konfiguration, die wir in unsere Datenquelle umwandeln müssen. Dazu erstellen wir eine Unterklasse von `jmp.DataConnector` und definieren eine Funktion `_do_as_data_source`, die diese Konvertierung durchführt.
Schließlich haben wir die Datenquelle selbst. Das ist eine weitere Unterklasse. Wir definieren Funktionen, die uns Auskunft über die Schemas (falls vorhanden), die Tabellen und die Daten einer bestimmten Tabelle geben. Obwohl wir dies in unserer Demo nicht zeigen, ist Folgendes zu beachten: Falls Ressourcen nicht automatisch bereinigt werden – beispielsweise Verbindungen ohne dieses Verhalten –, sollten Sie die spezielle Python-Methode `get()` (mit doppeltem Unterstrich) verwenden, um diese Ressourcen zu bereinigen, sobald sie nicht mehr referenziert werden. Denn JMP überlässt die Bereinigung Python, um das Schließen der Datenquelle zu gewährleisten.
Vor diesem Hintergrund schauen wir uns den Code noch einmal an. Wir sehen SimpleFolderConnectorType, eine Unterklasse von jmp.DataConnectorType. Wie bereits erwähnt, verfügt sie über Felder mit verschiedenen Optionen. Die erste und einzige Option ist hier „Ordner“.
In diesem Fall bedeutet „Ordner“ – und damit ist unsere SimpleFolder-Verbindung –, dass wir unsere Datenquelle haben. Das entspricht einem einzelnen Ordner auf meinem lokalen Dateisystem, und dieser Ordner stellt Daten in Form der darin enthaltenen Dateien bereit.
Zunächst benötigen wir die Klasse „Folder“. Ihr Wert in diesem Wörterbuch, das unsere Optionen beschreibt, ist vom Typ str | None. Dies bedeutet, dass wir einen optionalen String-Wert verwenden. Anschließend definieren wir unsere Konfigurationsklasse SimpleFolderConnector, die von jmp.DataConnector erbt. Sie definiert die Funktion _do_as_data_source, die die Daten aus unserer Konfiguration konvertiert bzw. verbindet.
Wir können auf unseren Konfigurationswert „Ordner“ zugreifen, indem wir einfach auf „self“ zugreifen, genau wie bei einem integrierten Wörterbuch. Wir prüfen, ob der Wert „none“ ist, falls der Benutzer diesen Standardwert weggelassen hat, und weisen ihn gegebenenfalls durch eine Fehlermeldung darauf hin, dass er erforderlich ist.
Zum Schluss konvertieren wir die Datenquelle. Die Datenquellenklasse steht hier ganz unten auf unserer Liste. Natürlich müssen wir sie erstellen können. Dazu definieren wir eine Initialisierungsfunktion. In diesem Fall prüfen wir, ob es sich tatsächlich um ein Verzeichnis handelt, denn wir möchten den Benutzer – also Sie selbst oder jeden, der den Code verwendet – über eventuelle Fehler informieren. Die Datenquelle sollte beim Erstellen verbunden werden. In diesem Fall ist zwar keine direkte Verbindung erforderlich, aber wir können zumindest prüfen, ob der Ordner existiert.
Als Nächstes stand Get-Schemas auf dem Programm. In diesem Fall geht es bei der Datenquelle darum, dass keine Schemas existieren. Wir haben direkten Zugriff auf die Tabellen. Daher müssen wir Get-Schemas nicht definieren, und JMP erkennt automatisch, dass unsere Datenquelle keine Schemas verwendet.
Wir müssen jedoch definieren, was die Tabellen sind. Obwohl wir in diesem Fall einen Schema-Parameter benötigen, ignorieren wir ihn, da wir ihn nicht verwenden. Da wir uns aber die Dateien ansehen, verwenden wir eine Methode, um diese zu benennen. In diesem Fall genügt der Dateiname. Wir durchlaufen den Ordner und geben für jede darin enthaltene Datei ihren Namen zurück.
Schließlich müssen wir die Datentabellen abrufen. Genau dafür ist diese letzte Funktion zum Öffnen von Tabellen gedacht. Zuerst müssen wir den Pfad der Datei rekonstruieren, die die Daten enthält. Wir nehmen den Tabellennamen, der sich aus dem Dateinamen und dem Ordnernamen zusammensetzt, und geben dann den Pfad als Zeichenkette zurück.
Das eben erwähnte Modell erfordert die Rückgabe einer Datentabelle, und das ist auch möglich. Wenn Sie, wie ich vorhin mein Beispiel genannt habe, einen Web-Endpunkt haben, gibt dieser hierarchisches JSON oder Ähnliches zurück. Das sollten Sie wahrscheinlich selbst in eine Datentabelle umwandeln oder direkt zurückgeben.
Da es sich hier aber um eine Datei handelt – ein Fall, den wir bereits bei der Entwicklung der S3- und SharePoint-Add-Ins beobachtet haben und der, soweit ich weiß, auch für den Zugriff auf andere dateiähnliche Datenspeicher Interesse geweckt hat –, ist es möglich, die Datei nicht direkt, sondern durch Übergabe dieser Zeichenkette zu öffnen. JMP öffnet die Datei dann für uns.
Es kümmert sich um Dinge wie das private Öffnen der Datei. Die hier zurückgegebene Datentabelle ist ein Implementierungsdetail und sollte dem Benutzer nicht direkt zugänglich gemacht werden. Wenn Sie den Abfrage-Generator verwenden, werden keine Zwischentabellen angezeigt, sondern nur das Endergebnis. In diesem Fall übernimmt JMP das für uns. Dadurch bleiben auch alle Einstellungen erhalten, die beim Öffnen der Tabelle relevant sein könnten. Darauf gehe ich später noch genauer ein.
Schließlich haben wir hier den Aufruf der Funktion `jmp.DataConnector.tie`. Diese Funktion nimmt ihre beiden Argumente – die Typklasse und die Konnektorklasse – entgegen und stellt sicher, dass sie einander kennen. Aktuell referenziert keine der beiden Klassen die andere, aber die Klasse `DataConnectorType` oben dient JMP als Zugriffspunkt. Der Typ ist allumfassend und erfasst den gesamten Code und alle Definitionen, die die Verbindung herstellen. Sie müssen einander kennen.
Abschließend folgt hier ein Kommentar, der den Typ der letzten Zeichenkette angibt. Es könnte sich um DBC oder ODBC handeln. Auch SAS Viya oder SAS Remote wären mögliche Optionen. Im Fall von Python steht hier der Doppelpunkt, der auf einen Funktionstyp hinweist. Die Variable `__main__` ist der Name des Moduls, da wir es direkt über JMP ausgeführt haben. Schließlich folgt noch `SimpleFolderConnectorType`, der Name der Klasse.
Schauen wir uns das in der Praxis an. Wenn ich den Datenkonnektor-Dialog öffne und eine neue Verbindung erstelle, öffnet sich der zugehörige Datenkonnektor-Editor. Wenn wir den Typ auf Python ändern, können wir hier den restlichen Text eingeben. Wir füllen ihn aus.
Sobald ich das getan habe, sehen wir unsere Option „Ordner“. Sie hat keinen Wert, was „None“ entspricht. Wenn ich nun versuche, die Verbindung herzustellen und diese Funktion aufzurufen, sehen wir die Fehlermeldung: „Ordner erforderlich.“
Um nun auf die Daten zugreifen zu können, verwende ich die mit JMP mitgelieferten Beispielimportdaten. Das ist dieser Ordner hier. Ich kopiere ihn. Ich zeige ihn noch einmal. Wir kopieren den Pfad, gehen zu JMP und fügen ihn hier ein. Wir sehen, was wir getestet haben. Jetzt funktioniert alles, also stellen wir die Verbindung her.
Nachdem die Verbindung hergestellt ist, sehen Sie hier eine Liste der Tabellen. Diese Tabellen entsprechen den hier vorhandenen Dateien. Wir sehen hier beispielsweise die Datei „Animals_L.txt“. Ein Blick ins Protokoll zeigt, dass sich die Verwendung dieser Protokollierungsfunktion als nützlich erwiesen hat. Wir sehen, dass wir „_do_as_data_source“ und die Initialisierung der Datenquelle während der Tests mehrfach aufgerufen haben. Außerdem sehen wir, dass „get-tables“ aufgerufen wurde, wodurch wir erneut diese Liste erhalten.
Wenn ich hier den Abfrage-Generator aufrufe, sehen wir, dass wir Zugriff auf die Spalten haben. Wir sehen, dass wir diese Spalten hinzufügen können, wenn wir die Abfrage erstellen. Wir können hier auch filtern. Beispielsweise könnten wir nur zwei dieser Jahreszeiten auswählen. Wenn wir uns den SQL-Code ansehen, sehen wir, dass er all dies erfasst. Führen wir die Abfrage aus, erhalten wir unsere Ergebnisse.
Sie fragen sich vielleicht, wie das alles funktioniert. Wir erstellen eine SQL-Abfrage. Wir führen SQL-Code aus. Doch als wir die Dinge zuvor definierten, gab es kaum eine Vorstellung von SQL. Es funktioniert, weil wir diesen OPEN-TABLE-Aufruf bereitgestellt haben; wir haben diesen Weg zum Abrufen der Daten angegeben. JMP erledigt dann den Rest. Es verwendet SQLite, eine Art eingebettete Datenbank, um die vorhandenen Daten zugänglich zu machen und SQL-Code ausführen zu können. Zum Beispiel die WHERE-Klausel, die uns nur zwei der Jahreszeiten anzeigt.
Schauen wir uns die komplexere Datei an. Vielleicht kehren wir zu unserer Lieblingsdatei zurück, die wir hier in Excel haben. Öffnen Sie erneut den Abfrage-Generator. Wir sehen, dass vor jeder Aktion dieser Dialog hier erschienen ist. Wir haben entschieden, dass man bei Dateien [unverständlich 00:17:43] Mal aufgefordert werden muss, den Inhalt anzugeben. Wenn JMP versucht, diese Datei zu öffnen, werden Sie aufgefordert, in diesem Fall die benötigten Informationen mithilfe des Import-Assistenten einzugeben.
Das sieht alles gut aus, also klicken Sie auf „Importieren“. Jetzt sehen Sie wie zuvor die Spaltennamen und den Screenshot. Ich klicke jetzt einfach auf „Importieren“. Unsere Daten sind da. Sie fragen sich jetzt vielleicht, ob das jedes Mal nötig ist? Die Antwort ist nein.
Schauen wir uns dieses Quellskript an. Ganz oben sehen wir, was wir erwarten. Dort steht „Neue SQL-Abfrage“. Außerdem sind unsere Verbindungsinformationen enthalten, die in diesem Fall vom Datenkonnektor bereitgestellt werden. Man sieht, dass er auf unseren Typ verweist und auch den von uns angegebenen Ordner enthält.
Wenn wir uns die Tabelle genauer ansehen, stellen wir fest, dass es hier die neue Option „Öffnen-Einstellungen“ gibt. Diese Einstellungen übernehmen die im Importassistenten festgelegten Werte. Insbesondere werden die zusätzlichen Argumente, die in den Quellskripten der zugrunde liegenden großen Klassentabelle an „Öffnen“ übergeben wurden, hier bereitgestellt.
Wenn ich das jetzt erneut ausführe, sehe ich, dass alles geöffnet ist und gut aussieht. Hätten wir bei den Einstellungen etwas Ungewöhnliches gemacht, beispielsweise mit einer späteren Spalte beginnen müssen, wäre das hier immer noch sichtbar. Wir sehen im Protokoll, dass alles von vorne begonnen hat. Wir sehen, dass wir `_do_as_data_source` erneut aufgerufen haben. Dann haben wir die Tabellenliste erhalten und diese Tabelle erneut geöffnet.
Das ist die Basis. Das hier sieht etwas komplizierter aus. Aber es ist nicht nur komplizierter, sondern bietet auch mehr Funktionen. Das hier war sozusagen das Minimum, das Kleinste, was man tun kann, um eine Verbindung herzustellen.
Es sieht jetzt etwas ausgefeilter aus. Anstelle eines einfachen Ordnerverbinders haben wir nun einen vollwertigen Ordnerverbinder. Die Felddefinition ist zwar deutlich komplexer, besteht aber im Wesentlichen aus ähnlichen Bausteinen wie zuvor.
Neu ist in diesem Fall zunächst die Verwendung von `jmp.DataConnectorGroupedFields`. Dadurch können wir festlegen, dass die Felder in verschiedenen Gruppen angeordnet sind. Dies beeinflusst deren Darstellung im Datenkonnektor-Editor. Bei ODBC werden die Optionen in verschiedene Gruppen eingeteilt, und dieselbe Funktionalität können wir auch hier mit Python nutzen.
Jede Gruppe definiert ein Paar in dieser Liste, das an `jmp.DataConnectorGroupedFields` übergeben wird. Dieses Paar enthält den Namen und ein Wörterbuch, ähnlich dem vorherigen, das den Optionsnamen und die Felddefinition enthält. In der Felddefinition ist weiterhin der Typ `str | None` erkennbar. Zusätzlich wird sie in `jmp.DataConnectorField` eingebettet, das ich aufgrund seiner häufigen Verwendung und der Länge als Alias verwendet habe. Dadurch können zusätzliche Informationen angegeben werden, beispielsweise ein Tooltip, der im Datenkonnektor-Editor angezeigt wird, wenn man mit der Maus über den Namen einer Option fährt.
Sie legen einen Standardwert fest. Sie können auch einen Namen angeben, der im Datenkonnektor-Editor angezeigt wird und sich von dem Namen unterscheidet, der in den Konfigurationsdateien für JSL verwendet wird. Wir nutzen diese Funktion beispielsweise in JMP mit ODBC, um die Optionsnamen zu lokalisieren oder aussagekräftigere Zeichenketten zu verwenden, da diese standardmäßig in JSL verwendet werden. Wir benötigen also einen Namen im JSL-Stil.
„Ordner“ ist hier, glaube ich, das deutsche Wort für Ordner. Das werden wir später sehen. Was die Art und Weise betrifft, wie wir unsere Datenquelle betrachten: Sie basiert weiterhin auf dem Ordner, aber wir werden optional auch Schemas unterstützen. In diesem Fall haben wir die Möglichkeit, die Daten nicht wie bisher zu betrachten, sondern sie auf eine neue Weise zu analysieren, bei der wir Unterordner des hier angegebenen Ordners als Schemas betrachten und deren Dateien dann als Datentabellen.
Wir werden eine weitere Option haben, die die Art und Weise, wie wir die Zuordnung von Tabellennamen zu den zugrunde liegenden Dateien betrachten, verändern wird, indem wir auf bestimmte Erweiterungen beschränken und diese auch abschneiden.
Die Konvertierung zu einer Datenquelle beim Verbindungsaufbau ist ähnlich, aber etwas komplexer, da wir mehr Optionen haben. Wir prüfen weiterhin „Ordner“, aber zusätzlich auch diese Erweiterungsoption. Wir lösen einen Fehler aus und übergeben dann alle Daten an unsere neue Datenquelle.
Unsere neue Datenquelle prüft die Ordner im Voraus und legt die weiteren Optionen fest. Sie stellt Schemas bereit. Wenn wir die Schemas verwenden, sehen wir einen ähnlichen Code aus, der die Ordner im Zielordner durchsucht. Jedes Unterverzeichnis erhält seinen Namen, der dann als Name des Schemas verwendet wird.
Wenn wir keine Schemas verwenden, also unsere neue Option nicht aktiviert haben, geben wir einfach `None` zurück. Zuvor haben wir keine Schemas definiert (`get-schemas`), aber da wir hier keine optionale Funktion definieren können, ist es erlaubt, `None` zurückzugeben, um auszudrücken: „Ich habe keine.“ Wir verwenden keine Schemas.
Mit Get-Tables funktioniert es ähnlich wie zuvor. Letztendlich ermitteln wir die Namen mehrerer Dateien. Aufgrund der verschiedenen Optionen gibt es dafür mehrere Möglichkeiten. Wir ermitteln das Verzeichnis. Die Vorgehensweise hängt vom verwendeten Schema ab, genauer gesagt davon, ob wir überhaupt Schemas verwenden. Anschließend filtern wir die Dateien, bevor wir ihre Namen ermitteln, oder wenden eine komplexere Methode an, falls wir die Dateierweiterungen verarbeiten.
Um schließlich die Datentabelle zu erhalten, kehren wir den Prozess von `get-schemas` und `get-tables` um. Wir müssen den Pfad rekonstruieren. Wir könnten die Dateiendung wieder anhängen. Dadurch wird aber das zugehörige Verzeichnis nicht erfasst, daher fügen wir den Dateinamen wieder an, bevor wir den Pfad erneut als Zeichenkette zurückgeben. Wir verknüpfen die beiden Teile und erhalten so wie zuvor unseren Typnamen.
Schauen wir uns das mal an. Ich scrolle mal hier zurück, damit wir es nachschlagen können. Wie zuvor legen wir hier den Typ fest. Wir sehen hier unseren benutzerdefinierten Namen zusammen mit dem Tooltip. Für den Ordner verwenden wir denselben wie zuvor. Holen wir uns den Pfad dazu. Gehen wir sogar einen Schritt weiter. Nutzen wir unsere Schema-Funktionalität. Wir kopieren das.
Dann können wir also sagen, dass wir Unterordner als Schemas verwenden möchten. Da wir diese praktische Option hinzugefügt haben, werden wir sie nutzen. Stellen Sie sicher, dass alles gut aussieht. Ja. Die Verbindung kann hergestellt werden. Achten Sie darauf, dass alle Fenster im Vordergrund sind.
Links sehen wir nun die Schemas, die in Wirklichkeit nur die Ordnernamen sind. Hier sind unsere Importdaten. Wir haben sie auf .txt-Dateien beschränkt. Nehmen wir wie zuvor unser Beispiel mit den Tieren und öffnen es. Die Daten sind da. Alles funktioniert. Die Aufrufe sind wie zuvor vorhanden. Im Protokoll sehen wir Aufrufe von `get-schemas`, `get-tables`, unserer Hilfsfunktion und `open table`.
Sie haben sich all diese Mühe gemacht, diese Typen zu erstellen. Jetzt möchten Sie sie mit anderen teilen. Das ist der letzte Punkt, über den wir sprechen möchten: wie das geht. Ich habe noch eine Checkliste.
Sie haben Ihren Python-Code geschrieben, aber je nachdem, wie Sie ihn erstellt haben, möchten Sie ihn vielleicht in einem Paket strukturieren. Ziel der Paketstrukturierung ist es, sicherzustellen, dass alles zusammengehört und mit einem Tool wie pip oder in diesem Fall jpip, das von JMP umschlossen wird, installiert werden kann. Dabei können Sie Abhängigkeiten angeben. Beispielsweise benötigen wir für S3 das Boto3-Paket, das auf PyPI verfügbar ist. Die Verwendung eines Pakets bietet eine sehr einfache Möglichkeit, diese Abhängigkeit zu spezifizieren.
Sie sollten Basiskonfigurationen erstellen. Erinnern Sie sich, dass ich vorhin den Typnamen direkt im Datenkonnektor-Editor eingegeben habe? Das ist zwar praktisch, aber es wäre einfacher, wenn ich einfach etwas in der Konfigurationsliste finden könnte. Darauf basierend könnte ich dann etwas Neues erstellen, anstatt mir den vollständigen Namen merken zu müssen.
Sie werden wahrscheinlich ein Installationsskript schreiben wollen. Wir haben dieses tolle Python-Paket, aber wir müssen es an einem Ort ablegen, wo es auch tatsächlich verwendet werden kann. Wenn wir das automatisieren könnten, wäre das super.
Abschließend möchten wir alles in ein Add-in packen. Mit einem Add-in haben wir eine einfach zu installierende Lösung, die wir über den Marketplace vertreiben können. Kurz gesagt: Alles ist in einer einzigen Paketdatei zusammengefasst.
Schauen wir uns das mal an. Ich habe hier ein Add-in mit einer weiterentwickelten Version des Codes, den wir uns heute schon angesehen haben. Ich habe es hier entpackt, damit wir sehen können, was alles drin ist. Das Erste auf der Liste war, glaube ich, das Python-Paket. Ich habe es hier erstellt. Wir haben unseren Python-Code, aber dieser ist in einem Python-Projekt strukturiert… Entschuldigung, in einem Python-Paket. Wir haben unsere pyproject.toml-Datei. Ich habe heute leider keine Zeit, genau zu erklären, wie man so etwas erstellt, aber es gibt dazu Online-Ressourcen.
Wir haben einen Ordner namens „Data Connectors“. Hier befinden sich die Konfigurationen, die zum Add-on gehören, in diesem Fall also die Basiskonfigurationen. Wenn ich mir beispielsweise eine dieser Konfigurationen ansehe, sehen wir, dass sie nur eine Zeile enthält, die den Typ angibt. Sie enthält keine weiteren Konfigurationseinstellungen, sondern bietet dem Benutzer lediglich eine Referenz. Dann gibt es noch den Ordner „addinLoad“, der das Installationsskript enthält.
Natürlich können Sie das alles direkt erstellen, aber Sie können auch den Add-In-Editor von JMP verwenden. Gehen Sie dazu auf „Datei“, „Neu“, „Add-In“. Dort können Sie einen Namen und eine ID vergeben. Außerdem können Sie die Mindestversion von JMP festlegen, in diesem Fall 19. Im Feld „Startskript“ fügen Sie das Skript ein, das das Paket installiert. Wir möchten sicherstellen, dass es nur einmal installiert wird.
Wir haben die Dateien, die wir hinzufügen möchten. In diesem Fall sind sie bereits entpackt, aber falls Sie das Add-in zum ersten Mal selbst erstellen, befinden sie sich möglicherweise an einem anderen Ort. Wir können das Paket hinzufügen. Sehen Sie, wir haben alles da. Wir können die Datenkonnektoren hinzufügen. Wenn wir das Subskript haben, können wir unser eigenes Add-in speichern und erstellen. Sobald alles vorhanden ist, sollte der Erstellungsprozess recht einfach sein.
Das war alles, was ich hier zeigen wollte. Fassen wir zusammen. Zunächst möchte ich darauf eingehen, warum eine Integration sinnvoll ist. Wie wir zu Beginn gesehen haben, bietet das Data Connector Framework viele Möglichkeiten, Konfigurationen zu bearbeiten, zu teilen und mit dem Query Builder interaktiv Abfragen zu erstellen. Das ist ein guter Grund, die Datenquelle einzubinden. Hier kommt es ins Spiel. Wir haben besprochen, dass in JMP alles als Datentabelle behandelt wird, und wir möchten, dass es wie eine Datenbank aussieht.
Welchen Code muss man schreiben? Wir haben die verschiedenen Unterklassen besprochen, die man definieren sollte, die verschiedenen Funktionen, die man schreiben muss, und wie man die Optionen festlegt. Abschließend haben wir darüber gesprochen, wie man ein Add-in erstellen und seine Arbeit mit anderen teilen oder auf dem JMP Marketplace veröffentlichen kann.
Dies ist in gewisser Weise ein relativ schneller Überblick über alle Möglichkeiten. Einige von Ihnen machen sich vielleicht sehr gute Notizen und erstellen viele Screenshots oder Fotos, aber wenn es Ihnen wie mir geht, möchten Sie wahrscheinlich noch etwas anderes als Referenz haben. Die gute Nachricht ist: Wir haben die Informationen und arbeiten an weiteren.
Die heute vorgestellte API ist bereits dokumentiert. Sie finden die Dokumentation in den EA-Hinweisen im Abschnitt „Datenzugriff“. Bitte stellen Sie sicher, dass Sie die neueste Version verwenden. Diese ist möglicherweise nicht die aktuellste Version Ihres Expert Advisors, falls keine Änderungen vorgenommen wurden. Wir ergänzen die Dokumentation um weitere Informationen im Skriptindex. Diese bietet zwar nicht den gleichen Überblick wie beispielsweise die EA-Hinweise, dient aber hoffentlich als Referenz für einzelne API-Funktionen.
Abschließend noch das Add-in, das ich vorhin gezeigt habe: Wir entwickeln es gerade weiter und werden es im JMP Marketplace veröffentlichen. Es soll als Ressource dienen, um sowohl die API vorzustellen als auch zu zeigen, wie man ein Python-Paket erstellt und dieses dann als Add-in veröffentlicht.
Wir werden Ihnen die gesamte Dokumentation noch einmal zeigen und Ihnen außerdem einige weitere Funktionen vorstellen, die ich aus Zeitgründen nicht besprechen konnte. Diese sind etwas fortgeschrittener, könnten aber dennoch nützlich sein. Schauen Sie unbedingt mal rein!
Abschließend möchte ich auf unsere zukünftigen Pläne eingehen. In JMP 20 und höher sind zusätzliche API-Erweiterungen geplant, die wir derzeit prüfen. Beispielsweise ist Ihnen vielleicht aufgefallen, dass JMP zur Datenverarbeitung Ihre gesamte Datentabelle lokal lädt, da diese vom Befehl `opentable` zurückgegeben werden muss. Anschließend verwenden wir die Daten lokal, wie bereits erwähnt, mithilfe von SQLite.
Wenn Sie jedoch einen Teil dieser Verarbeitung serverseitig durchführen können, sodass Sie nicht alles lokal herunterladen müssen, möchten wir das unterstützen. Wir werden uns damit befassen, wie wir diese Funktionalität ebenfalls bereitstellen können.
Damit wären wir fertig. Vielen Dank fürs Zuhören. Ich hoffe, Sie können das Gelernte nutzen, um neue Datenquellen zu erstellen, die in dieses Data-Connector-Framework integriert sind. So können Sie Add-Ins veröffentlichen und insgesamt einfacher und effizienter mit Ihren Daten arbeiten und sie in JMP importieren. Nochmals vielen Dank. Das war's.