Color of node wont change in Pyvis - python

I am trying to build a networkx digraph of blockchain transaction data and visualize it using Pyvis. I believe that I have the graph working, but I want to change the color of the transactions that involve Uniswap. I am having trouble doing that though as the colors never change. Here is my code:
G = nx.DiGraph()
# Read data in from csv and seperate data
data = pd.read_csv('apecoin_trans_data_1day_072822.csv')
fro = data['address_from']
to = data['address_to']
date_time = data['date_time']
amount = data['amount']
edges_data = zip(fro, to, date_time, amount)
transaction = []
# Create the graph
for e in edges_data:
src = e[0]
tar = e[1]
G.add_node(src)
G.add_node(tar)
transaction.append((src, tar))
G.add_edges_from(transaction)
net = Network(height='750px', width='100%', notebook=False, directed=True)
net.from_nx(G)
# Get adjacency list for graph
neighbor_map = net.get_adj_list()
for node in net.nodes:
node["value"] = len(neighbor_map[node["id"]])
if node["id"] == "\xac4b3dacb91461209ae9d41ec517c2b9cb1b7daf":
node["color"] = "red"
else:
node["color"] = "blue"
net.show("networkmap.html")
The data is formatted like so:
address_from,address_to,date_time,amount
\xdbb69ea87507525fffbd1c4f1ad6f7d30a9a402e,\x0000000000007f150bd6f54c40a34d7c3d5e9f56,2022-07-27T23:02:04+00:00,93.4673619317370716
\xba12222222228d8ba445958a75a0704d566bf2c8,\x0000000000007f150bd6f54c40a34d7c3d5e9f56,2022-07-27T23:02:30+00:00,95.7735945510702722
\xf784470541ad1f94902c387514756c7d831e20a7,\x0000000000007f150bd6f54c40a34d7c3d5e9f56,2022-07-28T00:06:38+00:00,8422.2499709617088153
\xf784470541ad1f94902c387514756c7d831e20a7,\x0000000000007f150bd6f54c40a34d7c3d5e9f56,2022-07-28T00:08:08+00:00,1337.1683051620927162
\x6eb0ed09ac237f4c607a18b8dc63b48efe61b9b8,\x00000000009726632680fb29d3f7a9734e3010e2,2022-07-28T13:57:26+00:00,1000.0000000000000000

I ended up figuring it out. I was doing the following:
if node["id"] == "\xac4b3dacb91461209ae9d41ec517c2b9cb1b7daf"
When it should have been this:
if node["id"] == r'\xac4b3dacb91461209ae9d41ec517c2b9cb1b7daf'

Related

OSError: The topology is loaded by filename extension, and the detected ".pd" format is not supported

I'm writing a code to generate features of ligands. Code is:
def parsePDB(self):
top = self.pdb.topology
residues = [str(residue)[:3] for residue in top.residues]
residues_cp = residues.copy()
# number of all groups in the complex except the ligand
LIG_number = residues.index('LIG')
self.residues_indices = [i for i in range(top.n_residues) if i != LIG_number]
# Get the types of atoms in the protein and ligand
self.rec_indices = top.select('protein')
self.lig_indices = top.select('resname LIG')
table, bond = top.to_dataframe()
self.all_ele = table['element']
self.lig_ele = table['element'][self.lig_indices]
H_num = []
for num, i in enumerate(self.all_ele):
if i == 'H':
H_num.append(num)
# Get the serial number of the atom in each residue or group
removes = []
for i in self.residues_indices:
atoms = top.residue(i).atoms
each_atoms = [j.index for j in atoms]
heavy_atoms = [x for x in each_atoms if not x in H_num]
if len(heavy_atoms) == 0:
removes.append(i)
else:
self.atoms_indices.append(heavy_atoms)
if len(removes) != 0:
for i in removes:
self.residues_indices.remove(i)
self.residues = [residues_cp[x] for x in self.residues_indices]
# Get the 3D coordinates for all atoms
self.xyz = self.pdb.xyz[0]
return self
I'm getting this error:
OSError: The topology is loaded by filename extension, and the detected ".pd" format is not supported. Supported topology formats include ".pdb", ".pdb.gz", ".h5", ".lh5", ".prmtop", ".parm7", ".prm7", ".psf", ".mol2", ".hoomdxml", ".gro", ".arc", ".hdf5" and ".gsd".
Can anyone please suggest me how to resolve this issue? Thanks

Folium put markers in marker clusters AND in layers based on a value

So, I'm working with a dataset of stores, each store with its lat, lng, name and category.
Since we are talking about several hundreds of even thousands of stores, I'm using marker clusters, and they are working fine...
Now, I need to also set these stores in different layers based on their category, so that when I click on say "electronics stores", I only get those stores in the map (and they should be removed from the marker cluster as well)
Consider this sample data:
stores = [(-23.5578906,-46.6665546, 'store1','electronics'),
(-23.562711,-46.674363, 'store2','home goods'),
(-23.5642399,-46.6681833, 'store3','beauty'),
(-23.584167,-46.678497, 'store4','electronics'),
(-23.5956238,-46.6865377, 'store5','electronics'),
(-23.5868682,-46.6773554,'store6','home goods'),
(-23.6011096,-46.6739275, 'store7','beauty'),
(-23.6087354,-46.6973713, 'store8','home goods'),
(-23.5943515,-46.6846959, 'store9','beauty')]
My code works ok for putting the markers in clusters, but when I try to also add them to layers based on their categories it doesn't work. I get no errors, and the map "loads", but the markers and clusters don't get displayed, and I get no layers on the map.
This is my code:
mymap = folium.Map(location=[y_map, x_map], zoom_start=11,tiles=None)
folium.TileLayer(name="Mapbox Bright",control=False).add_to(mymap)
markers_list = []
all_gp = []
for lat, lng, name, category zip(df_stores['LAT'],
df_stores['LNG'],
df_stores['NAME'],
df_stores['CATEGORY']
):
html = '''NAME: ''' + name + '''<br>CATEGORY: ''' + category
iframe = folium.IFrame(html,
width=300,
height=130)
popup = folium.Popup(iframe,
max_width=300)
lead_marker = folium.Marker(
[lat, lng],
popup=popup,
icon=folium.Icon(color='purple', icon='glyphicon-cutlery', prefix='glyphicon')
)
markers_list.append(lead_marker)
pg = category
all_gp.append(pg)
mCluster = MarkerCluster(name="Stores").add_to(mymap)
for pnt in markers_list:
pnt.add_to(mCluster)
######################################################################
# Create point_layer object
unique_gp = list(set(all_gp))
vlist = []
for i,k in enumerate(unique_gp):
locals()[f'point_layer{i}'] = folium.FeatureGroup(name=k)
vlist.append(locals()[f'point_layer{i}'])
# Creating list for point_layer
pl_group = []
for n in all_gp:
for v in vlist:
if n == vars(v)['layer_name']:
pl_group.append(v)
for pnt,pg in zip(markers_list,pl_group):
pnt.add_to(pg)
pg.add_to(mymap)
######################################################################
folium.LayerControl().add_to(mymap)
mymap.add_child(MeasureControl())
mymap.render()
mymap.save('stores.html')
The code between the lines of ############ I took form another post here (How to add categorical layered data to LayerControl() in python Folium map?) and adapted it to my code, but it seems I'm missing something. If I take out the last for cycle from the code, the map loads correctly with its clusters working ok, any suggestions?
I will answer with the understanding that the question is how to create a category layer, add markers for the information that belongs to it, and control the show/hide with a layer control. First, set the respective column data from the row information in the data frame and add the pop-up information. Add the category information based on the category information to the pre-prepared per-category layer.
import pandas as pd
import numpy as np
import folium
from folium.plugins import MarkerCluster
stores = [(-23.5578906,-46.6665546, 'store1','electronics'),
(-23.562711,-46.674363, 'store2','home goods'),
(-23.5642399,-46.6681833, 'store3','beauty'),
(-23.584167,-46.678497, 'store4','electronics'),
(-23.5956238,-46.6865377, 'store5','electronics'),
(-23.5868682,-46.6773554,'store6','home goods'),
(-23.6011096,-46.6739275, 'store7','beauty'),
(-23.6087354,-46.6973713, 'store8','home goods'),
(-23.5943515,-46.6846959, 'store9','beauty')]
df = pd.DataFrame(stores, columns=['LAT','LNG','NAME','CATEGORY'])
mymap = folium.Map(location=[df['LAT'].mean(), df['LNG'].mean()], zoom_start=12)
#mCluster = MarkerCluster(name="Stores").add_to(mymap)
mCluster_hg = MarkerCluster(name="home goods").add_to(mymap)
mCluster_ele = MarkerCluster(name="electronics").add_to(mymap)
mCluster_bea = MarkerCluster(name="beauty").add_to(mymap)
for row in df.itertuples():
#print(row)
location = row[1], row[2]
icon=folium.Icon(color='purple', icon='glyphicon-cutlery', prefix='glyphicon')
html = '''NAME: ''' + row[3] + '''<br>CATEGORY: ''' + row[4]
iframe = folium.IFrame(html, width=300, height=130)
popup = folium.Popup(iframe, max_width=300)
marker = folium.Marker(location=location, popup=popup, icon=icon)
#folium.Popup(popup).add_to(marker)
#mCluster_bea.add_child(marker)
if row[4] == 'electronics':
mCluster_ele.add_child(marker)
elif row[4] == 'home goods':
mCluster_hg.add_child(marker)
elif row[4] == 'beauty':
mCluster_bea.add_child(marker)
folium.LayerControl().add_to(mymap);
mymap

Retrieving data from the Air Quality Index (AQI) website through the API and only recieving small nr. of stations

I'm working on a personal project and I'm trying to retrieve air quality data from the https://aqicn.org website using their API.
I've used this code, which I've copied and adapted for the city of Bucharest as follows:
import pandas as pd
import folium
import requests
# GET data from AQI website through the API
base_url = "https://api.waqi.info"
path_to_file = "~/path"
# Got token from:- https://aqicn.org/data-platform/token/#/
with open(path_to_file) as f:
contents = f.readlines()
key = contents[0]
# (lat, long)-> bottom left, (lat, lon)-> top right
latlngbox = "44.300264,25.920181,44.566991,26.297836" # For Bucharest
trail_url=f"/map/bounds/?token={key}&latlng={latlngbox}" #
my_data = pd.read_json(base_url + trail_url) # Joined parts of URL
print('columns->', my_data.columns) #2 cols ‘status’ and ‘data’ JSON
### Built a dataframe from the json file
all_rows = []
for each_row in my_data['data']:
all_rows.append([each_row['station']['name'],
each_row['lat'],
each_row['lon'],
each_row['aqi']])
df = pd.DataFrame(all_rows, columns=['station_name', 'lat', 'lon', 'aqi'])
# Cleaned the DataFrame
df['aqi'] = pd.to_numeric(df.aqi, errors='coerce') # Invalid parsing to NaN
# Remove NaN entries in col
df1 = df.dropna(subset = ['aqi'])
Unfortunately it only retrieves 4 stations whereas there are many more available on the actual site. In the API documentation the only limitation I saw was for "1,000 (one thousand) requests per second" so why can't I get more of them?
Also, I've tried to modify the lat-long values and managed to get more stations, but they were outside the city I was interested in.
Here is a view of the actual perimeter I've used in the embedded code.
If you have any suggestions as of how I can solve this issue, I'd be very happy to read your thoughts. Thank you!
Try using waqi through aqicn... not exactly a clean API but I found it to work quite well
import pandas as pd
url1 = 'https://api.waqi.info'
# Get token from:- https://aqicn.org/data-platform/token/#/
token = 'XXX'
box = '113.805332,22.148942,114.434299,22.561716' # polygon around HongKong via bboxfinder.com
url2=f'/map/bounds/?latlng={box}&token={token}'
my_data = pd.read_json(url1 + url2)
all_rows = []
for each_row in my_data['data']:
all_rows.append([each_row['station']['name'],each_row['lat'],each_row['lon'],each_row['aqi']])
df = pd.DataFrame(all_rows,columns=['station_name', 'lat', 'lon', 'aqi'])
From there its easy to plot
df['aqi'] = pd.to_numeric(df.aqi,errors='coerce')
print('with NaN->', df.shape)
df1 = df.dropna(subset = ['aqi'])
df2 = df1[['lat', 'lon', 'aqi']]
init_loc = [22.396428, 114.109497]
max_aqi = int(df1['aqi'].max())
print('max_aqi->', max_aqi)
m = folium.Map(location = init_loc, zoom_start = 5)
heat_aqi = HeatMap(df2, min_opacity = 0.1, max_val = max_aqi,
radius = 60, blur = 20, max_zoom = 2)
m.add_child(heat_aqi)
m
Or as such
centre_point = [22.396428, 114.109497]
m2 = folium.Map(location = centre_point,tiles = 'Stamen Terrain', zoom_start= 6)
for idx, row in df1.iterrows():
lat = row['lat']
lon = row['lon']
station = row['station_name'] + ' AQI=' + str(row['aqi'])
station_aqi = row['aqi']
if station_aqi > 300:
pop_color = 'red'
elif station_aqi > 200:
pop_color = 'orange'
else:
pop_color = 'green'
folium.Marker(location= [lat, lon],
popup = station,
icon = folium.Icon(color = pop_color)).add_to(m2)
m2
checking for stations within HK, returns 19
df[df['station_name'].str.contains('HongKong')]

reducing scale of uv map for voxel faces python api

I would have a voxel object on which I map a texture. The problem is it looks really weird because the faces of the voxel cubes have more than one colour to them. I would like to reduce the color down to a singular colour for each voxel face. I found a way to do that within blender but since I want to run this headlessly I need to do the same thing at a lower level and run it via api call.
Attaching the code below. Any and all help would be appreciated.
import bpy
import os
removeThese = bpy.context.copy()
removeThese['selected_objects'] = list(bpy.context.scene.objects)
bpy.ops.object.delete(removeThese)
sourceDirectory = "model_folder"
model_name = "model.obj"
path = os.path.join(sourceDirectory, model_name)
bpy.ops.import_scene.obj(filepath=path, axis_forward='-Z', axis_up='Y', filter_glob="*.obj;*.mtl")
model_obj = bpy.context.scene.objects[model_name.split(".")[0]]
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = model_obj
model_obj.select_set(True)
sourceName = bpy.context.object.name
source = bpy.data.objects[sourceName]
#duplicating source model
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'})
duplicate_obj = bpy.context.scene.objects[model_name.split(".")[0]+".001"]
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = duplicate_obj
duplicate_obj.select_set(True)
bpy.context.object.name = sourceName + "_Voxelized"
bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)
bpy.ops.object.convert(target='MESH')
#source.hide_render = True
#source.hide_viewport = True
targetName = bpy.context.object.name
target = bpy.data.objects[targetName]
#converting to blocks
bpy.ops.object.modifier_add(type='REMESH')
bpy.context.object.modifiers["Remesh"].mode = 'BLOCKS'
bpy.context.object.modifiers["Remesh"].octree_depth = 7
bpy.context.object.modifiers["Remesh"].scale = 0.5
bpy.context.object.modifiers["Remesh"].use_remove_disconnected = True
bpy.ops.object.modifier_apply(modifier="Remesh")
#transferring UVs from source to target
bpy.ops.object.modifier_add(type='DATA_TRANSFER')
bpy.context.object.modifiers["DataTransfer"].use_loop_data = True
bpy.context.object.modifiers["DataTransfer"].data_types_loops = {'UV'}
bpy.context.object.modifiers["DataTransfer"].loop_mapping = 'POLYINTERP_NEAREST'
bpy.context.object.modifiers["DataTransfer"].object = source
bpy.ops.object.datalayout_transfer(modifier="DataTransfer")
bpy.ops.object.modifier_apply(modifier="DataTransfer")
#this is the chunk that reduces each voxel face to one colour
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_mode(type='FACE')
bpy.context.area.ui_type = 'UV'
bpy.context.scene.tool_settings.use_uv_select_sync = False
bpy.context.space_data.uv_editor.sticky_select_mode = 'DISABLED'
bpy.context.scene.tool_settings.uv_select_mode = 'FACE'
bpy.context.space_data.pivot_point = 'INDIVIDUAL_ORIGINS'
bpy.ops.mesh.select_all(action='DESELECT')
#singularizing colours on each voxel face
count = 0
while count < 100:
bpy.ops.mesh.select_random(ratio=(count/100) + 0.01, seed=count)
bpy.ops.uv.select_all(action='SELECT')
bpy.ops.transform.resize(value=(0.01, 0.01, 0.01))
bpy.ops.mesh.hide(unselected=False)
count+=1
#returning to previous context
bpy.context.area.ui_type = 'VIEW_3D'
bpy.ops.mesh.reveal()
bpy.ops.object.editmode_toggle()
bpy.context.area.ui_type = 'TEXT_EDITOR'
#deleting source and keeping target
bpy.ops.object.select_all(action='DESELECT')
source.select_set(True)
bpy.ops.object.delete()
#selecting target
target.select_set(True)
#exporting voxelized model
output_directory = sourceDirectory
vox_model_name = targetName + '.obj'
output_file = os.path.join(output_directory, vox_model_name)
print(output_file)
bpy.ops.export_scene.obj(filepath=output_file)

Vertical positioning of nodes in Sankey diagram to avoid collision with links

I'm trying to make a Sankey-plot using Plotly, which follows the filtering of certain documents into either being in scope or out of scope, i.e. 1 source, 2 targets, however some documents are filtered during step 1, some during step 2 etc. This leads to the following Sankey-plot:
Current output
Now what I would ideally like is for it to look something like this:
Ideal output
I've already tried to look through the documentation on : https://plot.ly/python/reference/#sankey but I fail to find what I'm looking for, ideally I would like to implement a feature to prevent the plot from overlapping nodes and links.
This is the code I'm using the generate the plot object:
def genSankeyPlotObject(df, cat_cols=[], value_cols='', visible = False):
### COLORPLATTE TO USE
colorPalette = ['472d3c', '5e3643', '7a444a', 'a05b53', 'bf7958', 'eea160', 'f4cca1', 'b6d53c', '71aa34', '397b44',
'3c5956', '302c2e', '5a5353', '7d7071', 'a0938e', 'cfc6b8', 'dff6f5', '8aebf1', '28ccdf', '3978a8',
'394778', '39314b', '564064', '8e478c', 'cd6093', 'ffaeb6', 'f4b41b', 'f47e1b', 'e6482e', 'a93b3b',
'827094', '4f546b']
### CREATES LABELLIST FROM DEFINED COLUMNS
labelList = []
for catCol in cat_cols:
labelListTemp = list(set(df[catCol].values))
labelList = labelList + labelListTemp
labelList = list(dict.fromkeys(labelList))
### DEFINES THE NUMBER OF COLORS IN THE COLORPALLET
colorNum = len(df[cat_cols[0]].unique()) + len(df[cat_cols[1]].unique()) + len(df[cat_cols[2]].unique())
TempcolorPallet = colorPalette * math.ceil(len(colorPalette)/colorNum)
shuffle(TempcolorPallet)
colorList = TempcolorPallet[0:colorNum]
### TRANSFORMS DF INTO SOURCE -> TARGET PAIRS
for i in range(len(cat_cols)-1):
if i==0:
sourceTargetDf = df[[cat_cols[i],cat_cols[i+1],value_cols]]
sourceTargetDf.columns = ['source','target','count']
else:
tempDf = df[[cat_cols[i],cat_cols[i+1],value_cols]]
tempDf.columns = ['source','target','count']
sourceTargetDf = pd.concat([sourceTargetDf,tempDf])
sourceTargetDf = sourceTargetDf.groupby(['source','target']).agg({'count':'sum'}).reset_index()
### ADDING INDEX TO SOURCE -> TARGET PAIRS
sourceTargetDf['sourceID'] = sourceTargetDf['source'].apply(lambda x: labelList.index(x))
sourceTargetDf['targetID'] = sourceTargetDf['target'].apply(lambda x: labelList.index(x))
### CREATES THE SANKEY PLOT OBJECT
data = go.Sankey(node = dict(pad = 15,
thickness = 20,
line = dict(color = "black",
width = 0.5),
label = labelList,
color = colorList),
link = dict(source = sourceTargetDf['sourceID'],
target = sourceTargetDf['targetID'],
value = sourceTargetDf['count']),
valuesuffix = ' ' + value_cols,
visible = visible)
return data

Categories