Showing
8 changed files
with
318 additions
and
68 deletions
| 1 | #include "stdafx.h" | 1 | #include "stdafx.h" |
| 2 | #include "GraphItem.h" | 2 | #include "GraphItem.h" |
| 3 | 3 | ||
| 4 | -GraphItem::GraphItem(ifstream& fin, int numOfLines) | 4 | +GraphItem::GraphItem(const char *filename) |
| 5 | { | 5 | { |
| 6 | - //numOfLines == ifstream에서 읽을 라인의 수 | 6 | + fin.open(filename); |
| 7 | - | ||
| 8 | if (!fin) | 7 | if (!fin) |
| 9 | - throw std::exception("graph file input is invalid"); | 8 | + throw std::exception("graph file is not available"); |
| 10 | - else if (numOfLines < 1) | 9 | + |
| 11 | - throw std::exception("invalid numOfLines"); | 10 | + graph = new Graph(); |
| 11 | + read_more(); | ||
| 12 | +} | ||
| 12 | 13 | ||
| 14 | +GraphItem::~GraphItem() | ||
| 15 | +{ | ||
| 16 | + fin.close(); | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +void GraphItem::read_more() | ||
| 20 | +{ | ||
| 13 | /** | 21 | /** |
| 14 | - * Parse Paper dataset | 22 | + * Parse Paper dataset |
| 15 | - * - paper_key, [author_list], publish_year | 23 | + * - paper_key, [author_list], publish_year |
| 16 | - * Column Delimiter: || | 24 | + * Column Delimiter: || |
| 17 | - * Author list Delimiter: && | 25 | + * Author list Delimiter: && |
| 18 | - */ | 26 | + */ |
| 19 | std::string line; | 27 | std::string line; |
| 20 | vector<std::string> tokens; | 28 | vector<std::string> tokens; |
| 21 | vector<std::string> authors; | 29 | vector<std::string> authors; |
| 22 | - vector<pair<string, string>> edges; | 30 | + /*vector<pair<string, string>> edges;*/ |
| 23 | - | 31 | + |
| 24 | - //String <--> int 양방향 변환을 위해 bidirectional map 상숑 | 32 | + //vector<simple_edge> edges_indexes; |
| 25 | - //map<string, int> -> <vertex label, vertex index> | 33 | + |
| 26 | - /*typedef boost::bimap<string, int> bm_type;*/ | ||
| 27 | - /*bm_type node_ids; | ||
| 28 | - vector<simple_edge> edges_indexes*/; //int로 변환된 edge | ||
| 29 | - | ||
| 30 | - int node_cnt = 0; | ||
| 31 | int line_cnt = 0; | 34 | int line_cnt = 0; |
| 32 | qDebug() << "* graph reading start"; | 35 | qDebug() << "* graph reading start"; |
| 33 | - | 36 | + |
| 34 | //한 줄씩 읽어서 Parse | 37 | //한 줄씩 읽어서 Parse |
| 38 | + int node_cnt = 0; | ||
| 35 | while (std::getline(fin, line) && !line.empty()) { | 39 | while (std::getline(fin, line) && !line.empty()) { |
| 36 | //boost::split 이용해 문자열 분리 | 40 | //boost::split 이용해 문자열 분리 |
| 37 | //tokens[0]: Paper-key. ex) conf/iastedCSN/KeimS06 | 41 | //tokens[0]: Paper-key. ex) conf/iastedCSN/KeimS06 |
| ... | @@ -39,53 +43,72 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) | ... | @@ -39,53 +43,72 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) |
| 39 | //tokens[2]: Published year. | 43 | //tokens[2]: Published year. |
| 40 | boost::split(tokens, line, boost::is_any_of("||"), boost::token_compress_on); | 44 | boost::split(tokens, line, boost::is_any_of("||"), boost::token_compress_on); |
| 41 | boost::split(authors, tokens[1], boost::is_any_of("&&"), boost::token_compress_on); | 45 | boost::split(authors, tokens[1], boost::is_any_of("&&"), boost::token_compress_on); |
| 42 | - | 46 | + |
| 43 | const string& paper_key = tokens[0]; | 47 | const string& paper_key = tokens[0]; |
| 44 | if (node_ids.left.find(paper_key) == node_ids.left.end()) { | 48 | if (node_ids.left.find(paper_key) == node_ids.left.end()) { |
| 45 | - node_ids.insert(bm_type::value_type(paper_key, node_cnt++)); | 49 | + node_ids.insert(bm_type::value_type(paper_key, node_cnt + whole_node_cnt)); |
| 50 | + ++node_cnt; | ||
| 46 | } | 51 | } |
| 47 | - | 52 | + |
| 48 | for (auto author : authors) { | 53 | for (auto author : authors) { |
| 49 | edges.push_back(pair<string, string>(paper_key, author)); | 54 | edges.push_back(pair<string, string>(paper_key, author)); |
| 50 | if (node_ids.left.find(author) == node_ids.left.end()) { | 55 | if (node_ids.left.find(author) == node_ids.left.end()) { |
| 51 | - node_ids.insert(bm_type::value_type(author, node_cnt++)); | 56 | + node_ids.insert(bm_type::value_type(author, node_cnt + whole_node_cnt)); |
| 57 | + ++node_cnt; | ||
| 52 | } | 58 | } |
| 53 | } | 59 | } |
| 54 | - | 60 | + |
| 55 | //debug | 61 | //debug |
| 56 | ++line_cnt; | 62 | ++line_cnt; |
| 57 | - if (line_cnt >= numOfLines) break; | 63 | + if (line_cnt >= READ_LINE_UNIT) break; |
| 58 | } | 64 | } |
| 59 | qDebug() << "* graph reading complete"; | 65 | qDebug() << "* graph reading complete"; |
| 60 | qDebug() << "* # of read line: " << line_cnt; | 66 | qDebug() << "* # of read line: " << line_cnt; |
| 61 | qDebug() << "* # of nodes: " << node_cnt; | 67 | qDebug() << "* # of nodes: " << node_cnt; |
| 62 | - qDebug() << "* # of edges: " << edges.size(); | 68 | + //qDebug() << "* # of edges: " << edges.size(); |
| 69 | + | ||
| 63 | 70 | ||
| 71 | + | ||
| 64 | //edge conversion | 72 | //edge conversion |
| 65 | //<string, string> to <int, int> | 73 | //<string, string> to <int, int> |
| 66 | //using boost::bimap (bidirectional map) | 74 | //using boost::bimap (bidirectional map) |
| 75 | + edges_indexes.clear(); | ||
| 67 | for (auto edge : edges) { | 76 | for (auto edge : edges) { |
| 68 | edges_indexes.push_back({ | 77 | edges_indexes.push_back({ |
| 69 | node_ids.left.find(edge.first)->get_right(), | 78 | node_ids.left.find(edge.first)->get_right(), |
| 70 | node_ids.left.find(edge.second)->get_right() | 79 | node_ids.left.find(edge.second)->get_right() |
| 71 | }); | 80 | }); |
| 72 | } | 81 | } |
| 73 | - //Graph --> defined in "PaperGraphWidget.h" | 82 | + |
| 74 | //Graph graph(edges_indexes.begin(), edges_indexes.end(), node_ids.size()); | 83 | //Graph graph(edges_indexes.begin(), edges_indexes.end(), node_ids.size()); |
| 84 | + //graph = new Graph(edges_indexes.begin(), edges_indexes.end(), node_ids.size()); | ||
| 85 | + //for (auto& e: edges_indexes) { | ||
| 86 | + // boost::add_edge(e.first, e.second, graph); | ||
| 87 | + //} | ||
| 88 | + | ||
| 89 | + if (graph) { | ||
| 90 | + delete graph; | ||
| 91 | + graph = nullptr; | ||
| 92 | + } | ||
| 75 | graph = new Graph(edges_indexes.begin(), edges_indexes.end(), node_ids.size()); | 93 | graph = new Graph(edges_indexes.begin(), edges_indexes.end(), node_ids.size()); |
| 94 | + | ||
| 76 | 95 | ||
| 96 | + | ||
| 77 | //set index property | 97 | //set index property |
| 78 | qDebug() << "* set vertex property start"; | 98 | qDebug() << "* set vertex property start"; |
| 79 | vertex_iterator vi, vi_end; | 99 | vertex_iterator vi, vi_end; |
| 80 | int i = 0; | 100 | int i = 0; |
| 81 | - for (boost::tie(vi, vi_end)=vertices(*graph); vi!=vi_end; ++vi) { | 101 | + for (boost::tie(vi, vi_end) = vertices(*graph); vi != vi_end; ++vi) { |
| 82 | //Vertex Property 설정 | 102 | //Vertex Property 설정 |
| 83 | - //index: 0 ~ ... | 103 | + //index: n ~ ... |
| 84 | //name : map의 value(i) 기준으로 찾은 Key | 104 | //name : map의 value(i) 기준으로 찾은 Key |
| 85 | - // map --> map<string, int> (boost bidirectional map) | 105 | + // map --> map<string, int> (boost bidirectional map) |
| 86 | std::string node_label = node_ids.right.find(i)->get_left(); | 106 | std::string node_label = node_ids.right.find(i)->get_left(); |
| 87 | boost::put(vertex_index, *graph, *vi, i); | 107 | boost::put(vertex_index, *graph, *vi, i); |
| 88 | boost::put(vertex_name, *graph, *vi, node_label); | 108 | boost::put(vertex_name, *graph, *vi, node_label); |
| 109 | + boost::put(vertex_record, *graph, *vi, 0); | ||
| 110 | + | ||
| 111 | + qDebug() << "** index: " << i << ", name: " << node_label.c_str(); | ||
| 89 | 112 | ||
| 90 | //node type 설정 | 113 | //node type 설정 |
| 91 | if (boost::regex_match(node_label, paper_reg)) { | 114 | if (boost::regex_match(node_label, paper_reg)) { |
| ... | @@ -99,7 +122,7 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) | ... | @@ -99,7 +122,7 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) |
| 99 | ++i; | 122 | ++i; |
| 100 | } | 123 | } |
| 101 | qDebug() << "* set vertex property end"; | 124 | qDebug() << "* set vertex property end"; |
| 102 | - | 125 | + whole_node_cnt += node_cnt; |
| 103 | 126 | ||
| 104 | //qDebug("* set edges weight start"); | 127 | //qDebug("* set edges weight start"); |
| 105 | ////모든 edge의 weight를 1로 설정 | 128 | ////모든 edge의 weight를 1로 설정 |
| ... | @@ -133,7 +156,7 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) | ... | @@ -133,7 +156,7 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) |
| 133 | //while (current != boost::vertex(start_idx, *graph)) { | 156 | //while (current != boost::vertex(start_idx, *graph)) { |
| 134 | //} | 157 | //} |
| 135 | //qDebug("* path highlighting end"); | 158 | //qDebug("* path highlighting end"); |
| 136 | - | 159 | + |
| 137 | 160 | ||
| 138 | //graph layout calculation | 161 | //graph layout calculation |
| 139 | //using boost::random_graph_layout and boost::kamada_kawai_spring_layout | 162 | //using boost::random_graph_layout and boost::kamada_kawai_spring_layout |
| ... | @@ -148,18 +171,18 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) | ... | @@ -148,18 +171,18 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) |
| 148 | Topology::point_difference_type extent; | 171 | Topology::point_difference_type extent; |
| 149 | extent[0] = extent[1] = (double)SCREEN_SIZE; | 172 | extent[0] = extent[1] = (double)SCREEN_SIZE; |
| 150 | rectangle_topology<> rect_top(gen, | 173 | rectangle_topology<> rect_top(gen, |
| 151 | - -SCREEN_SIZE/2, -SCREEN_SIZE/2, | 174 | + -SCREEN_SIZE / 2, -SCREEN_SIZE / 2, |
| 152 | - SCREEN_SIZE/2, SCREEN_SIZE/2); | 175 | + SCREEN_SIZE / 2, SCREEN_SIZE / 2); |
| 153 | - | 176 | + |
| 154 | switch (LAYOUT_MODE) { | 177 | switch (LAYOUT_MODE) { |
| 155 | case GRAPH_LAYOUT::RANDOM_LAYOUT: | 178 | case GRAPH_LAYOUT::RANDOM_LAYOUT: |
| 156 | random_graph_layout(*graph, get(vertex_position, *graph), rect_top); | 179 | random_graph_layout(*graph, get(vertex_position, *graph), rect_top); |
| 157 | break; | 180 | break; |
| 158 | - | 181 | + |
| 159 | case GRAPH_LAYOUT::CIRCLE_LAYOUT: | 182 | case GRAPH_LAYOUT::CIRCLE_LAYOUT: |
| 160 | - circle_graph_layout(*graph, get(vertex_position, *graph), SCREEN_SIZE/2); | 183 | + circle_graph_layout(*graph, get(vertex_position, *graph), SCREEN_SIZE / 2); |
| 161 | break; | 184 | break; |
| 162 | - | 185 | + |
| 163 | case GRAPH_LAYOUT::FRUCHTERMAN_REINGOLD_LAYOUT: | 186 | case GRAPH_LAYOUT::FRUCHTERMAN_REINGOLD_LAYOUT: |
| 164 | fruchterman_reingold_force_directed_layout(*graph, | 187 | fruchterman_reingold_force_directed_layout(*graph, |
| 165 | get(vertex_position, *graph), | 188 | get(vertex_position, *graph), |
| ... | @@ -172,14 +195,18 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) | ... | @@ -172,14 +195,18 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) |
| 172 | qDebug() << "* make graph layout end"; | 195 | qDebug() << "* make graph layout end"; |
| 173 | 196 | ||
| 174 | 197 | ||
| 198 | + //clear lists | ||
| 199 | + nodeList.clear(); | ||
| 200 | + edgeList.clear(); | ||
| 201 | + | ||
| 175 | //add edges | 202 | //add edges |
| 176 | - auto position = get(vertex_position, *graph); | 203 | + auto position = boost::get(vertex_position, *graph); |
| 177 | - auto label = get(vertex_name, *graph); | 204 | + auto label = boost::get(vertex_name, *graph); |
| 178 | - auto nodeType = get(vertex_type, *graph); | 205 | + auto nodeType = boost::get(vertex_type, *graph); |
| 179 | 206 | ||
| 180 | edge_iterator ei, ei_end; | 207 | edge_iterator ei, ei_end; |
| 181 | vertex_descriptor u, v; | 208 | vertex_descriptor u, v; |
| 182 | - for (boost::tie(ei, ei_end)=boost::edges(*graph); ei!=ei_end; ++ei) { | 209 | + for (boost::tie(ei, ei_end) = boost::edges(*graph); ei != ei_end; ++ei) { |
| 183 | u = source(*ei, *graph); | 210 | u = source(*ei, *graph); |
| 184 | v = target(*ei, *graph); | 211 | v = target(*ei, *graph); |
| 185 | Point p1 = position[u]; | 212 | Point p1 = position[u]; |
| ... | @@ -187,14 +214,14 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) | ... | @@ -187,14 +214,14 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) |
| 187 | 214 | ||
| 188 | //make edge item and push it to list | 215 | //make edge item and push it to list |
| 189 | EdgeItem *edge; | 216 | EdgeItem *edge; |
| 190 | - | 217 | + |
| 191 | edge = new EdgeItem(p1[0], p1[1], p2[0], p2[1], QColor(Qt::black), 0); | 218 | edge = new EdgeItem(p1[0], p1[1], p2[0], p2[1], QColor(Qt::black), 0); |
| 192 | edge->setPos(p1[0], p1[1]); | 219 | edge->setPos(p1[0], p1[1]); |
| 193 | edgeList << edge; | 220 | edgeList << edge; |
| 194 | } | 221 | } |
| 195 | 222 | ||
| 196 | //add nodes | 223 | //add nodes |
| 197 | - for (boost::tie(vi, vi_end)=vertices(*graph); vi!=vi_end; ++vi) { | 224 | + for (boost::tie(vi, vi_end) = vertices(*graph); vi != vi_end; ++vi) { |
| 198 | Point p = position[*vi]; | 225 | Point p = position[*vi]; |
| 199 | auto nt = nodeType[*vi]; | 226 | auto nt = nodeType[*vi]; |
| 200 | std::string name = label[*vi]; | 227 | std::string name = label[*vi]; |
| ... | @@ -203,7 +230,8 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) | ... | @@ -203,7 +230,8 @@ GraphItem::GraphItem(ifstream& fin, int numOfLines) |
| 203 | NodeItem *node; | 230 | NodeItem *node; |
| 204 | if (nt == NODE_TYPE::NODE_PAPER) { | 231 | if (nt == NODE_TYPE::NODE_PAPER) { |
| 205 | node = new NodeItem(p[0], p[1], QColor(Qt::darkGreen), QString(name.c_str()), nt); | 232 | node = new NodeItem(p[0], p[1], QColor(Qt::darkGreen), QString(name.c_str()), nt); |
| 206 | - } else { | 233 | + } |
| 234 | + else { | ||
| 207 | node = new NodeItem(p[0], p[1], QColor(Qt::green), QString(name.c_str()), nt); | 235 | node = new NodeItem(p[0], p[1], QColor(Qt::green), QString(name.c_str()), nt); |
| 208 | } | 236 | } |
| 209 | node->setPos(QPointF(p[0], p[1])); | 237 | node->setPos(QPointF(p[0], p[1])); |
| ... | @@ -262,6 +290,63 @@ void GraphItem::reset_color() | ... | @@ -262,6 +290,63 @@ void GraphItem::reset_color() |
| 262 | } | 290 | } |
| 263 | } | 291 | } |
| 264 | 292 | ||
| 293 | +void GraphItem::topK_highlight() | ||
| 294 | +{ | ||
| 295 | + // 저자 노드별 실적 계산 | ||
| 296 | + vertex_iterator vi, vi_end; | ||
| 297 | + Graph::adjacency_iterator ai, ai_end; | ||
| 298 | + | ||
| 299 | + auto nodeLabel = boost::get(vertex_name, *graph); | ||
| 300 | + auto nodeType = boost::get(vertex_type, *graph); | ||
| 301 | + auto numOfRecords = boost::get(vertex_record, *graph); | ||
| 302 | + | ||
| 303 | + //실적 count 초기화 | ||
| 304 | + //for (boost::tie(vi, vi_end) = boost::vertices(*graph); vi != vi_end; ++vi) { | ||
| 305 | + // if (nodeType[*vi] != NODE_TYPE::NODE_AUTHOR) { | ||
| 306 | + // continue; | ||
| 307 | + // } | ||
| 308 | + // boost::put(vertex_record, *graph, *vi, 0); | ||
| 309 | + //} | ||
| 310 | + | ||
| 311 | + // <record, label> | ||
| 312 | + TopKHeap<pair<int, string>> heap(TOP_K); | ||
| 313 | + for (boost::tie(vi, vi_end) = boost::vertices(*graph); vi != vi_end; ++vi) { | ||
| 314 | + if (nodeType[*vi] != NODE_TYPE::NODE_AUTHOR) { | ||
| 315 | + continue; | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + int record_cnt = 0; | ||
| 319 | + for (boost::tie(ai, ai_end) = boost::adjacent_vertices(*vi, *graph); | ||
| 320 | + ai != ai_end; ++ai) { | ||
| 321 | + if (nodeType[*vi] == NODE_TYPE::NODE_PAPER) { | ||
| 322 | + ++record_cnt; | ||
| 323 | + } | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + boost::put(vertex_record, *graph, *vi, record_cnt); | ||
| 327 | + heap.push(make_pair(record_cnt, nodeLabel[*vi])); | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + //get top K records | ||
| 331 | + pair<int, string> topk_arr[TOP_K]; | ||
| 332 | + for (int i = 0; i < TOP_K; ++i) { | ||
| 333 | + topk_arr[i] = heap.pop(); | ||
| 334 | + } | ||
| 335 | + | ||
| 336 | + for (auto& n: nodeList) { | ||
| 337 | + auto label = n->getLabel(); | ||
| 338 | + n->setColor(QColor(Qt::lightGray)); | ||
| 339 | + for (auto& p: topk_arr) { | ||
| 340 | + if (label.toStdString() == p.second) { | ||
| 341 | + n->setColor(QColor(Qt::red)); | ||
| 342 | + break; | ||
| 343 | + } | ||
| 344 | + } | ||
| 345 | + } | ||
| 346 | + | ||
| 347 | + //delete[] topk_arr; | ||
| 348 | +} | ||
| 349 | + | ||
| 265 | //event handler | 350 | //event handler |
| 266 | void GraphItem::mousePressEvent(QGraphicsSceneMouseEvent *event) | 351 | void GraphItem::mousePressEvent(QGraphicsSceneMouseEvent *event) |
| 267 | { | 352 | { | ... | ... |
| ... | @@ -13,7 +13,12 @@ class GraphItem | ... | @@ -13,7 +13,12 @@ class GraphItem |
| 13 | : public QGraphicsItem | 13 | : public QGraphicsItem |
| 14 | { | 14 | { |
| 15 | public: | 15 | public: |
| 16 | - GraphItem(ifstream& fin, int numOfLines); | 16 | + //GraphItem(ifstream* pFin); |
| 17 | + GraphItem(const char* filename); | ||
| 18 | + virtual ~GraphItem(); | ||
| 19 | + | ||
| 20 | + //io | ||
| 21 | + void read_more(); | ||
| 17 | 22 | ||
| 18 | //overrides | 23 | //overrides |
| 19 | QRectF boundingRect() const override; | 24 | QRectF boundingRect() const override; |
| ... | @@ -23,6 +28,7 @@ public: | ... | @@ -23,6 +28,7 @@ public: |
| 23 | //methods | 28 | //methods |
| 24 | void path_highlighting(std::string start, std::string end); | 29 | void path_highlighting(std::string start, std::string end); |
| 25 | void reset_color(); | 30 | void reset_color(); |
| 31 | + void topK_highlight(); | ||
| 26 | 32 | ||
| 27 | protected: | 33 | protected: |
| 28 | void mousePressEvent(QGraphicsSceneMouseEvent *event) override; | 34 | void mousePressEvent(QGraphicsSceneMouseEvent *event) override; |
| ... | @@ -30,8 +36,12 @@ protected: | ... | @@ -30,8 +36,12 @@ protected: |
| 30 | void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; | 36 | void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; |
| 31 | 37 | ||
| 32 | private: | 38 | private: |
| 39 | + ifstream fin; | ||
| 33 | bm_type node_ids; | 40 | bm_type node_ids; |
| 41 | + vector<pair<string, string>> edges; | ||
| 34 | vector<simple_edge> edges_indexes; | 42 | vector<simple_edge> edges_indexes; |
| 43 | + int whole_node_cnt = 0; | ||
| 44 | + | ||
| 35 | Graph *graph = nullptr; | 45 | Graph *graph = nullptr; |
| 36 | QList<NodeItem *> nodeList; | 46 | QList<NodeItem *> nodeList; |
| 37 | QList<EdgeItem *> edgeList; | 47 | QList<EdgeItem *> edgeList; | ... | ... |
| ... | @@ -25,35 +25,56 @@ MainWindow::~MainWindow() | ... | @@ -25,35 +25,56 @@ MainWindow::~MainWindow() |
| 25 | 25 | ||
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | -void MainWindow::print_graph(std::ifstream& fin) | 28 | +void MainWindow::print_graph(const char * filename) |
| 29 | { | 29 | { |
| 30 | - graphWidget->print_graph(fin); | 30 | + graphWidget->print_graph(filename); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | +//void MainWindow::print_graph(std::ifstream *pFin) | ||
| 34 | +//{ | ||
| 35 | +// graphWidget->print_graph(pFin); | ||
| 36 | +//} | ||
| 37 | + | ||
| 33 | ////////////////////////////////////////////////////////////////// | 38 | ////////////////////////////////////////////////////////////////// |
| 34 | // private methods | 39 | // private methods |
| 35 | ////////////////////////////////////////////////////////////////// | 40 | ////////////////////////////////////////////////////////////////// |
| 36 | void MainWindow::createActions() | 41 | void MainWindow::createActions() |
| 37 | { | 42 | { |
| 38 | - testHighlightAct = new QAction(tr("&Highlight"), this); | 43 | + readMoreAct = new QAction(tr("Read more"), this); |
| 44 | + readMoreAct->setStatusTip(tr("read more lines from file")); | ||
| 45 | + connect(readMoreAct, &QAction::triggered, this, &MainWindow::read_more); | ||
| 46 | + | ||
| 47 | + testHighlightAct = new QAction(tr("Highlight"), this); | ||
| 39 | testHighlightAct->setStatusTip(tr("Highlighting node")); | 48 | testHighlightAct->setStatusTip(tr("Highlighting node")); |
| 40 | connect(testHighlightAct, &QAction::triggered, this, &MainWindow::test_highlighting); | 49 | connect(testHighlightAct, &QAction::triggered, this, &MainWindow::test_highlighting); |
| 41 | - | 50 | + topkAct = new QAction(tr("topK"), this); |
| 42 | - resetColorAct = new QAction(tr("&Reset colors"), this); | 51 | + topkAct->setStatusTip(tr("highlight who was top k papers")); |
| 52 | + connect(topkAct, &QAction::triggered, this, &MainWindow::topk); | ||
| 53 | + resetColorAct = new QAction(tr("Reset colors"), this); | ||
| 43 | resetColorAct->setStatusTip(tr("Reset all node's color")); | 54 | resetColorAct->setStatusTip(tr("Reset all node's color")); |
| 44 | connect(resetColorAct, &QAction::triggered, this, &MainWindow::reset_color); | 55 | connect(resetColorAct, &QAction::triggered, this, &MainWindow::reset_color); |
| 45 | } | 56 | } |
| 46 | 57 | ||
| 47 | void MainWindow::createMenus() | 58 | void MainWindow::createMenus() |
| 48 | { | 59 | { |
| 60 | + fileMenu = menuBar()->addMenu(tr("&File")); | ||
| 61 | + fileMenu->addAction(readMoreAct); | ||
| 62 | + | ||
| 49 | actionMenu = menuBar()->addMenu(tr("&Actions")); | 63 | actionMenu = menuBar()->addMenu(tr("&Actions")); |
| 50 | actionMenu->addAction(testHighlightAct); | 64 | actionMenu->addAction(testHighlightAct); |
| 65 | + actionMenu->addAction(topkAct); | ||
| 51 | actionMenu->addAction(resetColorAct); | 66 | actionMenu->addAction(resetColorAct); |
| 52 | } | 67 | } |
| 53 | 68 | ||
| 54 | ////////////////////////////////////////////////////////////////// | 69 | ////////////////////////////////////////////////////////////////// |
| 55 | // slots | 70 | // slots |
| 56 | ////////////////////////////////////////////////////////////////// | 71 | ////////////////////////////////////////////////////////////////// |
| 72 | +void MainWindow::read_more() | ||
| 73 | +{ | ||
| 74 | + qDebug("* MainWindow::read_more"); | ||
| 75 | + graphWidget->read_more(); | ||
| 76 | +} | ||
| 77 | + | ||
| 57 | void MainWindow::test_highlighting() | 78 | void MainWindow::test_highlighting() |
| 58 | { | 79 | { |
| 59 | /*QMessageBox::information(this, "test", | 80 | /*QMessageBox::information(this, "test", |
| ... | @@ -62,7 +83,12 @@ void MainWindow::test_highlighting() | ... | @@ -62,7 +83,12 @@ void MainWindow::test_highlighting() |
| 62 | //graphWidget->update(); | 83 | //graphWidget->update(); |
| 63 | } | 84 | } |
| 64 | 85 | ||
| 86 | +void MainWindow::topk() | ||
| 87 | +{ | ||
| 88 | + graphWidget->topk(); | ||
| 89 | +} | ||
| 90 | + | ||
| 65 | void MainWindow::reset_color() | 91 | void MainWindow::reset_color() |
| 66 | { | 92 | { |
| 67 | graphWidget->reset_color(); | 93 | graphWidget->reset_color(); |
| 68 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 94 | +} | ... | ... |
| ... | @@ -12,14 +12,18 @@ public: | ... | @@ -12,14 +12,18 @@ public: |
| 12 | MainWindow(QWidget *parent = 0); | 12 | MainWindow(QWidget *parent = 0); |
| 13 | ~MainWindow(); | 13 | ~MainWindow(); |
| 14 | 14 | ||
| 15 | - void print_graph(std::ifstream& fin); | 15 | + //void print_graph(std::ifstream *pFin); |
| 16 | - /*void test_highlighting();*/ | 16 | + void print_graph(const char* filename); |
| 17 | + | ||
| 17 | 18 | ||
| 18 | private: | 19 | private: |
| 19 | PaperGraphWidget *graphWidget; | 20 | PaperGraphWidget *graphWidget; |
| 20 | 21 | ||
| 22 | + QMenu *fileMenu; | ||
| 23 | + QAction *readMoreAct; | ||
| 21 | QMenu *actionMenu; | 24 | QMenu *actionMenu; |
| 22 | QAction *testHighlightAct; | 25 | QAction *testHighlightAct; |
| 26 | + QAction *topkAct; | ||
| 23 | QAction *resetColorAct; | 27 | QAction *resetColorAct; |
| 24 | 28 | ||
| 25 | private: | 29 | private: |
| ... | @@ -27,7 +31,9 @@ private: | ... | @@ -27,7 +31,9 @@ private: |
| 27 | void createMenus(); | 31 | void createMenus(); |
| 28 | 32 | ||
| 29 | private slots: | 33 | private slots: |
| 34 | + void read_more(); | ||
| 30 | void test_highlighting(); | 35 | void test_highlighting(); |
| 36 | + void topk(); | ||
| 31 | void reset_color(); | 37 | void reset_color(); |
| 32 | }; | 38 | }; |
| 33 | 39 | ... | ... |
| ... | @@ -25,23 +25,47 @@ PaperGraphWidget::PaperGraphWidget(QWidget *parent) | ... | @@ -25,23 +25,47 @@ PaperGraphWidget::PaperGraphWidget(QWidget *parent) |
| 25 | setWindowTitle(tr("dblp paper graph visualization")); | 25 | setWindowTitle(tr("dblp paper graph visualization")); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | -void PaperGraphWidget::print_graph(ifstream& fin) | 28 | +//void PaperGraphWidget::print_graph(ifstream* pFin) |
| 29 | +//{ | ||
| 30 | +// qDebug("* PaperGraphWidget::print_graph"); | ||
| 31 | +// //QGraphicsItem *graph_item = new GraphItem(fin); | ||
| 32 | +// if (graphItem) | ||
| 33 | +// throw std::exception("already have graph item"); | ||
| 34 | +// | ||
| 35 | +// graphItem = new GraphItem(pFin); | ||
| 36 | +// graphItem->setPos(0, 0); | ||
| 37 | +// scene->addItem(graphItem); | ||
| 38 | +//} | ||
| 39 | + | ||
| 40 | +void PaperGraphWidget::print_graph(const char * filename) | ||
| 29 | { | 41 | { |
| 30 | - //QGraphicsItem *graph_item = new GraphItem(fin); | ||
| 31 | if (graphItem) | 42 | if (graphItem) |
| 32 | throw std::exception("already have graph item"); | 43 | throw std::exception("already have graph item"); |
| 33 | 44 | ||
| 34 | - graphItem = new GraphItem(fin, READ_LINE_UNIT); | 45 | + graphItem = new GraphItem(filename); |
| 35 | graphItem->setPos(0, 0); | 46 | graphItem->setPos(0, 0); |
| 36 | scene->addItem(graphItem); | 47 | scene->addItem(graphItem); |
| 37 | } | 48 | } |
| 38 | 49 | ||
| 50 | +void PaperGraphWidget::read_more() | ||
| 51 | +{ | ||
| 52 | + qDebug("* PaperGraphWidget::read_more"); | ||
| 53 | + graphItem->read_more(); | ||
| 54 | + scene->update(); | ||
| 55 | +} | ||
| 56 | + | ||
| 39 | void PaperGraphWidget::path_highlight() | 57 | void PaperGraphWidget::path_highlight() |
| 40 | { | 58 | { |
| 41 | graphItem->path_highlighting(std::string(""), std::string("")); | 59 | graphItem->path_highlighting(std::string(""), std::string("")); |
| 42 | scene->update(); | 60 | scene->update(); |
| 43 | } | 61 | } |
| 44 | 62 | ||
| 63 | +void PaperGraphWidget::topk() | ||
| 64 | +{ | ||
| 65 | + graphItem->topK_highlight(); | ||
| 66 | + scene->update(); | ||
| 67 | +} | ||
| 68 | + | ||
| 45 | void PaperGraphWidget::reset_color() | 69 | void PaperGraphWidget::reset_color() |
| 46 | { | 70 | { |
| 47 | graphItem->reset_color(); | 71 | graphItem->reset_color(); | ... | ... |
| ... | @@ -11,9 +11,13 @@ class PaperGraphWidget : public QWidget | ... | @@ -11,9 +11,13 @@ class PaperGraphWidget : public QWidget |
| 11 | 11 | ||
| 12 | public: | 12 | public: |
| 13 | PaperGraphWidget(QWidget *parent = 0); | 13 | PaperGraphWidget(QWidget *parent = 0); |
| 14 | - void print_graph(ifstream& fin); | 14 | + //void print_graph(ifstream* pFin); |
| 15 | + void print_graph(const char* filename); | ||
| 15 | 16 | ||
| 17 | +//main window slots | ||
| 18 | + void read_more(); | ||
| 16 | void path_highlight(); | 19 | void path_highlight(); |
| 20 | + void topk(); | ||
| 17 | void reset_color(); | 21 | void reset_color(); |
| 18 | 22 | ||
| 19 | private slots: | 23 | private slots: | ... | ... |
| ... | @@ -9,9 +9,9 @@ int main(int argc, char *argv[]) | ... | @@ -9,9 +9,9 @@ int main(int argc, char *argv[]) |
| 9 | MainWindow m; | 9 | MainWindow m; |
| 10 | 10 | ||
| 11 | try { | 11 | try { |
| 12 | - ifstream fin(PAPER_FILENAME); | 12 | + //ifstream fin(PAPER_FILENAME); |
| 13 | - m.print_graph(fin); | 13 | + m.print_graph(PAPER_FILENAME); |
| 14 | - fin.close(); | 14 | + //fin.close(); |
| 15 | } catch (const std::exception& e) { | 15 | } catch (const std::exception& e) { |
| 16 | qDebug() << "Error: " << e.what(); | 16 | qDebug() << "Error: " << e.what(); |
| 17 | return EXIT_FAILURE; | 17 | return EXIT_FAILURE; | ... | ... |
| ... | @@ -28,13 +28,20 @@ | ... | @@ -28,13 +28,20 @@ |
| 28 | #include <boost/graph/topology.hpp> | 28 | #include <boost/graph/topology.hpp> |
| 29 | #include <boost/regex.hpp> | 29 | #include <boost/regex.hpp> |
| 30 | 30 | ||
| 31 | +#include <cstdio> | ||
| 32 | +#include <cstdlib> | ||
| 33 | +#include <cstring> | ||
| 34 | + | ||
| 31 | #include <algorithm> | 35 | #include <algorithm> |
| 32 | #include <exception> | 36 | #include <exception> |
| 33 | #include <fstream> | 37 | #include <fstream> |
| 34 | #include <iostream> | 38 | #include <iostream> |
| 35 | #include <iterator> | 39 | #include <iterator> |
| 40 | +#include <limits> | ||
| 36 | #include <map> | 41 | #include <map> |
| 42 | +#include <queue> | ||
| 37 | #include <string> | 43 | #include <string> |
| 44 | +#include <utility> | ||
| 38 | #include <vector> | 45 | #include <vector> |
| 39 | 46 | ||
| 40 | using namespace boost; | 47 | using namespace boost; |
| ... | @@ -43,9 +50,11 @@ using namespace std; | ... | @@ -43,9 +50,11 @@ using namespace std; |
| 43 | /* enums */ | 50 | /* enums */ |
| 44 | enum vertex_position_t { vertex_position }; | 51 | enum vertex_position_t { vertex_position }; |
| 45 | enum vertex_type_t { vertex_type }; | 52 | enum vertex_type_t { vertex_type }; |
| 53 | +enum vertex_record_t { vertex_record }; | ||
| 46 | namespace boost { | 54 | namespace boost { |
| 47 | BOOST_INSTALL_PROPERTY(vertex, position); | 55 | BOOST_INSTALL_PROPERTY(vertex, position); |
| 48 | BOOST_INSTALL_PROPERTY(vertex, type); | 56 | BOOST_INSTALL_PROPERTY(vertex, type); |
| 57 | + BOOST_INSTALL_PROPERTY(vertex, record); | ||
| 49 | } | 58 | } |
| 50 | enum NODE_TYPE { | 59 | enum NODE_TYPE { |
| 51 | NODE_PAPER, | 60 | NODE_PAPER, |
| ... | @@ -64,7 +73,8 @@ typedef square_topology<>::point_type point; | ... | @@ -64,7 +73,8 @@ typedef square_topology<>::point_type point; |
| 64 | typedef boost::property<vertex_index_t, int, | 73 | typedef boost::property<vertex_index_t, int, |
| 65 | boost::property<vertex_name_t, std::string, | 74 | boost::property<vertex_name_t, std::string, |
| 66 | boost::property<vertex_position_t, point, | 75 | boost::property<vertex_position_t, point, |
| 67 | - boost::property<vertex_type_t, int>>> | 76 | + boost::property<vertex_type_t, int, |
| 77 | + boost::property<vertex_record_t, int>>>> | ||
| 68 | > VertexProperties; | 78 | > VertexProperties; |
| 69 | typedef boost::adjacency_list< | 79 | typedef boost::adjacency_list< |
| 70 | listS, //outEdgeList | 80 | listS, //outEdgeList |
| ... | @@ -77,6 +87,7 @@ typedef boost::adjacency_list< | ... | @@ -77,6 +87,7 @@ typedef boost::adjacency_list< |
| 77 | > Graph; | 87 | > Graph; |
| 78 | typedef typename graph_traits<Graph>::edge_iterator edge_iterator; | 88 | typedef typename graph_traits<Graph>::edge_iterator edge_iterator; |
| 79 | typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; | 89 | typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; |
| 90 | +//typedef boost::graph_traits<Graph>::adjacency_iterator adjacency_iterator; | ||
| 80 | typedef boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor; | 91 | typedef boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor; |
| 81 | typedef square_topology<> Topology; | 92 | typedef square_topology<> Topology; |
| 82 | typedef typename Topology::point_type Point; | 93 | typedef typename Topology::point_type Point; |
| ... | @@ -95,14 +106,98 @@ namespace { | ... | @@ -95,14 +106,98 @@ namespace { |
| 95 | const int NODE_SIZE = 4; | 106 | const int NODE_SIZE = 4; |
| 96 | const int LAYOUT_MODE = GRAPH_LAYOUT::RANDOM_LAYOUT; | 107 | const int LAYOUT_MODE = GRAPH_LAYOUT::RANDOM_LAYOUT; |
| 97 | const int SCREEN_SIZE = 1000; | 108 | const int SCREEN_SIZE = 1000; |
| 98 | - const int READ_LINE_UNIT = 100; //한 번에 몇 라인을 읽을지 | 109 | + const int READ_LINE_UNIT = 5; //한 번에 몇 라인을 읽을지 |
| 99 | 110 | ||
| 100 | /* topK */ | 111 | /* topK */ |
| 101 | - const int TOP_K = 10; //상위 몇 개 아이템에 대해 할 지 | 112 | + const int TOP_K = 10; //상위 몇 개 아이템에 대해 highlight 할 지 |
| 102 | 113 | ||
| 103 | } | 114 | } |
| 104 | 115 | ||
| 105 | - | 116 | +/* boost */ |
| 106 | namespace boost { | 117 | namespace boost { |
| 107 | const boost::regex paper_reg("(conf|journals).*"); | 118 | const boost::regex paper_reg("(conf|journals).*"); |
| 108 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 119 | +} | ||
| 120 | + | ||
| 121 | +/* topK heap */ | ||
| 122 | +template <typename T> | ||
| 123 | +class TopKHeap { | ||
| 124 | +private: | ||
| 125 | + int k; //max size | ||
| 126 | + int size; //current size | ||
| 127 | + T *heap; | ||
| 128 | + | ||
| 129 | +private: | ||
| 130 | + void reHeapDown(int root) { | ||
| 131 | + //after pop | ||
| 132 | + int minIdx, left, right; | ||
| 133 | + | ||
| 134 | + left = root * 2 + 1; | ||
| 135 | + right = root * 2 + 2; | ||
| 136 | + | ||
| 137 | + if (left <= (size - 1)) { | ||
| 138 | + if (left == (size - 1)) | ||
| 139 | + minIdx = left; | ||
| 140 | + else { | ||
| 141 | + minIdx = ((heap[left] <= heap[right]) ? left : right); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + if (heap[root] > heap[minIdx]) { | ||
| 145 | + swap(heap[root], heap[minIdx]); | ||
| 146 | + reHeapDown(minIdx); | ||
| 147 | + } | ||
| 148 | + } | ||
| 149 | + } | ||
| 150 | + void reHeapUp(int root, int bottom) { | ||
| 151 | + //bottom: 위로 올릴 노드 idx | ||
| 152 | + //after push | ||
| 153 | + if (root > bottom) { | ||
| 154 | + int parent = (bottom - 1) / 2; | ||
| 155 | + if (heap[parent] < heap[bottom]) { | ||
| 156 | + swap(heap[parent], heap[bottom]); | ||
| 157 | + reHeapUp(root, parent); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | +public: | ||
| 163 | + TopKHeap(int _k) : k(_k), size(0) { | ||
| 164 | + if (_k <= 0) abort(); | ||
| 165 | + heap = new T[_k]; | ||
| 166 | + memset(heap, 0, sizeof(heap)); | ||
| 167 | + } | ||
| 168 | + ~TopKHeap() { | ||
| 169 | + if (heap) delete[] heap; | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | +public: | ||
| 173 | + void push(T elem) { | ||
| 174 | + if (size < k) { | ||
| 175 | + heap[size++] = elem; | ||
| 176 | + } | ||
| 177 | + else { | ||
| 178 | + if (elem < heap[0]) { | ||
| 179 | + //less than minimum | ||
| 180 | + } | ||
| 181 | + else { | ||
| 182 | + pop(); | ||
| 183 | + heap[size++] = elem; | ||
| 184 | + } | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + reHeapUp(0, size - 1); | ||
| 188 | + } | ||
| 189 | + T pop() { | ||
| 190 | + if (size <= 0) | ||
| 191 | + abort(); | ||
| 192 | + else if (size == 1) { | ||
| 193 | + T ret = heap[--size]; | ||
| 194 | + return ret; | ||
| 195 | + } | ||
| 196 | + else { | ||
| 197 | + T ret = heap[0]; | ||
| 198 | + heap[0] = heap[--size]; | ||
| 199 | + reHeapDown(0); | ||
| 200 | + return ret; | ||
| 201 | + } | ||
| 202 | + } | ||
| 203 | +}; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or login to post a comment