How to specify edge length in Networkx based off of edge weight - networkx

import networkx as nx
import numpy as np
import pylab as plt
#Generate graph with 4 nodes
erdo_graph = nx.erdos_renyi_graph(4, 0.7, directed=False)
#Add edge weights
for u,v,d in erdo_graph.edges(data=True):
d['weight'] = np.random.choice(np.arange(1, 7), p=[0.1, 0.05, 0.05, 0.2,])
#If you want to print out the edge weights:
labels = nx.get_edge_attributes(erdo_graph,'weight')
print("Here are the edge weights: ", labels)
#Following "Networkx Spring Layout with different edge values" link that you supplied:
initialpos = {1:(0,0), 2:(0,3), 3:(0,-1), 4:(5,5)}
pos = nx.spring_layout(erdo_graph, weight='weight', pos=initialpos)
nx.draw_networkx(erdo_graph, pos)
plt.show()
Whenever I try to position the nodes based off of a layout, I expect nodes that are connected by a lower edge weight to be closer to each other, but that doesn't seem to be the case.

Related

Migrating from basemap to cartopy - coordinates offset?

I was happy with basemap showing some points of interest I have visited, but since basemap is dead, I am moving over to cartopy.
So far so good, I have transferred all the map features (country borders, etc.) without major problems, but I have noticed my points of interest are shifted a bit to North-East in cartopy.
Minimal example from the old basemap (showing two points of interest on the Germany-Czech border):
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
map = Basemap(projection='merc', epsg='3395',
llcrnrlon = 11.5, urcrnrlon = 12.5,
llcrnrlat = 50, urcrnrlat = 50.7,
resolution = 'f')
map.fillcontinents(color='Bisque',lake_color='LightSkyBlue')
map.drawcountries(linewidth=0.2)
lats = [50.3182289, 50.2523744]
lons = [12.1010486, 12.0906336]
x, y = map(lons, lats)
map.plot(x, y, marker = '.', markersize=1, mfc = 'red', mew = 1, mec = 'red', ls = 'None')
plt.savefig('example-basemap.png', dpi=200, bbox_inches='tight', pad_inches=0)
And the same example from cartopy - both points are slightly shifted to North-East as can be verified also e.g. via google maps:
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
ax = plt.axes(projection=ccrs.Mercator())
ax.set_extent([11.5, 12.5, 50, 50.7])
ax.add_feature(cfeature.LAND.with_scale('10m'), color='Bisque')
ax.add_feature(cfeature.LAKES.with_scale('10m'), alpha=0.5)
ax.add_feature(cfeature.BORDERS.with_scale('10m'), linewidth=0.2)
lats = [50.3182289, 50.2523744]
lons = [12.1010486, 12.0906336]
ax.plot(lons, lats, transform=ccrs.Geodetic(),
marker = '.', markersize=1, mfc = 'red', mew = 1, mec = 'red', ls = 'None')
plt.savefig('cartopy.png', dpi=200, bbox_inches='tight', pad_inches=0)
Any idea how to get cartopy plot the points on expected coordinates? Tried cartopy 0.18 and 0.20 with the same result.

Extract objects (fingerprint and signature) from an image using OpenCV and python

At my website I receive an image contains the user fingerprint and signature, I wan't to extract these two pieces of information.
for example:
Original Image
import os
import cv2
import numpy as np
def imshow(label, image):
cv2.imshow(label, image)
cv2.waitKey(0)
cv2.destroyAllWindows()
#read image
rgb_img = cv2.imread('path')
rgb_img = cv2.resize(rgb_img, (900, 600))
gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
Gray Image
#canny edge detection
canny = cv2.Canny(gray_img, 50, 120)
canny edge image
# Morphology Closing
kernel = np.ones((7, 23), np.uint8)
closing = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel)
Morphology Closing
# Find contours
contours, hierarchy = cv2.findContours(closing.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# Sort Contors by area and then remove the largest frame contour
n = len(contours) - 1
contours = sorted(contours, key=cv2.contourArea, reverse=False)[:n]
copy = rgb_img.copy()
# Iterate through contours and draw the convex hull
for c in contours:
if cv2.contourArea(c) < 750:
continue
hull = cv2.convexHull(c)
cv2.drawContours(copy, [hull], 0, (0, 255, 0), 2)
imshow('Convex Hull', copy)
Image divided to parts
Now my goals are:
Know which part is the signature and which is the fingerprint
Resolve the contours overlapping if exist
P.S: I'm not sure if the previous steps are final so please if you have better steps tell me.
These are some hard examples i may wanna deal with
You can use morphology for finger print and signature selecting.
By example:
import cv2
import numpy as np
img = cv2.imread('fhZCs.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
img=cv2.bitwise_not(img) #negate image
#color definition
blue_upper = np.array([130,255,255])
blue_lower = np.array([115,0,0])
#blue color mask (sort of thresholding, actually segmentation)
mask = cv2.inRange(hsv, blue_lower, blue_upper)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20,20))
finger=cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask2=cv2.morphologyEx(finger, cv2.MORPH_DILATE, kernel)
signature=cv2.compare(mask2, mask, cv2.CMP_LT)
signature=cv2.morphologyEx(signature, cv2.MORPH_DILATE, kernel)
signature=cv2.bitwise_and(img, img, mask=signature)
signature=cv2.bitwise_not(signature)
finger=cv2.bitwise_and(img, img, mask=finger)
finger=cv2.bitwise_not(finger)
cv2.imwrite('finger.png', finger)
cv2.imwrite('signature.png',signature)

cartopy: map overlay on NOAA APT image

I am working on a project trying to decode NOAA APT images, so far I reached the stage where I can get the images from raw IQ recordings from RTLSDRs. Here is one of the decoded images,
Decoded NOAA APT image this image will be used as input for the code (seen as m3.png here on)
Now I am working on overlaying map boundaries on the image (Note: Only on the left half part of the above image)
We know, the time at which the image was captured and the satellite info: position, direction etc. So, I used the position of the satellite to get the center of map projection and and direction of satellite to rotate the image appropriately.
First I tried in Basemap, here is the code
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
from scipy import ndimage
im = plt.imread('m3.png')
im = im[:,85:995] # crop only the first part of whole image
rot = 198.3913296679117 # degrees, direction of sat movement
center = (50.83550180700588, 16.430852851867176) # lat long
rotated_img = ndimage.rotate(im, rot) # rotate image
w = rotated_img.shape[1]*4000*0.81 # in meters, spec says 4km per pixel, but I had to make it 81% less to get better image
h = rotated_img.shape[0]*4000*0.81 # in meters, spec says 4km per pixel, but I had to make it 81% less to get better image
m = Basemap(projection='cass',lon_0 = center[1],lat_0 = center[0],width = w,height = h, resolution = "i")
m.drawcoastlines(color='yellow')
m.drawcountries(color='yellow')
im = plt.imshow(rotated_img, cmap='gray', extent=(*plt.xlim(), *plt.ylim()))
plt.show()
I got this image as a result, which seems pretty good
I wanted to move the code to Cartopy as it is easier to install and is actively being developed. I was unable to find a similar way to set boundaries i.e. width and height in meters. So, I modified most similar example. I found a function which would add meters to longs and lats and used that to set the boundaries.
Here is the code in Cartopy,
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
from scipy import ndimage
import cartopy.feature
im = plt.imread('m3.png')
im = im[:,85:995] # crop only the first part of whole image
rot = 198.3913296679117 # degrees, direction of sat movement
center = (50.83550180700588, 16.430852851867176) # lat long
def add_m(center, dx, dy):
# source: https://stackoverflow.com/questions/7477003/calculating-new-longitude-latitude-from-old-n-meters
new_latitude = center[0] + (dy / 6371000.0) * (180 / np.pi)
new_longitude = center[1] + (dx / 6371000.0) * (180 / np.pi) / np.cos(center[0] * np.pi/180)
return [new_latitude, new_longitude]
fig = plt.figure()
img = ndimage.rotate(im, rot)
dx = img.shape[0]*4000/2*0.81 # in meters
dy = img.shape[1]*4000/2*0.81 # in meters
leftbot = add_m(center, -1*dx, -1*dy)
righttop = add_m(center, dx, dy)
img_extent = (leftbot[1], righttop[1], leftbot[0], righttop[0])
ax = plt.axes(projection=ccrs.PlateCarree())
ax.imshow(img, origin='upper', cmap='gray', extent=img_extent, transform=ccrs.PlateCarree())
ax.coastlines(resolution='50m', color='yellow', linewidth=1)
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', edgecolor='yellow')
plt.show()
Here is the result from Cartopy, it is not as good as the result from Basemap.
I have following questions:
I found it impossible to rotate the map instead of the image, in
both basemap and cartopy. Hence I resorted to rotating the image, is
there a way to rotate the map?
How do I improve the output of cartopy? I think it is the way in
which I am calculating the extent a problem. Is there a way I can
provide meters to set the boundaries of the image?
Is there a better way to do what I am trying to do? any projection that are specific to these kind of applications?
I am adjusting the scale (the part where I decide the number of kms per pixel) manually, is there a way to do this based
on
satellite's altitude?
Any sort of input would be highly appreciated. Thank you so much for your time!
If you are interested you can find the project here.
As far as I can see, there is no ability for the underlying Proj.4 to define satellite projections with rotated perspectives (happy to be shown otherwise - I'm no expert!) (note: perhaps via ob_tran?). This is the main reason you can't do this in "native" coordinates/orientation with Basemap or Cartopy.
This question really comes down to a georeferencing problem, to which I couldn't find enough information in places like https://www.cder.dz/download/Art7-1_1.pdf.
My solution is entirely a fudge, but does get you quite close to referencing this image. I double the fudge factors are actually universal, which is a bit of an issue if you want to write general-purpose code.
Some of the fudges I had to make (trial-and-error):
adjust the satellite bearing by 3.2 degrees
adjust where the image centre is by moving it along the satellite trajectory by 10km
adjust where the image centre is by moving it perpendicularly along the satellite trajectory by 10km
scale the x and y pixel sizes by 0.62 and 0.65 respectively
use the "near-sided perspective" projection at an unrealistic satellite_height
The result is what appears to be a relatively well registered image, but as I say, seems unlikely to be generally applicable to all images received:
The code to produce this image (fairly involved, but complete):
import urllib.request
urllib.request.urlretrieve('https://i.stack.imgur.com/UBIuA.jpg', 'm3.jpg')
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
from scipy import ndimage
import cartopy.feature
im = plt.imread('m3.jpg')
im = im[:,85:995] # crop only the first part of whole image
rot = 198.3913296679117 # degrees, direction of sat movement
center = (50.83550180700588, 16.430852851867176) # lat long
import numpy as np
from cartopy.geodesic import Geodesic
import matplotlib.transforms as mtransforms
from matplotlib.axes import Axes
tweaked_rot = rot - 3.2
geod = Geodesic()
# Move the center along the trajectory of the satellite by 10KM
f = np.array(
geod.direct([center[1], center[0]],
180 - tweaked_rot,
10000))
tweaked_center = f[0, 0], f[0, 1]
# Move the satellite perpendicular from its proposed trajectory by 15KM
f = np.array(
geod.direct([tweaked_center[0], tweaked_center[1]],
180 - tweaked_rot + 90,
10000))
tweaked_center = f[0, 0], f[0, 1]
data_crs = ccrs.NearsidePerspective(
central_latitude=tweaked_center[1],
central_longitude=tweaked_center[0],
)
# Compute the center in data_crs coordinates.
center_lon_lat_ortho = data_crs.transform_point(
tweaked_center[0], tweaked_center[1], ccrs.Geodetic())
# Define the affine rotation in terms of matplotlib transforms.
rotation = mtransforms.Affine2D().rotate_deg_around(
center_lon_lat_ortho[0], center_lon_lat_ortho[1], tweaked_rot)
# Some fudge factors. Sorry - there are entirely application specific,
# perhaps some reading of https://www.cder.dz/download/Art7-1_1.pdf
# would enlighten these... :(
ff_x, ff_y = 0.62, 0.65
ff_x = ff_y = 0.81
x_extent = im.shape[1]*4000/2 * ff_x
y_extent = im.shape[0]*4000/2 * ff_y
img_extent = [-x_extent, x_extent, -y_extent, y_extent]
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection=data_crs)
ax.margins(0.02)
with ax.hold_limits():
ax.stock_img()
# Uing matplotlib's image transforms if the projection is the
# same as the map, otherwise we need to fall back to cartopy's
# (slower) image resampling algorithm
if ax.projection == data_crs:
transform = rotation + ax.transData
else:
transform = rotation + data_crs._as_mpl_transform(ax)
# Use the original Axes method rather than cartopy's GeoAxes.imshow.
mimg = Axes.imshow(ax, im, origin='upper', cmap='gray',
extent=img_extent, transform=transform)
lower_left = rotation.frozen().transform_point([-x_extent, -y_extent])
lower_right = rotation.frozen().transform_point([x_extent, -y_extent])
upper_left = rotation.frozen().transform_point([-x_extent, y_extent])
upper_right = rotation.frozen().transform_point([x_extent, y_extent])
plt.plot(lower_left[0], lower_left[1],
upper_left[0], upper_left[1],
upper_right[0], upper_right[1],
lower_right[0], lower_right[1],
marker='x', color='black',
transform=data_crs)
ax.coastlines(resolution='10m', color='yellow', linewidth=1)
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', edgecolor='yellow')
sat_pos = np.array(geod.direct(tweaked_center, 180 - tweaked_rot,
np.linspace(-x_extent*2, x_extent*2, 50)))
with ax.hold_limits():
plt.plot(sat_pos[:, 0], sat_pos[:, 1], transform=ccrs.Geodetic(),
label='Satellite path')
plt.plot(tweaked_center, 'ob')
plt.legend()
As you can probably tell, I got a bit carried away with this question. It is a super interesting problem, but not really a cartopy/Basemap one per-say.
Hope that helps!

Node attributes in for loops, NetworkX

I'm trying to model voting dynamics on networks, and would like to be able to create a graph in NetworkX where I can iterate the voter process on nodes, having their colour change corresponding to their vote 'labels'.
I've managed to get this code to let me see the attributes for each node, but how do I go about using those in a for loop to designate colour?
H = nx.Graph()
H.add_node(1,vote='labour')
H.add_node(2,vote='labour')
H.add_node(3,vote='conservative')
h=nx.get_node_attributes(H,'vote')
h.items()
Gives me the result:
[(1, 'labour'), (2, 'labour'), (3, 'conservative')]
I've got a for loop to do this type of colour coding based on the node number as follows, but haven't managed to make it work for my 'vote' status.
S=nx.star_graph(10)
colour_map=[]
for node in S:
if node % 2 ==0:
colour_map.append('blue')
else: colour_map.append('yellow')
nx.draw(S, node_color = colour_map,with_labels = True)
plt.show()
You can iterate the node attributes with H.nodes(data=True) which returns the node name and the node attributes in a dictionary. Here's a full example using your graph.
import networkx as nx
import matplotlib.pyplot as plt
H = nx.Graph()
H.add_node(1, vote='labour')
H.add_node(2, vote='labour')
H.add_node(3, vote='conservative')
color_map = []
for node, data in H.nodes(data=True):
if data['vote'] == 'labour':
color_map.append(0.25) # blue color
elif data['vote'] == 'conservative':
color_map.append(0.7) # yellow color
nx.draw(H, vmin=0, vmax=1, cmap=plt.cm.jet, node_color=color_map, with_labels=True)
plt.show()
This code will draw a different layout of nodes each time you run it (some layouts, as e.g. draw_spring, are available here).
Regarding colors, I use 0.25 for blue and 0.7 for yellow. Note that I use the jet matplotlib colormap and that I set vmin=0 and vmax=1 so that the color values are absolute (and not relative to eachother).
Output of the code above:
UPDATE:
I wasn't aware that you could simply use color names in matplotlib. Here's the updated for loop:
for node, data in H.nodes(data=True):
if data['vote'] == 'labour':
color_map.append("blue")
elif data['vote'] == 'conservative':
color_map.append("yellow")
And the updated draw command:
nx.draw(H, node_color=color_map, with_labels=True)
Note that this way you get different shades of blue and yellow than in the image above.

How to have 100% zoom factor withChaco

As an example, in chaco/examples/demo/basic/image_inspector.py, how to set the zoom factor such that 1 array point corresponds to 1 screen pixel (100% zoom). It seems that the ZoomTool methods (zoom_in, zoom_out, ...) only deal with zoom factor changes, not with absolute factor setting.
I would try something with plot.range2d.low, plot.range2d.high and plot.outer_bounds. The first two relate to data space, while the latter relates to the size of the picture area. By setting the limits of the data space using the picture area, you can map 1 pixel to 1 data unit. Here's an example, the interesting bit is in the _zoom_100_percent method:
import numpy as np
from chaco.api import Plot, ArrayPlotData
from chaco.tools.api import PanTool, ZoomTool
from enable.api import ComponentEditor
from traits.api import Button, HasTraits, Instance, on_trait_change
from traitsui.api import Item, View
class HundredPercentZoom(HasTraits):
plot = Instance(Plot)
zoom_button = Button('100% Zoom')
traits_view = View(
Item('plot', editor=ComponentEditor(), show_label=False),
'zoom_button',
width=800,
height=600,
)
def _plot_default(self):
t = np.linspace(0, 1000, 200)
y = 400 * (np.sin(t) + 0.1 * np.sin(t * 100))
plot = Plot(ArrayPlotData(t=t, y=y))
plot.plot(('t', 'y'))
plot.tools.append(PanTool(plot))
plot.tools.append(ZoomTool(plot))
return plot
#on_trait_change('zoom_button')
def _zoom_100_percent(self):
low = self.plot.range2d.low
bounds = self.plot.outer_bounds
print(bounds)
self.plot.range2d.high = (low[0] + bounds[0], low[1] + bounds[1])
if __name__ == "__main__":
hpz = HundredPercentZoom()
hpz.configure_traits()
I added a print statement in there so you can see that the plot area is different than the window area, which is 800x600. I also added a PanTool and ZoomTool, so you can pan around once zoomed in. You can go back to the orignal zoom state using the Escape key, as long as your plot has a ZoomTool.
The solution I have arrived to, starting from the original example image_inspector.py . A button allows to have a 100 % zoom factor around a point chosen as the zoom center.
All is in the _btn_fired method in class Demo.
There may still be a problem of 1 not being subtracted or added to some bounds or limits, as the button operation is not strictly involutive (a second press should not do anything) as it should.
Anything simpler?
#!/usr/bin/env python
"""
Demonstrates the ImageInspectorTool and overlay on a colormapped image
plot. The underlying plot is similar to the one in cmap_image_plot.py.
- Left-drag pans the plot.
- Mousewheel up and down zooms the plot in and out.
- Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular
region to zoom. If you use a sequence of zoom boxes, pressing alt-left-arrow
and alt-right-arrow moves you forwards and backwards through the "zoom
history".
- Pressing "p" will toggle the display of the image inspector overlay.
"""
# Major library imports
from numpy import linspace, meshgrid, pi, sin, divide, multiply
# Enthought library imports
from enable.api import Component, ComponentEditor
from traits.api import HasTraits, Instance, Button, Float
from traitsui.api import Item, Group, View, HGroup
# Chaco imports
from chaco.api import ArrayPlotData, jet, Plot
from chaco.tools.api import PanTool, ZoomTool
from chaco.tools.image_inspector_tool import ImageInspectorTool, \
ImageInspectorOverlay
#===============================================================================
# # Create the Chaco plot.
#===============================================================================
def _create_plot_component():# Create a scalar field to colormap
xbounds = (-2*pi, 2*pi, 600)
ybounds = (-1.5*pi, 1.5*pi, 300)
xs = linspace(*xbounds)
ys = linspace(*ybounds)
x, y = meshgrid(xs,ys)
z = sin(x)*y
# Create a plot data obect and give it this data
pd = ArrayPlotData()
pd.set_data("imagedata", z)
# Create the plot
plot = Plot(pd)
img_plot = plot.img_plot("imagedata",
xbounds = xbounds[:2],
ybounds = ybounds[:2],
colormap=jet)[0]
# Tweak some of the plot properties
plot.title = "My First Image Plot"
plot.padding = 50
# Attach some tools to the plot
plot.tools.append(PanTool(plot))
zoom = ZoomTool(component=plot, tool_mode="box", always_on=False)
plot.overlays.append(zoom)
imgtool = ImageInspectorTool(img_plot)
img_plot.tools.append(imgtool)
overlay = ImageInspectorOverlay(component=img_plot, image_inspector=imgtool,
bgcolor="white", border_visible=True)
img_plot.overlays.append(overlay)
return plot
#===============================================================================
# Attributes to use for the plot view.
size = (800, 600)
title="Inspecting a Colormapped Image Plot"
#===============================================================================
# # Demo class that is used by the demo.py application.
#===============================================================================
class Demo(HasTraits):
plot = Instance(Component)
center_x = Float
center_y = Float
btn = Button('100 %')
def _btn_fired(self):
img_plot, = self.plot.plots['plot0']
zoom_center = (self.center_x, self.center_y)
# Size of plot in screen pixels
plot_size = img_plot.bounds
# Zoom center in screen space
zoom_center_screen, = img_plot.map_screen(zoom_center)
# Get actual bounds in data space
low, high = (img_plot.index_mapper.range.low,
img_plot.index_mapper.range.high)
# Get data space x and y units in terms of x and y array indices
sizes = [item.get_size() for item in img_plot.index.get_data()]
(min_x, min_y), (max_x, max_y) = img_plot.index.get_bounds()
unit = divide((max_x - min_x, max_y - min_y), sizes)
# Calculate new bounds
new_low = zoom_center - multiply(zoom_center_screen, unit)
new_high = new_low + multiply(plot_size, unit)
# Set new bounds
img_plot.index_mapper.range.set_bounds(new_low,new_high)
traits_view = View(
Group(
Item('plot', editor=ComponentEditor(size=size),
show_label=False),
HGroup('center_x', 'center_y', 'btn'),
orientation = "vertical"
),
resizable=True, title=title
)
def _plot_default(self):
return _create_plot_component()
demo = Demo()
if __name__ == "__main__":
demo.configure_traits()