Commit 4dbdc276 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

draw_hierarchy(): Implement "hshortcuts" and "hide" parameters

parent acedc700
......@@ -2150,7 +2150,7 @@ struct enum_from_int
};
void get_cts(GraphInterface& gi, GraphInterface& tgi, boost::any otpos,
boost::any obeta, boost::any octs);
boost::any obeta, boost::any octs, bool);
BOOST_PYTHON_MODULE(libgraph_tool_draw)
{
......
......@@ -23,6 +23,7 @@
#include "graph_properties.hh"
#include <boost/mpl/quote.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <cmath>
......@@ -159,6 +160,32 @@ void tree_path(Graph& g, size_t s, size_t t, vector<size_t>& path)
}
template <class Graph>
void graph_path(Graph& g, size_t s, size_t t, vector<size_t>& path)
{
typename property_map_type::apply<size_t,
typename property_map<Graph, vertex_index_t>::type>::type
cpred;
auto pred = cpred.get_unchecked(num_vertices(g));
UndirectedAdaptor<Graph> ug(g);
boost::breadth_first_search(ug, s,
boost::visitor(
boost::make_bfs_visitor(
boost::record_predecessors(
pred,
boost::on_tree_edge()))));
size_t pos = t;
path.push_back(pos);
while (pos != s)
{
pos = pred[pos];
path.push_back(pos);
}
std::reverse(path.begin(), path.end());
}
template<class T>
void pack(vector<point_t>& cp, vector<T>& ncp)
{
......@@ -173,7 +200,7 @@ void pack(vector<point_t>& cp, vector<T>& ncp)
struct do_get_cts
{
template <class Graph, class Tree, class PosProp, class BProp, class CMap>
void operator()(Graph& g, Tree* t, PosProp tpos, BProp beta, CMap cts) const
void operator()(Graph& g, Tree* t, PosProp tpos, BProp beta, CMap cts, bool is_tree) const
{
vector<size_t> path;
vector<point_t> cp;
......@@ -187,7 +214,10 @@ struct do_get_cts
continue;
path.clear();
if (is_tree)
tree_path(*t, u, v, path);
else
graph_path(*t, u, v, path);
cp.clear();
get_control_points(path, tpos, beta[e], cp);
ncp.clear();
......@@ -208,8 +238,8 @@ struct get_pointers
};
};
void get_cts(GraphInterface& gi, GraphInterface& tgi,
boost::any otpos, boost::any obeta, boost::any octs)
void get_cts(GraphInterface& gi, GraphInterface& tgi, boost::any otpos,
boost::any obeta, boost::any octs, bool is_tree)
{
typedef property_map_type::apply<vector<double>,
GraphInterface::edge_index_map_t>::type
......@@ -221,9 +251,9 @@ void get_cts(GraphInterface& gi, GraphInterface& tgi,
eprop_t cts = boost::any_cast<eprop_t>(octs);
beprop_t beta = boost::any_cast<beprop_t>(obeta);
run_action<graph_tool::detail::always_directed, boost::mpl::true_>()
run_action<>()
(gi, std::bind(do_get_cts(), placeholders::_1, placeholders::_2,
placeholders::_3, beta, cts),
placeholders::_3, beta, cts, is_tree),
get_pointers::apply<graph_tool::detail::always_directed>::type(),
vertex_scalar_vector_properties())
(tgi.GetGraphView(), otpos);
......
......@@ -1727,6 +1727,14 @@ def get_hierarchy_tree(state, empty_branches=True):
This transforms a :class:`~graph_tool.NestedBlockState` instance into a
single :class:`~graph_tool.Graph` instance containing the hierarchy tree.
Parameters
----------
state : :class:`~graph_tool.community.NestedBlockState`
Nested block model state.
empty_branches : ``bool`` (optional, default: ``True``)
If ``empty_branches == False``, dangling branches at the upper layers
will be pruned.
Returns
-------
......@@ -1738,9 +1746,6 @@ def get_hierarchy_tree(state, empty_branches=True):
order : :class:`~graph_tool.PropertyMap`
A vertex property map containing the relative ordering of each layer
according to the total degree of the groups at the specific levels.
empty_branches : ``bool`` (optional, default: ``True``)
If ``empty_branches == False``, dangling branches at the upper layers
will be pruned.
"""
bstack = state.get_bstack()
......
......@@ -27,6 +27,8 @@ import os
import warnings
import numpy
from .. topology import shortest_distance
try:
import cairo
except ImportError:
......@@ -1224,7 +1226,7 @@ def transform_scale(M, scale):
scale / np.sqrt(2))
return np.sqrt(p[0] ** 2 + p[1] ** 2)
def get_hierarchy_control_points(g, t, tpos, beta=0.8, cts=None):
def get_hierarchy_control_points(g, t, tpos, beta=0.8, cts=None, is_tree=True):
r"""Return the Bézier spline control points for the edges in ``g``, given the hierarchical structure encoded in graph `t`.
Parameters
......@@ -1248,6 +1250,9 @@ def get_hierarchy_control_points(g, t, tpos, beta=0.8, cts=None):
cts : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
Edge property map of type ``vector<double>`` where the control points
will be stored.
is_tree : ``bool`` (optional, default: ``True``)
If ``True``, ``t`` must be a directed tree, otherwise it can be any
connected graph.
Returns
......@@ -1326,7 +1331,8 @@ def get_hierarchy_control_points(g, t, tpos, beta=0.8, cts=None):
tu._Graph__graph,
_prop("v", tu, tpos),
_prop("e", u, beta),
_prop("e", u, cts))
_prop("e", u, cts),
is_tree)
return cts
#
......@@ -1414,8 +1420,8 @@ class GraphArtist(matplotlib.artist.Artist):
def draw_hierarchy(state, pos=None, layout="radial", beta=0.8, ealpha=0.4,
halpha=0.6, subsample_edges=None, deg_order=True,
deg_size=True, vsize_scale=1, hsize_scale=1,
empty_branches=True, verbose=False, **kwargs):
deg_size=True, vsize_scale=1, hsize_scale=1, hshortcuts=0,
hide=0, empty_branches=True, verbose=False, **kwargs):
r"""Draw a nested block model state in a circular hierarchy layout with edge
bundling.
......@@ -1448,6 +1454,11 @@ def draw_hierarchy(state, pos=None, layout="radial", beta=0.8, ealpha=0.4,
Multiplicative factor of the vertex sizes.
hsize_scale : ``float`` (optional, default: ``1.``)
Multiplicative factor of the sizes of the hierarchy nodes.
hshortcuts : ``int`` (optional, default: ``0``)
Include shortcuts to the number of upper layers in the hierarchy
determined by this parameter.
hide : ``int`` (optional, default: ``0``)
Hide upper levels of the hierarchy.
empty_branches : ``bool`` (optional, default: ``False``)
If ``empty_branches == False``, dangling branches at the upper layers
will be pruned.
......@@ -1570,12 +1581,30 @@ def draw_hierarchy(state, pos=None, layout="radial", beta=0.8, ealpha=0.4,
else:
tpos = t.own_property(layout)
hvvisible = t.new_vertex_property("bool", True)
if hide > 0:
root = t.vertex(t.num_vertices() - 1)
dist = shortest_distance(t, source=root)
hvvisible.fa = dist.fa >= hide
hevisible = t.new_edge_property("bool", True)
if hshortcuts > 0:
root = t.vertex(t.num_vertices() - 1)
dist = shortest_distance(t, source=root)
nodes = [v for v in t.vertices() if dist[v] <= hshortcuts]
for v in nodes:
for u in nodes:
if u == v:
continue
t.add_edge(u, v)
pos = g.own_property(tpos.copy())
if verbose:
print("getting cts...")
cts = get_hierarchy_control_points(g, t, tpos, beta)
cts = get_hierarchy_control_points(g, t, tpos, beta,
is_tree=hshortcuts == 0)
if verbose:
print("done.")
......@@ -1646,7 +1675,9 @@ def draw_hierarchy(state, pos=None, layout="radial", beta=0.8, ealpha=0.4,
tlabels = t.new_vertex_property("string")
t_orig = t
t = GraphView(t, vfilt=lambda v: int(v) >= g.num_vertices(True))
t = GraphView(t,
vfilt=lambda v: int(v) >= g.num_vertices(True) and hvvisible[v],
efilt=hevisible)
if verbose:
print("joining graphs")
props = [(pos, tpos),
......@@ -1783,7 +1814,8 @@ def draw_hierarchy(state, pos=None, layout="radial", beta=0.8, ealpha=0.4,
vmask = gg.vertex_index.copy("int")
u = GraphView(gg, directed=False, vfilt=vmask.fa < g.num_vertices())
cts = eprops["control_points"]
get_hierarchy_control_points(u, t_orig, pos, beta, cts=cts)
get_hierarchy_control_points(u, t_orig, pos, beta, cts=cts,
is_tree=hshortcuts == 0)
def draw_branch(widget, gg, key_id, picked, pos, vprops, eprops):
if key_id == ord('b'):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment