This is a very specific inforgraphic challange altough the fundemental question is how do you build archs between words using matplotlib, cario or an other python libary.
Given a the following data structure.
me, you, 7 |
me, apple, 9 |
apple, you, 1 |
bike, me, 5
Names would be displayed horizontally the names with the most relationships larger than the others and then there would be weighted archs between the names. A 10 weighted arch would be twice as thick as a 5 weighted arch.
Inspiration comes from: similar diverstiy. http://similardiversity.net/
Let the challange commence!
matplotlib isn't the right library here, since it's not a general purpose graphics library. What you need here is either something like Cairo, or much simpler, you can do with the graphics capabilities of any GUI toolkit, such as PyQt. Another feasible approach is PyGame, which has good drawing capabilities as well.
If you want an example, see this Cairo samples page, the first sample - arc. You just write the text words and then use the arc code for an arc of any width and color between them.
There are several libraries, at least one of which relies on Matplotlib, that will do what you want. I recommend Networkx (www.networkx.lanl.gov) to build your graph structure, and which you can then use to call the relevant Matplotlib methods to plot. Networkx and Matplotlib work very well together.
import networkx as NX
import matplotlib.pyplot as PLT
Gh = NX.Graph()
Gh.add_edge("You", "Bike", weight=1.0)
Gh.add_edge("Bike", "Apple", weight=0.9)
Gh.add_edge("Me", "Bike", weight=1.1)
all_nodes = Gh.nodes()
# to scale node size with degree:
scaled_node_size = lambda(node) : NX.degree(Gh, node) * 700
position = NX.spring_layout(Gh) # just choose a layout scheme
NX.draw_networkx_nodes(Gh, position, node_size=map(scaled_node_size, all_nodes))
NX.draw_network_edges(Gh, position, Gh.edges(), width=1.0, alpha=1.0, edge_color="red")
# now for the Matplotlib part:
PLT.axis("off")
PLT.show()
As you can see, you could scale the edges by applying a factor to vary the 'weight' parameter to any of the 'edge' methods, just the same way as i did it for node scaling.
I would also recommend pygraphviz (obviously using graphviz as its backend). It is very similar to Netwworkx (same lead developer).
I don't really see where the difficulty or challenge is. All you need is a graphics library that can draw text and half circles, which is possible in pretty much everything. There is no need for Bezier curves. For example you could simply create an SVG file (then you don't even need any library and can nicely embed this in a webpage and use some JavaScript to make it interactive).
The actual plotting is simple: the center of a circle is in the middle between the two words, the radius is half the distance between them. You can then adjust the stroke to reflect other quantities.
Related
I would like to know how best to generate a schematic diagram, something like this, from a graph (created using the Python NetworkX library) that contains the latitude and longitude of each node (city) and the lines connecting them in the Indian railway network.
The cities (nodes) should be located reasonably close to their actual position, but not necessarily exactly. I am OK with using the plate carrée projection that simply maps lat/long onto X/Y in the diagram.
The rail lines (edges) can be straight lines or even curves if it fits better.
On the diagram should be displayed the cities (preferably as dots) along with a short (max 4 characters) label for each, the lines connecting them, and a single label for each line (the given example has quite long labels for the lines).
Preferably the amount of manual tweaking of coordinates to get things to fit should be minimised.
Using Graphviz was my first idea. But I don't know how well neato/fdp (required for fixed positioning of nodes) will perform with large numbers of nodes/edges. Also, making Graphviz display labels separately outside the nodes (rather than inline) seems to need a lot of manual positioning of each label, which would be pretty boring. Is there any better way to get this kind of layout?
Doable (https://forum.graphviz.org/t/another-stupid-graphviz-trick-geographic-graphs/256), but does not seem to use many Graphviz features. In addition to tools mentioned in the link, maybe consider pikchr (https://pikchr.org/home/doc/trunk/homepage.md)
I need to create a complex image with lanes (like a cross functional flowchart). Is it possible to use Graphviz to automatically (based on a csv file) generate something like the picture below? If not, how can I achieve that?
Technically, Graphviz could probably do it, but the spline connecting the 12 triangular nodes would be the only "easy" part of the effort. For everything else, you would explicitly position/draw the nodes, swimlanes, and arrow edges. Ugh!
The dpic variant of the pic language is closer fit, but I don't think it supports rotated text
I'd look at TikZ, Asymptote, and/or straight SVG
I don't know what your input file looks like, but the mapping to your output language will be challenging. Good luck.
You could probably render some of it in Graphviz, such as in the cluster example, but Graphviz isn't really suited to this type of diagram. Its strength is directed graphs and hierarchical info.
Have a look at some of the declarative graphics libraries such as Altair or Matplotlib or Plotly. There is various levels of support for plotting axes in the style of lanes, then the rest is mostly textual annotations.
I'm plotting netowrk graphs (Water distribution networks) using bokeh and or matplotlib. From the reference software the plots look like this:
As you can see pumps and water towers have their own little symbols.
I'm using matplotlib and bokeh to plot the same graphs (with a little more info on the system state):
As you can see we have squares and triangles as symbols now. So I would like to either add my own symbols based on some vector graphic of the symbols in the first plot, or at least rotate the triangles to be aligned with the arcs, such that they point along them. Any ideas on how to achieve either? I find the bokeh documentation rather confusing (as you can tell I'm a civil engineer not a programmer)
Instead of rotating the triangle, you may consider arrows.
If you really want to rotate the triangle, I normally rotate the three points of the triangle around its center (by rotation matrix).
About custom symbols, I have never import any external symbols into my matplotlib figure. I usually create the symbol as a polygon and then draw it using the polygon patches.
Hope it helps.
I am trying to visualize graphs generated from networkx, using d3py.
I used the example provided (https://github.com/mikedewar/d3py/blob/master/examples/d3py_graph.py) but all I get is the graph without node names, how do I plot node names as well?
Also, how do I change edge and node colors?
Here is a partial answer, but also read the caveat at the end.
The easiest thing is changing the node colour. If you run the example you pointed to with
with d3py.NetworkXFigure(G, width=500, height=500) as p:
p += d3py.ForceLayout()
p.css['.node'] = {'fill': 'blue', 'stroke': 'magenta'}
p.show()
then you will have blue nodes with a magenta outline (you can use any html colour you like).
For edge colour, there is a hardcoded stroke: black; in the file d3py/geoms/graph.py. You can comment it out and reinstall d3py
line = {
"stroke-width": "1px",
"stroke": "black",
}
self.css[".link"] = line
Then you can specify edge colour and width as follows:
with d3py.NetworkXFigure(G, width=500, height=500) as p:
p += d3py.ForceLayout()
p.css['.node'] = {'fill': 'blue', 'stroke': 'magenta'}
p.css['.link'] = {'stroke': 'red', 'stoke-width': '3px'}
p.show()
There does not seem to be any way to add node labels easily with d3py. Using just d3.js, it can be done relatively easily (see this example). Which leads us to the major caveat...
Caveat
As #flup already mentioned, d3py does not seem really mature (the code from their Github repository does not even run the NetworkX example, there is a missing host parameter in networkx_figure.py). There has been no activity in the repo since a couple of months, so I guess the project is maybe abandoned. You could probably reach your goal much more easily using d3.js directly.
Just in case anyone ends up here looking around at d3py. I made d3py a couple of years ago now to see what it would feel like to plot d3 graphics from Python. It was fun! But I didn't have the time to do it properly, which was a shame.
However, Rob Story did! He made vincent, which is available at https://github.com/wrobstory/vincent. It's a much better implementation, and is much better thought out. Please do check it out!
Drawing 'static' graphs with networkx.
I would suggest trying mathplotlib.
networkx itself recommends using matplotlib as a plotting supplement.
It is easy to use and draws really nice graphs.
Say you have a networkx Graph "G". You can just plot it in 3 lines of code.
>>> import matplotlib.pyplot as plt
>>> nx.draw(G)
>>> plt.show()
Further, there is a flexibility of choosing between different layouts.
>>> nx.draw_random(G)
>>> nx.draw_circular(G)
>>> nx.draw_spectral(G)
Using an nx.draw*(G) command does not render the graph, until you use the plt.show().
It is as a "plot in the mind" or an abstract representation which you could customize before really rendering it.
Drawing interactive javascript / html5 graphs-
matplotlib is useful to draw static graphs. If you want to plot interactive Javascript graphs, then here are some interesting libraries (including D3.js)
d3.js
arbor.js
cytoscape.js
raphael.js
This libraries are independent and their use with networkx is generally more useful in web applications where networkx code resides in the backend and the Javascript code lies in the front end.
I have to draw graphs along with edges according to a file input by the user. I am using wxPython for the same.
Once the positions are clear I can easily create circles and edges between the nodes but
I have a problem that given a panel to draw on is there any way I can get to know optimum positions for the vertices to be if I know the number of vertices ?
By optimum I mean simply that its readable what has been drawn and written along with it.....
So say that I have to draw 3 vertices I just want that I am able to clearly get the coordinates of where to place the nodes and if I can make the system automated....
Please help ....
You want a Graph Drawing algorithm. There is ongoing research in this area, but a simple force-directed algorithm can give good results for small graphs. Look at this wikipedia article for the algorithm. You can also get some open source libraries that handle this problem, like NodeBox and Graphvis.
Also a good lib: igraph
It offers a nice collection of layout algorithms