I'm wondering how, given contour lines generate trough the contour() function from Matplotlib, one can iterate to each level to get its vertices. I know that I can iterate over the paths with this code:
cs = plt.contour(x, y, (f - g))
for collection in cs.collections:
paths = collection.get_paths()
for path in paths:
print(path.vertices.shape)
plt.show()
However, how could I find the level of each path, or directly iterate over each level of a contour?
Thank you.
This is maybe very clear to you, but I would like to highlight that care is needed with the proposed code.
See also:
https://github.com/matplotlib/matplotlib/issues/367
Each path may be just an array of vertices corresponding to a single open or closed polygon, which is what most people expect, but a path may also correspond to 2 or more polygons if the member codes is set to indicate at which indices the polygons start. Naive use of the paths may not be what is wanted; often the use of path.to_polygons() is better.
In short, this code will work as expected on most simple examples but might cause problems for complex cases. A better alternative is:
cs = plt.contour(x, y, (f - g))
for collection in cs.collections:
for path in collection.get_paths():
print path.to_polygons()
Related
I am trying to write a script that will automatically mesh geometries for CFD analysis using the Gmsh Python API. There are a few issues I am running into:
First of all, I would like to be able to write Gmsh script files (.geo) for debugging purposes. I looked through the source code of the Gmsh API and found that the .geo_unrolled extension is supported for the gmsh.write() function, but not just .geo. This extension does the trick mostly, but it seems that any meshing operations (such as marking curves as transfinite) or transformations (such as dilate) are not written to the output file when using gmsh.write('test.geo_unrolled'). I assume this has something to do with the _unrolled part. But is there any way to get the full Gmsh script out of the API?
Secondly, when I try to make a copy of a spline like in this example:
p1 = gmsh.model.geo.addPoint(-1, 0.5, 0, 0.1)
p2 = gmsh.model.geo.addPoint(0, 1, 0, 0.1)
p3 = gmsh.model.geo.addPoint(1, 0.5, 0, 0.1)
s1 = gmsh.model.geo.addSpline([p1, p2, p3])
s2 = gmsh.model.geo.copy([s1])
I get ValueError: ('gmshModelGeoCopy returned non-zero error code: ', 1). The error code, 1, seems to indicate that the tag of the original spline (s1) cannot be found when copy() is called. Am I missing something here? I have tried, for example, to call gmsh.model.geo.synchronize() before attempting to call copy(), but this had no effect.
Finally, when I use the dilate transformation in the Gmsh GUI using Modules - Geometry - Elementary entities - Transform - Scale, checking the Apply scaling on copy option in the dialog, on the example spline from above, I indeed get a scaled version of the curve as expected, including the three points. Assuming I was able to accomplish the same with the API, how do I then refer to the three new points that the scaled spline goes through, for example, if I wanted to draw a line between the start point of the original spline and that of the scaled spline?
In the end, what I want to accomplish is the following: draw a spline through a list of points, create a scaled copy of this spline, draw lines between the start and end points, and create a plane surface bounded by the two splines and lines. Is there a better way to do this than what I am trying to do with the dilation?
It's probably too late, but you never know.
I've never had to create .geo files using the API. But I found this discussion in the Gmsh mailing list archive, which may be helpful.
Regarding your error with copy, you have to specify the dimension of the entity to be copied, and not just the tag (check the documentation, which refers to dimTag). It's the same thing with transformations such as rotate, symmetrize etc. Using the following should work:
s2 = gmsh.model.geo.copy([(1, s1)])
NB: when copying only one entity, I think either the inner parentheses or the brackets are superfluous, and otherwise you have to provide a list of tuples of the form [(dim_1, tag_1), (dim_2, tag_2), ..., (dim_n, tag_n)].
Keep in mind that copy will return a variable of the same kind (list of tuples), i.e. in your case the variable s2 will be [(1, tag_s2)]. Therefore you might not want to use the same kind of variable name, since in order to get the tag you'll have to use s2[0][1] instead of simply s2.
Here you have a partial answer to the following question, as the tags of copied entities will be contained in your return variable.
Hope that helps you or others!
I'm learning how to use Python and Basemap and would like to create a loop that produces a map of each projection type.
The projection types are: cea, mbtfpq, aeqd, sinu, poly, etc. So I just want a loop that does Basemap(width=x, height=y, projection=[projection type], ...) but can't figure out how to return the actual types of possible projections.
So far I've tried things like
proj = Basemap()
print(dir(proj))
and
proj = Basemap().projection
print(dir(proj))
but neither returns the types of projections it could be. I tried
for value in Basemap().projection:
print (value)
But it just returned
c
y
l
and that's it.
Closest I've gotten is
for value in Basemap().__dict__.items():
print (value)
but that returns a lot of info, seemingly the default values, but one of them is cyl, which is the default projection. I'm getting close but can't see how to iterate through each projection.
(My semantics are incorrect, so please correct me if I'm wrong!)
Edit: I'd like to learn how to do this without "cheating", i.e. since I know the types of projections possible, load those into an array and loop through the array. I'm trying to learn how to do it if I didn't know the possible values.
There's no need to cheat; looking at the source, you have a supported_projections list that contains all supported projections. You can just use that.
I have made a three way venn diagram. I have three issues with it that I can't seem to solve.
What is the code to move the circle labels (i.e."Set1","Set2","Set3") because right now one is too far away from the circle.
What is the code to make the circles be three equal sizes/change the circle size?
What is the code to move the circles around the plot. Right now, set2 is within set3 (but coloured differently), I would like the diagram to look more like the "standard" way of showing a venn diagram (i.e. 3 separate circles with some overlap in the middle).
On another note, I found it difficult to find what the commands such as "set_x", "set_alpha" should be; if anyone knew of a manual that would answer by above questions I would appreciate it, I couldn't seem to find one place with all the information I needed.
import sys
import numpy
import scipy
from matplotlib_venn import venn3,venn3_circles
from matplotlib import pyplot as plt
#Build three lists to make 3 way venn diagram with
list_line = lambda x: set([line.strip() for line in open(sys.argv[x])])
set1,set2,set3 = list_line(1),list_line(2),list_line(3)
#Make venn diagram
vd = venn3([set1,set2,set3],set_labels=("Set1","Set2","Set3"))
#Colours: get the HTML codes from the net
vd.get_patch_by_id("100").set_color("#FF8000")
vd.get_patch_by_id("001").set_color("#5858FA")
vd.get_patch_by_id("011").set_color("#01DF3A")
#Move the numbers in the circles
vd.get_label_by_id("100").set_x(-0.55)
vd.get_label_by_id("011").set_x(0.1)
#Strength of color, 2.0 is very strong.
vd.get_patch_by_id("100").set_alpha(0.8)
vd.get_patch_by_id("001").set_alpha(0.6)
vd.get_patch_by_id("011").set_alpha(0.8)
plt.title("Venn Diagram",fontsize=14)
plt.savefig("output",format="pdf")
What is the code to move the circle labels (i.e."Set1","Set2","Set3") because right now one is too far away from the circle.
Something like that:
lbl = vd.get_label_by_id("A")
x, y = lbl.get_position()
lbl.set_position((x+0.1, y-0.2)) # Or whatever
The "A", "B", and "C" are predefined identifiers, denoting the three sets.
What is the code to make the circles be three equal sizes/change the circle size?
If you do not want the circle/region sizes to correspond to your data (not necessarily a good idea), you can get an unweighted ("classical") Venn diagram using the function venn3_unweighted:
from matplotlib_venn import venn3_unweighted
venn3_unweighted(...same parameters you used in venn3...)
You can further cheat and tune the result by providing a subset_areas parameter to venn3_unweighted - this is a seven-element vector specifying the desired relative size of each region. In this case the diagram will be drawn as if the region areas were subset_areas, yet the numbers will be shown from the actual subsets. Try, for example:
venn3_unweighted(...., subset_areas=(10,1,1,1,1,1,1))
What is the code to move the circles around the plot.
The need to "move the circles around" is somewhat unusual - normally you would either want the circles to be positioned so that their intersection sizes correspond to your data, or use the "default" positioning. The functions venn3 and venn3_unweighted cater to those two requirements. Moving circles around arbitrarily is possible, but would require some lower-level coding and I'd advice against that.
I found it difficult to find what the commands such as "set_x", "set_alpha" should be
The object you get when you call v.get_label_by_id is a Matplotlib Text object. You can read about its methods and properties here. The object returned by v.get_patch_by_id is a PathPatch, look here and here for reference.
I would like to find all vertices (vertex id's) sharing the same edge attribute (so there can be tons of vertices like this) by using Igraph. This would be very convenient when I want to find all "villages" (the vertices of my graph) on a "road", let's say "Route 69" (an edge attribute).
Is there a simple way in Igraph to do this? Maybe I've overcomplicated it.
Actually what I need is the opposite of: g.es.select(_within=g.vs[2:5]) or
>>> men = g.vs.select(gender="m")
>>> women = g.vs.select(gender="f")
>>> g.es.select(_between=(men, women))
because I know the edge attribute but I don't know the vertices.
I will select the edge and hope that it will return all related vertices.
Maybe I'm only tired now, but I don't find my way around this problem. I appreciate if somebody helps me out with the right way. Or maybe there is a method I miss in tutorial and documentation. It smells like there is a very simple method to this. Thank you in advance for any advice!
First, select all the edges on Route 69:
edges = g.es.select(name="Route69")
Then iterate through the selected edges and collect the endpoints of the vertices:
vertices = set()
for edge in edges:
vertices.update(edge.tuple)
This will give you a set containing the vertex IDs of all the vertices that are incident on at least one edge with name Route69. If you need a VertexSeq, you can simply do this:
vertices = g.vs[sorted(vertices)]
You should be able to do the following:
r69edges = g.es.select(name_eq='Route69') #Select all edges where name=='Route69'
sg = r69edges.subgraph() #Create a subgraph containing only the selected edges (and attached vertices)
village_verts = sg.vs.select(name_eq='villages') #Select the vertices where name=='villages'
This assumes that 'villages' and 'Route69' are stored in an attribute called 'name' on the vertices and edges... Adjust appropriately to match your attributes.
Of course - you can squash this all into one line if you want:
village_verts = g.es.select(name_eq='Route69').subgraph().vs.select(name_eq='villages')
Not sure if this is the most efficient way (though I'm not seeing any shortcuts in the documentation), but it should get you what you're after.
I have a Graph in Python like this one:
# Each element is a tuple with coordinates (x,y,z).
# The index is the id of the vertex
vertexList = [(0,0,0),(1,0,0),(1,1,0),(0,1,0),
(0,0,1),(1,0,1),(1,1,1),(0,1,1)]
# Each element is a tuple with the vertex-ids and a weight (vertexId1, vertexId2, weight)
edgeList = [(0,1,1), (1,2,1), (2,3,1), (3,0,1),
(0,4,1),
(4,5,1), (5,6,1), (6,7,1), (7,4,1)]
graph = (vertexList, edgeList)
This is a small example. The application I wrote uses graphs with about 100 vertexes and 300 edges.
I would like to visualize this with python, preferably with a library which is available for Ubuntu. It would be great if it were possible to move the graph in the 3D-visualisation.
What I've done so far
At the moment I use UBIGRAPH. The visualization and interaction is very good, but I can't specify coordinates for the vertexes:
def visulizeGraph(Graph):
vertexList, edgeList = Graph
server_url = 'http://127.0.0.1:20738/RPC2'
server = xmlrpclib.Server(server_url)
G = server.ubigraph;
G.clear()
for identifier, vertex in enumerate(vertexList):
G.new_vertex_w_id(identifier)
for vertex1, vertex2, weight in edgeList:
x1, y1, z1 = vertexList[vertex1]
x2, y2, z2 = vertexList[vertex2]
G.new_edge(vertex1, vertex2)
matplot
I've found matplotlib, but its very big. I didn't find an example which does what I like, but I might have missed it. Its available for Ubuntu.
vtk
The same problem as with matplot. If you could give me some working examples it might be the best solution.
When you looked at matplotlib, did you see mplot3d? This may be what you require.
MPlot3D
If not, I'm sorry I probably can't help any more than that.
I've not used this myself yet (beyond running example scripts) but mayavi2 looks promising. It comes bundled with the enthought python distribution.
Also, a little of topic as it's not in your question, but networkx is pretty nice if your working with graphs in python.
Hope this helps a bit.