I am very new to graph visualizations and software like graph-tool (gt). My main field is mathematics, but I am somewhat familiar with Python and programming in general. However, I'm not a programmer, so my code may be less than elegant; any suggestions of improvement will be gratefully appreciated.
Description:
I am very fond of the circular layout with edge bundling used to visualize very large graphs. As an example, I am trying to plot the C.Elegans connectome using the wonderful Python module graph-tool by Tiago Peixoto. For this I use the following:
import graph_tool.all as gt
g_celegans = gt.load_graph("c.elegans_neural.male_1.graphml")
v_prop = g_celegans.vertex_properties
celegans_state = gt.minimize_nested_blockmodel_dl(g_celegans)
celegans_state.draw(vertex_text = v_prop['name'], bg_color = 'w')
which produces:
Questions:
How could I (in gt) place the vertex labels on a line drawn from the center? Like this
Can I plot a similar layout, i.e. circular and edge bundling, but using a clustering (partition of the vertices) of my own, instead of the stochastic block model? In a sense, I guess I would just like to be able to use the circular + edge bundling feature on its own. Or am I missing the whole point somewhat?
(Would anyone recommend a good introductory treatment on graph visualizations including this type (connectogram)?)
Attempt at Question 1:
So, I managed to at least get somewhere with this:
def getAngle(vec):
norm_vec = vec / np.linalg.norm(vec)
one_vec = np.array([1,0])
dot_product = np.dot(norm_vec, one_vec)
return np.arccos(dot_product)
text_rot = [0]*len(list(text_pos))
for i, p in enumerate(text_pos):
if p[0]>=0 and p[1]>=0:
text_rot[i] = getAngle(p)
elif p[0]>=0 and p[1]<0:
text_rot[i] = -getAngle(p)
elif p[0]<0 and p[1]>=0:
text_rot[i] = getAngle(p)-np.pi
elif p[0]<0 and p[1]<0:
text_rot[i] = -getAngle(p)+np.pi
text_rot = np.asarray(text_rot)
t_rot = g_celegans.new_property('v','float', vals = text_rot)
options = {'pos': pos,
'vertex_text': v_prop['name'],
'vertex_text_rotation':t_rot,
'bg_color': 'w',
'vertex_shape': 'none',
'vertex_font_size': 5,
'edge_end_marker': 'none'
}
celegans_state.draw(**options)
which produces:
So, the rotation is fine, but I would like to offset the labels a bit further out. Now they're in the center of an invisible vertex. There are two vertex properties called 'text_position' and 'text_offset', which you may read about here.
Now, any value for 'vertex_text_position', such as -1 or 'centered' or if I pass a VertexPropertyMap object like for 'vertex_text_rotation' above, generates an IndexError:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-197-d529fcf5647e> in <module>
9 }
10
---> 11 celegans_state.draw(**options)
~/anaconda3/envs/gt/lib/python3.9/site-packages/graph_tool/inference/nested_blockmodel.py in draw(self, **kwargs)
986 draws the hierarchical state."""
987 import graph_tool.draw
--> 988 return graph_tool.draw.draw_hierarchy(self, **kwargs)
989
990
~/anaconda3/envs/gt/lib/python3.9/site-packages/graph_tool/draw/cairo_draw.py in draw_hierarchy(state, pos, layout, beta, node_weight, vprops, eprops, hvprops, heprops, subsample_edges, rel_order, deg_size, vsize_scale, hsize_scale, hshortcuts, hide, bip_aspect, empty_branches, **kwargs)
2121 kwargs[k] = u.own_property(v.copy())
2122
-> 2123 pos = graph_draw(u, pos, vprops=t_vprops, eprops=t_eprops, vorder=tvorder,
2124 **kwargs)
2125
~/anaconda3/envs/gt/lib/python3.9/site-packages/graph_tool/draw/cairo_draw.py in graph_draw(g, pos, vprops, eprops, vorder, eorder, nodesfirst, output_size, fit_view, fit_view_ink, adjust_aspect, ink_scale, inline, inline_scale, mplfig, output, fmt, bg_color, **kwargs)
1074 vprops.get("fill_color", _vdefaults["fill_color"]),
1075 vcmap)
-> 1076 vprops["text_color"] = auto_colors(g, bg,
1077 vprops.get("text_position",
1078 _vdefaults["text_position"]),
~/anaconda3/envs/gt/lib/python3.9/site-packages/graph_tool/draw/cairo_draw.py in auto_colors(g, bg, pos, back)
724 return color_contrast(back)
725 c = g.new_vertex_property("vector<double>")
--> 726 map_property_values(bgc_pos, c, conv)
727 return c
728
~/anaconda3/envs/gt/lib/python3.9/site-packages/graph_tool/__init__.py in map_property_values(src_prop, tgt_prop, map_func)
1189 u = GraphView(g, directed=True, reversed=g.is_reversed(),
1190 skip_properties=True)
-> 1191 libcore.property_map_values(u._Graph__graph,
1192 _prop(k, g, src_prop),
1193 _prop(k, g, tgt_prop),
~/anaconda3/envs/gt/lib/python3.9/site-packages/graph_tool/draw/cairo_draw.py in conv(x)
722 return color_contrast(bgc)
723 else:
--> 724 return color_contrast(back)
725 c = g.new_vertex_property("vector<double>")
726 map_property_values(bgc_pos, c, conv)
~/anaconda3/envs/gt/lib/python3.9/site-packages/graph_tool/draw/cairo_draw.py in color_contrast(color)
694 def color_contrast(color):
695 c = np.asarray(color)
--> 696 y = c[0] * .299 + c[1] * .587 + c[2] * .114
697 if y < .5:
698 c[:3] = 1
IndexError: too many indices for array: array is 0-dimensional, but 1 were indexed
If I do 'vertex_text_offset = pos', this would mean that I offset each vertex by its own coordinates, and I could then just scale by say 0.1 to get them appropriately far out, which actually DID work great without rotation. Then I rotated the text, which yielded this (without scaling):
The problem seems to be that the center for rotation is the center of the vertex, which is not ideal if the text is moved out from the vertex. So, even if 'vertex_text_position' above would have worked, I'm guessing the rotation would have messed that up as well.
Weirdly enough, If I rotate the vertices using 'vertex_rotation' instead, the labels are rotated along with them (great!), but when I offset the text with vertex position (which should "push" outwards), I get the same faulty plot as above.
Next I tried 'vertex_shape = circle', and filling the vertices with white using 'vertex_fill_color = 'w''. Thus I would push the text out a bit from the edge by increasing the size of the vertex. For some reason this made all the edges of the graph white as well; so no colors at all in the plot. I guess the edges are thus colored based on the vertex colors.
What I ended up doing is to use the vertex properties 'text_out_color' and 'text_out_width', with a width of 0.003. This gives a nice bold style to the text, which makes it more readable against the colored background.
But, now I'm pretty much out of ideas.
Do anyone know a solution to my problem? i.e. placing the labels like I have them, but moving them further out (in the direction outwards from the center) or framing them in white so that they're more readable, but so that the plot still looks nice; as well as to question 2 above.
This is a couple months late so hopefully you figured it out but I'll leave this here for future reference:
To get those labels to look the way you want them to in this case is when you call the draw function you'll want to specify the position of the vertex text like so:
celegans_state.draw(vertex_text = v_prop['name'], bg_color = 'w', vertex_text_position='centered')
(as can be seen in the list of properties in the documentation 'centered' gives this exact effect: https://graph-tool.skewed.de/static/doc/draw.html#graph_tool.draw.graph_draw)
To get a circular graph I figure you want to use the radial tree layout (https://graph-tool.skewed.de/static/doc/draw.html?highlight=radial_tree_layout#graph_tool.draw.radial_tree_layout)
Hopefully this helps!
Related
In pyBullet, I have struggled a bit with generating a dataset. What I want to achieve is to get pictures of what the camera is seeing: img = p.getCameraImage(224, 224, renderer=p.ER_BULLET_HARDWARE_OPENGL)
Basically: to get the images that are seen in Synthetic Camera RGB data and Synthetic Camera Depth Data (especially this one), which are the camera windows you can see in the following picture on the left.
p.resetDebugVisualizerCamera(cameraDistance=0.5, cameraYaw=yaw, cameraPitch=pitch, cameraTargetPosition=[center_x, center_y, 0.785])
img = p.getCameraImage(224, 224, renderer=p.ER_BULLET_HARDWARE_OPENGL)
rgbBuffer = img[2]
depthBuffer = img[3]
list_of_rgbs.append(rgbBuffer)
list_of_depths.append(depthBuffer)
rgbim = Image.fromarray(rgbBuffer)
depim = Image.fromarray(depthBuffer)
rgbim.save('test_img/rgbtest'+str(counter)+'.jpg')
depim.save('test_img/depth'+str(counter)+'.tiff')
counter += 1
I already run the following, so I don't know if it is related to the settings. p.configureDebugVisualizer(p.COV_ENABLE_DEPTH_BUFFER_PREVIEW, 1)
I have tried several methods because the depth part is complicated. I don't understand if it needs to be treated separately because of the pixel color information or if I need to work with the project matrixes and view matrixes.
I need to save it as a .tiff because I get some cannot save F to png errors. I tried playing a bit with the bit information but acomplished nothing. In case you asked,
# depthBuffer[depthBuffer > 65535] = 65535
# im_uint16 = np.round(depthBuffer).astype(np.uint16)
# depthBuffer = im_uint16
The following is an example of the the .tiff image
And to end, just to remark that these depth images keep changing (looking at all of them, then to the RGB and passing again to the depth images, shows different images regardless of being the same image. I have never ever seen something like this before.
I thought "I managed to fix this some time ago, might as well post the answer found".
The data structure of img has to be taken into account!
img = p.getCameraImage(224, 224, shadow = False, renderer=p.ER_BULLET_HARDWARE_OPENGL)
rgb_opengl = (np.reshape(img[2], (IMG_SIZE, IMG_SIZE, 4)))
depth_buffer_opengl = np.reshape(img[3], [IMG_SIZE, IMG_SIZE])
depth_opengl = far * near / (far - (far - near) * depth_buffer_opengl)
seg_opengl = np.reshape(img[4], [IMG_SIZE, IMG_SIZE]) * 1. / 255.
rgbim = Image.fromarray(rgb_opengl)
rgbim_no_alpha = rgbim.convert('RGB')
rgbim_no_alpha.save('dataset/'+obj_name+'/'+ obj_name +'_rgb_'+str(counter)+'.jpg')
# plt.imshow(depth_buffer_opengl)
plt.imsave('dataset/'+obj_name+'/'+ obj_name+'_depth_'+str(counter)+'.jpg', depth_buffer_opengl)
# plt.show()
Final Images:
I've been trying to understand NeRF. I finished reading the paper(Tancik) and watched some of the videos. I have been looking at some parts of the code. However, I can't quite wrap my head around what the get_rays function does in terms of the code. Could anybody just run through line-by-line about what each line in the the get_rays function is supposed to do?
def get_rays(H,W , focal, c2w): #c2w is pose
i, j = tf.meshgrid(tf.range(W, dtype=tf.float32), tf.range(H, dtype=tf.float32), indexing='xy')
dirs = tf.stack([(i-W*.5)/focal, -(j-H*.5)/focal, -tf.ones_like(i)], -1)
rays_d = tf.reduce_sum(dirs[..., np.newaxis, :] * c2w[:3,:3], -1)
rays_o = tf.broadcast_to(c2w[:3,-1], tf.shape(rays_d))
return rays_o, rays_d
It creates two lists, rays_o represents points where rays originate (camera centre) and rays_d represents direction vectors of each ray casting through the centre of every pixel of the camera. In this case, all values in the rays_o are the same because the function gets rays from a single camera.
Do you know how to plot a Gantt chart in Matlab without using a third-party software?
At the end I would love to obtain something like this:
What I was able to obtain so far is
using this code:
% Create data for childhood disease cases
measles = [38556 24472 14556 18060 19549 8122 28541 7880 3283 4135 7953 1884]';
mumps = [20178 23536 34561 37395 36072 32237 18597 9408 6005 6268 8963 13882]';
chickenPox = [37140 32169 37533 39103 33244 23269 16737 5411 3435 6052 12825 23332]';
% Create a stacked bar chart using the bar function
fig = figure;
bar(1:12, [measles mumps chickenPox], 0.5, 'stack');
axis([0 13 0 100000]);
title('Childhood diseases by month');
xlabel('Month');
ylabel('Cases (in thousands)');
legend('Measles', 'Mumps', 'Chicken pox');
That is not what I want but, maybe, goes in this direction
Here, I share the solution I have just found (maybe it is not the most elegant one but it works for the purpose I have):
[the main idea is to draw a bar and "delete" the beginning overdrawing up on it another white bar]
Let's say you have two vector:
start =[6907402; 2282194; 4579536; 2300332; 10540; 2307970; 4603492; 0];
stop =[9178344; 9168694;6895050; 4571400; 2280886; 4579044; 6897152 ;2271186];
There are 8 elements in each: every element is a task. In the start array, there is the start time of each task and in stop there is the end of the "execution" of a given task.
barh(stop)
hold on
barh(start,'w')
At the end here you have the Gantt:
UPDATE:
My scripts are evolved of course and, more, on the matlab website, there is more information. Here 2 example more to complete the answer:
Option 1:
Positions=[1,2,3,4];
Gap_Duration=[0,2,5,3,5,3;
3,5,3,5,3,4;
9,3,0,0,12,2;
13,2,2,2,8,3];
barh(Positions,Gap_Duration,'stacked');
Option 2:
Positions=[1,2,3,4];
Gap_Duration=[0,2,5,3,5,3;
3,5,3,5,3,4;
9,3,0,0,12,2;
13,2,2,2,8,3];
barh(Positions,Gap_Duration,'stacked');
set(H([1 3 5]),'Visible','off')
I'm trying to implement mouse selection for my game. When I QueryAABB it looks like it's treating objects much larger than they really are.
Here's what's going on in the image
The blue box is an actor containing a body that I'd like to select
The outline on the blue box is drawn by Box2DDebugRenderer
The mouse selects a region on the screen (white box), this is entirely graphical
The AABB is converted to meters and passed to QueryAABB
The callback was called for the blue box and turned it red
The green outline left behind is a separate body to check if my conversions were correct, this is not used for the actual selection process
It seems to be connected to my meter size, the larger it is, the more inaccurate the result is. At 1 meter = 1 pixel it works perfectly.
Meter conversions
val MetersToPixels = 160f
val PixelsToMeters = 1/MetersToPixels
def toMeters(n: Float) = n * PixelsToMeters
def toPixels(n: Float) = n * MetersToPixels
In the image I'm using MetersToPixels = 160f so the inaccuracy is more visible, but I really want MetersToPixels = 16f.
Relevant selection code
val x1 = selectPos.x
val y1 = selectPos.y
val x2 = getX
val y2 = getY + getHeight
val (l,r) =
if (x2 < x1)
(x2,x1)
else
(x1,x2)
val (b,t) =
if (y2 < y1)
(y2,y1)
else
(y1,y2)
world.QueryAABB(selectCallback, toMeters(l),toMeters(b), toMeters(r),toMeters(t))
This code is inside the act method of my CursorActor class. And selectPos represents the initial point where the use pressed down the left mouse button and getX and getY are Actor methods giving the current position. The next bit sorts them because they might be out of order. Then they are converted to meters because they are all in pixel units.
selectCallback: QueryCallback
override def reportFixture(fixture: Fixture): Boolean = {
fixture.getBody.getUserData match {
case selectable: Selectable =>
selected += selectable
true
case _ => true
}
}
Selectable is a trait that sets a boolean flag internally after the query which helps determines the color of the blue box. And selected is a mutable.HashSet[Selectable] defined inside of CursorActor.
Other things possibly worth noting
I'm new to libgdx and box2d.
The camera is scaled x2
My Box2DDebugRenderer uses the camera's combined matrix multiplied by MetersToPixels
From what I was able to gather, QueryAABB is naturally inaccurate for optimization. However, I've hit a roadblock with libgdx because it doesn't have any publicly visible function like b2testOverlap and from what I understand, there's no plan for there to be one any time soon.
I think my best solution would probably be to use jbox2d and pretend that libgdx's physics implementation doesn't exist.
Or as noone suggested I could add it to libgdx myself.
UPDATE
I decided to go with a simple solution of gathering the vertices from the fixture's shape and using com.badlogic.gdx.math.Intersector against the vertices of the selection. It works I guess. I may stop using QueryAABB all together if I decide to switch to using a sensor for the select box.
How to get the square root sign inside a legend?
I tried \surd, but did not consider all my expression below this symbol.
\sqrt and \square do not work at all.
m=[2 4.8 7 9.1 11.5 15 20 29 59 90 130 190 250];
size(Te);
s=0:0.02:0.246;
size(s);
E0=0.1;
t0=0.05;
f=0.01;
I0=2e9;
I1=1e14.*[m./(3680.*(1.08)^(1./3))].^(1.5);
hold on
Ifitting=I0./(sqrt(2.*pi).*f).*exp(-[s-t0].^2./(2.*f.^2));
[ay,h1,h2]=plotyy(s.*1e6,I1,s.*1e6,Ifitting,'loglog','plot')
axes(ay(1)); ylabel(' Intensity');
axes(ay(2)); ylabel('Intensity [fitting]');
set(ay(1),'Ylim',[0 2e12])
set(ay(2),'Ylim',[0 2e12])
xlabel('time [\mu m]','FontSize',16,'FontName','Times-Roman');
set([h1],'marker','o')
set([h2],'marker','o')
b=legend([h1 h2], ['I=10^{14}'],['I_{fitting}=I_0$$\sqrt{(2)\sigma}$$e^{\sigma}']);
set(b,'Interpreter','latex','fontsize',24)
you can try this:
plot(sqrt(1:10));
h = legend(['$$\sqrt{blah}$$'])
set(h,'Interpreter','latex','fontsize',24)
Create the legend with LaTeX-style text, and then set to 'latex' the 'interpreter' property of all children of the lenged that are of type 'text':
leg = legend('$\sqrt{x-1}$'); %// this will give a warning; ignore it
t = findobj('Parent',leg,'Type','text');
set(t,'Interpreter','latex')
It would be easier if legend accepted the 'interpreter' property directly (legend('$\sqrt{x-1}$','interpreter','latex')), but it doesn't, at least in R2010b. ... However, it seems to work if after the legend object has been created; see natan's answer.