Code Monkey home page Code Monkey logo

ipyforcegraph's Issues

Node and Link Visibility

Elevator Pitch

Add visibility to nodes and links.

Motivation

  • This is a bit of weak ask, but putting in an issue for tracking purposes.
    • same effect could be achieved by setting the color to rgb(0,0,0,0), i.e., zero opacity.
  • Could be useful for two reasons:
    • to mimic the force-graph API a bit closer.
    • make it more obvious that nodes and links can be made invisible for those that don't know about the alpha in rgb.

Design Ideas

  • Add visible to NodeShapes and LinkShapes.
    • e.g., for links: visible: TBoolFeature = _make_trait("is the link visible", boolish=True)

Heat/Reheat controls for ForceGraph

Elevator Pitch

The ability to control the simulation heat/reheat parameters when making changes to the source and/or behaviors. A method for ex. pausing the simulation when applying certain style changes (e.g. node color), and a recommended design patter (within docs?) for how to achieve this desired effect.

Motivation

We are developing apps using ipyforcegraph, and updating this such as node/edge visibility, color, and other styles (as part of the ipyforcegraph supported behaviors) causes the visualization to "reheat" the graph layout. Under certain conditions it would be valuable to allow users of ipyforcegraph to control the heat settings so that operations can be performed on the source and behaviors without causing the visualization to reheat. A recommended implementation from the dev team will help ensure that the most effective manner for controlling these options is used downstream.

Design Ideas

Possibly set the config on the ForceGraph class (simplified e.g. fg.reheat = False) before modifying behaviors/source/etc.

Return node position data

Elevator Pitch

Method to return the current x,y (or x,y,z for 3D) positions of the graph nodes as a DataFrame. The node data on the frontend updates those field values when the forcegraph layout sim runs. It would be useful to return those positions.

Motivation

This would allow for better manual positioning of nodes between user interaction (e.g. reset-graph option without running sim), and potentially enable some interesting capability when toggling between 2D and 3D engines.

Design Ideas

Not sure how this would be connected to the sim process (i.e. requesting before sim runs/completes).

N/A (at the moment)

Gather client, kernel, and server coverage during acceptance tests

Elevator Pitch

Add an instrumented frontend build with istanbuljs and reporting with nyc. Run the jupyter_server and ipykernel processes under coverage.

Motivation

At present, the frontend has no assessment of test coverage, and the backend coverage from unit tests is lower than what is actually covered.

Design Ideas

  • add any additional webpack tools to gather coverage
  • add some robot keywords to capture coverage for frontend and backend
    • may need a custom kernel launcher
  • combine and report frontend coverage
  • consider using codecov, etc. for capturing coverage trends

For some concrete examples, see jupyterlab-deck.

Retain node locations on new source

Elevator Pitch

  • When loading a new source that has some of the same nodes (by ID), have an option to retain their x,y,z location

Motivation

  • This can currently be done by getting the graph data on the python side, and including the x,y,z locations in the new dataframe and giving that back to ipyforcegraph. But this adds complexity and overhead to the process.

Design Ideas

  • Add a boolean trait to forcegraph that determines if node locations should be retained. default=True
  • When creating new nodes on the typescript side, try to set x,y,z (and vx,vy,vz?) if the node already exists.

Emit link particles on demand

Elevator Pitch

Particles are a unique story telling device in the force-graph library. Having the ability to specify a set of links to emit particles can allow more nuances to those stories.

Motivation

Some ways we might use particle links:

  • a dynamic way to highlight shortest paths
  • show propagation of some stimulus through the nodes.

Design Ideas

Example from the force-graph library

Expose nodeLabel API

Elevator Pitch

Be able to show labels with the nodeLabel feature.

Design Ideas

Add a new Behavior subclass that shows labels.

Explore whether this makes sense in metadata, or as a separate ndarray, or something else entirely.

Add context to behaviors

Elevator Pitch

  • Add context to behaviors so appropriate metadata is specified at that level and does not have to be inferred from names or modules.

Motivation

Original

Rather than inferencing order of behaviors, would see adding a rank to the behaviors, which get sorted out on the front-end, with some sensible defaults... warnings and complex validation methods can still get swallowed when things are done "live,"

Originally posted by @nrbgt in #69 (comment)

Additional Clarifications

  • Current behavior order warning is inferring what the behaviors applies to based on the name, and the ranking is hard coded based on the behavior module. This was introduced in #69. This is not ideal as new behaviors being added will require modifying this other part of the code.
    • Why warn users about this? Order of behaviors as they are specified on the ForceGraph can produce different effects, the more common issue is Selection and Shape, if Shape is included first in the <ForceGraph>.behaviors trait, the selection shapes will not be displayed. As we add behaviors, these ordering interactions can become more complex.
  • Automatically generating User Interfaces to control Behaviors needs to know what they apply to (e.g., ForceGraph, links, nodes), it would be good to have that information specified in the Behavior itself. This was refined in #69, but is intended to be refactored in #61.

Design Ideas

  • Add class variables to Behaviors to check order of behaviors and specifies the context they apply to, e.g., None, links, nodes.
  • Update behavior checks to use these new class variables.
  • Update the automatic UI generation (Utils.ipynb) to use this information.

Original comment

Add opt-in facet caching

Elevator Pitch

Add cache=True to most facets.

Motivation

While a number of facets require a simulation-driven value (e.g. x and y) or a dynamic value (such as created by a Selection) behavior, a number can be cached based on when the underlying graphData changes.

This is particularly noticeable on e.g. LinkShape.line_dash, which can make a graph with a high link count drop to a very low framerate, as noticed on #68, which has a few hundred nodes and a few thousand edges.

Design Ideas

  • add cache=False to all aspects
  • determine a way to populate (and invalidate) cache when the data changes for selected aspects

Add more "well-known" Sources

Elevator Pitch

Expose more DataFrameSource subclasses that know how to work with different files/local features.

Motivation

Inspecting the current environment and local files is good for delivering novel data, at scale, in a way that is relevant to the user's current environment and tools. The WidgetSource added in #35 demonstrates some useful patterns, and could be extended in useful ways, such as toggling features to include in the graph.

Design Ideas

Potential Sources

  • PythonSource([imported_module, "module_name"])
    • use the built-in features of e.g. importlib.metadata to discover the relationships between packages and have interesting features like versioned dependencies, named entry_points and other useful features
  • CondaSource(["package-name"])
    • be able to look at as-installed on-disk JSON information to gather package dependencies, entry points and other
    • this would not work in lite
  • SphinxInventorySource(["path/to/objects.inv])
    • show the relationships of documented symbols to documentation files
  • LabPluginsSource(["plugin:id"])
    • show the relationships between extensions, plugins, settings, signals from the live running jupyterlab-derived site
    • this would be difficult to unit test, but would work in lite
  • DoitSource("path/to/dodo.py", ["task", "path/to/target.file"])
    • show the task, file and other relationships between doit tasks
      • this is possible in lite, but still pretty hard, as the doit task loader pattern is... complex

Common API

These would all have some common patterns, which would be useful to extract into a common BaseSource, which would become the superclass of DataFrameSource (where most would be no-op`) and these new sources:

  • BaseSource.value: TypedTuple(Any())
    • use the upstream convention of a predictable value
      • some sources would accept tuples ofPath/string/JSON
      • others might accept "live" python objects
  • BaseSource.node_features: Enum and CustomSource.link_features: Enum
    • provide a common way to mark features which can be discovered in the graph
    • these would become the type field in the node and link data
  • BaseSource.find_graph_data()
    • top-level common entry, which would handle processing
      • potentially offer an alternate async entry point, if data will be expensive to discover/parse
  • BaseSource.get_default_behaviors(self) -> Tuple[Behavior]
    • return a tuple of behaviors that would get installed by any graph that adds them
    • this would allow for "nice" views, as the data set would know its own column names, etc.
    • probably make this opt-in with BaseSource.add_default_behaviors = True

Out of scope

  • adding default ui for all these things
    • the value of this rapidly diminishes as it rapidly increases complexity, and is often still not what a user wants
    • providing more examples like #7 is a better path forward

Lighten up binder environment

Elevator Pitch

Reduce the number of packages and complexity required to run binder demo.

Motivation

Using binder in the PR review cycle is very handy: having them build and load faster would increase reviewability, and might uncover dependency issues.

Design Ideas

The binder environment can't be faster than the total npm build time, but otherwise might be better optimized.

Visibility behavior

Elevator Pitch

Ability to toggle node/link visibility (style method in force-graph) would be great.

Motivation

In conjunction with #36, this would allow filtering on node/edge, thereby reducing visual clutter, without causing significant layout changes.

Design Ideas

n/a

Handle background color

Elevator Pitch

Allow changing the background color

Motivation

This would be useful for customizing the display.

Design Ideas

Either:

  • make the background transparent so the built-in layout.background_color can be used
    • failing that, expose background_color

When NodeSelection.multiple is False, Deselecting a node is not possible

Description

The default library behaviors includes NodeSelection with the optional kwarg multiple: bool that changes the ability to select multiple nodes. The default ForceGraph behavior is that shift+click allows user to select multiple nodes, and if a node is already selected this deselects the node.

When multiple=False the deselect behavior no longer works.

Reproduce

  1. Go to Binder
  2. Launch Behaviors.ipynb
  3. Scroll down to NodeSelection behavior
  4. Change kwargs to class (add multiple=False)
  5. Scroll back up to the widget
  6. Note that you can no longer select multiple nodes, but deselect is also broken.

Expected behavior

I would expect multiselect to be disabled, but deselect to still work.

Context

  • Operating System and version: Windows 10
  • Browser and version: Chrome 109.0.5414.120 (Official Build) (64-bit)
  • JupyterLab version: 3.6.1
  • IPyForceGraph version(s): 0.1.0 (also on binder)

Release 0.2.0

  • merge all outstanding PRs
  • ensure the versions have been bumped (check with doit)
  • ensure the CHANGELOG is up-to-date
    • move the new release to the top of the stack
  • validate on binder
  • validate on ReadTheDocs
  • wait for a successful build of main
  • download the dist archive and unpack somewhere (maybe a fresh dist)
  • create a new release through the GitHub UI
    • paste in the relevant CHANGELOG entries
    • upload the artifacts
  • actually upload to npm.com, pypi.org
    cd dist
    twine upload *.tar.gz *.whl
    npm login
    npm publish jupyrdf-jupyter-forcegraph-$VERSION.tgz
    npm logout
  • postmortem
    • handle conda-forge feedstock tasks
    • validate on binder via simplest-possible gists
      • pip Binder
      • conda Binder
    • bump to next development version
    • bump the CACHE_EPOCH
    • rebuild yarn.lock
    • update release procedures with lessons learned

Link Directionality

Elevator Pitch

Add visual representation for the directionality of links.

Motivation

  • In complex digraphs, understanding the direction the edges go can be important.
  • The force-graph libraries offer static (arrows) and dynamic (particles) representations for this.
  • This representation can also be used to convey properties of the link (e.g., number of particles could represent data flows)

Design Ideas

  • Keep the python interface for the 2D and 3D the same.
  • Control the aesthetic representation and location of the arrows and particles
    • For the arrows allow changing linkDirectionalArrowRelPos, linkDirectionalArrowColor, linkDirectionalArrowLength from python side
    • For the particles allow changing linkDirectionalParticleSpeed, linkDirectionalParticleWidth, linkDirectionalParticleColor, maybe we need a separate behavior for doing particle emission (i.e., emitParticle)
  • Would be great if we could drive these based on properties of the links

Update docs for ipywidgets

What I am trying to do...

As a reader of the docs, I want to dig deeper into ipywidgets upstreams.

How I would like to learn how to do it...

In the API documentation, drill down further into ipywidgets.rtfd.io

How the project might keep the docs accurate...

More/cached external link checking.

Add declarative JSON schema for configuring known behaviors

Elevator Pitch

Provide a read/write JSON-compatible structure for instantiating and "serializing" the configuration of a forcegraph

Motivation

Having a single, JSON-schema constrained description of a force graph's configuration would simplify a number of use cases.

Additionally, as JSON, it would be theoretically possible to create a mime renderer of a force graph, with this as the metadata. This might be a lower-touch way for other modules to emit a snaphshot of a graph.

Design Ideas

This would allow for something like:

ForceGraph(
    source=src, 
    json={
        "alpha_decay": {},
        "node_labels": {"template": "{{ node.label }}"},
        "node_selection": {"selected": [1,2,3]} 
    }
)

Under the hood these would map to the existing behaviors.

It should then also be possible to extract this back out.

Limitations

It would be challenging to extract de-referenced pointers to the behaviors: this could be somewhat fixed by one of:

  • make behaviors an OrderedDict or InstanceDict
  • adding a name to each of the behaviors, and exposing them as a "squishy" @property or other getter approach
    • this would then need a @T.validate to ensure each has a unique name

Retrieve canvas from browser as image

Elevator Pitch

It would be good to be able to request a snapshot of the graph back from the browser for the kernel to have access to it.

Motivation

Many use cases would benefit from having access to the image, not least of which would be testing.

Design Ideas

Add a ImageSnapshot behavior which can stuff the canvas as a png into a buffer. As this would be pretty expensive, this would have a enabled flag so it could be turned on and off.

UI for Behaviors

Elevator Pitch

  • Look into having a basic UI generator for controlling behaviors.

Motivation

  • After gh-57, there were experiments with an auto-generated UI for controlling behaviors.

Design Ideas

  • Give it a graph and let it make the UI controls from there by inspecting the behaviors associated with the ForceGraph.

Documentation items for 0.3.2

What I am trying to do...

Clean up documentation after #58, which needs to land to unblock other things.

How I would like to learn how to do it...

all pages

  • update icon links

per-page

  • CHANGELOG.md
  • README.md
    • update screenshots
  • CONTRIBUTING.md
    • clean up title to just "Contributing"
  • examples/Shapes.ipynb
    • finish up the demo controls (addressed in #69)
  • reference/forces.html
    • fix some dangling "" characters after node`, etc.
  • examples/Behaviors.ipynb
    • clean up task_arrows and task_particles labels (addressed in #69)
    • use fewer accordions-in-accordions
  • docs/reference/base.html
    • missing HasDimensions, etc. so downstream inheritance links are also broken
      • fixed on #66, but could do a docs hotfix against main

How the project might keep the docs accurate...

  • maybe find some patterns that can be statically checked
    • find all xref not inside a link (link check will find if a link is broken, but not missing)
  • maybe add some more CLI/robot tests of notebooks
    • remove old future notebooks that don't work anymore

Tunable d3 forceLayout

Elevator Pitch

Force layout diagrams will be more flexible by exposing some of the underlying forceLayout simulation parameters. Specifically the d3Forces link, charge and center can enable tuning of the layout based on communities in the graph.

Motivation

This will let users tune their simulation engine to generate more nuanced layouts.

  • Different link strengths based on edge weight.
  • Grouping clusters of nodes based on similarity

Design Ideas

Examples

Release 0.3.1

Create example app

Elevator Pitch

Create a more full-featured example notebook application.

Motivation

For a better demonstration of the capability (and value of being connected to the widget bus), create an annotated App.ipynb (with an importnb "for show" notebook that imports it)

Design Ideas

  • get a larger representative data set with a few thousand nodes/edges
    • use the force: maybe a star wars example
  • create some linked views
    • a "map" 2d forcegraph showing all the data
    • a table of the same data
      • ideally, figure out a way to do this by reference into one of the grid tools
    • enable selection
      • use the selection to (optionally) update the table
    • a 3d graph that shows the selected nodes (and relevant links)
    • allow expanding to n nearest neighbors from graph
  • wrap in a jupyterlab-deck experience

Release 0.1.0

  • merge all outstanding PRs
  • ensure the versions have been bumped (check with doit)
  • ensure the CHANGELOG is up-to-date
    • move the new release to the top of the stack
  • validate on binder
  • validate on ReadTheDocs
  • wait for a successful build of main
  • download the dist archive and unpack somewhere (maybe a fresh dist)
  • create a new release through the GitHub UI
    • paste in the relevant CHANGELOG entries
    • upload the artifacts
  • actually upload to npm.com, pypi.org
    cd dist
    twine upload *.tar.gz *.whl
    npm login
    npm publish jupyrdf-jupyter-forcegraph-$VERSION.tgz
    npm logout
  • postmortem
    • handle conda-forge feedstock tasks
    • validate on binder via simplest-possible gists
    • bump to next development version
    • bump the CACHE_EPOCH
    • rebuild yarn.lock
    • update release procedures with lessons learned

Add Color for Nodes and Links

Elevator Pitch

Add ability to color nodes and links.

Motivation

  • Color provides a clear means to illustrate properties (continuous or categorical) of the nodes and links, and identify patterns within the structure of the graph.
  • force-graph has a means to do this without much effort, e.g., this example.

Design Ideas

  • Would be another Behavior
    • Must decide if it is better to have many small Behaviors (that need to be composable in a predictable way), or to have broader Behaviors, e.g., instead of just color, one that allows changing opacity, size or edge-width, shape of nodes, the color of the labels, other aesthetic properties.
  • Most basic implementation could simply be to parse a column on the nodes or links called color that can be used to color the nodes by, but it would leave most of the work to the back-end.
  • Would also be good to allow default colors to be set (maybe that's a property of the ForceGraph?), but would need to change the unselected color in the Selection behavior.
  • Finally, not required because it could be processed on the python side, but the behavior could have a color_by property that uses the node or link properties to color them by.
    • the force-graph library already has a nodeAutoColorBy method that can be used, but unclear how to expose the palettes.
    • If not using that, we'd have to roll our own, and then handle discrete or continuous palettes depending on the type of property used, and allow for dynamically defining the palettes.

โš ๏ธ Important

  • This may have to be de-conflicted with other Behaviors (e.g., NodeSelection) which should either not have an unselected color option, or prefer the ColorNode behavior's color and only use the unselected one if nodes don't have a set color.

`conda` packaging

๐Ÿ—ฃ๏ธ Elevator Pitch

There are enough capabilities to merit making this conda installable.

๐Ÿƒ Motivation

Other projects can start testing the library, but it'd make it easier for them to do that if they could conda install ipyforcegraph.

๐Ÿ’ก Design Ideas

  • Submit a new recipe to conda-forge

Native continuous colorscales/colormaps

Elevator Pitch

It would be extremely helpful if ipyforcegraph supported continuous colormaps (e.g. viridis) as part of the Nunjucks templating. Users would be able to specify columns that contain continuous values (age, weight, etc.) and a colormap, and ipyforcegraph would be able to apply the color as part of the e.g. NodeShape behavior without requiring additional dependencies i.e. matplotlib.

Motivation

Bringing in additional dependencies to support styling with ipyforcegraph can complicate build chains, recipes, etc. It would be valuable to reduce complexity of leveraging ipyforcegraph to include common colormaps for continuous values, which are more complicated to implement than discrete maps (which can be easily added with e.g. dictionaries).

Design Ideas

Something akin to {{ node.value | colormap('viridis') }} would be extremely powerful.

Broken vs `jupyterlab_widgets` 3.0.6

Description

Serialization to JSON got nastier: all our half-specified serializers break.

Reproduce

  • Run Test_Forces.ipynb
  • See browser console complaint about
DOMException: Failed to execute 'structuredClone' on 'Window': #<Promise> could not be cloned.

Expected behavior

No error message

Context

Fixed here, needs backport and hotfix release.

Better Explanations for Using Templates for Behavior Attributes

What I am trying to do...

  • Add more comprehensive and better organized explanations for how to use the Nunjucks templating.
  • Based on original comment by @nrbgt on #69.

How I would like to learn how to do it...

  • a dedicated notebook, with in-links from various places
    • and/or include this content in the docs
    • potentially with a more full demo, not attached to a renderer
  • a dedicated .md, so that it is searchable within the docs
  • in-line in the docstring of the python Nunjucks class itself
  • in-line in the text of the TypeScript class and start building typescript

How the project might keep the docs accurate...

  • if they are part of a notebook, the notebook could be executed to ensure it runs without issues, so at least we would know the docs were updated if the API changed, but may need additional tests to ensure that.

Add 3d-force-graph

Elevator Pitch

Offer the threejs-based 3d-source-graph.

Motivation

There are some nice features available here.

Having the Python API be very similar would be useful, as would 3d and 2d views of the same data, with linked selection, etc.

Design Ideas

  • either
    • use name tricks
      • expose a second plugin in the same npm package
      • but under a different registered name
    • use lerna
      • make a fully separate package @jupyrdf/jupyter-3dforcegraph that depends on @jupyrdf/jupyter-forcegraph

Allow node labels to be templates

Elevator Pitch

Instead of a single column, node labels could be composed on the front end from many columns.

Motivation

The return value of nodeLabel can be an HTML string, and might be interesting to have more data. With access to the node and full graph data, one could print out some nice values, including:

  • images
  • information about linked values
  • inline CSS

References

  • blocked by #4

Design Idea

  • add a template
    • a jinja2/nunjucks template that gets access to the node and the graphData

Adopt a `dev` branch workflow

Elevator Pitch

Start a long-lived dev branch. Target main only with hotfixes, docs fixes, and releases. Target all other PRs on main.

Motivation

This would simplify the binder badge situation, and make it a bit easier to have up-to-date dev docs for unreleased stuff, as well as the stable releases on PyPI.

Design Ideas

  • create the long running branch
  • retarget open PRs to dev
  • update CONTRIBUTING.md and release.md to reflect the changes
  • ???

Sync front-end when `nodes` & `links` are updated in `DataFrameSource`

Issue

Right now, even if one makes a new DataFrame for the nodes or links in a DataFrameSource, the data does not get propagated to the front-end. This may be by design or something that has not yet been implemented.

Replication

import json
from pathlib import Path

import ipywidgets as W

from ipyforcegraph.forcegraph import DataFrameSource, ForceGraph

def make_a_simple_example(
    source=None, dataset="datasets/miserables.json", GraphClass=ForceGraph, node_color=None,
):
    if source is None:
        data = json.loads(Path(dataset).read_text())
        source = DataFrameSource(**data)
        if node_color:
            source.nodes["color"] = node_color

    fg = GraphClass(source=source, layout=dict(height="500px"))
    box = W.HBox([fg, W.VBox([])])
    return fg, box

if __name__ == "__main__":
    fg, box = make_a_simple_example(node_color="red")
    display(box)

Nodes should be red but they show up the default steelblue. If a new source is made, or we run fg.source.send_state() the nodes show up red.

Design Ideas

  • It would be preferred if it didn't re-solve the positions of the nodes if it is the same set of nodes (e.g., have the same ids?)
    • maybe we can try to get the existing nodes in here if the node's id match?

Related to

Add Additional Link Shape Properties

Elevator Pitch

Add line_dash and curvature to the links.

Motivation

  • curvature and line dashes could be used to convey information about relationships.
  • would produce a more complete 1:1 with the force-graph API.

Design Ideas

  • For curvature it would be pretty straight forward from the python side.
    curvature: TNumFeature = _make_trait("the curvature of the link, 0: straight, 1: circular", numeric=True)
  • The line_dash presents a more complicated challenge, as the data is really a list of numbers, as per the HTML Canvas setLineDash method.
    line_dash: TListNumFeature = _make_trait(
        "the dash pattern, e.g., [5, 15] to draw a repeating pattern of a 5 pixel segment followed by a 15 pixel blank",
        numeric=True,
        is_list=True,
    )

Text On Links

Elevator Pitch

  • Would like to see the ability to have permanent labels in a graph as per these 2D and 3D examples.

Motivation

  • Annotating links with a permanent label can help understand the meaning of relationships in a graph, e.g., when visualizing an RDF graph we tend to have many types of predicates, and coloring tends to not be enough to differentiate.
  • Would be very useful to be able to generate graphs similar to what Neo4j offers:
    image

Design Ideas

  • For the 2D case, it is probably not worth it to implement a flexible linkCanvasObject, a "simple" wrapper for only Text will probably be more than sufficient, therefore, we could add the following attributes to LinkShapes:
    • label the text label to use, could be str, Column, or Nunjucks.
    • label_max_font_size: equivalent of MAX_FONT_SIZE in the 2D example.
    • label_margin: equivalent of LABEL_NODE_MARGIN in the 2D example.
    • label_font: the font to use, not including size as that needs to be calculated
    • label_color: the color of the label (maybe label_fill would be a better name, specially if we also add label_stroke)
    • label_background: the fill to use for the rectangle background
    • Future versions could figure out how to use more flexible LinkShapes, once we figure out a good pattern for NodeShapes.
  • For 3D it seems we would just have a floating label that is always horizontal, which is more than fine, and all the attributes described above would remain consistent.
  • We need to support selection of links by clicking on the link or their label.
  • We need to ensure the text looks correct when applied to curved links.

Edge Cases to Consider

Inevitably it's about what will actually be needed for weird edge cases:

  • how many labels per link?
    • โœ”๏ธ allow only 1 label
    • ๐Ÿšซ multiple labels per link
  • multi-line text?
    • โœ”๏ธ replace \n with some indicator (e.g., |)
    • ๐Ÿšซ allowed
    • ๐Ÿšซ not allowed
  • alignment/line height?
    • โœ”๏ธ center only
    • โœ”๏ธ controlling height of the text would be good, but could be font-size
  • text baseline relative to above below?
    • โœ”๏ธ center only
  • clickability requirements?
    • โœ”๏ธ edges must be clickable
    • highlighting
      • โœ”๏ธ text can also be highlighted (but this would be handled like the nodes Text shape, where the stroke (for example) can be changed based on selected column_name
      • ๐Ÿšซ link is highlighted but not text
  • work with curvature, line-dash
    • curvature
      • text curve with the link (if not too hard)
      • text can be divorced from link (i.e., text is straight, link is not) (if it is too hard to make the text curve)
      • text can't be rendered if link is curved
    • line-dash
      • โœ”๏ธ do nothing special about this
      • ๐Ÿšซ text get's dashed (this sounds like a terrible idea)
  • what happens with particles? and arrows?
    • ๐Ÿšซ make text mutually exclusive with particles and arrows?
    • particles:
      • not sure we need to be concerned about this, let people do it if they want to for whatever reason
    • arrows:
      • โœ”๏ธ let people do what they want, if we can control opacity and order of labels/arrows, we could still see both depending on what is drawn first and what's the opacity of the things above
      • ๐Ÿšซ have option to show arrow over remaining portion of the link (probably too complicated to implement)
      • ๐Ÿšซ drop an ascii arrow at the end (or beginning) of the label (this may make things complicated because text should probably never be upside down)
  • how to handle very long labels?
    • โœ”๏ธ put ellipses after a certain number of characters (...)
    • ๐Ÿšซ make text smaller

Allow syncing a subset of node/link columns/rows

Elevator Pitch

A source should be able to control the columns and rows in links and nodes that are synced with the front end.

Motivation

This would allow for using a "big and tall" DataFrame that included more data than was relevant to a graph without creating intermediate frames.

Design ideas

  • add include_(node|link)_columns?
  • add ignore_(node|link)_columns?
  • add iloc_?
  • all?

Release 0.3.0

Occasional incorrect sorting of nodes when using preserve columns

Description

Graphs that use id's that can be coerced into numbers, get their nodes and links sorted when the preserve columns functionality is used, breaking the indexing used by the NodeSelection and LinkSelection.

Reproduce

import json
from pathlib import Path
from time import sleep

import ipyforcegraph.graphs as G
import ipyforcegraph.sources as S
import ipyforcegraph.behaviors as B

source_data = json.loads(Path("./datasets/blocks.json").read_text())

source = S.DataFrameSource(
    **source_data,
    node_preserve_columns=["x", "y"],
)

selection, get_data = behaviors = [
    B.NodeSelection(column_name="_selected"),
    B.GraphData(),
]

fg = G.ForceGraph(
    source=source,
    behaviors=behaviors,
    layout=dict(height="100%"),
)

# select a node
selection.selected = [850]

# capture data from front-end
get_data.capturing = True

# compare id of selected node as per the backend and the frontend
# note: need to add appropriate async awaits for this to work
id_per_backend_source = source.nodes.id[selection.selected[0]]

frontend_nodes_data = get_data.sources[0].nodes
id_per_frontend_source = frontend_nodes_data.id[frontend_nodes_data._selected == True].iloc[0]

# this assert fails
assert id_per_backend_source == id_per_frontend_source

# as does this one:
assert tuple(source.nodes.id) == tuple(frontend_nodes_data.id)

Expected behavior

Would have expected the nodes to be in the same order as that is what the NodeSelection and LinkSelection use.

Context

Believe the issue is that Object.values (used here) sorts the results by the keys if those can be coerced into numbers, and because in this example some of the keys can be while others are alphanumeric, some nodes show up in a different order in the front-end vs the back-end. This can also be verified by looking at the order of the nodes dataframe retrieved by GraphData, which may be a better test. Also manually prepended "_" to all the ids in the graph and the issue did not pop up.

  • Operating System and version: Windows 10
  • Browser and version: Chrome 113.0.5672.93 (Official Build) (64-bit)
  • JupyterLab version: 3.6.3
  • IPyForceGraph version(s): 0.3.2
Required: installed server extensions
Config dir: C:\Users\sb282\.jupyter

Config dir: C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\etc\jupyter
jupyter_server_fileid enabled
- Validating jupyter_server_fileid...
Package jupyter_server_fileid took 0.0117s to import
jupyter_server_fileid 0.9.0 ok
jupyter_server_terminals enabled
- Validating jupyter_server_terminals...
Package jupyter_server_terminals took 0.0412s to import
jupyter_server_terminals 0.4.4 ok
jupyter_server_ydoc enabled
- Validating jupyter_server_ydoc...
Package jupyter_server_ydoc took 0.3604s to import
jupyter_server_ydoc 0.8.0 ok
jupyterlab enabled
- Validating jupyterlab...
Package jupyterlab took 0.3751s to import
jupyterlab 3.6.3 ok
jupyterlab_link_share enabled
- Validating jupyterlab_link_share...
Package jupyterlab_link_share took 0.3288s to import
jupyterlab_link_share 0.2.5 ok
nbclassic enabled
- Validating nbclassic...
Package nbclassic took 0.0000s to import
A _jupyter_server_extension_points function was not found in nbclassic. Instead, a _jupyter_server_extension_paths function was found and will be used for now. This function name will be deprecated in future releases of Jupyter Server.
nbclassic 1.0.0 ok
notebook_shim enabled
- Validating notebook_shim...
Package notebook_shim took 0.0000s to import
A _jupyter_server_extension_points function was not found in notebook_shim. Instead, a _jupyter_server_extension_paths function was found and will be used for now. This function name will be deprecated in future releases of Jupyter Server.
notebook_shim ok

Config dir: C:\ProgramData\jupyter

Required: installed lab extensions
        bqplot v0.5.40 enabled ok (python, bqplot)
        ipydatagrid v1.1.15 enabled ok
        ipylab v0.7.1 enabled ok (python, ipylab)
        jupyterlab-link-share v0.2.5 enabled ok (python, jupyterlab-link-share)
        jupyterlab_pygments v0.2.2 enabled ok (python, jupyterlab_pygments)
        @deathbeds/jupyterlab-deck v0.1.3 enabled ok
        @deathbeds/jupyterlab-font-anonymous-pro v2.1.1 enabled ok (python, jupyterlab-fonts)
        @deathbeds/jupyterlab-font-dejavu-sans-mono v2.1.1 enabled ok (python, jupyterlab-fonts)
        @deathbeds/jupyterlab-font-fira-code v2.1.1 enabled ok (python, jupyterlab-fonts)
        @deathbeds/jupyterlab-fonts v2.1.1 enabled ok (python, jupyterlab-fonts)
        @jupyrdf/jupyter-forcegraph v0.3.2 enabled ok
        @jupyter-widgets/jupyterlab-manager v5.0.7 enabled ok (python, jupyterlab_widgets)
        @jupyterlite/pyodide-kernel-extension v0.0.8 enabled ok (python, jupyterlite_pyodide_kernel)
Troubleshoot Output
$PATH:
        C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6
        C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Library\mingw-w64\bin
        C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Library\usr\bin
        C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Library\bin
        C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Scripts
        C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\bin
        C:\mf\envs\doit\condabin
        C:\Program Files (x86)\Integrity\ILMClient11.2\bin
        C:\WINDOWS\system32
        C:\WINDOWS
        C:\WINDOWS\System32\Wbem
        C:\WINDOWS\System32\WindowsPowerShell\v1.0
        C:\WINDOWS\System32\OpenSSH
        C:\PROGRA~2\INTEGR~1\Toolkit\mksnt
        C:\Program Files (x86)\Webex\Plugins
        C:\HashiCorp\Vagrant\bin
        C:\Program Files\Docker\Docker\resources\bin
        C:\ProgramData\DockerDesktop\version-bin
        C:\Program Files\RedHat\java-14-openjdk-14.0.1-1\bin
        C:\Program Files\MATLAB\R2021b\bin
        .
        C:\Program Files\RedHat\Podman
        C:\Users\sb282\AppData\Local\Microsoft\WindowsApps
        C:\Users\sb282\AppData\Local\Programs\Microsoft VS Code\bin
        C:\Program Files\Java\jdk-13\bin
        C:\Gradle\gradle-6.5.1\bin
        C:\Users\sb282\AppData\Local\Programs\Git\cmd

sys.path:
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Scripts
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\python311.zip
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\DLLs
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Lib
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Lib\site-packages
C:\sandboxes\ipyforcegraph\src
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Lib\site-packages\win32
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Lib\site-packages\win32\lib
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Lib\site-packages\Pythonwin

sys.executable:
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\python.exe

sys.version:
3.11.3 | packaged by conda-forge | (main, Apr 6 2023, 08:50:54) [MSC v.1934 64 bit (AMD64)]

platform.platform():
Windows-10-10.0.19045-SP0

where jupyter:
C:\sandboxes\ipyforcegraph\envs\py3.11_lab3.6\Scripts\jupyter.exe

pip list:
Package Version Editable project location
------------------------------ ----------- --------------------------
accessible-pygments 0.0.4
aiofiles 22.1.0
aiosqlite 0.19.0
alabaster 0.7.13
ansi2html 0.0.0
anyio 3.6.1
argon2-cffi 21.3.0
argon2-cffi-bindings 21.2.0
asttokens 2.2.1
async-generator 1.10
attrs 23.1.0
autodoc-traits 1.1.0
autopep8 2.0.2
Babel 2.12.1
backcall 0.2.0
backports.functools-lru-cache 1.6.4
beautifulsoup4 4.12.2
black 23.3.0
bleach 6.0.0
bqplot 0.12.39
brotlipy 0.7.0
cattrs 22.2.0
certifi 2023.5.7
cffi 1.15.1
charset-normalizer 3.1.0
click 8.1.3
cloudpickle 2.2.1
cmarkgfm 0.8.0
colorama 0.4.6
comm 0.1.3
coverage 7.2.5
cryptography 40.0.2
debugpy 1.6.7
decorator 5.1.1
defusedxml 0.7.1
docutils 0.19
doit 0.36.0
entrypoints 0.4
exceptiongroup 1.1.1
execnet 1.9.0
executing 1.2.0
fastjsonschema 2.16.3
flit 3.8.0
flit_core 3.8.0
gast 0.4.0
greenlet 2.0.2
h11 0.14.0
html5lib 1.1
idna 3.4
imagesize 1.4.1
importlib-metadata 6.6.0
importlib-resources 5.12.0
importnb 2023.1.7
iniconfig 2.0.0
ipydatagrid 1.1.15
ipyforcegraph 0.3.2 C:\sandboxes\ipyforcegraph
ipykernel 6.23.0
ipylab 0.7.1
ipython 8.13.2
ipython-genutils 0.2.0
ipywidgets 8.0.6
itsdangerous 2.1.2
jaraco.classes 3.2.3
jedi 0.18.2
Jinja2 3.1.2
json5 0.9.5
jsonschema 4.17.3
jupyter-cache 0.6.1
jupyter_client 8.2.0
jupyter_core 5.3.0
jupyter-events 0.6.3
jupyter_server 2.5.0
jupyter_server_fileid 0.9.0
jupyter_server_terminals 0.4.4
jupyter_server_ydoc 0.8.0
jupyter-ydoc 0.2.3
jupyterlab 3.6.3
jupyterlab-deck 0.1.3
jupyterlab-fonts 2.1.1
jupyterlab-link-share 0.3.0
jupyterlab-pygments 0.2.2
jupyterlab_server 2.22.1
jupyterlab-widgets 3.0.7
jupyterlite-core 0.1.0
jupyterlite-pyodide-kernel 0.0.8
keyring 23.13.1
libarchive-c 4.0
livereload 2.6.3
lxml 4.9.2
markdown-it-py 2.2.0
MarkupSafe 2.1.2
matplotlib-inline 0.1.6
mdit-py-plugins 0.3.5
mdurl 0.1.0
mistune 2.0.5
more-itertools 9.1.0
msgpack 1.0.5
mypy 1.2.0
mypy-extensions 1.0.0
myst-nb 0.17.2
myst-parser 0.18.1
natsort 8.3.1
nbclassic 1.0.0
nbclient 0.7.4
nbconvert 7.4.0
nbformat 5.8.0
nbqa 1.7.0
nbstripout 0.6.1
nest-asyncio 1.5.6
networkx 3.1
notebook 6.5.4
notebook_shim 0.2.3
numcodecs 0.11.0
numpy 1.24.3
orjson 3.8.12
outcome 1.2.0
packaging 23.1
pandas 2.0.1
pandocfilters 1.5.0
parso 0.8.3
pathspec 0.11.1
pickleshare 0.7.5
pip 23.1.2
pkginfo 1.9.6
pkgutil_resolve_name 1.3.10
platformdirs 3.5.0
pluggy 1.0.0
prometheus-client 0.16.0
prompt-toolkit 3.0.38
psutil 5.9.5
pure-eval 0.2.2
py 1.11.0
py2vega 0.6.1
pycodestyle 2.10.0
pycparser 2.21
pydata-sphinx-theme 0.13.3
Pygments 2.15.1
pyOpenSSL 23.1.1
pyproject-fmt 0.11.2
pyrsistent 0.19.3
PySocks 1.7.1
pytest 7.3.1
pytest-asyncio 0.21.0
pytest_check_links 0.8.0
pytest-cov 4.0.0
pytest-html 3.2.0
pytest-json-report 1.5.0
pytest-metadata 2.0.4
pytest-xdist 3.2.1
python-dateutil 2.8.2
python-json-logger 2.0.7
pytz 2023.3
pywin32 304
pywin32-ctypes 0.2.0
pywinpty 2.0.10
PyYAML 6.0
pyzmq 25.0.2
readme-renderer 37.3
requests 2.29.0
requests-cache 1.0.1
requests-toolbelt 1.0.0
rfc3339-validator 0.1.4
rfc3986 2.0.0
rfc3986-validator 0.1.1
rich 13.3.5
rich-click 1.6.1
robotframework 6.0.2
robotframework-jupyterlibrary 0.4.2
robotframework-pabot 2.15.0
robotframework-pythonlibcore 4.1.2
robotframework-robocop 3.1.1
robotframework-seleniumlibrary 6.1.0
robotframework-stacktrace 0.4.1
robotframework-tidy 4.2.1
ruff 0.0.265
scour 0.38.2
selenium 4.9.1
Send2Trash 1.8.2
setuptools 67.7.2
six 1.16.0
sniffio 1.3.0
snowballstemmer 2.2.0
sortedcontainers 2.4.0
soupsieve 2.3.2.post1
Sphinx 5.3.0
sphinx-autobuild 2021.3.14
sphinx_autodoc_typehints 1.21.8
sphinx-copybutton 0.5.2
sphinxcontrib-applehelp 1.0.4
sphinxcontrib-devhelp 1.0.2
sphinxcontrib-htmlhelp 2.0.1
sphinxcontrib-jsmath 1.0.1
sphinxcontrib-qthelp 1.0.3
sphinxcontrib-serializinghtml 1.1.5
SQLAlchemy 2.0.12
ssort 0.11.6
stack-data 0.6.2
stringcase 1.2.0
tabulate 0.9.0
terminado 0.17.0
tinycss2 1.2.1
tokenize-rt 5.0.0
toml 0.10.2
tomli 2.0.1
tomli_w 1.0.0
tomlkit 0.11.8
tornado 6.3
traitlets 5.9.0
traittypes 0.2.1
trio 0.22.0
trio-websocket 0.10.2
twine 4.0.2
typing_extensions 4.5.0
tzdata 2023.3
ujson 5.7.0
url-normalize 1.4.3
urllib3 1.26.15
wcwidth 0.2.6
webencodings 0.5.1
websocket-client 1.5.1
wheel 0.40.0
widgetsnbextension 4.0.7
win-inet-pton 1.1.0
wsproto 1.2.0
y-py 0.5.9
ypy-websocket 0.8.2
zipp 3.15.0

LinkSelection Behavior

Elevator Pitch

Just like behaviors.NodeSelection, but for links.

Motivation

Display information for links onClick, etc.

Design Ideas

n/a

Refactor Behaviors

Elevator Pitch

Refactor Behaviors to use the new Column and Nunjuck widgets, as developed in #54.

Motivation

  • This will make the behaviors more compact, and easier to use, and ultimately help new users understand how to use the library.
    • It will avoid issues with combining the individual behaviors, e.g., with the particles not displaying correctly unless they are all set to appropriate values.
    • Would make it easier to add validation to the results, helping users understand what values are not appropriate.

Design Ideas

  • Move away from the Behavior.(column_name|template), favoring dedicated widget subclasses Column and Nunjuck.
    • Work a means to coerce values into an appropriate type for the output of Nunjuck templates, this will help make falsey python types evaluate to false in js
  • Group behaviors into reasonable groups, e.g.,
    • NodeStyle combines NodeColors and NodeSizes
    • LinkStyle combines LinkColors and LinkWidths
    • LinkArrow combines LinkDirectionalArrowColor, LinkDirectionalArrowLength, and LinkDirectionalArrowRelPos
    • LinkParticles combines LinkDirectionalParticleColor, LinkDirectionalParticleSpeed, LinkDirectionalParticleWidth, amd LinkDirectionalParticles
  • Should we extend this pattern to Forces? It does not seem to be immediately relevant, but maybe there is a common way to think about them?
  • If not, should we refactor the python API and put the style related behaviors in their own submodule, e.g., ipyforcegraph/behaviors/style/ where we would have node.py, link.py, and shape.py?

Release 0.3.2

Verify behavior with JupyterLab 3.6.1

Elevator Pitch

Update the test infrastructure to include JupyterLab 3.5.* and 3.6.1

Motivation

JupyterLab 3.6.1 is a semi-breaking release.

JupyterLite will not be adopting it.

We should make sure everything works in both lines.

Design Ideas

Add an additional factor to the lock files, testing lab 3.5.2+ on the oldest python and 3.6.1+ on the newest.

Camera Controls

Elevator Pitch

Better/smoother story telling through controlled panning and zooming on nodes / neighborhoods.

Motivation

Two things:

  • Examples a model of the camera (e.i. what is the current view looking at)
  • Moving the view to highlight a change from some other interactive elements.
    • Maybe two linked graphs where selecting a node in one moves the camera focus in the other.

Design Ideas

Under https://github.com/vasturiano/force-graph#render-control there is a section that highlights several different camera control functions:

  • centerAt([x], [y], [ms]) - getter and setter
  • zoom([num], [ms]) - getter and setter
  • zoomToFit([ms], [px], [nodeFilterFn])
  • minZoom
  • maxZoom

https://github.com/vasturiano/force-graph#utility

  • getGraphBbox - could be combined with some other node checks to get a list of nodes currently in view of the camera.

Other rendering functions that could be wrapped. Potentially for a follow on ticket.

  • autoPauseRedraw
  • resumeAnimation
  • pauseAnimation
  • onRenderFramePre
  • onRenderFramePost

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.