-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Package Graph #102
Merged
Merged
Package Graph #102
Changes from 1 commit
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
170aafc
Package Graph
hbcarlos f3e8446
Vis-network and new query argument in PackagesHandler GET route
hbcarlos a559c89
Added graph to jupyter_conda
hbcarlos 86a1d28
Changes
hbcarlos 97ded1c
merge
hbcarlos c99b81a
Cancel task
hbcarlos 7915432
delete jupyter_conda bundles
hbcarlos bdfca10
Check test
hbcarlos e25fe8c
highlight and font size
hbcarlos 516fc11
eslint
hbcarlos 2d497fb
Apply suggestions from code review
fcollonval 3e786e0
Apply some more suggestions from code review
fcollonval b0c10dd
Fixing usage when mamba is missing
fcollonval 906810a
Fix eslint error
fcollonval File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
import { | ||
MainAreaWidget, | ||
ReactWidget | ||
} from '@jupyterlab/apputils'; | ||
|
||
import { Widget } from '@lumino/widgets'; | ||
|
||
import { HTMLSelect } from '@jupyterlab/ui-components'; | ||
|
||
import cytoscape from 'cytoscape'; | ||
|
||
import * as React from 'react'; | ||
|
||
import { CondaEnvironments } from '../services'; | ||
import { Conda } from '../tokens'; | ||
|
||
class Graph extends Widget { | ||
constructor(model: CondaEnvironments) { | ||
super(); | ||
this._model = model; | ||
this._selected = ''; | ||
this._pkgManager = this._model.getPackageManager(); | ||
this._updatePackages(); | ||
} | ||
|
||
update(): void { | ||
const layout = (): cytoscape.LayoutOptions => { | ||
const ns = new Set<string>(); | ||
this._nodes.forEach((n: cytoscape.NodeDefinition) => { | ||
ns.add(n.data.name); | ||
}); | ||
if (ns.size >= 50) { | ||
return { | ||
name: 'circle', | ||
nodeDimensionsIncludeLabels: true, | ||
padding: 5, | ||
spacingFactor: 0.1, | ||
avoidOverlap: true | ||
}; | ||
} | ||
return { | ||
name: 'concentric', | ||
nodeDimensionsIncludeLabels: true, | ||
spacingFactor: 0.5, | ||
avoidOverlap: true | ||
}; | ||
}; | ||
|
||
this._cy = cytoscape({ | ||
layout: layout(), | ||
container: this.node, | ||
elements: { | ||
nodes: this._nodes, | ||
edges: this._edges | ||
}, | ||
style: [ | ||
{ | ||
selector: 'node', | ||
style: { | ||
width: 'label', | ||
shape: 'rectangle', | ||
content: 'data(name)', | ||
'padding-bottom': '10px', | ||
'text-valign': 'center', | ||
'background-color': '#81bc00', | ||
'background-opacity': 0.4, | ||
'border-width': 1, | ||
'border-color': 'black' | ||
} | ||
}, | ||
{ | ||
selector: 'edge', | ||
style: { | ||
'curve-style': 'bezier', | ||
'target-arrow-shape': 'triangle' | ||
} | ||
} | ||
] | ||
}); | ||
} | ||
|
||
public setEnv(env: string): void { | ||
this._selected = env; | ||
this._updatePackages(); | ||
} | ||
|
||
private async _updatePackages(): Promise<void> { | ||
const available = await this._pkgManager.refresh(true, this._selected); | ||
|
||
this._nodes = []; | ||
this._edges = []; | ||
let anterior = ""; | ||
|
||
available.forEach( (pkg: Conda.IPackage) => { | ||
if (pkg.version_installed) { | ||
console.debug(pkg); | ||
this._nodes.push({ data: { id: pkg.name, name:pkg.name } }); | ||
if (anterior !== "") { | ||
this._edges.push({ | ||
data: { | ||
source: pkg.name, | ||
target: anterior | ||
}, | ||
style: { | ||
'line-style': 'solid', | ||
'line-color': '#F5A636' | ||
}, | ||
classes: 'top-center' | ||
}); | ||
} | ||
|
||
anterior = pkg.name; | ||
} | ||
}); | ||
|
||
this.update(); | ||
} | ||
|
||
protected onResize(): void { | ||
if (this._cy) { | ||
this._cy.resize(); | ||
this._cy.fit(); | ||
} | ||
} | ||
|
||
private _model: CondaEnvironments; | ||
private _pkgManager: Conda.IPackageManager; | ||
private _cy: cytoscape.Core; | ||
private _selected: string; | ||
private _nodes: Array<cytoscape.NodeDefinition> = []; | ||
private _edges: Array<cytoscape.EdgeDefinition> = []; | ||
} | ||
|
||
export class GraphContainer extends MainAreaWidget<Graph> { | ||
constructor(model: CondaEnvironments) { | ||
super({ content: new Graph(model) }); | ||
this.toolbar.addItem('envs', new EnvSwitcher(this.content, model)); | ||
} | ||
} | ||
|
||
class EnvSwitcher extends ReactWidget { | ||
constructor(graph: Graph, model: CondaEnvironments) { | ||
super(); | ||
this.addClass('jp-LogConsole-toolbarLogLevel'); | ||
this._graph = graph; | ||
this._model = model; | ||
this._selected = ''; | ||
this._envs = []; | ||
|
||
this._model.environments | ||
.then( (envs: Conda.IEnvironment[]) => { | ||
envs.forEach( (env: Conda.IEnvironment) => { | ||
this._envs.push(env.name); | ||
if (env.is_default) this._selected = env.name; | ||
}); | ||
|
||
this.update(); | ||
}); | ||
} | ||
|
||
private handleChange = (event: React.ChangeEvent<HTMLSelectElement>): void => { | ||
this._selected = event.target.value; | ||
this._graph.setEnv(this._selected); | ||
this.update(); | ||
}; | ||
|
||
private handleKeyDown = (event: React.KeyboardEvent): void => { | ||
if (event.keyCode === 13) this._graph.update(); | ||
}; | ||
|
||
render(): JSX.Element { | ||
const envs = this._envs.map(value => { return {label: value, value}; }); | ||
|
||
return ( | ||
<> | ||
<label>Env:</label> | ||
<HTMLSelect | ||
className="jp-LogConsole-toolbarLogLevelDropdown" | ||
onChange={this.handleChange} | ||
onKeyDown={this.handleKeyDown} | ||
value={this._selected} | ||
aria-label="Env" | ||
options={envs} | ||
/> | ||
</> | ||
); | ||
} | ||
|
||
private _graph: Graph; | ||
private _model: CondaEnvironments; | ||
private _selected: string; | ||
private _envs: string[]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2648,6 +2648,11 @@ | |
dependencies: | ||
"@babel/types" "^7.3.0" | ||
|
||
"@types/cytoscape@^3.14.9": | ||
version "3.14.9" | ||
resolved "https://registry.yarnpkg.com/@types/cytoscape/-/cytoscape-3.14.9.tgz#5e28a54ea53a37b6225465552f76af33dae37082" | ||
integrity sha512-iFPBdTNQEgEEileVXze3XzLrIzyQ3y51RHJEArMi+7PTTDrc1qSmXPqYYYorlw56qIWsDaiQ5SC6ln5Xum+tCQ== | ||
|
||
"@types/dom4@^2.0.1": | ||
version "2.0.1" | ||
resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.1.tgz#506d5781b9bcab81bd9a878b198aec7dee2a6033" | ||
|
@@ -4558,6 +4563,14 @@ cyclist@^1.0.1: | |
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" | ||
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= | ||
|
||
cytoscape@^3.16.3: | ||
version "3.16.3" | ||
resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.16.3.tgz#8880911da5d6192f6acda1095d18aa7662e89d2f" | ||
integrity sha512-OGu9r5jsU2IgmqDy0NpW1M7ze2muvnJ3yNIB1mlzDLA7fcGI0aeE2hmLIoowi8E3+6HJF8Scx2iXGp11tbXHEg== | ||
dependencies: | ||
heap "^0.2.6" | ||
lodash.debounce "^4.0.8" | ||
|
||
dargs@^4.0.1: | ||
version "4.1.0" | ||
resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" | ||
|
@@ -6346,6 +6359,11 @@ [email protected]: | |
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" | ||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== | ||
|
||
heap@^0.2.6: | ||
version "0.2.6" | ||
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" | ||
integrity sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw= | ||
|
||
hmac-drbg@^1.0.0: | ||
version "1.0.1" | ||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" | ||
|
@@ -7950,6 +7968,11 @@ lodash.clonedeep@^4.5.0: | |
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" | ||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= | ||
|
||
lodash.debounce@^4.0.8: | ||
version "4.0.8" | ||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" | ||
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= | ||
|
||
lodash.escape@^4.0.1: | ||
version "4.0.1" | ||
resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the previous implementation from: https://github.com/mamba-org/mamba-navigator/blob/84a3d5a700b30017112d68b98fdd7e63adc9f182/src/components/Network.vue#L70
It looks like it was using the
vis.Network
, which is likely to be the one from https://visjs.org:Maybe it's a just a matter of using an equivalent as a cytoscape plugin to have a similar layout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this one looks nicer.
I'll look for a similar layout and modify the backend to get the dependencies.
Maybe something like this one: https://cytoscape.org/cytoscape.js-cose-bilkent/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it could also be good to have a lighter library than cytoscape.
Possible alternative:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks both for the info.
I changed the library and added an argument to the
PackageHandler
API, so now we can request package dependencies.Would be great to access this graph when clicking on a package in
jupyter_conda
. Maybe having a new column for dependencies or a link in the package description to open the graph in adialog
.Let me know what do you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
Yes maybe that's the simplest and most visible way for now?