ipycytoscape, draw subgraph - jupyter

I'm noob in ipycytoscape and Jupyter and seems need help. I'm trying to find a sutable way to show/draw subgraph after I click by node.
For example.
I have graph with node1---node2---node3 . I click by node1 and want to show
node1 --- node2.1 - node2.2 node2.3 --- node3.
Don't know how to make this. Tried to find in Google but coudn't find any suitable approach.
This is my simplest code for this. I no idea how to show and aftger hide (expand and collapse) subgraph. This code don't have this part.
I heard something about layouts but couldn't find sutable example for ipycytoscape.
Any ideas are welcome.
import ipycytoscape
import ipywidgets as widgets
import networkx as nx
counter = 0 # need to make new nodes with uniq id
data = {
'nodes': [
{ 'data': { 'id': 'desktop', 'name': 'Cytoscape', 'href': 'http://cytoscape.org' } },
{ 'data': { 'id': 'a', 'name': 'Grid', 'href': 'http://cytoscape.org', 'parent': 'Cola' } },
{ 'data': { 'id': 'c', 'name': 'Popper', 'href': 'http://cytoscape.org', 'parent': 'Cola' } },
{ 'data': { 'id': 'b', 'name': 'Cola', 'href': 'http://cytoscape.org' } },
{ 'data': { 'id': 'js', 'name': 'Cytoscape.js', 'href': 'http://js.cytoscape.org' } }
],
'edges': [
{'data': { 'source': 'desktop', 'target': 'js' }},
{'data': { 'source': 'a', 'target': 'b' }},
{'data': { 'source': 'a', 'target': 'c' }},
{'data': { 'source': 'b', 'target': 'c' }},
{'data': { 'source': 'js', 'target': 'b' }}
]
}
custom_inherited = ipycytoscape.CytoscapeWidget()
custom_inherited.graph.add_graph_from_json(data)
custom_inherited.set_style([{
'selector': 'node',
'css': {
'content': 'data(name)',
'text-valign': 'center',
'color': 'white',
'text-outline-width': 2,
'text-outline-color': 'green',
'background-color': 'green'
}
},
{
'selector': 'node[classes = "collapsed-childS"]',
'css': {
'background-color': 'red',
'line-color': 'blue',
'target-arrow-color': 'red',
'source-arrow-color': 'red',
'text-outline-color': 'red'
},
}
])
# When I click to node by mouse I add some nodes. I made this because don't know how to show and hide subgraph. The question in this place.
def paint_blue(event):
global counter
for node in cytoscapeobj.graph.nodes:
if node.data['id'] == event['data']['id']:
auxNode = node
auxNode.data['classes'] = "collapsed-childS"
station_NUR = ipycytoscape.Node()
station_NUR.data['id'] = "NUR" + str(counter)
station_NUR.data['name'] = station_NUR.data['id']
station_NUR.data['classes'] = "collapsed-childS"
station_FRA = ipycytoscape.Node()
station_FRA.data['id'] = "FRA" + str(counter)
station_FRA.data['name'] = station_FRA.data['id']
station_FRA.data['classes'] = "collapsed-childS"
new_edge1 = ipycytoscape.Edge()
new_edge1.data['id'] = "line6" + str(counter)
new_edge1.data['source'] = station_NUR.data['id']
new_edge1.data['target'] = station_FRA.data['id']
new_edge2 = ipycytoscape.Edge()
new_edge2.data['id'] = "line7" + str(counter)
new_edge2.data['source'] = station_NUR.data['id']
new_edge2.data['target'] = auxNode.data['id']
custom_inherited.graph.add_node(station_NUR)
custom_inherited.graph.add_node(station_FRA)
custom_inherited.graph.add_edges([new_edge1,new_edge2])
counter = counter + 1
custom_inherited.on('node', 'click', paint_blue)
custom_inherited

Related

How to unwind/merge arrays from hierarchical document structure?

I have a nested document structure and I am able to filter it with pluck to show the relevant parts:
Is there an elegant way to merge all entries of the last level to a single array?
Expected result (entries are not unique on purpose):
[
'3425b91f-f019-4db3-ad56-c336bf55279b',
'3d07946e-183d-4992-9acd-676f5122e1b1',
'3425b91f-f019-4db3-ad56-c336bf55279b',
'3d07946e-183d-4992-9acd-676f5122e1b1',
'2cd652a6-4dcd-4920-9592-d4cdc5a034bf',
'70fe1812-e1de-447b-ac4f-d89fead4756d',
'2cd652a6-4dcd-4920-9592-d4cdc5a034bf',
'70fe1812-e1de-447b-ac4f-d89fead4756d'
]
I tried to use
r.table('periods')['regions']['sites']['plants']['product']['process']['technologies'].run()
but it gives the error "Cannot perform bracket on a sequence of sequences".
=> Is there some alternative operator to get a merged sequence instead a "sequence of sequences" for each step?
Something like
r.table('periods').unwind('regions.sites.plants.product.process.technologies')
Here is some python code to create example data:
from rethinkdb import RethinkDB
r = RethinkDB()
r.connect({}).repl()
r.table_create("periods")
def uniqueid():
return r.uuid().run()
periodid_first = uniqueid()
periodid_second = uniqueid()
companyid_2000 = uniqueid()
companyid_2001 = uniqueid()
technologyid_2000_first = uniqueid()
technologyid_2000_second = uniqueid()
technologyid_2001_first = uniqueid()
technologyid_2001_second = uniqueid()
energy_carrierid_2000_first = uniqueid()
energy_carrierid_2000_second = uniqueid()
energy_carrierid_2001_first = uniqueid()
energy_carrierid_2001_second = uniqueid()
periods = [
{
'id': periodid_first,
'start': 2000,
'end': 2000,
# 'sub_periods': [],
'regions': [
{
'id': 'DE',
# 'sub_regions': [],
'sites': [
{
'id': 'first_site_in_germany',
'company': companyid_2000, # => verweist auf periods => companies
'plants': [
{
'id': 'qux',
'product': {
'id': 'Ammoniak',
'process': {
'id': 'SMR+HB',
'technologies': [
technologyid_2000_first, # => verweist auf periods => technologies
technologyid_2000_second
]
}
}
}
]
}
]
},
{
'id': 'FR',
# 'sub_regions': [],
'sites': [
{
'id': 'first_site_in_france',
'company': companyid_2000, # => verweist auf periods => companies
'plants': [
{
'id': 'qux',
'product': {
'id': 'Ammoniak',
'process': {
'id': 'SMR+HB',
'technologies': [
technologyid_2000_first, # => verweist auf periods => technologies
technologyid_2000_second
]
}
}
}
]
}
]
}
],
'companies': [
{
'id': companyid_2000,
'name': 'international_company'
}
],
'technologies': [
{
'id': technologyid_2000_first,
'name': 'SMR',
'specific_cost_per_year': 123,
'specific_energy_consumptions': [
{
'energy_carrier': energy_carrierid_2000_first,
'specific_consumption': 5555
}, # => verweist auf periods => energy_carriers
{
'energy_carrier': energy_carrierid_2000_second,
'energy_consumption': 2333
}
]
},
{
'id': technologyid_2000_second,
'name': 'HB',
'specific_cost_per_year': 1234,
'specific_energy_consumptions': [
{
'energy_carrier': energy_carrierid_2000_first,
'specific_consumption': 555
}, # => verweist auf periods => energy_carriers
{
'energy_carrier': energy_carrierid_2000_second,
'energy_consumption': 233
}
]
}
],
'energy_carriers': [
{
'id': energy_carrierid_2000_first,
'name': 'oil',
'group': 'fuel'
},
{
'id': energy_carrierid_2000_second,
'name': 'gas',
'group': 'fuel'
},
{
'id': uniqueid(),
'name': 'conventional',
'group': 'electricity'
},
{
'id': uniqueid(),
'name': 'green',
'group': 'electricity'
}
],
'networks': [
{
'id': uniqueid(),
'name': 'gas',
'sub_networks': [],
'pipelines': [
]
},
{
'id': uniqueid(),
'name': 'gas',
'sub_networks': [],
'pipelines': [
]
}
]
},
{
'id': periodid_second,
'start': 2001,
'end': 2001,
# 'sub_periods': [],
'regions': [
{
'id': 'DE',
# 'sub_regions': [],
'sites': [
{
'id': 'first_site_in_germany',
'company': companyid_2001, # => verweist auf periods => companies
'plants': [
{
'id': 'qux',
'product': {
'id': 'Ammoniak',
'process': {
'id': 'SMR+HB',
'technologies': [
technologyid_2001_first, # => verweist auf periods => technologies
technologyid_2001_second
]
}
}
}
]
}
]
},
{
'id': 'FR',
# 'sub_regions': [],
'sites': [
{
'id': 'first_site_in_france',
'company': companyid_2001, # => verweist auf periods => companies
'plants': [
{
'id': 'qux',
'product': {
'id': 'Ammoniak',
'process': {
'id': 'SMR+HB',
'technologies': [
technologyid_2001_first, # => verweist auf periods => technologies
technologyid_2001_second
]
}
}
}
]
}
]
}
],
'companies': [
{
'id': companyid_2001,
'name': 'international_company'
}
],
'technologies': [
{
'id': technologyid_2001_first,
'name': 'SMR',
'specific_cost_per_year': 123,
'specific_energy_consumptions': [
{
'energy_carrier': energy_carrierid_2001_first,
'specific_consumption': 5555
}, # => verweist auf periods => energy_carriers
{
'energy_carrier': energy_carrierid_2001_second,
'energy_consumption': 2333
}
]
},
{
'id': technologyid_2001_second,
'name': 'HB',
'specific_cost_per_year': 1234,
'specific_energy_consumptions': [
{
'energy_carrier': energy_carrierid_2001_first,
'specific_consumption': 555
}, # => verweist auf periods => energy_carriers
{
'energy_carrier': energy_carrierid_2001_second,
'energy_consumption': 233
}
]
}
],
'energy_carrieriers': [
{
'id': energy_carrierid_2001_first,
'name': 'oil',
'group': 'fuel'
},
{
'id': energy_carrierid_2001_second,
'name': 'gas',
'group': 'fuel'
},
{
'id': uniqueid(),
'name': 'conventional',
'group': 'electricity'
},
{
'id': uniqueid(),
'name': 'green',
'group': 'electricity'
}
],
'networks': [
{
'id': uniqueid(),
'name': 'gas',
'sub_networks': [],
'pipelines': [
]
},
{
'id': uniqueid(),
'name': 'gas',
'sub_networks': [],
'pipelines': [
]
}
]
}
]
r.table('periods') \
.insert(periods) \
.run()
Related:
RethinkDB: RqlRuntimeError: Cannot perform bracket on a sequence of sequences
Nested concat_map in combination with r.row operator and bracket drill down does the trick:
r.table('periods') \
.concat_map(r.row['regions']) \
.concat_map(r.row['sites']) \
.concat_map(r.row['plants'])['product']['process'] \
.concat_map(r.row['technologies']) \
.run()

Flutter: how to return the value by using other value inside the List<Map>

I have a List<Map<String, String>> like below
[
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
]
And, the ID list **List** as ['bb', 'aa']. By using the ID list, I want to return a new list ['Jane', 'John'] as **List _selectedList**.
I have tried to do it with the .**indexWhere**, however, I am stuck on the List where it has more than one value.
How can I return the List only with the name-value when there is more than one value to look for?
void main() {
var a = [
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
];
var b = ['bb', 'aa'];
var c = a.where((m) => b.contains(m['id'])).map((m) => m['name']);
print(c);
}
Result
(John, Jane)
Use a set to filter out the IDs efficiently.
var ids = ["aa", "cc"];
var idSet = Set<String>.from(ids);
var json = [
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
];
var _selectedList = json.where((data) => idSet.contains(data["id"]))
.map((data) => data["name"]).toList();
print(_selectedList);
Here, .where filters out the data where the ID matches one in the input list "IDs". Sets make the process efficient. Then, the resultant objects are passed to .map where the "name" field is extracted. Finally, the whole thing is converted into a list thus returning the list of names.
Output of the above code:
[John, Lisa]

Color title mapbox

Does anyone know how to change the title color of a marker on a mapbox,
I would like home to be in blue, I tried to add paint : color-size:"blue", but it doesn't work,
thank you for your help!!
map.on('load', function () {
map.loadImage(
'https://docs.mapbox.com/mapbox-gl-js/assets/custom_marker.png',
function (error, image) {
if (error) throw error;
map.addImage('custom-marker', image);
map.addSource('points', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
// feature for Mapbox
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [6.157902659395512,49.3612254277963],
},
'properties': {
'title': 'Lieu de repas',
'scale': 2,
},
}
]
}
});
map.addLayer({
'id': 'points',
'type': 'symbol',
'source': 'points',
'layout': {
'icon-image': 'custom-marker',
'text-field': ['get', 'title'],
"text-size": 28,
'text-font': [
'Open Sans Regular',
],
'text-offset': [0, 1.25],
'text-anchor': 'top',
}
});
}
);
});
You could possibly create an HTML marker for that in a way similar to this:
var el = document.createElement('div');
el.innerHTML = 'Lieu de repas';
el.style.color = 'blue';
new mapboxgl.Marker(el)
.setLngLat([6.157902659395512,49.3612254277963])
.addTo(map);

In mapbox how do I move a Feature to top (z-index wise)?

I have a layer full of state border "Features". When a user clicks on a State, I want to move that state's Feature to the top of the stack (z-index wise).
export function drawStateBorders() {
$.getJSON('https://www.mapbox.com/mapbox-gl-js/assets/us_states.geojson').then((data) => {
this.stateGeoJSON = data;
this.map
.addSource('states', {
type: 'geojson',
data,
})
.addLayer({
id: 'state-borders',
type: 'line',
source: 'states',
paint: {
'line-color': [
'case', ['boolean', ['feature-state', 'selected'], false],
'#8d8b76',
'#bfe2ab',
],
'line-width': [
'case', ['boolean', ['feature-state', 'selected'], false],
6,
3,
],
},
});
});
}
When I select the state
export function stateSelected(state) {
const stateFeatures = this.map.queryRenderedFeatures({
layers: ['state-borders'],
filter: [
'==', 'STATE_NAME', state,
],
});
const features = this.stateGeoJSON.features;
const currentFeature = stateFeatures[0];
if (!currentFeature) {
return;
}
// same state
if (currentFeature.id === this.selectedStateId) return;
// move to front HERE ?????
// old selected state
if (this.selectedStateId) {
this.map.setFeatureState({
source: 'states',
id: this.selectedStateId,
}, {
selected: false,
});
}
this.selectedStateId = currentFeature.id;
this.map.setFeatureState({
source: 'states',
id: this.selectedStateId,
}, {
selected: true,
});
}
So far I've tried
features.splice(features.indexOf(currentFeature), 1);
features.push(currentFeature);
this.map.getSource('states').setData(this.stateGeoJSON);
This seems to do some really crazy stuff to the array (duplicating some states, removing others). No idea what's happening
Adding the state to another layer worked (thanks #AndrewHarvey for the advice).
In case anyone is interested here is my code
export function stateSelected(state) {
const features = this.stateGeoJSON.features;
const currentFeature = features.find(s => s.properties.NAME === state);
if (!currentFeature) {
return;
}
// removes active layer
this.removeLayersContaining('state-borders-active');
this.drawActiveStateLayer(currentFeature);
}
export function drawActiveStateLayer(feature) {
this.map
.addLayer({
id: 'state-borders-active',
type: 'line',
source: {
type: 'geojson',
data: feature
},
paint: {
'line-color': '#8d8b76',
'line-width': 6,
},
});
}
export function drawStateBorders() {
$.getJSON('states.json').then((data) => {
this.stateGeoJSON = data;
this.map
.addSource('states', {
type: 'geojson',
data,
})
.addLayer({
id: 'state-borders',
type: 'line',
source: 'states',
paint: {
'line-color': '#bfe2ab',
'line-width': 3,
},
});
});
Also this is the shapefile I'm using: http://eric.clst.org/assets/wiki/uploads/Stuff/gz_2010_us_040_00_500k.json

GroupBy and CountBy for multiple values

I am trying to use underscorejs to groupBy multiple values based on below data.
var obj = [
{
'Name': 'A',
'Status': 'Ticket Closed'
},{
'Name': 'B',
'Status': 'Ticket Open To Close'
},{
'Name': 'A',
'Status': 'Ticket Closed'
},{
'Name': 'B',
'Status': 'Ticket Open'
},{
'Name': 'A',
'Status': 'Ticket Open To Closed'
},{
'Name': 'A',
'Status': 'Ticket Open'
},{
'Name': 'B',
'Status': 'Ticket Open'
}
];
The expected output is
[{
'Name': Closed',
'Count': [2, 0]
},{
'Name': Open',
'Count': [2, 3]
}]
First object counts all closed tickets (Where the status contains the word closed) for A and B simultaneously. Similarly the second object counts for Open tickets. Here is what I tried
var arr = _.groupBy(obj, function (row) {
return (row["Status"].indexOf('Open') > 0 ? "Open" : "Closed");
});
var arr1 = _.groupBy(arr["Closed"], 'Name');
var arr2 = _.groupBy(arr["Open"], 'Name');
var cData = [];
cData.push(arr1);
cData.push(arr2);
Unable to get count from same code. Any help?
Ok. So I was able to resolve this. Here's the working example
http://jsfiddle.net/7ETKV/
Here is the solved code:
var jsondata = jsondata.sort(function (a, b) {
return a.Name.localeCompare(b.Name);
});
_.each(jsondata, function (row, idx) {
((row.Status.indexOf('Open') > 0) ? jsondata[idx].bgStatus = 'Open' : jsondata[idx].bgStatus = 'Closed');
});
var cdata = [], xobj = {};
var gd = _.groupBy(jsondata, 'bgStatus');
var cats = _.keys(_.groupBy(jsondata, 'Name'));
for (var p in gd) {
var arr = _.countBy(gd[p], function (row) {
return row.Name;
});
_.each(cats, function (row) {
if (!arr.hasOwnProperty(row)) arr[row] = 0;
});
xobj.Name = p;
xobj.Data = _.values(arr);
cdata.push(xobj);
xobj = {};
}
Hope might help someone. Any updates to the code / optimizations are welcome.