Coder Social home page Coder Social logo

jupyrdf / ipyelk Goto Github PK

View Code? Open in Web Editor NEW
36.0 36.0 4.0 3.19 MB

Jupyter Widgets for interactive graphs powered by the Eclipse Layout Kernel (ELK)

License: BSD 3-Clause "New" or "Revised" License

Python 66.10% TypeScript 24.91% CSS 1.41% RobotFramework 7.57%

ipyelk's People

Contributors

bollwyvl avatar dfreeman06 avatar nrbgt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ipyelk's Issues

Mechanism to attach additional metadata

Problem

For interactive applications when using the contrib.elements there needs to be a mechanism to connect the Element back to some other data structures.

Proposed

Adding a metadata dictionary field onto the BaseElement class for users to attach data useful outside the layouter logic.

Revisit Elk, Sprotty cardinality

We might only need One Elk and One Sprotty Server, as it appears they can both handle multiplexing requests.

It would still be good to be able to cull them when there are no more views on the page, probably.

release ipyelk 0.3.0

  • features
    • #60: shapes, etc.
  • infrastructure
  • docs
    • #71: update readme
      • some new screenshots (maybe a wide table of three?)
    • #68: update changelog
    • #64: initial readthedocs
    • #71: logo
  • pick a funny new deer species
    • Megaloceros giganteus
  • validate binder
  • tag
  • release on
    • pypi
    • npm
  • handle conda-forge update
  • make 0.3.x branch
  • bump to next working version, e.g. 0.3.1
  • update release procedure with lessons learned

πŸ•πŸŒ­ Show some data-driven, reusable software documentation examples

This project is (or will soon be) complex enough to show non-trivial demos of:

  • source code navigation
    • show a nested file treemap (sized by SLOC, etc.), click to view syntax-highlighted source
  • architecture diagrams
    • see how we're subclassing Widget, Box, etc.
  • automation processes
    • look at the doit graph
  • dependencies
    • see the fully resolved pip/conda relationships represented in lock files, etc.
  • profile information
    • call graph
  • widget linkages
  • test logs
    • show robot screenshots in plots

These would be cute to test, as we could take the generated SVG artifacts and put them in (eventual) documentation, but these seem like useful tools, especially for canonical outputs of common developer tools.

Sprotty Duplicate ID

Appears to be an issue if the hierarchy changes sprotty will throw a "duplicate id" error when recursively adding children.

Potential fixes:

  • python side clear diagram values between hierarchy changes
  • javascript side - improve hierarchy change detection

πŸ•ΈοΈ Support RDFLib Graph

Without adding RDFlib as a hard dependency, let's offer a variant which uses the existing networkx machinery to create nice ELK JSON with ports.

Release ipyelk 0.2.0

It's time for another ipyelk release!

  • bug fixes?
    • #36 Async multi sprotty views
  • merge features
    • #15 text resizer (bumps versions to 0.2.0 because of API changes)
    • #27 SVG
    • #24 more layout options
    • #34 more label options
  • infrastructure
    • #20 πŸ€–
    • importnb #30
    • #36 update miniconda
  • update changelog
  • pick a funny new deer species
    • current front-runner is Mazama Zetta
  • tag
  • release on
    • pypi
    • npm
  • handle conda-forge update
  • update release procedure with lessons learned
  • bump to next working version

Add ReadTheDocs

Elevator Pitch

Let's have some proper docs that somebody else builds/versions/maintains.

References

  • #42 expands the (already quite large) API
  • #62 will have some fairly significant changes for installation, etc

Job Sketch

this can play out over several PRs, not bound to lab version (but should likely land for final lab 1 release)

Properties dropped by transformer

With master, it looks like adding a "properties": {"cssClasses": "custom-class-from-data-foo"}} to an edge does not result in it getting added to the DOM.

We probably just need to initialize all of the properties from the data, rather than None, and special-case cssClasses.

This seems worthwhile to test.

Extend ElkJSON Validation Rules

  • Need to catch if the produced ElkJson structure has duplicative IDs.
  • validate that hierarchy graph given to the XELK transformer is a tree

Investigate Moving Collapse/Expand Logic to Client

Currently the logic to handle the collapsing is in the XELK transformer. But there are a few benefits from moving to the browser:

  • Embed diagrams as static artifacts then this would also maintain good interactions
  • Generalize the logic so other transforms do not need to re-implement

Additional layout option examples

From a code perspective, it looks fine, if somewhat hard to grasp... however, there's almost no way I'd be able to look at the docs and actually make one of these custom thingers work. I think refining a few, targeted examples, for e.g. the edge collapsing, would be helpful... linking to the source is fine.

Originally posted by @nrbgt in #24 (comment)

Connector Shapes in Firefox

The connector ends in Firefox are cropped to a half of the image.

This happens on Windows and Linux versions of Firefox. Works fine in Chrome.

image

Sprotty Action/Command callbacks

Connect the completion of sprotty actions and commands back to the python kernel.

  • needed for knowing when the diagram has finished rendering
  • capturing potential issues elkjs or sprotty errors

Signular Elk

Example attempt below:

+const Theelk = new ELK.default({
+  workerFactory: () => {
+    ELK_DEBUG && console.warn('ELK Worker created');
+    return new (Worker as any)();
+  }
+} as any);
+
 export class ELKModel extends DOMWidgetModel {
   static model_name = 'ELKModel';
 
@@ -91,24 +98,25 @@ export class ELKModel extends DOMWidgetModel {
   }
 
   protected cullElk() {
-    const elk: any = this._elk;
-    if (elk != null) {
-      ELK_DEBUG && console.warn('ELK worker culling for', this.cid);
-      elk.worker?.terminate();
-    } else {
-      ELK_DEBUG && console.warn('ELK was already culled for', this.cid);
-    }
-    this._elk = null;
+    // const elk: any = this._elk;
+    // if (elk != null) {
+    //   ELK_DEBUG && console.warn('ELK worker culling for', this.cid);
+    //   elk.worker?.terminate();
+    // } else {
+    //   ELK_DEBUG && console.warn('ELK was already culled for', this.cid);
+    // }
+    // this._elk = null;
   }
 
   protected ensureElk() {
     if (this._elk == null) {
-      this._elk = new ELK.default({
-        workerFactory: () => {
-          ELK_DEBUG && console.warn('ELK Worker created');
-          return new (Worker as any)();
-        }
-      } as any);
+      this._elk = Theelk;
+      // this._elk = new ELK.default({
+      //   workerFactory: () => {
+      //     ELK_DEBUG && console.warn('ELK Worker created');
+      //     return new (Worker as any)();
+      //   }

Add an example with a "family tree" nested hierarchy

Let's consider some examples for showing different kinds of strict (or ambiguous) family trees:

  • the deer

Examples

  • geneaology
    • show images, tags, consistent labels, interactivity, time
    • gramps
  • deer
    • show images, maybe location
    • Screenshot from 2020-11-12 12-27-44

refactor custom elk options as JSON schema

  • follow-on to #24

We likely need an offline pipeline (appears to have been started) for scraping the elk options and capturing them in a format we can easily consume from python and ts.

This could be modeled, offline, as a notebook which graduated to a series of doit tasks:

  • download the index html
  • download each child html
  • transform each child html into a JSON structure
  • generate the JSON schema for each option
  • potentially inject additional things we are unlikely to be able to automate
    • building regular expressions for placement
  • generate a composite schema
  • check the composite schema in, so we can track deltas

Assets:

  • the pages look generally machine written, so should generally be machine readable
  • the Last-Modified times appear to be meaningful, which will let us do some things to track provenance
    • a git commit would be better, might be worth pursuing

Container Nodes

Investigate how to implement container nodes and their implication with building the elk json.

πŸŽ›οΈ Diagram Control Overlay

Allow jupyterlab widgets to overlay as control surfaces on top of certain elements. The use case it to provide a richer and reactive UI as the user navigates a particular diagram.

Add Mypy

Adding Mypy tooling would add addition rigor to the library with better type understanding.

use importnb for (functional) examples

Elevator Pitch

Making the examples notebooks work with importnb, restructuring the discrete functional examples into humane names, e.g. an_ipyelk_example_with_bells(and_whistles=True)

Motivation

  • reduces copy-pasta
  • makes even more surer notebooks stay restart-run-all-able
  • would type well #25

Design Ideas

Many of these ideas have been developed over on @deathbeds/wxyz, where all the examples are importable, with a "kitchen sink" example that tests out having everything on the page at once, which can find DOM conflicts and performance issues.

Concretely, the "simple" example could become a function, e.g.

def make_a_simple_elk_example(elk_json=None) -> Tuple[W.Box, ElkDiagram]:
    diagram = ElkDiagram()
    elk_json = elk_json or ...
    ...
    return box, diagram

if __name__ == "__main__":
    box, diagram = make_a_simple_elk_example(**kwargs)
    IPython.display.display(box)

then the SVG exporter could:

with importnb.Notebook():
    from 00_Introduction import make_a_simple_elk_example

def make_a_simple_example_with_svg_export(box_diagram=None, **kwargs) -> Tuple[W.Box, ElkDiagram, ElkExporter]:
    box, diagram = box_diagram or make_a_simple_elk_example(**kwargs)
    exporter = ElkExporter(diagram=simple)
    ...
    return box, diagram, exporter

if __name__ == "__main__":
    box, diagram, exporter = make_a_simple_example_with_svg_export()
    IPython.display.display(box)

Alternatives

  • do-nothing
    • πŸ‘Ž the examples, which are already getting long, will get longer and more cantankerous to maintain
  • heavyweight Box subclasses
    • πŸ‘ can show good practices w/r/t dlinking
    • πŸ‘Ž harder to track as subclasses are used

Release ipyelk 0.2.1

It's time for another ipyelk release!

  • bug fixes
    • #46 correctly merge elk element properties
    • #48 label improvements, css text sizing, custom label key
  • infrastructure
    • #52 stubbing out unit tests
  • update changelog
  • pick a funny new deer species
  • tag
  • release on
    • pypi
    • npm
  • handle conda-forge update
  • update release procedure with lessons learned
  • bump to next working version

doit tasks

Developing off master. Running doit lab after a git clean -xdf results in everything building with no errors and lab starting. However, inside the example notebooks jupyterlab cannot find the diagram widget with the error:

Module @jupyrdf/jupyter-elk, semver range 1.0.1 is not registered as a widget module

It looks like the ipyelk extension isn't registered/being discovered. !jupyter labextension list only lists bqplot and the widget-manager.

Mime type render

It would be useful to have a mime type render for simple diagrams. The main use case is for having diagrams rendered in the built docs.

🍱 Add an ElkBox

Elevator Pitch

Make a Box subclass which uses the position of Elk nodes to place its children.

Motivation

For some kinds of interaction, it would be interesting to put interactive elements directly on an elk diagram.

Who cares?

With a real plotting library (as a demo dependency) on the widget bus, e.g. bqplot, we could show things like signals being transformed based on inputs, e.g. a slider:

|-----------------|    |-----------------|
|                 |    |     --          |
| X ----O---- 0.3 []--[]    /  \         |
|                 |    |----     --------|
|-----------------|    |-----------------|

Design Considerations

The python side of the house would probably just require a child_nodes = T.Dict() that mapped each child (or the index in children, lighter-weight) to the id of a node (or a label or port, i guess).

The typescript side will be... weird. We have this over on wxyz, which was (grossly, much any) ported from ipylayouts. We can repurpose a lot of this, and replace a good deal of the expensive DOM measurement code with _mark_layouts and the root <g transform="scale(z) translate(x, y)">. Unlike that, this would allow for elements that are off-canvas, so the box DOM might be something like:

<div class="p-Widget p-Panel jupyter-widgets widget-container widget-box widget-vbox styled-widget-140473608868624 jp-ElkBoxView" style="overflow: hidden;">
  <div class="p-Widget jp-ElkView"></div>
  <div class="p-Widget jp-FloatSlider" 
          style="position: absolute; left: 50px; top: 50px; zoom: 0.5"; width: 50px; height: 20px;"></div>
</div>

We would likely not publish the details back to the kernel, unless asked, as this would be doing LOTS of calculations during a pan/zoom interaction... indeed, we may want to hide the elements altogether until the DOM "cools off".

XELK Transformer Restructure

  • Refactor XELK to use a flatter approach to ElkNode generation rather than recursive.
  • Avoid None to mark the XELK root node. Consider adding a Sentinel singleton in case None is a node in the incoming Networkx graph.
  • Investigate moving dynamic visibility functionality from XELK to more general ElkTransformer
  • Improve the to_dict and from_dict. Issue with a port dict that has an ElkLabel instance instead of a dict that looks like an ElkLabel
  • Simplify transformer.py by pulling out logic into smaller more testable pieces
  • discuss how get_properties get_layout and get_css should work. Remove them?

πŸ–ΌοΈ Export SVG

It would be lovely to be able to export properly-styled SVG of the current viewport, suitable for printing.

As this would be expensive, it would likely be a message-based thing, rather than a mode trait.

It would be required to inject a fair amount of CSS to make it look right.

Some added, super-amazing features:

  • being able to specify and export with xlink:href to make things clickable
  • embed a dumb SVG pan/zoom library

fix labels labels schema

Issue with the schema generated for labels. Elklabels are allowed to have Elklabeks with extended properties.

  • fix schema
  • add test for labeled labels

release ipyelk 1.0.0

Not a "real" 1.0.0 (will be basically the same as 0.3.0 #69) , the major version bump will help us distinguish in the packaging approach w/r/t jupyterlab 3, and let us do backports/releases more simply.

  • dependencies
  • bug fixes
  • infrastructure
  • docs
    • update changelog
  • pick a funny new deer species
    • ...
  • validate binder
  • tag
  • release on
    • pypi
    • npm
  • handle conda-forge update
  • update release procedure with lessons learned
  • #76: bump to next working version e.g. 1.0.1

🐦 Add dodo

The build is a little brittle right now: adding a doit approach would:

  • help ensure running the same code locally, in ci, and on binder
  • clearly define the dependencies between build artifacts

As a follow-on to #4, #2, and probably a pre-requisite to more robust testing, docs, etc.

overhauling elements / shapes /symbols api

The usability can be improved with a clearer api surface area.

  • promote the contrib.elements to ipyelk.elements
  • adding metadata to BaseElement
  • fix hover exception for some elk ids not in the transformer registry
  • standardizing transformer registry items to Marks
  • convert Compound class to MarkFactory
  • rework Symbol and Shape schema and api.
  • rename ConnectorDef aka ElementSymbol offset fields

svg exporter style for use's href

  • Make reading of the collected svg styles easier
  • Build new ids for hrefs so more robust when exporting

Example diff for cleaner style tags

diff --git a/src/exporter.ts b/src/exporter.ts
index 7ceb3e1..c435492 100644
--- a/src/exporter.ts
+++ b/src/exporter.ts
@@ -151,6 +151,14 @@ export class ELKExporterModel extends WidgetModel {
     this._update_timeout = setTimeout(() => this._on_layout_updated(), 1000);
   }
 
+  makeStyleTag(style: string) {
+    return !style.trim().length ? "" : `<style type="text/css">
+      <![CDATA[
+        ${style}
+      ]]>
+    </style>`;
+  }
+
   async _on_layout_updated() {
     if (!this.enabled) {
       return;
@@ -166,17 +174,13 @@ export class ELKExporterModel extends WidgetModel {
     const strip_ids = this.get('strip_ids');
     const add_xml_header = this.get('add_xml_header');
     const raw_app_css = this.app_raw_css;
-    const rawStyle = `
-        ${STANDALONE_CSS}
-        ${raw_app_css.join('\n')}
-        ${this.get('extra_css') || ''}
-    `;
-    const style = `
-      <style type="text/css">
-        <![CDATA[
-          ${rawStyle}
-        ]]>
-      </style>`;
+    const rawStyle = [
+      STANDALONE_CSS,
+      raw_app_css.join('\n'),
+      this.get('extra_css') || '',
+    ]
+
+    const style = rawStyle.map(this.makeStyleTag).join("\n");
     const g: SVGGElement = svg.querySelector('g');
     const transform = g.attributes['transform'].value;
     let scaleFactor = 1.0;
@@ -189,13 +193,17 @@ export class ELKExporterModel extends WidgetModel {
     let withCSS = outerHTML
       .replace(
         /<svg([^>]+)>/,
-        `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width / scaleFactor +
-          padding} ${height / scaleFactor + padding}" $1>
+        `<svg xmlns="http://www.w3.org/2000/svg"
+          xmlns:xlink="http://www.w3.org/1999/xlink"
+          viewBox="0 0 ${width / scaleFactor + padding} ${height / scaleFactor + padding}"
+          $1>

Async Rendering With Multiple Views

Sometimes creating a new sprotty that is initially hidden will result in the diagram not rendering.

  • Need to trigger resize events when sprotty view is correctly viewed.
  • Bulk text sizer message queue not caching messages properly
  • Validate create new view for output preserves edges

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.