How to check if an edge has an attribute in Networkx - attributes

I created a graph in yEd and I want to check if an edge has an attribute. For example some edges have a label but some dont. When I try to do this I get an an error:
for n, nbrs in G.adjacency_iter():
for nbr,eattr in nbrs.items():
evpn = eattr['vpn']
elabel = eattr['label'] #error is here
if evpn != "No":
nlabel = G[n].get("label")
platform = G[n].get("platform")
if G[nbr].get("platform") == platform:
g_vpn.add_nodes_from([n,nbr], label, platform) # I dont know if this way
#to set attributes is right
While vpn attribute works because I have set a default value. I know I could just put a label value in all edges but I want my program to check if label is missing and setting a default value like what I do below. Although it doesn't work because it can't find the label attribute in some edges:
for e,v in G.edges():
if G[e][v].get("label") == ""
label = "".join("vedge",i)
i+=1
G[e][v]['label']=label
Also if you could check the rest of that code and tell me if it needs any improvement or make some things easier to do. Thanks

The edge attributes are stored as a dictionary so you can test to see if the key is in the dictionary:
In [1]: import networkx as nx
In [2]: G = nx.Graph()
In [3]: G.add_edge(1,2,color='blue')
In [4]: G.add_edge(2,3)
In [5]: 'color' in G[1][2]
Out[5]: True
In [6]: 'color' in G[2][3]
Out[6]: False

Related

Find an index in a list of lists using an index inside one of the lists in pyton

I'm trying to determine if there is a way to access an index essentially by making a list of lists, where each inner list has a tuple that provides essentially grid coordinates, i.e:
example = [
['a', (0,0)], ['b',(0,1)], ['c', (0,2)],
['d', (1,0)], ['e',(1,1)], ['d', (1,2)],
.....
]
and so on.
So, If I have coordinates (0,1), I want to be able to return example[1][0], or at the very least example[1] since these coordinates correlate with example[1].
I tried using index(), but this doesn't go deep enough. I also looked into itertools, but I cannot find a tool that finds it and doesn't return a boolean.
Using a number pad as an example:
from itertools import chain
def pinpad_test():
pad=[
['1',(0,0)],['2',(0,1)],['3',(0,2)],
['4',(1,0)],['5',(1,1)],['6',(1,2)],
['7',(2,0)],['8',(2,1)],['9',(2,2)],
['0',(3,1)]
]
tester = '1234'
print(tester)
for dig in tester:
print(dig)
if dig in chain(*pad):
print(f'Digit {dig} in pad')
else:
print('Failed')
print('end of tester')
new_test = pad.index((0,1)in chain(*pad))
print(new_test)
if __name__ == '__main__':
pinpad_test()
I get an value error at the initiation of new_test.
You can just yield from simple generator expression:
coords = (0, 1)
idx = next((sub_l[0] for sub_l in pad if sub_l[1] == coords), None)
print(idx)
2
You can create a function that will give you want
def on_coordinates(coordinates:tuple, list_coordinates:list):
return next(x for x in list_coordinatesif x[1] == coordinates)

geopandas doesn't find point in polygon even though it should?

I have some lat/long coordinates and need to confirm if they are with the city of Atlanta, GA. I'm testing it out but it doesn't seem to work.
I got a geojson from here which appears to be legit:
https://gis.atlantaga.gov/?page=OPEN-DATA-HUB
import pandas as pd
import geopandas
atl = geopandas.read_file('Official_City_Boundary.geojson')
atl['geometry'] # this shows the image of Atlanta which appears correct
I plug in a couple of coordinates I got from Google Maps:
x = [33.75865421788594, -84.43974601192079]
y = [33.729117878816, -84.4017757998275]
z = [33.827871937500255, -84.39646813516548]
df = pd.DataFrame({'latitude': [x[0], y[0], z[0]], 'longitude': [x[1], y[1], z[1]]})
geometry = geopandas.points_from_xy(df.longitude, df.latitude)
points = geopandas.GeoDataFrame(geometry=geometry)
points
geometry
0 POINT (-84.43975 33.75865)
1 POINT (-84.40178 33.72912)
2 POINT (-84.39647 33.82787)
But when I check if the points are in the boundary, only one is true:
atl['geometry'].contains(points)
0 True
1 False
2 False
Why are they not all true? Am I doing it wrong?
I found some geometry similar to what you refer to
an alternative approach is to use intersects() to find the contains relationship. NB use of unary_union as the Atlanta geometry I downloaded contains multiple polygons
import pandas as pd
import geopandas
from pathlib import Path
atl = geopandas.read_file(Path.home().joinpath("Downloads").joinpath('Official_City_Council_District_Boundaries.geojson'))
atl['geometry'] # this shows the image of Atlanta which appears correct
x = [33.75865421788594, -84.43974601192079]
y = [33.729117878816, -84.4017757998275]
z = [33.827871937500255, -84.39646813516548]
df = pd.DataFrame({'latitude': [x[0], y[0], z[0]], 'longitude': [x[1], y[1], z[1]]})
geometry = geopandas.points_from_xy(df.longitude, df.latitude)
points = geopandas.GeoDataFrame(geometry=geometry, crs="epsg:4326")
points.intersects(atl.unary_union)
0 True
1 True
2 True
dtype: bool
As it is said in documentation:
It does not check if an element of one GeoSeries contains any element
of the other one.
So you should use a loop to check all points.

if else statement python using plot parameters in function

I have an if else statement in my function that is not wokring the way i want it to. Mind you I am still learning python and all things programming.
I have a function to define a plot. Idea is to create a large python repo for data analysis. EDIT: i added a working make shift dataframe for you to try
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
#import numpy as np
#import os
#import dir_config as dcfg
#import data_config as datacfg
import matplotlib.dates as md
#import cartopy.crs as ccrs
data = {'dates': [20200901,20200902,20200903,20200904,20200905,20200906,20200907,20200908,20200909,20200910],
'depth': [1,2,3,4,5,6,7,8,9,10],
'cond': [30.1,30.2,30.3,30.6,31,31.1,31.0,31.4,31.1,30.9]
}
df = pd.DataFrame(data, columns = ['dates', 'depth', 'cond'])
df['pd_datetime'] = pd.to_datetime(df['dates'])
def ctd_plots_timeseries(time=[],cond=[], sal =[], temp=[], depth=[], density=[]):
#-----------
# CONDUCTIVITY PLOT
#-----------
if cond == []:
print("there is no data for cond")
pass
else:
plt.scatter(time,depth,s=15,c=cond,marker='o', edgecolor='none')
plt.show()
#-----------
# SALINITY (PSU) PLOT: I do not want this to plot at all due to its parameter being 'empty' in the function when called
#-----------
if sal == []:
print('there is no salinity data')
pass
else:
plt.scatter(time,depth,s=15,c=sal,marker='o', edgecolor='none')
plt.show()
ctd_plots_timeseries(depth = df['depth'], time = df['pd_datetime'], cond = df['cond'])
The idea here is that if there is no data in the cond value, do pass to not show the plot.
However ever time I run this, the plot shows, even thought there is no data for it.
When i call the function i put in plot_timeseries(time=time_data, depth=depth_data temp=temp_data)
my aim is for only the temp data in this example to show, not a cond graph with no variables.
what i have tried is
if cond != []:
plotting code
plt.show()
else:
print('there is no cond data')
pass
and
plotting code
if cond == []:
print('no cond data')
pass
else:
plt.show()
to no avail.
note that there are 4 other plots in this function i would like to do the same thing. thanks for any insight this community can give me.
UPDATE:
I changed the conditions in the function to def ctd_plots_timeseries(time=0,cond=0, sal =0, temp=0, depth=0, density=0):
and then changed conditional statement to
if cond != 0:
graphing code
else:
print('no data here')
i get the following error:
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
I've simplified it. Try that:
def plots_timeseries(cond = []): # Single argument for clarity
if not cond:
print('there is no cond value')
else:
print('There is cond')
plots_timeseries()
# there is no cond value
So I figured out a working solution.
if len(cond) == 0:
print('there is no cond data')
else:
plt.scatter(time,depth,s=15,c=cond)
plt.show()
Lots of time and effort was put in to trying to solve this, and this solution was a test, after a good night sleep. Thanks for all the help. hope this helps someone else if that have a similar issue

Cannot get Bokeh graph to show using Python

I'm pretty new to Python and this is my first time using Bokeh. I've followed a tutorial using NFL data to show graphs and I cannot get the graph to show on my machine. The script runs without error, but nothing shows. I'm sure I'm missing something very simple... but I just don't know what that is... Can someone please help me? Below is my code:
import pandas as pd
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, FactorRange, FixedTicker
from bokeh.io import output_notebook
from collections import Counter
from bokeh.transform import factor_cmap
from bokeh.palettes import Paired, Spectral
import itertools
pd.set_option('display.max_columns', 150)
output_notebook()
filename = '/Users/ksilva/Downloads/NFL Play by Play 2009-2017 (v4).csv'
df = pd.read_csv(filename,dtype={25: object, 51: object})
# print(df.shape)
# df['down'].isnull().sum()
pd.to_numeric(df['down'], errors='coerce').isnull().sum()
# print(df.loc[51])
# filter by team if desired
team = 'all'
if team == 'all':
team_df = df
else:
team_df = df.loc[df['posteam'] == team]
# drop rows will null in the 'down' column
team_df = team_df.loc[df['down'].notnull()]
all_play_types = Counter(team_df['PlayType'])
# print(team_df)
# print(all_play_types)
# list of downs I care about
downs = ['1','2','3','4']
# list of plays I care about
plays = ['Pass', 'Run', 'Punt', 'Field Goal']
# define x-axis categories to be used in the vbar plot
x = list(itertools.product(downs, plays))
# x = [('1', 'Pass'), ('1', 'Run'), ('1', 'Punt'), ..., ('4', 'Punt'), ('4', 'Field Goal')]
# create a list of Counters for each down--will include ALL PlayTypes for each down
plays_on_down = [Counter(team_df.loc[team_df['down'] == int(down)]['PlayType']) for down in downs]
# create a list of counts for each play in plays for each down in downs
counts = [plays_on_down[int(down)-1][play] for down, play in x]
# load the into the ColumnDataSource
source = ColumnDataSource(data=dict(x=x, counts=counts))
# get the figure ready
p = figure(x_range=FactorRange(*x), plot_height=350, plot_width=750, title='Play by Down',
toolbar_location=None, tools='')
# create the vbar
p.vbar(x='x', top='counts', width=0.9, source=source, line_color='white',
fill_color=factor_cmap('x', palette=Spectral[4], factors=plays, start=1, end=2))
p.y_range.start = 0
p.x_range.range_padding = 0.1
p.xaxis.major_label_orientation = 1
p.xaxis.axis_label = 'Down'
p.yaxis.axis_label = 'Number of Plays'
p.xgrid.grid_line_color = None
show(p)
For whatever reason, nothing happens when executed from the terminal.
Any help is greatly appreciated!
Thanks.
You are setting calling output_notebook. This activates a mode that only diplays in a Jupyter notebook. If you want to execute plain python scripts to generate HTML file output, you should use output_file.

In Bokeh, how do I add tooltips to a Timeseries chart (hover tool)?

Is it possible to add Tooltips to a Timeseries chart?
In the simplified code example below, I want to see a single column name ('a','b' or 'c') when the mouse hovers over the relevant line.
Instead, a "???" is displayed and ALL three lines get a tool tip (rather than just the one im hovering over)
Per the documentation (
http://docs.bokeh.org/en/latest/docs/user_guide/tools.html#hovertool), field names starting with “#” are interpreted as columns on the data source.
How can I display the 'columns' from a pandas DataFrame in the tooltip?
Or, if the high level TimeSeries interface doesn't support this, any clues for using the lower level interfaces to do the same thing? (line? multi_line?) or convert the DataFrame into a different format (ColumnDataSource?)
For bonus credit, how should the "$x" be formatted to display the date as a date?
thanks in advance
import pandas as pd
import numpy as np
from bokeh.charts import TimeSeries
from bokeh.models import HoverTool
from bokeh.plotting import show
toy_df = pd.DataFrame(data=np.random.rand(5,3), columns = ('a', 'b' ,'c'), index = pd.DatetimeIndex(start='01-01-2015',periods=5, freq='d'))
p = TimeSeries(toy_df, tools='hover')
hover = p.select(dict(type=HoverTool))
hover.tooltips = [
("Series", "#columns"),
("Date", "$x"),
("Value", "$y"),
]
show(p)
Below is what I came up with.
Its not pretty but it works.
Im still new to Bokeh (& Python for that matter) so if anyone wants to suggest a better way to do this, please feel free.
import pandas as pd
import numpy as np
from bokeh.charts import TimeSeries
from bokeh.models import HoverTool
from bokeh.plotting import show
toy_df = pd.DataFrame(data=np.random.rand(5,3), columns = ('a', 'b' ,'c'), index = pd.DatetimeIndex(start='01-01-2015',periods=5, freq='d'))
_tools_to_show = 'box_zoom,pan,save,hover,resize,reset,tap,wheel_zoom'
p = figure(width=1200, height=900, x_axis_type="datetime", tools=_tools_to_show)
# FIRST plot ALL lines (This is a hack to get it working, why can't i pass in a dataframe to multi_line?)
# It's not pretty but it works.
# what I want to do!: p.multi_line(df)
ts_list_of_list = []
for i in range(0,len(toy_df.columns)):
ts_list_of_list.append(toy_df.index.T)
vals_list_of_list = toy_df.values.T.tolist()
# Define colors because otherwise multi_line will use blue for all lines...
cols_to_use = ['Black', 'Red', 'Lime']
p.multi_line(ts_list_of_list, vals_list_of_list, line_color=cols_to_use)
# THEN put scatter one at a time on top of each one to get tool tips (HACK! lines with tooltips not yet supported by Bokeh?)
for (name, series) in toy_df.iteritems():
# need to repmat the name to be same dimension as index
name_for_display = np.tile(name, [len(toy_df.index),1])
source = ColumnDataSource({'x': toy_df.index, 'y': series.values, 'series_name': name_for_display, 'Date': toy_df.index.format()})
# trouble formating x as datestring, so pre-formating and using an extra column. It's not pretty but it works.
p.scatter('x', 'y', source = source, fill_alpha=0, line_alpha=0.3, line_color="grey")
hover = p.select(dict(type=HoverTool))
hover.tooltips = [("Series", "#series_name"), ("Date", "#Date"), ("Value", "#y{0.00%}"),]
hover.mode = 'mouse'
show(p)
I’m not familiar with Pandas,I just use python list to show the very example of how to add tooltips to muti_lines, show series names ,and properly display date/time。Below is the result.
Thanks to #bs123's answer and #tterry's answer in Bokeh Plotting: Enable tooltips for only some glyphs
my result
# -*- coding: utf-8 -*-
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.models import HoverTool
from datetime import datetime
dateX_str = ['2016-11-14','2016-11-15','2016-11-16']
#conver the string of datetime to python datetime object
dateX = [datetime.strptime(i, "%Y-%m-%d") for i in dateX_str]
v1= [10,13,5]
v2 = [8,4,14]
v3= [14,9,6]
v = [v1,v2,v3]
names = ['v1','v2','v3']
colors = ['red','blue','yellow']
output_file('example.html',title = 'example of add tooltips to multi_timeseries')
tools_to_show = 'hover,box_zoom,pan,save,resize,reset,wheel_zoom'
p = figure(x_axis_type="datetime", tools=tools_to_show)
#to show the tooltip for multi_lines,you need use the ColumnDataSource which define the data source of glyph
#the key is to use the same column name for each data source of the glyph
#so you don't have to add tooltip for each glyph,the tooltip is added to the figure
#plot each timeseries line glyph
for i in xrange(3):
# bokeh can't show datetime object in tooltip properly,so we use string instead
source = ColumnDataSource(data={
'dateX': dateX, # python datetime object as X axis
'v': v[i],
'dateX_str': dateX_str, #string of datetime for display in tooltip
'name': [names[i] for n in xrange(3)]
})
p.line('dateX', 'v',source=source,legend=names[i],color = colors[i])
circle = p.circle('dateX', 'v',source=source, fill_color="white", size=8, legend=names[i],color = colors[i])
#to avoid some strange behavior(as shown in the picture at the end), only add the circle glyph to the renders of hover tool
#so tooltip only takes effect on circle glyph
p.tools[0].renderers.append(circle)
# show the tooltip
hover = p.select(dict(type=HoverTool))
hover.tooltips = [("value", "#v"), ("name", "#name"), ("date", "#dateX_str")]
hover.mode = 'mouse'
show(p)
tooltips with some strange behavior,two tips displayed at the same time
Here is my solution. I inspected the glyph render data source to see what are the names on it. Then I use those names on the hoover tooltips. You can see the resulting plot here.
import numpy as np
from bokeh.charts import TimeSeries
from bokeh.models import HoverTool
from bokeh.plotting import show
toy_df = pd.DataFrame(data=np.random.rand(5,3), columns = ('a', 'b' ,'c'), index = pd.DatetimeIndex(start='01-01-2015',periods=5, freq='d'))
#Bockeh display dates as numbers so convert to string tu show correctly
toy_df.index = toy_df.index.astype(str)
p = TimeSeries(toy_df, tools='hover')
#Next 3 lines are to inspect how are names on gliph to call them with #name on hover
#glyph_renderers = p.select(dict(type=GlyphRenderer))
#bar_source = glyph_renderers[0].data_source
#print(bar_source.data) #Here we can inspect names to call on hover
hover = p.select(dict(type=HoverTool))
hover.tooltips = [
("Series", "#series"),
("Date", "#x_values"),
("Value", "#y_values"),
]
show(p)
The original poster's code doesn't work with the latest pandas (DatetimeIndex constructor has changed), but Hovertool now supports a formatters attribute that lets you specify a format as a strftime string. Something like
fig.add_tool(HoverTool(
tooltip=[
('time', '#index{%Y-%m-%d}')
],
formatters={
'#index': 'datetime'
}
))

Resources