import dash from dash import dcc, html from dash.dependencies import Input, Output import os import re import json import pandas as pd import numpy as np import plotly.graph_objects as go from flask import request from urllib.parse import urlparse, parse_qs import base64 app = dash.Dash(__name__) meta_df = pd.read_json( "/home/georg/data/arxiv_ml_meta.json", dtype={"id": str}, lines=True, ) meta_df['submit_date'] = pd.to_datetime(meta_df['submit_date'], unit='ms') DEFAULT_ORG_SET = set(["Facebook", "Google", "Microsoft", "Amazon", "Nvidia"]) def _get_paper_df(search_term, min_date="2015", min_citation=5, org_set=DEFAULT_ORG_SET): # format orgs meta_df['orgs_main'] = [ " & ".join([o for o in s.split(" & ") if o in org_set]) for s in meta_df['orgs'].values ] meta_df['orgs_main'] = meta_df['orgs_main'].replace("", "other") # filter papers plot_df = meta_df[ ( meta_df['title'].str.contains(r"\b{}\b".format(search_term), flags=re.IGNORECASE) | (meta_df['abstract'].str.count(r"\b{}\b".format(search_term), flags=re.IGNORECASE) >= 2) ) & ( ( (meta_df['submit_date'].dt.year >= int(min_date)) & (meta_df['n_citation'] >= min_citation) ) | ( ((meta_df['submit_date'].max() - meta_df['submit_date']).dt.days <= 90) & (meta_df['orgs_main'] != "other") ) ) ].copy() plot_df.loc[( ((meta_df['submit_date'].max() - meta_df['submit_date']).dt.days <= 90) & (meta_df['orgs_main'] != "other") ), "n_citation"] += min_citation return plot_df def get_data(search_term): plot_df = _get_paper_df(search_term) global dfs dfs = [] data = [] trace_names = list(plot_df['orgs_main'].unique()) for name in trace_names: _df = plot_df[plot_df['orgs_main'] == name].copy() dfs.append(_df) customdata = _df['orgs'].values trace_data = { "x": _df["submit_date"], "y": _df["n_citation"], "name": name, "text": _df['title'], "customdata": customdata, "hovertemplate": "%{text}
" + "%{x|%Y %b} - %{customdata}
" + "", "mode": "markers", 'marker': { 'size': 10, 'line': { 'width': 1, 'color': '#888', }, 'opacity': 0.75, }, } if name == "other": trace_data["marker"]["color"] = "#ccc" data.append(trace_data) return data loader_style = { 'height': '100%', 'width': '100%', 'display': 'flex', 'justify-content': 'center', 'padding-top': '50px', 'position': 'absolute', 'z-index': '100', 'background-color': 'white', } spinner_style = { 'display': 'block', 'width': '80px', } encoded_img = base64.b64encode(open('dash/spinner.gif', 'rb').read()).decode("utf8") app.layout = html.Div(children=[ dcc.Location(id='url', refresh=False), html.Div( id="sidebar-loader-div", style=loader_style, children=[ html.Div( id="sidebar-loader", children=[ html.Img( src='data:image/gif;base64,{}'.format(encoded_img), style=spinner_style ) ] ) ] ), dcc.Graph(id='paper-graph'), dcc.Store(id='clientside-figure-store'), html.Div(id="fig-output", children=""), ]) output_css={ "font-family": "'Helvetica Neue', Helvetica, Arial", } output_css2={ "font-family": "'Helvetica Neue', Helvetica, Arial", "font-size": "0.9em", } @app.callback( Output('clientside-figure-store', 'data'), Input('url', 'search')) def store_data(url_query_str): global dfs parsed_url = urlparse(url_query_str) query_dict = parse_qs(parsed_url.query) search_term = query_dict["search_term"][0] figdata = get_data(search_term) data = { "figdata": figdata, "title": "Most cited papers for
`{}`".format(search_term), "npoints": [df.shape[0] for df in dfs] } return data app.clientside_callback( """ function(data, clickData) { fig_json = { 'data': data.figdata, 'layout': { 'title': { 'text': data.title, 'y': 0.88, 'x': 0.5, 'xanchor': 'center', 'yanchor': 'top' }, 'xaxis': {'title': 'Publication date'}, 'yaxis': {'type': 'log', 'visible': false, 'showticklabels': false} }, } document.getElementById("sidebar-loader-div").style['display'] = 'none'; if (typeof clickData == 'undefined') return fig_json // update size of points trace_idx = clickData.points[0].curveNumber point_idx = clickData.points[0].pointNumber for (let n = 0; n < data.npoints.length; n++) { data.figdata[n].marker.size = 10; } const size_vec = []; for (let n = 0; n < data.npoints[trace_idx]; n++) { if (n == point_idx) size_vec[n] = 20; else size_vec[n] = 10; } data.figdata[trace_idx].marker.size = size_vec; return fig_json } """, Output('paper-graph', 'figure'), Input('clientside-figure-store', 'data'), Input('paper-graph', 'clickData'), ) @app.callback( Output('fig-output', 'children'), Input('paper-graph', 'clickData')) def display_click_data(clickData): if clickData is None: return None global dfs trace_idx = clickData["points"][0]["curveNumber"] point_idx = clickData["points"][0]["pointNumber"] row = dfs[trace_idx].iloc[point_idx] info_str = row["submit_date"].strftime("%Y %b") if len(row["orgs"]) > 0: info_str += " - " + row["orgs"] info_str += ", {} citations".format(row["n_citation"]) output_layout = html.Div(children=[ html.Div(children=html.A( href="https://arxiv.org/abs/{}".format(row['id']), target="_blank", children="paper link", ), style=output_css2), html.Div(children=html.B(children=row['title']), style=output_css), html.Div(children=html.Pre(children=info_str)), html.Div(children=row['abstract'], style=output_css2) ]) return output_layout if __name__ == '__main__': context = ('cert/383fff33778762e8.crt', 'cert/383fff33778762e8.key') app.run_server(debug=False, host='0.0.0.0', port=7880, ssl_context=context)