Схема Фрухтермана-Рейнгольда не сходится

Я хочу построить график сворачивания РНК с помощью BGL, он имеет гарантированную плоскую структуру, и все ребра должны иметь одинаковую длину (есть два типа ребер: нормальная последовательность и связи, выделенные красным), например:

http://www.ncrna.org/frnadb/sec_structure/png/FR096703.png

namespace boost {
    enum vertex_position_t { vertex_position };
    BOOST_INSTALL_PROPERTY(vertex, position);
};

template<class PairIterator>
void layout(std::string seq, PairIterator begin, PairIterator end) {
    using namespace boost; using namespace std;

    // backbone edges + bonding edges
    vector<pair<size_t,size_t>> edge_list(begin, end);
    for(size_t i = 0 ; i < seq.size() - 1 ; i++)
        edge_list.push_back(make_pair(i, i + 1));

    typedef rectangle_topology<> topology;
    typedef topology::point_type point;
    boost::minstd_rand random;
    topology space(random, -1000, -1000, 2000, 2000);

    adjacency_list<vecS, vecS, undirectedS,
        property<vertex_position_t, point>
    > g(edge_list.begin(), edge_list.end(), seq.size());

    random_graph_layout(g, get(vertex_position, g), space);
    fruchterman_reingold_force_directed_layout(g, get(vertex_position, g), space,
        cooling(linear_cooling<double>(100)));

    // draw
}

Однако это дает мне очень случайную раскладку (для кулдауна 100, 200, 400). Более длительные кулдауны просто вдавливают вершины в углы (изображения показывают полный макет). Края кажутся постоянно слишком длинными...

выход

Я хотел бы указать целевую длину для краев и не останавливать симуляцию, пока она не будет достигнута в пределах некоторого запаса.

Мой код собран из образцов повышения, но мне не нужно придерживаться карт свойств и т. д., я просто хочу макет, не прибегая к GraphViz.


person pascal    schedule 05.05.2012    source источник


Ответы (1)


Похоже, макет начинает работать на крайнем правом изображении, но места слишком мало, чтобы его можно было развернуть в правильную форму: может, для начала попробовать использовать более компактный случайный макет?

Или может помочь более сильная сила притяжения. Обратите внимание, что, согласно документации, привлекательным по умолчанию force, square_distance_attractive_force делит силу притяжения на дескриптор ребра --- таким образом, меньшие дескрипторы ребер означают более близкие вершины.


Вы можете определить «целевую длину» (вроде) для ребер, учитывая, что для хорошо организованного планарного графа каждая вершина близка только к вершинам, с которыми она связана ребрами. Это очень похоже на простой случай, когда у нас есть две вершины, соединенные одним ребром (и если бы у вас была обычная сетка вершин, она не была бы больше, чем в 4 раза):

  • Функция силы отталкивания (по умолчанию) равна (vertex descriptor value, V)^2/distance для всех пар вершин.
  • Функция силы притяжения (по умолчанию) равна distance^2/(edge descriptor value, E) для вершин, соединенных ребрами.

Они находятся в равновесии, когда:

V2 / расстояние = расстояние2 / E

so:

расстояние = V(2/3) E(1/3)

person James    schedule 08.05.2012
comment
Он прилипает к краю, когда я использую прямоугольник (-100,-100,200,200) для случайного макета. С пользовательской функцией привлекательности_силы 1e5 * d * d / k она создает некоторый макет, но это все еще довольно плохо. С пользовательской функцией охлаждения 100 - (1 - pow(steps/max_steps,4)) все становится немного лучше, но это далеко не то, что производит GraphViz… - person pascal; 09.05.2012
comment
Как выглядит график силы притяжения 1e5*? Может, попробовать еще выше? Также возможно вычислить целевую длину (вроде как) на основе ваших силовых функций притяжения и отталкивания — рассмотрим случай, когда у вас есть две вершины и одно ребро между ними. - person James; 09.05.2012
comment
хорошо, с кастомными силовыми функциями не хуже GraphViz neato, который тоже не рядом с картинкой в ​​моем посте, но с круговой раскладкой вместо случайной вполне приемлемо. - person pascal; 14.05.2012