graph-tool fit_view and output size - python

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.

Related

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

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.

NetworkX - Stop Nodes from Bunching Up - Tried Scale/K parameters

I have ~28 nodes with edges between most of them, and some being isolated (no edges). The isolated nodes are spread out nicely, but the ones which are connected are so stacked I cannot see anything. I've tried a variety of node_sizes, scale and k parameters and it always gives me (roughly) the same result. Any way to force a nicer view?
nx.draw_spring(candidateGraph, node_size = 1000, with_labels=True, scale=100, weight=weightVal, k=100)
plt.show( )
There are several ways to do this.
First a comment on how networkx draws things. Here's the documentation. It creates a dictionary pos which has the coordinates of each node. Using draw_networkx you can send the optional argument pos=my_position_dict to it.
Networkx also has commands that will define the positons for you. This way you can have more control over things.
You have several options to do what you want.
The simplest is to plot just the connected component and leave out the isolated nodes.
nodes_of_largest_component = max(nx.connected_components(G), key = len)
largest_component = G.subgraph(nodes_of_largest_component)
nx.draw_spring(largest_component)
Another would be to try one of the other (non-spring) layouts. For example:
nx.draw_spectral(G)
Alternately, you can start manipulating the positions. One way is to set a couple positions as fixed and let spring_layout handle the rest.
pre_pos = {Huck: (0,0), Christie:(0,1), Graham:(1,1), Bush: (1,2)}
my_pos = nx.spring_layout(G, pos=pre_pos, fixed = pre_pos.keys())
nx.draw_networkx(G,pos=my_pos)
Then it will hold the nodes fixed that you've specified in fixed.
Alternately, define all the positions for just the largest component. Then hold those fixed and add the other nodes. The largest component will "fill" most of the available space, and then I think spring_layout will try to keep the added nodes from being too far away (alternately once you see the layout, you can specify these by hand).
nodes_of_largest_component = max(nx.connected_components(G), key = len)
largest_component = G.subgraph(nodes_of_largest_component)
pos = nx.spring_layout(largest_component)
pos = nx.spring_layout(G,pos=pos,fixed=nodes_of_largest_component)
nx.draw_networkx(G,pos=pos)
One more thing to be aware of is that each call to spring_layout will result in a different layout. This is because it starts with some random positions. This is part of why it's useful to save the position dictionary, particularly if you plan to do anything fancy with the figure.

NetworkX graphviz_layout not working?

I encountered a problem when trying to plot a graph with many nodes using NetworkX and graphviz_layout. More specifically, the arguments that pass into nx.graphviz_layout do not help at all. Attached is the code I use:
G=some_graph()
import matplotlib.pyplot as plt
plt.figure(figsize=(32,32))
# use graphviz to find radial layout
pos=nx.graphviz_layout(G,prog="dot",
root=1000,
args='-splines=true -nodesep=0.6 -overlap=scalexy'
)
nx.draw(G,pos,
with_labels=True,
alpha=0.5,
node_size=600,
font_size=10
)
plt.savefig("imagenet_layout.png")
No matter how I change "args" in nx.graphviz_layout, the output image would be the same, and all nodes overlap with each other. Could anybody help me with this? Thanks!
For me it seems that in order to give args to the prog you need to use the format '-G' +'argsname=x'. I noticed in the example they give the docs the arg epsilon asG.draw(‘test.ps’,prog=’twopi’,args=’-Gepsilon=1’). So I tried out that pattern as shown below. I just added G in front of the arguments. Now, these arguments vary quite a bit depending on what prog you use, so you definitely want to use 'dot' for what you want to accomplish. You can see all the possible arguments and how they work with each prog here. For my porpoises, I needed to have the nodesep=0.01.
G=some_graph()
import matplotlib.pyplot as plt
plt.figure(figsize=(32,32))
# use graphviz to find radial layout
pos=nx.graphviz_layout(G,prog="dot",
root=1000,
args='-Gsplines=true -Gnodesep=0.6 -Goverlap=scalexy'
)
nx.draw(G,pos,
with_labels=True,
alpha=0.5,
node_size=600,
font_size=10
)
plt.savefig("imagenet_layout.png")
Here is a comparison of my graph with and without the args, with code. First without the args.
A = nx.nx_agraph.to_agraph(G) # convert to a graphviz graph
A.layout(prog='neato') # neato layout
#A.draw('test3.pdf')
A.draw('test3.png' )
With args
A = nx.nx_agraph.to_agraph(G) # convert to a graphviz graph
A.layout(prog='dot') # neato layout
#A.draw('test3.pdf')
A.draw('test3.png',args='-Gnodesep=0.01 -Gfont_size=1', prog='dot' )
SO you can see that the images are different once I got the args to work.
My reading of the documentation for pygraphviz suggests that overlap does not work with dot.
For nodesep :
In dot, this specifies the minimum space between two adjacent nodes in the same rank, in inches.
It's not clear if the overlaps you are observing are between nodes in the same rank or between the ranks. If it is just between ranks, you may want to modify ranksep.
I do see that you are setting the positions, and then later you set the nodesize, and you are making node_size quite a bit larger than the default (600 vs 300). Since it does not know what node_size you are going to use when it finds pos, using a large enough node_size will cause overlap.
So I would recommend setting node_size to be the default, and if overlap remains, setting node_size to be smaller. If you're having issues with the between or within rank separations being out of proportion, then play with ranksep and nodesep.
About “overlap”,do you mean there are nodes drawed last time in current output? If so, add "plt.clf()"after"plt.savefig(****)"!
About the node_size, the default is 300, but the unit is not given in the document. I am using networkx these days too, can you tell me the unit if you know that?

How to make savefig() save image for 'maximized' window instead of default size

I am using pylab in matplotlib to create a plot and save the plot to an image file. However, when I save the image using pylab.savefig( image_name ), I find that the SIZE image saved is the same as the image that is shown when I use pylab.show().
As it happens, I have a lot of data in the plot and when I am using pylab.show(), I have to maximize the window before I can see all of the plot correctly, and the xlabel tickers don't superimpose on each other.
Is there anyway that I can programmatically 'maximize' the window before saving the image to file? - at the moment, I am only getting the 'default' window size image, which results in the x axis labels being superimposed on one another.
There are two major options in matplotlib (pylab) to control the image size:
You can set the size of the resulting image in inches
You can define the DPI (dots per inch) for output file (basically, it is a resolution)
Normally, you would like to do both, because this way you will have full control over the resulting image size in pixels. For example, if you want to render exactly 800x600 image, you can use DPI=100, and set the size as 8 x 6 in inches:
import matplotlib.pyplot as plt
# plot whatever you need...
# now, before saving to file:
figure = plt.gcf() # get current figure
figure.set_size_inches(8, 6)
# when saving, specify the DPI
plt.savefig("myplot.png", dpi = 100)
One can use any DPI. In fact, you might want to play with various DPI and size values to get the result you like the most. Beware, however, that using very small DPI is not a good idea, because matplotlib may not find a good font to render legend and other text. For example, you cannot set the DPI=1, because there are no fonts with characters rendered with 1 pixel :)
From other comments I understood that other issue you have is proper text rendering. For this, you can also change the font size. For example, you may use 6 pixels per character, instead of 12 pixels per character used by default (effectively, making all text twice smaller).
import matplotlib
#...
matplotlib.rc('font', size=6)
Finally, some references to the original documentation:
http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.savefig, http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.gcf, http://matplotlib.sourceforge.net/api/figure_api.html#matplotlib.figure.Figure.set_size_inches, http://matplotlib.sourceforge.net/users/customizing.html#dynamic-rc-settings
P.S. Sorry, I didn't use pylab, but as far as I'm aware, all the code above will work same way in pylab - just replace plt in my code with the pylab (or whatever name you assigned when importing pylab). Same for matplotlib - use pylab instead.
You set the size on initialization:
fig2 = matplotlib.pyplot.figure(figsize=(8.0, 5.0)) # in inches!
Edit:
If the problem is with x-axis ticks - You can set them "manually":
fig2.add_subplot(111).set_xticks(arange(1,3,0.5)) # You can actually compute the interval You need - and substitute here
And so on with other aspects of Your plot. You can configure it all. Here's an example:
from numpy import arange
import matplotlib
# import matplotlib as mpl
import matplotlib.pyplot
# import matplotlib.pyplot as plt
x1 = [1,2,3]
y1 = [4,5,6]
x2 = [1,2,3]
y2 = [5,5,5]
# initialization
fig2 = matplotlib.pyplot.figure(figsize=(8.0, 5.0)) # The size of the figure is specified as (width, height) in inches
# lines:
l1 = fig2.add_subplot(111).plot(x1,y1, label=r"Text $formula$", "r-", lw=2)
l2 = fig2.add_subplot(111).plot(x2,y2, label=r"$legend2$" ,"g--", lw=3)
fig2.add_subplot(111).legend((l1,l2), loc=0)
# axes:
fig2.add_subplot(111).grid(True)
fig2.add_subplot(111).set_xticks(arange(1,3,0.5))
fig2.add_subplot(111).axis(xmin=3, xmax=6) # there're also ymin, ymax
fig2.add_subplot(111).axis([0,4,3,6]) # all!
fig2.add_subplot(111).set_xlim([0,4])
fig2.add_subplot(111).set_ylim([3,6])
# labels:
fig2.add_subplot(111).set_xlabel(r"x $2^2$", fontsize=15, color = "r")
fig2.add_subplot(111).set_ylabel(r"y $2^2$")
fig2.add_subplot(111).set_title(r"title $6^4$")
fig2.add_subplot(111).text(2, 5.5, r"an equation: $E=mc^2$", fontsize=15, color = "y")
fig2.add_subplot(111).text(3, 2, unicode('f\374r', 'latin-1'))
# saving:
fig2.savefig("fig2.png")
So - what exactly do You want to be configured?
I think you need to specify a different resolution when saving the figure to a file:
fig = matplotlib.pyplot.figure()
# generate your plot
fig.savefig("myfig.png",dpi=600)
Specifying a large dpi value should have a similar effect as maximizing the GUI window.
Check this:
How to maximize a plt.show() window using Python
The command is different depending on which backend you use. I find that this is the best way to make sure the saved pictures have the same scaling as what I view on my screen.
Since I use Canopy with the QT backend:
pylab.get_current_fig_manager().window.showMaximized()
I then call savefig() as required with an increased DPI per silvado's answer.
You can look in a saved figure it's size, like 1920x983 px (size when i saved a maximized window), then I set the dpi as 100 and the size as 19.20x9.83 and it worked fine. Saved exactly equal to the maximized figure.
import numpy as np
import matplotlib.pyplot as plt
x, y = np.genfromtxt('fname.dat', usecols=(0,1), unpack=True)
a = plt.figure(figsize=(19.20,9.83))
a = plt.plot(x, y, '-')
plt.savefig('file.png',format='png',dpi=100)
I had this exact problem and this worked:
plt.savefig(output_dir + '/xyz.png', bbox_inches='tight')
Here is the documentation:
[https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.savefig.html][1]
I did the same search time ago, it seems that he exact solution depends on the backend.
I have read a bunch of sources and probably the most useful was the answer by Pythonio here How to maximize a plt.show() window using Python
I adjusted the code and ended up with the function below.
It works decently for me on windows, I mostly use Qt, where I use it quite often, while it is minimally tested with other backends.
Basically it consists in identifying the backend and calling the appropriate function. Note that I added a pause afterwards because I was having issues with some windows getting maximized and others not, it seems this solved for me.
def maximize(backend=None,fullscreen=False):
"""Maximize window independently on backend.
Fullscreen sets fullscreen mode, that is same as maximized, but it doesn't have title bar (press key F to toggle full screen mode)."""
if backend is None:
backend=matplotlib.get_backend()
mng = plt.get_current_fig_manager()
if fullscreen:
mng.full_screen_toggle()
else:
if backend == 'wxAgg':
mng.frame.Maximize(True)
elif backend == 'Qt4Agg' or backend == 'Qt5Agg':
mng.window.showMaximized()
elif backend == 'TkAgg':
mng.window.state('zoomed') #works fine on Windows!
else:
print ("Unrecognized backend: ",backend) #not tested on different backends (only Qt)
plt.show()
plt.pause(0.1) #this is needed to make sure following processing gets applied (e.g. tight_layout)
Old question but to anyone in need, Here's what had worked for me a while ago:
You have to have a general idea of the aspect ratio that would maximise your plot fitting. This will take some trial and error to get right, but generally 1920x1080 would be a good aspect ratio for most modern monitors. I would still suggest playing around with the aspect ratios to best suit your plot.
Steps:
Before initiating the plot, set the size for the plot, use:
plt.figure(19.20, 10.80)
**notice how I have multiplied my aspect ratio by '0.01'.
At the end of the plot, when using plt.savefig, save it as follows:
plt.savefig('name.jpg', bbox_inches='tight', dpi=1000)
If I understand correctly what you want to do, you can create your figure and set the size of the window. Afterwards, you can save your graph with the matplotlib toolbox button. Here an example:
from pylab import get_current_fig_manager,show,plt,imshow
plt.Figure()
thismanager = get_current_fig_manager()
thismanager.window.wm_geometry("500x500+0+0")
#in this case 500 is the size (in pixel) of the figure window. In your case you want to maximise to the size of your screen or whatever
imshow(your_data)
show()

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