Here's the set up: I have a data frame, df, with columns labeled A,B,...,K. Each entry of column A is unique and will make up one of the two sets of vertices, call it X, in a bipartite graph, G. The entries of columns B,...,K (not all unique) make up the other set of vertices, call it Y, in the bipartite graph. We draw an edge from vertex y in Y to vertex x in X if y is in the same row as x.
Using this answer from another post, I have the following code which creates a bipartite graph with vertex sets given by the entries of column A (positioned on the right) and B (positioned on the left)
G = nx.Graph()
G.add_nodes_from(df['A'], bipartite=0)
G.add_nodes_from(df['B'], bipartite=1)
G.add_weighted_edges_from(
[(row['B'], row['A'], 1) for idx, row in df.iterrows()],
weight='weight')
pos = {node:[0, i] for i,node in enumerate(df['B'])}
pos.update({node:[1, i] for i,node in enumerate(df['A'])})
nx.draw(G, pos, with_labels = True)
plt.show()
I'm seeking advice/help with a few problems:
The number of vertices is large enough so that the vertices appear very bunched up. Is there a way of spreading out the vertices in each of the two vertex sets?
As I mentioned, this code makes a bipartite graph connecting some entries of B with some entries of A (again, based on row matching). How can I do this for each of the other columns (i.e. connecting elements of C,...,K with A in the same way)? I know there is a way to union graphs together with union(G1,G2) but I imagine there's a better way to achieve this.
I'd like to create some kind of edge coloring based on the degree of vertices in Y. I imagine the coloring will be implemented using the G.degree(), but I'm not sure how that works.
Please let me know if you have any suggestions for my problems. Thanks in advance!
Related
I am working on some shaders, and I need to transform normals.
I read in few tutorials the way you transform normals is you multiply them with the transpose of the inverse of the modelview matrix. But I can't find explanation of why is that so, and what is the logic behind that?
It flows from the definition of a normal.
Suppose you have the normal, N, and a vector, V, a tangent vector at the same position on the object as the normal. Then by definition N·V = 0.
Tangent vectors run in the same direction as the surface of an object. So if your surface is planar then the tangent is the difference between two identifiable points on the object. So if V = Q - R where Q and R are points on the surface then if you transform the object by B:
V' = BQ - BR
= B(Q - R)
= BV
The same logic applies for non-planar surfaces by considering limits.
In this case suppose you intend to transform the model by the matrix B. So B will be applied to the geometry. Then to figure out what to do to the normals you need to solve for the matrix, A so that:
(AN)·(BV) = 0
Turning that into a row versus column thing to eliminate the explicit dot product:
[tranpose(AN)](BV) = 0
Pull the transpose outside, eliminate the brackets:
transpose(N)*transpose(A)*B*V = 0
So that's "the transpose of the normal" [product with] "the transpose of the known transformation matrix" [product with] "the transformation we're solving for" [product with] "the vector on the surface of the model" = 0
But we started by stating that transpose(N)*V = 0, since that's the same as saying that N·V = 0. So to satisfy our constraints we need the middle part of the expression — transpose(A)*B — to go away.
Hence we can conclude that:
transpose(A)*B = identity
=> transpose(A) = identity*inverse(B)
=> transpose(A) = inverse(B)
=> A = transpose(inverse(B))
My favorite proof is below where N is the normal and V is a tangent vector. Since they are perpendicular their dot product is zero. M is any 3x3 invertible transformation (M-1 * M = I). N' and V' are the vectors transformed by M.
To get some intuition, consider the shear transformation below.
Note that this does not apply to tangent vectors.
Take a look at this tutorial:
https://paroj.github.io/gltut/Illumination/Tut09%20Normal%20Transformation.html
You can imagine that when the surface of a sphere stretches (so the sphere is scaled along one axis or something similar) the normals of that surface will all 'bend' towards each other. It turns out you need to invert the scale applied to the normals to achieve this. This is the same as transforming with the Inverse Transpose Matrix. The link above shows how to derive the inverse transpose matrix from this.
Also note that when the scale is uniform, you can simply pass the original matrix as normal matrix. Imagine the same sphere being scaled uniformly along all axes, the surface will not stretch or bend, nor will the normals.
If the model matrix is made of translation, rotation and scale, you don't need to do inverse transpose to calculate normal matrix. Simply divide the normal by squared scale and multiply by model matrix and we are done. You can extend that to any matrix with perpendicular axes, just calculate squared scale for each axes of the matrix you are using instead.
I wrote the details in my blog: https://lxjk.github.io/2017/10/01/Stop-Using-Normal-Matrix.html
Don't understand why you just don't zero out the 4th element of the direction vector before multiplying with the model matrix. No inverse or transpose needed. Think of the direction vector as the difference between two points. Move the two points with the rest of the model - they are still in the same relative position to the model. Take the difference between the two points to get the new direction, and the 4th element, cancels out to zero. Lot cheaper.
I'd like to compute the area inside of a curve defined by two vectors a and b. For your reference the curve looks something like this (pyplot.plot(a,b)):
I saw matplotlib has a fill functionality that let you fill the area enclosed by the curve:
I'm wondering, there's any way to obtain the area filled using that same function? It would be very useful as the other way I'm thinking of computing that area is through numerical integration, much more cumbersome.
Thank you for your time.
If you really want to find the area that was filled by matplotlib.pyplot.fill(a, b), you can use its output as follows:
def computeArea(pos):
x, y = (zip(*pos))
return 0.5 * numpy.abs(numpy.dot(x, numpy.roll(y, 1)) - numpy.dot(y, numpy.roll(x, 1)))
# pyplot.fill(a, b) will return a list of matplotlib.patches.Polygon.
polygon = matplotlib.pyplot.fill(a, b)
# The area of the polygon can be computed as follows:
# (you could also sum the areas of all polygons in the list).
print(computeArea(polygon[0].xy))
This method is based on this answer,
and it is not the most efficient one.
E.g., when processing the set of plane contours:
each one consists of N nodes and may be described by the matrix N*2
(x, y coordinates of every node).
In MATLAB it may be done with cell array Contours{}.
Every element corresponds to one contour and storeы the array of coordinates of the nodes.
What is the recommended object (data type) in Python for such set of contours ?
I've been trying to do this for a long time without success, so I'd better ask you.
First of all, I'm working on python 3 and networkx.
I have a bipartite graph as the image A, in which there are two types of nodes according to their 'group' attribute (group='R' and group='X'). Also, some relationships are reversible, as R4, and some are not (so I guess we would have to unfold the node in those cases).
What I need is to leave only the nodes of the R group and eliminate the X ones, but keeping the relations between them. That is, convert the green nodes into edges and keep a graph of only blue nodes.
Ohhh please!!, Can someone give me a hand?
Any help would be very welcome.
Thank you in advance wholeheartedly!
GRAPH IMAGE HERE:
https://media.springernature.com/full/springer-static/image/art%3A10.1038%2Fs41540-018-0067-y/MediaObjects/41540_2018_67_Fig1_HTML.png
Go over nodes of the graph, if the node is green add an edge between all its neighbours (which will only be blue). At the end remove all the green nodes.
to_remove = []
for node in G.nodes(data = True):
if node[1]["type"] == "Green": ## check if the node is green
to_remove.append(node[0])
## go over all neighbours of the node and add an edge between them
neighbours = list(G.neighbors(node[0]))
for i in range(0, len(neighbours)-1):
for j in range(i+1, len(neighbours)):
G.add_edge(neighbours[i],neighbours[j])
## remove the green nodes
G.remove_nodes_from(to_remove)
I am trying various visualizations for an Igraph in R (version.3.3.1).
Currently my visualizing is as shown as below, 2 nodes (blue and green) in circular layout.
Circular Layout
visNetwork(data$nodes,data$edges) %>% visIgraphLayout(layout="layout_in_circle")
Now I want to have a semicircle structure instead of a full circle as in the pic. All blue nodes form a semicircle, green nodes another semicircle. Each semicircle separated by a small distance as well. How can i achieve this. I found grid package has an option for semicircle, but i couldnt make it work with igraph. Please provide some pointers.
The layout argument accepts an arbitrary matrix with two columns and N rows if your graph has N vertices; all you need to do is to create a list of coordinates that correspond to a semicircle. You can make use of the fact that a vertex at angle alpha around a circle with radius r centered at (0, 0) is to be found at (r * cos(alpha), r * sin(alpha)). Since you are using R, alpha should be specified in radians, spaced evenly between 0 and pi (which corresponds to 180 degrees).