From 00735b52095a2928ea3cd54e554527e1a54ca4f8 Mon Sep 17 00:00:00 2001 From: Sebastian David <sebastian.david@uni-hamburg.de> Date: Thu, 23 Dec 2021 09:49:50 +0100 Subject: [PATCH] added verarbeitung and output to main program --- .citation_parser_ui.py.swp | Bin 0 -> 20480 bytes assets/cn.js | 548 +++++++++++++++++++++++++++++++++++++ assets/index.html | 107 ++++++++ assets/json_text.json | 1 + citation_parser_ui.py | 25 +- 5 files changed, 668 insertions(+), 13 deletions(-) create mode 100644 .citation_parser_ui.py.swp create mode 100644 assets/cn.js create mode 100644 assets/index.html create mode 100644 assets/json_text.json diff --git a/.citation_parser_ui.py.swp b/.citation_parser_ui.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..38c0d61d4724d853b03e358ed4916b537560e72f GIT binary patch literal 20480 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 VnTM(ayB(2a&<E6UszMr22LK?O0b~FG literal 0 HcmV?d00001 diff --git a/assets/cn.js b/assets/cn.js new file mode 100644 index 0000000..309678b --- /dev/null +++ b/assets/cn.js @@ -0,0 +1,548 @@ +/** +* creates a new zoom behavior +*/ +var zoom = d3.zoom().on("zoom", handle_zoom); + +/** +* creates svg object and associated attributes +* applies the zoom behavior to svg +*/ +var svg = d3.select("svg.graph") + .call(zoom), +width = svg.attr("width"), +height = svg.attr("height"), +perc; + +/** +* scale functions that return y coordinate/color of node depending on group +*/ +var color = d3.scaleOrdinal() + .domain(["height", "input", "depth"]) + .range([' #01d7c0', ' #8b90fe ', ' #a15eb2 ']), +y_scale = d3.scaleOrdinal() + .domain(["height", "input", "depth"]) + .range([0, 200, 400]), +to_remove; + +/** +* creates node object and (default) radius +*/ +var node, +r = 10; + +/** +* creates link object +*/ +var link; + +/** +* creates a background with a click functionality +*/ +var rect = svg.append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("height", height) + .attr("width", width) + .style("fill", 'white') + .on('click', click_rect); + +/** +* creates svg object (legend) and associated attributes +*/ +var svg_legend = d3.select("svg.legendsvg"), +legend_position = [65,95,125], +arrow_legend_position = [0,25], +arrow_group_names = ["citation","self-citation"], +group_names = ["cited by","input","reference"], +line_type = d3.scaleOrdinal() + .domain(["line","dotted"]) + .range([("8,0"),("8,8")]), +text_info = '', +text_abstract = ''; + +var legend = svg_legend.selectAll(".legend") + .data(legend_position) + .enter() + .append("g") + .attr("class","legend") + .attr("transform", function(d,i) {return "translate(0," + d + ")"; }); + +legend.append("text") + .attr("x", 80) + .attr("y", 0) + .attr("dy", ".35em") + .style("text-anchor", "start") + .text(function(d,i) {return group_names[i]}); + +legend.append("circle") + .attr("r", r) + .attr("cx",30-r) + .style("fill", color); + +var legend_arrow = svg_legend.selectAll(".legendarr") + .data(arrow_legend_position) + .enter() + .append("g") + .attr("class","legendarr") + .attr("transform", function(d) { return "translate(0," + d + ")"; }); + +legend_arrow.append("line") + .attr("x1", 10) + .attr("x2", 50) + .attr("y1", 10) + .attr("y2", 10) + .style("stroke-dasharray",line_type) + .style("stroke", '#999') + .style("stroke-width", "1px") + .style('pointer-events', 'none') + .attr('marker-end',update_marker('#999',this)); + +legend_arrow.append("text") + .attr("x", 80) + .attr("y", 10) + .attr("dy", ".35em") + .style("text-anchor", "start") + .text(function(d,i){return arrow_group_names[i]}); + +/** +* creates a new simulation +* updates the positions of the links and nodes when the + state of the layout has changed (simulation has advanced by a tick) +*/ +var simulation = d3.forceSimulation() + .force("link", d3.forceLink().id(function(d) {return d.doi;}).distance(50).strength(function(d) { + if (d.group == "input") {return 0;} + else {return 5;} + })) + .force("collide", d3.forceCollide(function(d) { + if (d.group == "input") {return 100;} + else {return 65;} + }).strength(0.5)) + .force("charge", d3.forceManyBody().strength(0.001)) + .force("center", d3.forceCenter(width/2, height/2+20)) + .force("yscale", d3.forceY().strength(function(d) { + if (d.group == "input") {return 1000;} + else {return 50;} + }).y(function(d) {return y_scale(d.group)})) + .alpha(0.005) + .on("end", zoom_to); + +/** +* creates group element +*/ +var g = svg.append("g") + .attr("class", "everything") + +/** +* loads JSON data and calls the update function +*/ +d3.json("json_text.json").then(function(graph) { + update(graph.links, graph.nodes); +}) + +/** +* calls update functions for links and nodes +* adds the nodes, links and tick functionality to the simulation +* @param {object} nodes - nodes +* @param {object} links - links +*/ +function update(links, nodes) { + update_links(links); + update_nodes(nodes); + + simulation + .nodes(nodes) + .on("tick", handle_tick); + simulation.force("link") + .links(links); + + link.attr('marker-end', function(d) {return update_marker("#999", d.target);}) + .style("stroke-dasharray",function(d){return self_citation(d.source,d.target)? ("8,8"): ("1,0")}); +} + +/** +* initializes and shows links +* @param {object} links - links +*/ +function update_links(links) { + link = g.append("g") + .selectAll(".link") + .data(links) + .enter() + .append("line") + .style("stroke-width", "1px") + .style("stroke", "#999") + .attr("class", "link"); +} + +/** +* initializes and shows nodes with circles, texts and a click functionality +* creates a new drag behavior and applies it to the circles +* @param {object} nodes - nodes +*/ +function update_nodes(nodes) { + node = g.selectAll(".node") + .data(nodes) + .enter() + .append("g") + .attr("class", "node") + .call(d3.drag() + .on("start", start_drag) + .on("drag", dragged) + ); + + node.append("circle") + .attr("class", "circle") + .attr("r", function(d) {return 1.5*r+d.citations*0.05}) + .style("fill", function(d){ return color(d.group)}) + .on('click', click_node); + + node.append("text") + .attr("class", "text") + .style("font-size", "15px") + .style('pointer-events', 'auto') + .text(function (d) {const first_author=d.author[0].split(" ") + return first_author[first_author.length-1];}) + .on('click', click_node); +} + +/** +* creates arrowhead and returns its url +* @param {string} color - color of arrowhead +* @param {string} target - target node +*/ +function update_marker(color, target) { + var radius = 1.5*r+target.citations*0.05; + svg.append('defs').append('marker') + .attr('id',color.replace("#", "")+radius) + .attr('viewBox','-0 -5 10 10') + .attr('refX',radius+9.5) + .attr('refY',0) + .attr('orient','auto') + .attr('markerWidth',10) + .attr('markerHeight',15) + .attr('xoverflow','visible') + .append('svg:path') + .attr('d', 'M 0,-5 L 10 ,0 L 0,5') + .attr('fill', color) + .style('stroke','none'); + return "url(" + color + radius + ")"; +}; + +/** +* sets color of circle and its links to black and removes the previous highlights +* displays overview info of node in textbox +* @param {object} node - node +*/ +function click_node(node) { + d3.select(this.parentNode).raise(); + fix_nodes(node); + if(to_remove){ + d3.select(to_remove).selectAll(".circle").style("stroke","none") + } + to_remove = this.parentNode; + d3.select(this.parentNode).selectAll(".circle").style("stroke","black") + mark_link(node) + textbox_content(node) + reset_button_highlight() + highlight_button("overview") +} + +/** +* removes the highlights of the circles and their links +*/ +function click_rect() { + fix_nodes(node); + d3.selectAll(".circle").style("stroke", "none") + d3.selectAll(".link") + .style("stroke", "#999") + .attr('marker-end', function(d) {return update_marker('#999', d.target);}) + text_abstract=''; + text_info=''; + reset_button_highlight() + document.getElementById('textbox').innerHTML = "Click node"; +} + +/** +* returns true if journals have a common author (self-citation) +* @param {object} source - node +* @param {object} target - node +*/ +function self_citation(source,target) { + return source.author.some(item=>target.author.includes(item)) +} + +/** +* sets color of link (line and arrowhead) to black if it is directly connected to node +* and to grey otherwise +* @param {object} node - node +*/ +function mark_link(node) { + d3.selectAll(".link") + .style("stroke", function(o) { + return is_link_for_node(node, o) ? "black" : "#999";}) + .attr('marker-end', function(o) { + return is_link_for_node(node, o) ? update_marker('#000000', o.target) : update_marker('#999', o.target);}) +} + +/** +* returns true if link is directly connected to node and false if it is not +* @param {object} node - node +* @param {object} link - link +*/ +function is_link_for_node(node, link) { + return link.source.index == node.index || link.target.index == node.index; +} + +/** +* saves text for overview and abstract of node +* outputs node info to textbox +* @param {object} node - node +*/ +function textbox_content(node) { + text_info = "Title:" + '</br>' + node.name + + '</br>' +'</br>'+"Author:"+ '</br>' +node.author+'</br>'+'</br>'+"Date:"+'</br>' + +node.year+'</br>'+'</br>'+"Journal:"+'</br>'+node.journal+'</br>'+'</br>'+"doi:" + +'</br>'+'<a href="'+node.doi+ '">'+node.doi+'</a>'+'</br>'+'</br>'+"Citations:" + +'</br>'+node.citations; + text_abstract = node.abstract; + document.getElementById('textbox').innerHTML = text_info; +} + +/** +* sets color of btn to dark gray +* @param {object} btn - button +*/ +function highlight_button(btn) { + reset_button_highlight(); + document.getElementById(btn).style.background = "#CACACA"; +} + +/** +* sets color of all buttons to default light gray +*/ +function reset_button_highlight() { + document.getElementById("overview").style.background = ''; + document.getElementById("abstract").style.background = ''; +} + +/** +* displays abstract in textbox if a is true, overview text otherwise +* @param {bool} a- bool +*/ +function display_abstract(a) { + if (text_abstract == '' && text_info == '') { + document.getElementById('textbox').innerHTML="Click node"; + } + else { + if (a == true) { + document.getElementById('textbox').innerHTML = text_abstract; + } + else { + document.getElementById('textbox').innerHTML = text_info; + } + } +} + +/** +* updates the positions of the links and nodes +*/ +function handle_tick() { + link.attr("x1", function (d) {return d.source.x;}) + .attr("y1", function (d) {return d.source.y;}) + .attr("x2", function (d) {return d.target.x;}) + .attr("y2", function (d) {return d.target.y;}); + node.attr("transform", function (d) {return "translate(" + d.x + ", " + d.y + ")";}); +} + +/** +* initializes the dragging of the node +* @param {object} node - node +*/ +function start_drag(node) { + d3.select(this).raise(); + if (!d3.event.active) + simulation.alphaTarget(0.3).restart() + node.fx = node.x; + node.fy = node.y; + fix_nodes(node); +} + +/** +* applies the dragging to the node +* @param {object} node - node +*/ +function dragged(node) { + node.fx = d3.event.x; + node.fy = d3.event.y; + fix_nodes(node); +} + +/** +* fix positions of all nodes except for the current node +* @param {object} this_node - node +*/ +function fix_nodes(this_node) { + node.each(function(d) { + if (this_node != d) { + d.fx = d.x; + d.fy = d.y; + } + }); +} + +/** +* applies the transformation (zooming or dragging) to the g element +*/ +function handle_zoom() { + d3.select('g').attr("transform", d3.event.transform); +} + +/** +* transforms svg so that the zoom is adapted to the size of the graph +*/ +function zoom_to() { + node_bounds = d3.selectAll("svg.graph").node().getBBox(); + svg_bounds = d3.select("rect").node().getBBox(); + + perc_x = width/(node_bounds.width+100); + perc_y = height/(node_bounds.height+100); + perc = d3.min([perc_x, perc_y]) + + d3.select('svg') + .call(zoom.scaleBy, perc); +} + +/** +* transforms svg so that the zoom and drag is reset +*/ +function reset_view() { + d3.select('svg') + .call(zoom.scaleTo, 1) + d3.select('svg') + .call(zoom.translateTo, 0.5 * width, 0.5 * height); + d3.select('svg') + .call(zoom.scaleBy, perc); +} + +/** +* save svg as png +*/ +function save_svg(){ + var svgString = get_svg_string(svg.node()); + svg_string_to_image(svgString, 2*width, 2*height, 'png', save); // passes Blob and filesize String to the callback + + function save( dataBlob, filesize ){ + saveAs(dataBlob, 'D3 vis exported to PNG.png'); // FileSaver.js function + } +}; + +/** +* generate svgString +* @param {object} svgNode - node +*/ +function get_svg_string(svgNode) { + svgNode.setAttribute('xlink', 'http://www.w3.org/1999/xlink'); + var cssStyleText = get_css_styles(svgNode); + append_css(cssStyleText, svgNode); + + var serializer = new XMLSerializer(); + var svgString = serializer.serializeToString(svgNode); + svgString = svgString.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace + svgString = svgString.replace(/NS\d+:href/g, 'xlink:href'); // Safari NS namespace fix + + return svgString; + + function get_css_styles(parentElement) { + var selectorTextArr = []; + + // Add Parent element Id and Classes to the list + selectorTextArr.push('#' + parentElement.id); + for (var c = 0; c < parentElement.classList.length; c++) + if (!contains('.'+parentElement.classList[c], selectorTextArr)) + selectorTextArr.push('.'+parentElement.classList[c]); + + // Add Children element Ids and Classes to the list + var nodes = parentElement.getElementsByTagName("*"); + for (var i = 0; i < nodes.length; i++) { + var id = nodes[i].id; + if (!contains('#'+id, selectorTextArr)) + selectorTextArr.push('#' + id); + + var classes = nodes[i].classList; + for (var c = 0; c < classes.length; c++) + if (!contains('.'+classes[c], selectorTextArr)) + selectorTextArr.push('.'+classes[c]); + } + + // Extract CSS Rules + var extractedCSSText = ""; + for (var i = 0; i < document.styleSheets.length; i++) { + var s = document.styleSheets[i]; + + try { + if(!s.cssRules) continue; + } catch(e) { + if(e.name !== 'SecurityError') throw e; // for Firefox + continue; + } + + var cssRules = s.cssRules; + for (var r = 0; r < cssRules.length; r++) { + if (contains(cssRules[r].selectorText, selectorTextArr)) + extractedCSSText += cssRules[r].cssText; + } + } + + + return extractedCSSText; + + function contains(str,arr) { + return arr.indexOf(str) === -1 ? false : true; + } + + } + + function append_css(cssText, element) { + var styleElement = document.createElement("style"); + styleElement.setAttribute("type","text/css"); + styleElement.innerHTML = cssText; + var refNode = element.hasChildNodes() ? element.children[0] : null; + element.insertBefore(styleElement, refNode); + } +} + +/** +* convert svgString to image and export it +* @param {object} svgString - svgString +* @param {object} width - width of image +* @param {object} height - height of image +* @param {object} format - format to save image in +* @param {object} callback - callback function +*/ +function svg_string_to_image( svgString, width, height, format, callback ) { + var format = format ? format : 'png'; + + var imgsrc = 'data:image/svg+xml;base64,'+ btoa(unescape(encodeURIComponent(svgString))); // Convert SVG string to data URL + + var canvas = document.createElement("canvas"); + var context = canvas.getContext("2d"); + + canvas.width = width; + canvas.height = height; + + var image = new Image(); + image.onload = function() { + context.clearRect(0, 0, width, height); + context.drawImage(image, 0, 0, width, height); + + canvas.toBlob(function(blob) { + var filesize = Math.round(blob.length/1024) + ' KB'; + if (callback) callback(blob, filesize); + }); + + }; + + image.src = imgsrc; +} + diff --git a/assets/index.html b/assets/index.html new file mode 100644 index 0000000..78560da --- /dev/null +++ b/assets/index.html @@ -0,0 +1,107 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + + <!-- style specifications for button and div elements --> + <style type="text/css"> + button { + width: 100px; + height:20px; + display: flex; + justify-content: center; + position: absolute; + left: 455px; + top: 575px; + transition-duration: 0.4s; + border-radius:3px; + border:1px solid #909090; + } + + .button:hover { + background-color: #CACACA; + } + + button.resetZoom { + margin-left: 110px; + } + + button.save { + margin-left: 220px; + } + + button.abstract { + width:146px; + position:absolute; + top: 181px; + left: 1114px; + border-radius:0; + border:1px solid #909090; + } + + button.overview { + width:147px; + position:absolute; + display:inline-block; + top: 181px; + left: 968px; + border-radius:0; + border:1px solid #909090; + } + + div.legendbox { + width:270px; + height:170px; + padding: 10px; + /*border: 1px solid #999;*/ + position: absolute; + top: 10px; + left: 968px; + display: inline-block; + margin: 0; + } + + div.textbox { + width:270px; + min-height:200px; + max-height:370px; + padding: 10px; + border: 1px solid #999; + position: absolute; + top: 200px; + left: 968px; + display: inline-block; + overflow-y: scroll; + margin: 0; + } + </style> +</head> + +<body> + <!-- graph --> + <svg class="graph" width="960" height="560"></svg> + + <!-- legend --> + <div class="legendbox"> <svg class="legendsvg"></svg></div> + + <!-- textbox --> + <div class="textbox" id = "textbox">Click node</div> + <button id="overview" class="overview" onclick='display_abstract(false), highlight_button("overview")'>Overview</button> + <button id="abstract" class="abstract" onclick='display_abstract(true), highlight_button("abstract")'>Abstract</button> + + <!-- buttons --> + <button onclick="location.reload()">Reload Graph</button> + <button class="resetZoom" onclick="reset_view()">Reset View</button> + <button class="save" onclick="save_svg()">Save</button> + + <!-- D3 (version 5) --> + <script src="https://d3js.org/d3.v5.min.js"></script> + + <!-- scripts to save svg element as png --> + <script src="https://cdn.rawgit.com/eligrey/canvas-toBlob.js/f1a01896135ab378aa5c0118eadd81da55e698d8/canvas-toBlob.js"></script> + <script src="https://cdn.rawgit.com/eligrey/FileSaver.js/e9d941381475b5df8b7d7691013401e171014e89/FileSaver.min.js"></script> + + <!-- javascript for force-directed graph --> + <script type="text/javascript" id="cn" src="cn.js"></script> +</body> +</html> \ No newline at end of file diff --git a/assets/json_text.json b/assets/json_text.json new file mode 100644 index 0000000..b2e4c5f --- /dev/null +++ b/assets/json_text.json @@ -0,0 +1 @@ +{"nodes": [{"doi": "https://doi.org/10.1021/acs.jcim.6b00709", "name": "Matched Molecular Series: Measuring SAR Similarity", "author": ["Emanuel S. R. Ehmki", "Christian Kramer"], "year": "May 1, 2017", "journal": "Journal of Chemical Information and Modeling", "group": "Input", "depth": 0, "citations": 5}, {"doi": "https://doi.org/10.1021/acs.jcim.0c00269", "name": "Matched Molecular Series Analysis for ADME Property Prediction", "author": ["Mahendra Awale", "Sereina Riniker", "Christian Kramer"], "year": "May 5, 2020", "journal": "Journal of Chemical Information and Modeling", "group": "Citedby", "depth": 1, "citations": 6}, {"doi": "https://doi.org/10.1021/acs.jcim.0c00290", "name": "Identification of Bioisosteric Substituents by a Deep Neural Network", "author": ["Peter Ertl"], "year": "June 15, 2020", "journal": "Journal of Chemical Information and Modeling", "group": "Citedby", "depth": 2, "citations": 2}], "links": [{"source": "https://doi.org/10.1021/acs.jcim.0c00269", "target": "https://doi.org/10.1021/acs.jcim.6b00709"}, {"source": "https://doi.org/10.1021/acs.jcim.0c00290", "target": "https://doi.org/10.1021/acs.jcim.0c00269"}]} \ No newline at end of file diff --git a/citation_parser_ui.py b/citation_parser_ui.py index 453ead9..7431a91 100644 --- a/citation_parser_ui.py +++ b/citation_parser_ui.py @@ -1,3 +1,4 @@ +import os import base64 import re import dash @@ -8,6 +9,7 @@ from dash.dependencies import Input, Output, State from dash.exceptions import PreventUpdate from input.interface import InputInterface import input.publication +from verarbeitung.process_main import Processing app = dash.Dash(__name__) @@ -76,7 +78,11 @@ app.layout = html.Div([ value=[]) ]), # Layer 4: For the Graph - html.Div([ + html.Div( + [html.Iframe( + src="assets/index.html", + style={"height": "600px", "width": "100%"}, + ), html.Div(id='test-output') ]) ]) @@ -125,6 +131,7 @@ def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs, # if clear-all-button was pressed: if 'clear-all-button' in changed_id: + os.remove('assets/json_text.json') return list(),list(),'','' # if clear-selected-button was pressed: @@ -147,7 +154,7 @@ def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs, i = InputInterface() pub = i.get_pub_light(input_value) except Exception as err: - return options,selected_inputs,'','{}'.format(err) + return all_inputs,selected_inputs,'','{}'.format(err) # Creates a more readable string to display in the checklist rep_str = pub.contributors[0] + ',' + pub.journal + \ ',' + pub.publication_date @@ -240,16 +247,8 @@ def generate_output(n_clicks,all_inputs,selected_inputs, raise PreventUpdate elif 'Update Automatically' in additional_options \ or 'start-button' in changed_id: - s = '' - for i in range(len(all_inputs)): - x = all_inputs[i]['value'] - if x in selected_inputs: - s += x*(abs(int(forward_depth)-int(backward_depth))) - else: - s += x*(int(forward_depth)+int(backward_depth)) - return s - else: - raise PreventUpdate + input_links = [x['value'] for x in all_inputs] + Processing(input_links,int(forward_depth),int(backward_depth),'assets/json_text.json') if __name__ == '__main__': - app.run_server(debug=True) + app.run_server(debug=False) -- GitLab