Toggle navigation
Toggle navigation
This project
Loading...
Sign in
조성현
/
graph-visualization
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
조성현
2017-03-21 07:11:54 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
ea8c2c0327d2c910894f02e05ae13be198834d68
ea8c2c03
1 parent
7aacd4ca
add comment, minor revision
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
204 additions
and
131 deletions
PaperGraph/NodeItem.cpp
PaperGraph/NodeItem.h
PaperGraph/PaperGraph.vcxproj
PaperGraph/PaperGraph.vcxproj.filters
PaperGraph/PaperGraphWidget.cpp
PaperGraph/PaperGraphWidget.h
PaperGraph/main.cpp
PaperGraph/NodeItem.cpp
View file @
ea8c2c0
...
...
@@ -13,13 +13,13 @@ void NodeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
}
NodeItem
::
NodeItem
(
int
x
,
int
y
)
NodeItem
::
NodeItem
(
int
x
,
int
y
,
QString
label
)
{
this
->
x
=
x
;
this
->
y
=
y
;
//this->color = QColor(Qt::green); //R, G, B
this
->
color
=
QColor
(
Qt
::
green
);
setZValue
((
x
+
y
)
%
2
);
this
->
label
=
label
;
setZValue
(
1
);
setFlags
(
ItemIsSelectable
|
ItemIsMovable
);
setAcceptHoverEvents
(
true
);
...
...
@@ -42,100 +42,23 @@ void NodeItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option
{
Q_UNUSED
(
widget
);
//QColor fillColor = (option->state & QStyle::State_Selected) ? color.dark(150) : color;
//if (option->state & QStyle::State_MouseOver)
// fillColor = fillColor.light(125);
//label
QFont
font
(
"Gulim"
,
10
);
font
.
setStyleStrategy
(
QFont
::
ForceOutline
);
painter
->
setFont
(
font
);
painter
->
save
();
painter
->
scale
(
0.3
,
0.3
);
painter
->
drawText
(
0
,
0
,
label
);
painter
->
restore
();
//const qreal& lod = option->levelOfDetailFromTransform(painter->worldTransform());
//if (lod < 0.2) {
// if (lod < 0.125) {
// painter->fillRect(QRectF(0, 0, 110, 70), fillColor);
// return;
// }
// QBrush b = painter->brush();
// painter->setBrush(fillColor);
// painter->drawRect(13, 13, 97, 57);
// painter->setBrush(b);
// return;
//}
//QPen oldPen = painter->pen();
//QPen pen = oldPen;
//int width = 0;
//if (option->state & QStyle::State_Selected)
// width += 2;
//pen.setWidth(width);
//QBrush b = painter->brush();
//painter->setBrush(QBrush(fillColor.dark(option->state & QStyle::State_Sunken ? 120 : 100)));
//painter->drawRect(QRect(14, 14, 79, 39));
//painter->setBrush(b);
//if (lod >= 1) {
// painter->setPen(QPen(Qt::gray, 1));
// painter->drawLine(15, 54, 94, 54);
// painter->drawLine(94, 53, 94, 15);
// painter->setPen(QPen(Qt::black, 0));
//}
//Rectangle
QColor
fillColor
=
(
option
->
state
&
QStyle
::
State_Selected
)
?
color
.
dark
(
150
)
:
color
;
if
(
option
->
state
&
QStyle
::
State_MouseOver
)
fillColor
=
fillColor
.
light
(
125
);
painter
->
setPen
(
QPen
(
Qt
::
black
));
QPen
pen
=
painter
->
pen
();
pen
.
setWidth
(
0
);
pen
.
setColor
(
QColor
(
Qt
::
black
));
painter
->
setPen
(
pen
);
painter
->
setBrush
(
QBrush
(
fillColor
));
painter
->
drawRect
(
0
,
0
,
NODE_SIZE
,
NODE_SIZE
);
//painter->fillRect(QRectF(0, 0, NODE_SIZE, NODE_SIZE), fillColor);
//painter->drawRect(0, 0, NODE_SIZE, NODE_SIZE);
// Draw text
//if (lod >= 2) {
// QFont font("Times", 10);
// font.setStyleStrategy(QFont::ForceOutline);
// painter->setFont(font);
// painter->save();
// painter->scale(0.1, 0.1);
// painter->drawText(170, 180, QString("Model: VSC-2000 (Very Small Chip) at %1x%2").arg(x).arg(y));
// painter->drawText(170, 200, QString("Serial number: DLWR-WEER-123L-ZZ33-SDSJ"));
// painter->drawText(170, 220, QString("Manufacturer: Chip Manufacturer"));
// painter->restore();
//}
// Draw lines
//QVarLengthArray<QLineF, 36> lines;
//if (lod >= 0.5) {
// for (int i = 0; i <= 10; i += (lod > 0.5 ? 1 : 2)) {
// lines.append(QLineF(18 + 7 * i, 13, 18 + 7 * i, 5));
// lines.append(QLineF(18 + 7 * i, 54, 18 + 7 * i, 62));
// }
// for (int i = 0; i <= 6; i += (lod > 0.5 ? 1 : 2)) {
// lines.append(QLineF(5, 18 + i * 5, 13, 18 + i * 5));
// lines.append(QLineF(94, 18 + i * 5, 102, 18 + i * 5));
// }
//}
//if (lod >= 0.4) {
// const QLineF lineData[] = {
// QLineF(25, 35, 35, 35),
// QLineF(35, 30, 35, 40),
// QLineF(35, 30, 45, 35),
// QLineF(35, 40, 45, 35),
// QLineF(45, 30, 45, 40),
// QLineF(45, 35, 55, 35)
// };
// lines.append(lineData, 6);
//}
//painter->drawLines(lines.data(), lines.size());
// Draw red ink
//if (stuff.size() > 1) {
// QPen p = painter->pen();
// painter->setPen(QPen(Qt::red, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
// painter->setBrush(Qt::NoBrush);
// QPainterPath path;
// path.moveTo(stuff.first());
// for (int i = 1; i < stuff.size(); ++i)
// path.lineTo(stuff.at(i));
// painter->drawPath(path);
// painter->setPen(p);
//}
}
...
...
PaperGraph/NodeItem.h
View file @
ea8c2c0
...
...
@@ -14,6 +14,7 @@ private:
int
x
;
int
y
;
QColor
color
;
QString
label
;
protected
:
void
mousePressEvent
(
QGraphicsSceneMouseEvent
*
event
)
override
;
...
...
@@ -21,7 +22,7 @@ protected:
void
mouseReleaseEvent
(
QGraphicsSceneMouseEvent
*
event
)
override
;
public
:
NodeItem
(
int
x
,
int
y
);
NodeItem
(
int
x
,
int
y
,
QString
label
);
QRectF
boundingRect
()
const
override
;
QPainterPath
shape
()
const
override
;
...
...
PaperGraph/PaperGraph.vcxproj
View file @
ea8c2c0
...
...
@@ -145,6 +145,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="EdgeItem.cpp" />
<ClCompile Include="GeneratedFiles\Debug\moc_GraphicsView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
...
...
@@ -217,6 +218,7 @@
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ClInclude Include="EdgeItem.h" />
<ClInclude Include="GeneratedFiles\ui_PaperGraphWidget.h" />
<CustomBuild Include="GraphicsView.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
...
...
PaperGraph/PaperGraph.vcxproj.filters
View file @
ea8c2c0
...
...
@@ -62,6 +62,9 @@
<ClCompile Include="GeneratedFiles\Release\moc_GraphicsView.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="EdgeItem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="PaperGraphWidget.h">
...
...
@@ -84,5 +87,8 @@
<ClInclude Include="NodeItem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EdgeItem.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
...
...
PaperGraph/PaperGraphWidget.cpp
View file @
ea8c2c0
#include "PaperGraphWidget.h"
#include "NodeItem.h"
#include "EdgeItem.h"
#include "GraphicsView.h"
#include <string>
PaperGraphWidget
::
PaperGraphWidget
(
QWidget
*
parent
)
:
QWidget
(
parent
)
{
...
...
@@ -20,6 +23,52 @@ PaperGraphWidget::PaperGraphWidget(QWidget *parent)
void
PaperGraphWidget
::
print_graph
(
const
Graph
&
graph
)
{
//print graph
typedef
square_topology
<>
Topology
;
typedef
typename
Topology
::
point_type
Point
;
const
int
rect_sz
=
4
;
auto
position
=
get
(
vertex_position
,
graph
);
auto
label
=
get
(
vertex_name
,
graph
);
//print edges
typename
graph_traits
<
Graph
>::
edge_iterator
ei
,
ei_end
;
typedef
boost
::
graph_traits
<
Graph
>::
vertex_descriptor
VertexDescriptor
;
VertexDescriptor
u
,
v
;
for
(
boost
::
tie
(
ei
,
ei_end
)
=
edges
(
graph
);
ei
!=
ei_end
;
++
ei
)
{
u
=
source
(
*
ei
,
graph
);
v
=
target
(
*
ei
,
graph
);
Point
p1
=
position
[
u
];
Point
p2
=
position
[
v
];
/*line = scene->addLine(
p1[0], p1[1],
p2[0], p2[1],
QPen(Qt::black)
);*/
//QGraphicsItem *edge =
// new EdgeItem(p1[0], p1[1], p2[0], p2[1]);
//edge->setPos(QPointF(p1[0], p1[1]));
//scene->addItem(edge);
scene
->
addLine
(
p1
[
0
],
p1
[
1
],
p2
[
0
],
p2
[
1
],
QPen
(
Qt
::
black
,
0
));
}
//print nodes
typename
graph_traits
<
Graph
>::
vertex_iterator
vi
,
vi_end
;
for
(
boost
::
tie
(
vi
,
vi_end
)
=
vertices
(
graph
);
vi
!=
vi_end
;
++
vi
)
{
//Point p = position[*vi];
//rectangle = scene->addRect(
// p[0], p[1], rect_sz, rect_sz,
// QPen(Qt::black),
// QBrush(Qt::green));
Point
p
=
position
[
*
vi
];
std
::
string
name
=
label
[
*
vi
];
QGraphicsItem
*
node
=
new
NodeItem
(
p
[
0
],
p
[
1
],
QString
(
name
.
c_str
()));
node
->
setPos
(
QPointF
(
p
[
0
],
p
[
1
]));
scene
->
addItem
(
node
);
}
}
void
PaperGraphWidget
::
initscene
()
...
...
PaperGraph/PaperGraphWidget.h
View file @
ea8c2c0
...
...
@@ -5,8 +5,8 @@
#include <QGraphicsScene>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/
kamada_kawai_spring_layout
.hpp>
#include <boost/graph/
random_layout
.hpp>
#include <boost/graph/
topology
.hpp>
#include <boost/graph/
graph_traits
.hpp>
#include "ui_PaperGraphWidget.h"
...
...
@@ -33,7 +33,6 @@ typedef adjacency_list<
listS
,
//VertexList
undirectedS
,
//vertex properties
//VertexProperties,
VertexProperties
,
//edge properties
boost
::
property
<
edge_weight_t
,
double
>
...
...
PaperGraph/main.cpp
View file @
ea8c2c0
...
...
@@ -10,14 +10,29 @@
#include <map>
#include <vector>
#include <boost/graph/fruchterman_reingold.hpp>
//#include <boost/graph/kamada_kawai_spring_layout.hpp>
#include <boost/graph/random_layout.hpp>
#include <boost/graph/circle_layout.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/algorithm/string.hpp> //boost::split
//#include <boost/bind.hpp>
#include <boost/bimap.hpp>
using
namespace
std
;
const
string
PAPER_FILENAME
=
"dblp-paper.txt"
;
/**
* Constants
*/
const
char
*
PAPER_FILENAME
=
"dblp-paper.txt"
;
enum
GRAPH_LAYOUT
{
RANDOM_LAYOUT
,
CIRCLE_LAYOUT
,
//KAMADA_KAWAI_LAYOUT,
FRUCHTERMAN_REINGOLD_LAYOUT
//slow
};
const
int
LAYOUT_MODE
=
GRAPH_LAYOUT
::
RANDOM_LAYOUT
;
const
int
SCREEN_SIZE
=
500
;
const
int
NODE_LIMIT
=
100
;
Graph
read_graph
(
ifstream
&
in
)
{
/**
...
...
@@ -31,82 +46,160 @@ Graph read_graph(ifstream& in) {
vector
<
std
::
string
>
authors
;
vector
<
pair
<
string
,
string
>>
edges
;
//String <--> int 양방향 변환을 위해 bidirectional map 상숑
typedef
boost
::
bimap
<
string
,
int
>
bm_type
;
bm_type
node_ids
;
vector
<
simple_edge
>
edges_indexes
;
vector
<
simple_edge
>
edges_indexes
;
//int로 변환된 edge
int
node_cnt
=
0
;
qDebug
()
<<
"* graph reading start"
<<
endl
;
qDebug
()
<<
"* graph reading start"
;
//한 줄씩 읽어서 Parse
while
(
std
::
getline
(
in
,
line
)
&&
!
line
.
empty
())
{
//boost::split 이용해 문자열 분리
//tokens[0]: Paper-key. ex) conf/iastedCSN/KeimS06
//tokens[1]: Authors. ex) Werner Keim&&Arpad L. Scholtz
//tokens[2]: Published year.
boost
::
split
(
tokens
,
line
,
boost
::
is_any_of
(
"||"
),
boost
::
token_compress_on
);
boost
::
split
(
authors
,
tokens
[
1
],
boost
::
is_any_of
(
"&&"
),
boost
::
token_compress_on
);
const
string
&
paper_key
=
tokens
[
0
];
if
(
node_ids
.
left
.
find
(
paper_key
)
==
node_ids
.
left
.
end
())
{
//node_ids[paper_key] = node_cnt++;
node_ids
.
insert
(
bm_type
::
value_type
(
paper_key
,
node_cnt
++
));
//qDebug() << paper_key.c_str() << " ";
}
for
(
auto
author
:
authors
)
{
edges
.
push_back
(
pair
<
string
,
string
>
(
paper_key
,
author
));
if
(
node_ids
.
left
.
find
(
author
)
==
node_ids
.
left
.
end
())
{
//node_ids[author] = node_cnt++;
node_ids
.
insert
(
bm_type
::
value_type
(
author
,
node_cnt
++
));
//qDebug() << author.c_str() << " ";
}
}
//debug
if
(
node_cnt
>
100
)
break
;
if
(
node_cnt
>
NODE_LIMIT
)
break
;
}
qDebug
()
<<
"* graph reading complete"
<<
endl
;
//std::sort(node_names.begin(), node_names.end()
);
qDebug
()
<<
"* graph reading complete"
;
qDebug
()
<<
"* # of nodes: "
<<
node_cnt
;
qDebug
()
<<
"* # of edges: "
<<
edges
.
size
(
);
//
Make graph
//
Graph --> defined in "PaperGraphWidget.h"
//
edge conversion
//
<string, string> to <int, int>
//using boost::bimap (bidirectional map)
for
(
auto
edge
:
edges
)
{
edges_indexes
.
push_back
({
node_ids
.
left
.
find
(
edge
.
first
)
->
get_right
(),
node_ids
.
left
.
find
(
edge
.
second
)
->
get_right
()
});
}
//Graph --> defined in "PaperGraphWidget.h"
Graph
graph
(
edges_indexes
.
begin
(),
edges_indexes
.
end
(),
node_ids
.
size
());
//print map
//for (auto it=node_ids.left.begin(), itend=node_ids.left.end();
// it!=itend; ++it) {
// qDebug() << it->first.c_str() << " " << it->second << endl;
//}
//set index property
qDebug
()
<<
"* set vertex property start"
;
typedef
typename
graph_traits
<
Graph
>::
edge_iterator
edge_iterator
;
typedef
typename
graph_traits
<
Graph
>::
vertex_iterator
vertex_iterator
;
vertex_iterator
vi
,
vi_end
;
int
i
=
0
;
for
(
boost
::
tie
(
vi
,
vi_end
)
=
vertices
(
graph
);
vi
!=
vi_end
;
++
vi
)
{
//Vertex Property 설정
//index: 0 ~ ...
//name : map의 value(i) 기준으로 찾은 Key
// map --> map<string, int> (boost bidirectional map)
boost
::
put
(
vertex_index
,
graph
,
*
vi
,
i
);
boost
::
put
(
vertex_name
,
graph
,
*
vi
,
node_ids
.
right
.
find
(
i
)
->
get_left
());
//VertexProperties prop = VertexProperties(i,
// boost::property<vertex_name_t, std::string,
// boost::property<vertex_position_t, point>>());
++
i
;
}
qDebug
()
<<
"* set vertex property end"
;
//
for (auto edge : edges) {
// //add edge
// //VertexProperties prop = VertexProperties()
// //add_edge(node_ids[edge.first], node_ids[edge.second],
);
//
}
//
모든 edge weight 1로 만들기
edge_iterator
ei
,
ei_end
;
for
(
boost
::
tie
(
ei
,
ei_end
)
=
boost
::
edges
(
graph
);
ei
!=
ei_end
;
++
ei
)
{
boost
::
put
(
edge_weight
,
graph
,
*
ei
,
1
);
}
//make graph layout
//path finding between two vertices
//using dijkstra algorithm
//ex) "Werner Keim" ---> "Arpad L. Scholtz" (in dataset 2nd line)
qDebug
()
<<
"* path finding start"
;
typedef
graph_traits
<
Graph
>::
vertex_descriptor
vertex_descriptor
;
std
::
vector
<
vertex_descriptor
>
parent
(
num_vertices
(
graph
));
std
::
vector
<
int
>
distance
(
num_vertices
(
graph
));
int
start_idx
=
node_ids
.
left
.
find
(
"Werner Keim"
)
->
get_right
();
vertex_descriptor
start_v
=
vertex
(
start_idx
,
graph
);
dijkstra_shortest_paths
(
graph
,
start_v
,
predecessor_map
(
boost
::
make_iterator_property_map
(
parent
.
begin
(),
get
(
boost
::
vertex_index
,
graph
))
).
distance_map
(
boost
::
make_iterator_property_map
(
distance
.
begin
(),
get
(
boost
::
vertex_index
,
graph
)))
);
qDebug
()
<<
"* path finding end"
;
int
aaaa
=
3
;
//graph layout calculation
//using boost::random_graph_layout and boost::kamada_kawai_spring_layout
//vertex마다 계산된 좌표를 property에 적용
//예제 코드: http://www.boost.org/doc/libs/1_63_0/libs/graph/test/layout_test.cpp
//(-> 콘솔 기반)
qDebug
()
<<
"* make graph layout start"
;
typedef
square_topology
<>
Topology
;
minstd_rand
gen
;
Topology
topology
(
gen
,
(
double
)
SCREEN_SIZE
);
Topology
::
point_type
origin
;
origin
[
0
]
=
origin
[
1
]
=
(
double
)
SCREEN_SIZE
;
Topology
::
point_difference_type
extent
;
extent
[
0
]
=
extent
[
1
]
=
(
double
)
SCREEN_SIZE
;
rectangle_topology
<>
rect_top
(
gen
,
-
SCREEN_SIZE
/
2
,
-
SCREEN_SIZE
/
2
,
SCREEN_SIZE
/
2
,
SCREEN_SIZE
/
2
);
std
::
vector
<
Topology
::
point_difference_type
>
displacements
(
num_vertices
(
graph
));
switch
(
LAYOUT_MODE
)
{
case
GRAPH_LAYOUT
:
:
RANDOM_LAYOUT
:
random_graph_layout
(
graph
,
get
(
vertex_position
,
graph
),
rect_top
);
break
;
case
GRAPH_LAYOUT
:
:
CIRCLE_LAYOUT
:
circle_graph_layout
(
graph
,
get
(
vertex_position
,
graph
),
SCREEN_SIZE
/
2
);
break
;
//case GRAPH_LAYOUT::KAMADA_KAWAI_LAYOUT:
// kamada_kawai_spring_layout(graph,
// get(vertex_position, graph),
// get(edge_weight, graph),
// topology,
// side_length((double)SCREEN_SIZE)
// );
// break;
case
GRAPH_LAYOUT
:
:
FRUCHTERMAN_REINGOLD_LAYOUT
:
//fruchterman_reingold_force_directed_layout(graph,
// get(vertex_position, graph),
// topology,
// square_distance_attractive_force(),
// square_distance_repulsive_force(),
// all_force_pairs(),
// linear_cooling<double>(SCREEN_SIZE/2),
// make_iterator_property_map(displacements.begin(),
// get(vertex_index, graph),
// Topology::point_difference_type())
//);
fruchterman_reingold_force_directed_layout
(
graph
,
get
(
vertex_position
,
graph
),
topology
,
attractive_force
(
square_distance_attractive_force
())
.
cooling
(
linear_cooling
<
double
>
(
50
))
);
break
;
}
qDebug
()
<<
"* make graph layout end"
;
return
graph
;
}
...
...
@@ -114,7 +207,7 @@ Graph read_graph(ifstream& in) {
int
main
(
int
argc
,
char
*
argv
[])
{
QApplication
app
(
argc
,
argv
);
app
.
setAttribute
(
Qt
::
AA_DontCreateNativeWidgetSiblings
);
//
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
PaperGraphWidget
w
;
...
...
Please
register
or
login
to post a comment