mayavi: two surfaces obstruct each other, even though they are non-intersecting - python

I am trying to plot two surfaces which touch at exactly two points but are otherwise well separated. Depending on the viewing angle, this renders either just fine (figure 1) or it makes some mess with the top surface s2 (plasma, red) obstructing the lower one s1 (figure 2). I suppose that is due to the order in which the surfaces are plotted, so mayavi just puts one in front even though mathematically it should be in the back. How can I solve this issue? Note that I would like to have different colormaps for both surfaces, as they represent different things. Thanks a lot!
figure 1, correct plot
figure 2, wrong plot
Here the code to produce the plot. Viewing angles were chosen in the interactive window, not sure how to get the numerical values.
import numpy as np
import mayavi.mlab
x,y = np.mgrid[-np.pi:np.pi:0.01, -np.pi:np.pi:0.01]
def surface1(x,y):
return -np.sqrt((np.cos(x) + np.cos(y) - 1)**2 + np.sin(x)**2)
def surface2(x,y):
return np.sqrt((np.cos(x) + np.cos(y) - 1)**2 + np.sin(x)**2)
s1 = mayavi.mlab.surf(x,y,surface1, colormap='viridis')
s2 = mayavi.mlab.surf(x,y,surface2, colormap='plasma')
mayavi.mlab.show()
EDIT:
Finally found the issue: Need to specify the correct backend for rendering. Using ipython3 --gui=qt solves the issue. Thus the issue only appears when using the default backend (whichever that is). I wish this would be documented more clearly somewhere, would have saved me a lot of work.

Related

graph-tool fit_view and output size

Here is basic script I use for drawing:
from graph_tool.all import *
g = load_graph("data.graphml")
g.set_directed(False)
pos = sfdp_layout(g)
graph_draw(g, pos=pos, output_size=(5000, 5000), vertex_text=g.vertex_index, vertex_fill_color=g.vertex_properties["color"], edge_text=g.edge_properties["name"], output="result.png")
Main problems here are ugly edge text and vertexes that are too close to parent. As I understand this happens because by default fit_view=True and result image scaled to fit size. When I set fit_view=False result image doesn't have graph (I see only little piece).
Maybe I need another output size for fit_view=False or some additional steps?
Today I ran into the same problem.
It seems that you can use fit_view=0.9, and by using a float number yo can scale the fit. In that case it would appear 90% than the normal size. If you use 1, will be the same size.
Hope it helps.

Equal Height subplots in matplotlib

I have a script that generates two plots side by side of two aspects of the same quantity. It's fairly long, so this is only the relevant (I believe) portion. The left hand plot is called by the function "plot_shearsticks2"
Depending on what data I'm plotting, the left hand plot may have slightly different dimensions, but I would like the two to have the same height always, and if the left hand one is wider, that's fine (and usually it ought to). Here is the relevant portion:
import matplotlib.pyplot as plt
figr = plt.figure(i,figsize=(11, 5))
fig=figr.add_subplot(121,aspect='equal')
figr.subplots_adjust(wspace=0.3)
shearplot = plot_shearsticks2(cat.data,[imoments[0],imoments[1],imoments[2],imoments[3],imoments[4]],scale_factor,'-k')
fig=figr.add_subplot(122,aspect='equal')
figr = plt.figure(i,figsize=(11, 5))
And below this, there are some instructions for making the right hand plot, but nothing that seems to indicate anything about how tall it is. Tinkering with the options in add_subplot, doesn't seem to have any effect -- the left hand side is always smaller for some reason. Any idea how to make them equal heights?
I always find it easier to ise the axes funciton. For example:
import pylab as pl
pl.figure(figsize=(4,3))
pl.axes([0.2, 0.2, 0.75, 0.35 ])
pl.axes([0.2, 0.55, 0.75, 0.35 ])
This way you have the ability to control the axis properties very accurately, and even partially/fully overlay one over the other. This gives you significant advantage over the subplot function.
Ended up redoing everything with GridSpec, and specifying plot heights with gs = gridspec.GridSpec(1,2,height_ratios=[1],width_ratios=[ratioxy,1]), having defined ratioxy with ratioxy=widthx/heighty

Simple arrow mayavi/tvtk in mlab weird behaviour (looks like a bug)

I am trying to do a simple arrow in mlab to point to different areas on the graph.
Consider this example:
fig = mlab.figure( bgcolor=(0, 0, 0))
b=visual.Box(x=0, y=10, z=10)
visual.set_viewer(fig)
b=visual.Box(x=0, y=10, z=10)
b2=visual.Box(x=10,y=10,z=10, color=(0,0,1))
a=visual.Arrow(x=10,y=10,z=10, color=(1,0,0))
So in my mind the arrow should appear from the blue box, however it lives it's own misterious life and is located absolutely off. That is very strange that boxes are located and bound to the grid (so if I put b to x=10,y=10,z=10 the two boxes will be collocated), however the arrow is not. Is this a bug or a feature?
Update:
I was playing around trying to fix the above and found the behaviour of the arrow very weird. This is what I do (in ipython for interaction):
from mayavi import mlab
from tvtk.tools import visual
fig=mlab.figure( bgcolor=(0, 0, 0))
visual.set_viewer(fig)
First put the box somewhere on canvas as a reference:
b=visual.Box(x=10,y=4,z=1)
Then I want an arrow sticking out of the box:
a=visual.Arrow(x=10,y=4,z=1)
Didn't work out (same as the first part of the question):
Now, let's change length of the cone without reason
a.length_cone
returns
0.35
Let's change it
a.length_cone=0.5
Now the arrow is sticking out of the box as it should be
Change length of the cone back to 0.35 to see if this changes the arrow back to wrong position
a.length_cone=0.35
No, the arrow stays in the box where it should be. This looks like a bug.
Playing around with arrow, I wrote the following function to generate an arrow from x1,y1,z1 to x2,y2,z2
def Arrow_From_A_to_B(x1, y1, z1, x2, y2, z2):
ar1=visual.arrow(x=x1, y=y1, z=z1)
ar1.length_cone=0.4
arrow_length=np.sqrt((x2-x1)**2+(y2-y1)**2+(z2-z1)**2)
ar1.actor.scale=[arrow_length, arrow_length, arrow_length]
ar1.pos = ar1.pos/arrow_length
ar1.axis = [x2-x1, y2-y1, z2-z1]
return ar1
Seems like ArrowSource doesn't allow for arrows extending beyond a short distance. It doesn't seem very useful at all. mlab functions like quiver3d return glyphs based on PolyDataSource instead.
This will plot two boxes and an arrow between them. I'm not sure if there's a simple way to do it with quiver3d which is definitely based off of PolyDataSource but may not have the same structure somehow.
b1=visual.Box()
b2=visual.Box(x=10)
v=mlab.pipeline.vectors(mlab.pipeline.vector_scatter(0,0,0,10,0,0)) #xyzuvw
v.glyph.glyph.clamping=False
Also, the behavior you encountered with ArrowSource doesn't seem like a bug, it's more like a minor feature that wasn't really developed.

How do I add a scale bar to a plot in Mayavi2/VTK?

I would like to add a scale bar (showing how big a micron is for example) to a mayavi plot I create with mlab.
For example, referencing this question: How to display a volume with non-cubic voxels correctly in mayavi
I can set the voxel size of a plot by using
from enthought.mayavi import mlab
import numpy as np
s=64
x,y,z = np.ogrid[0:s,0:s,0:s/2]
volume = np.sqrt((x-s/2)**2 + (y-s/2)**2 + (2*z-s/2)**2)
grid = mlab.pipeline.scalar_field(data)
grid.spacing = [1.0, 1.0, 2.0]
contours = mlab.pipeline.contour_surface(grid,
contours=[5,15,25], transparent=True)
mlab.show()
I would like an automated way of adding a some indicator of what the scale of the object I am showing is. Right now I am adding scale bars by hand with inkscape to exported images, but there has to be a better way.
A straightforward mayavi way would be most helpful, but if there is anything in vtk that would do it, I can always use mayavi's wrapper.
Something like text3d will let me add text, and then I suppose I could figure out how to draw a line as well and compute the correct scaling by hand, but I am hoping there is an easier way.
Try the following:
mlab.axes()
mlab.outline()
mlab.colorbar()
This reference: http://github.enthought.com/mayavi/mayavi/auto/mlab_reference.html would help as would the several examples.

Rasterizing a GDAL layer

Edit
Here is the proper way to do it, and the documentation:
import random
from osgeo import gdal, ogr
RASTERIZE_COLOR_FIELD = "__color__"
def rasterize(pixel_size=25):
# Open the data source
orig_data_source = ogr.Open("test.shp")
# Make a copy of the layer's data source because we'll need to
# modify its attributes table
source_ds = ogr.GetDriverByName("Memory").CopyDataSource(
orig_data_source, "")
source_layer = source_ds.GetLayer(0)
source_srs = source_layer.GetSpatialRef()
x_min, x_max, y_min, y_max = source_layer.GetExtent()
# Create a field in the source layer to hold the features colors
field_def = ogr.FieldDefn(RASTERIZE_COLOR_FIELD, ogr.OFTReal)
source_layer.CreateField(field_def)
source_layer_def = source_layer.GetLayerDefn()
field_index = source_layer_def.GetFieldIndex(RASTERIZE_COLOR_FIELD)
# Generate random values for the color field (it's here that the value
# of the attribute should be used, but you get the idea)
for feature in source_layer:
feature.SetField(field_index, random.randint(0, 255))
source_layer.SetFeature(feature)
# Create the destination data source
x_res = int((x_max - x_min) / pixel_size)
y_res = int((y_max - y_min) / pixel_size)
target_ds = gdal.GetDriverByName('GTiff').Create('test.tif', x_res,
y_res, 3, gdal.GDT_Byte)
target_ds.SetGeoTransform((
x_min, pixel_size, 0,
y_max, 0, -pixel_size,
))
if source_srs:
# Make the target raster have the same projection as the source
target_ds.SetProjection(source_srs.ExportToWkt())
else:
# Source has no projection (needs GDAL >= 1.7.0 to work)
target_ds.SetProjection('LOCAL_CS["arbitrary"]')
# Rasterize
err = gdal.RasterizeLayer(target_ds, (3, 2, 1), source_layer,
burn_values=(0, 0, 0),
options=["ATTRIBUTE=%s" % RASTERIZE_COLOR_FIELD])
if err != 0:
raise Exception("error rasterizing layer: %s" % err)
Original question
I'm looking for information on how to use osgeo.gdal.RasterizeLayer() (the docstring is very succinct, and I can't find it in the C or C++ API docs. I only found a doc for the java bindings).
I adapted a unit test and tried it on a .shp made of polygons:
import os
import sys
from osgeo import gdal, gdalconst, ogr, osr
def rasterize():
# Create a raster to rasterize into.
target_ds = gdal.GetDriverByName('GTiff').Create('test.tif', 1280, 1024, 3,
gdal.GDT_Byte)
# Create a layer to rasterize from.
cutline_ds = ogr.Open("data.shp")
# Run the algorithm.
err = gdal.RasterizeLayer(target_ds, [3,2,1], cutline_ds.GetLayer(0),
burn_values=[200,220,240])
if err != 0:
print("error:", err)
if __name__ == '__main__':
rasterize()
It runs fine, but all I obtain is a black .tif.
What's the burn_values parameter for ? Can RasterizeLayer() be used to rasterize a layer with features colored differently based on the value of an attribute ?
If it can't, what should I use ? Is AGG suitable for rendering geographic data (I want no antialiasing and a very robust renderer, able to draw very large and very small features correctly, possibly from "dirty data" (degenerate polygons, etc...), and sometimes specified in large coordinates) ?
Here, the polygons are differentiated by the value of an attribute (the colors don't matter, I just want to have a different one for each value of the attribute).
EDIT: I guess I'd use qGIS python bindings: http://www.qgis.org/wiki/Python_Bindings
That's the easiest way I can think of. I remember hand rolling something before, but it's ugly. qGIS would be easier, even if you had to make a separate Windows installation (to get python to work with it) then set up an XML-RPC server to run it in a separate python process.
I you can get GDAL to rasterize properly that's great too.
I haven't used gdal for a while, but here's my guess:
burn_values is for false color if you don't use Z-values. Everything inside your polygon is [255,0,0] (red) if you use burn=[1,2,3],burn_values=[255,0,0]. I'm not sure what happens to points - they might not plot.
Use gdal.RasterizeLayer(ds,bands,layer,burn_values, options = ["BURN_VALUE_FROM=Z"]) if you want to use the Z values.
I'm just pulling this from the tests you were looking at: http://svn.osgeo.org/gdal/trunk/autotest/alg/rasterize.py
Another approach - pull the polygon objects out, and draw them using shapely, which may not be attractive. Or look into geodjango (I think it uses openlayers to plot into browsers using JavaScript).
Also, do you need to rasterize? A pdf export might be better, if you really want precision.
Actually, I think I found using Matplotlib (after extracting and projecting the features) was easier than rasterization, and I could get a lot more control.
EDIT:
A lower level approach is here:
http://svn.osgeo.org/gdal/trunk/gdal/swig/python/samples/gdal2grd.py\
Finally, you can iterate over the polygons (after transforming them into a local projection), and plot them directly. But you better not have complex polygons, or you will have a bit of grief. If you have complex polygons ... you are probably best off using shapely and r-tree from http://trac.gispython.org/lab if you want to roll your own plotter.
Geodjango might be a good place to ask .. they will know a lot more than me. Do they have a mailing list? There's also lots of python mapping experts around, but none of them seem to worry about this. I guess they just plot it in qGIS or GRASS or something.
Seriously, I hope that somebody who knows what they are doing can reply.

Categories

Resources