From 91e45e0fda81b2d6a32f99cba8cd481470182b5c Mon Sep 17 00:00:00 2001 From: xyliu <xyliu@theobook160.fritz.box> Date: Sun, 4 Aug 2019 16:00:29 +0200 Subject: [PATCH] Add band_structure_visualization.ipynb. --- ...d_structure_visualization-checkpoint.ipynb | 4968 +++++++++++++++++ Nomad_tutorial_head.png | Bin 0 -> 52856 bytes band_structure_visualization.ipynb | 4968 +++++++++++++++++ js/jquery-3.2.1.min.js | 4 + js/jquery.event.move.js | 599 ++ js/jquery.flot.axislabels.js | 462 ++ js/jquery.flot.js | 3175 +++++++++++ js/jquery.flot.navigate.js | 336 ++ js/jquery.flot.navigate.min.js | 1 + js/jquery.flot.selection.js | 344 ++ 10 files changed, 14857 insertions(+) create mode 100644 .ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb create mode 100644 Nomad_tutorial_head.png create mode 100644 band_structure_visualization.ipynb create mode 100644 js/jquery-3.2.1.min.js create mode 100644 js/jquery.event.move.js create mode 100644 js/jquery.flot.axislabels.js create mode 100644 js/jquery.flot.js create mode 100644 js/jquery.flot.navigate.js create mode 100644 js/jquery.flot.navigate.min.js create mode 100644 js/jquery.flot.selection.js diff --git a/.ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb b/.ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb new file mode 100644 index 0000000..b2c4549 --- /dev/null +++ b/.ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb @@ -0,0 +1,4968 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "init_cell": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "<style>.container { width:100% !important; }</style>" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.core.display import display, HTML\n", + "display(HTML(\"<style>.container { width:100% !important; }</style>\"))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "init_cell": true + }, + "outputs": [], + "source": [ + "from IPython.core.display import Javascript\n", + "from IPython.display import display\n", + "\n", + "def run_cell_by_tag(tags):\n", + " display(Javascript(\"window.runCells('\"+tags+\"')\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "init_cell": true, + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script>\n", + " code_show=true; \n", + " function code_toggle() {\n", + " if (code_show)\n", + " {\n", + " $('div.input').hide();\n", + " } \n", + " else \n", + " {\n", + " $('div.input').show();\n", + " }\n", + " code_show = !code_show\n", + " } \n", + " $( document ).ready(code_toggle);\n", + "</script>\n", + "The raw code for this notebook is by default hidden for easier reading.\n", + "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>.\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script>\n", + " code_show=true; \n", + " function code_toggle() {\n", + " if (code_show)\n", + " {\n", + " $('div.input').hide();\n", + " } \n", + " else \n", + " {\n", + " $('div.input').show();\n", + " }\n", + " code_show = !code_show\n", + " } \n", + " $( document ).ready(code_toggle);\n", + "</script>\n", + "The raw code for this notebook is by default hidden for easier reading.\n", + "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "init_cell": true, + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "<div align=\"left\" style=\"background-color: rgba(149,170,79, 1.0); width: 100%; height: 390px; overflow: hidden;\">\n", + " <div >\n", + " <table>\n", + " <tr></tr>\n", + " <tr>\n", + " <td><img src=\"Nomad_tutorial_head.png\"></td>\n", + " </tr>\n", + " </table>\n", + " </div>\n", + "\n", + " <br><br>\n", + " <div style=\"position:relative; left:3%\"><font size=6em color=\"#20335d\" ><b> - Visualization of the band structure of materials </b></font></div>\n", + " <p style=\"position:relative;left:10%; \">\n", + " <br>\n", + " Created by:\n", + "\n", + " Xiangyue Liu<sup>1</sup>(<a href=\"mailto:xyliu@fhi-berlin.mpg.de\">email</a>),\n", + " \n", + " Fawzi Mohamed<sup>1</sup>,\n", + " \n", + " and Luca M. Ghiringhelli<sup>1</sup>(<a href=\"mailto:ghiringhelli@fhi-berlin.mpg.de\">email</a>), <br>\n", + "\n", + " <br><br>\n", + " <sup>1</sup> Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n", + " <br>\n", + "\n", + "\n", + " </p>\n", + " <br>\n", + " <div style=\"position:relative;bottom:3%\">\n", + " <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#999999\" size=\"10em\">v2.0.0</font></div>\n", + " <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#666666\" size=\"2.7em\">[Last updated: August 5, 2019]</font></div>\n", + " </div>\n", + "\n", + "</div>\n", + "\n", + "\n", + "<div style='text-align: right;'>\n", + " <a href=\"https://analytics-toolkit.nomad-coe.eu/home/\" class=\"btn btn-primary\" style=\"font-size:larger;\">Back to Analytics Home</a> \n", + " <a href=\"https://www.nomad-coe.eu/\" class=\"btn btn-primary\" style=\"font-size:larger; \">Back to nomad-coe</a> \n", + "</div>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "\n", + "\n", + "<div align=\"left\" style=\"background-color: rgba(149,170,79, 1.0); width: 100%; height: 390px; overflow: hidden;\">\n", + " <div >\n", + " <table>\n", + " <tr></tr>\n", + " <tr>\n", + " <td><img src=\"Nomad_tutorial_head.png\"></td>\n", + " </tr>\n", + " </table>\n", + " </div>\n", + "\n", + " <br><br>\n", + " <div style=\"position:relative; left:3%\"><font size=6em color=\"#20335d\" ><b> - Visualization of the band structure of materials </b></font></div>\n", + " <p style=\"position:relative;left:10%; \">\n", + " <br>\n", + " Created by:\n", + "\n", + " Xiangyue Liu<sup>1</sup>(<a href=\"mailto:xyliu@fhi-berlin.mpg.de\">email</a>),\n", + " \n", + " Fawzi Mohamed<sup>1</sup>,\n", + " \n", + " and Luca M. Ghiringhelli<sup>1</sup>(<a href=\"mailto:ghiringhelli@fhi-berlin.mpg.de\">email</a>), <br>\n", + "\n", + " <br><br>\n", + " <sup>1</sup> Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n", + " <br>\n", + "\n", + "\n", + " </p>\n", + " <br>\n", + " <div style=\"position:relative;bottom:3%\">\n", + " <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#999999\" size=\"10em\">v2.0.0</font></div>\n", + " <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#666666\" size=\"2.7em\">[Last updated: August 5, 2019]</font></div>\n", + " </div>\n", + "\n", + "</div>\n", + "\n", + "\n", + "<div style='text-align: right;'>\n", + " <a href=\"https://analytics-toolkit.nomad-coe.eu/home/\" class=\"btn btn-primary\" style=\"font-size:larger;\">Back to Analytics Home</a> \n", + " <a href=\"https://www.nomad-coe.eu/\" class=\"btn btn-primary\" style=\"font-size:larger; \">Back to nomad-coe</a> \n", + "</div>\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "init_cell": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script>\n", + " window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n", + " return (Jupyter.notebook.get_cells()\n", + " .filter(\n", + " ({metadata: {tags}}) => tags && tags.includes(tagName)\n", + " )\n", + " .map((cell) => Jupyter.notebook.find_cell_index(cell))\n", + " );\n", + " };\n", + "\n", + "\n", + " window.runCells = function runPlotCells(tags) {\n", + " var c = window.findCellIndicesByTag(tags);\n", + " Jupyter.notebook.execute_cells(c);\n", + " };\n", + "</script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script>\n", + " window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n", + " return (Jupyter.notebook.get_cells()\n", + " .filter(\n", + " ({metadata: {tags}}) => tags && tags.includes(tagName)\n", + " )\n", + " .map((cell) => Jupyter.notebook.find_cell_index(cell))\n", + " );\n", + " };\n", + "\n", + "\n", + " window.runCells = function runPlotCells(tags) {\n", + " var c = window.findCellIndicesByTag(tags);\n", + " Jupyter.notebook.execute_cells(c);\n", + " };\n", + "</script>" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "init_cell": true, + "tags": [ + "search_materials" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<br><br>\n", + "\n", + "<p style=\"color: #20335d;font-weight: 450; font-size: 14pt;font-family: Arial;\"> This tutorial visulizes the band structures and density of states (DOS) of the NOMAD materials.</p>\n", + "<br><br>\n", + "\n", + "<style>\n", + ".button {\n", + " background-color: #e7e7e7;\n", + " border: 0.5px solid #A4A4A4;\n", + " color: black;\n", + " padding: 15px 32px;\n", + " text-align: center;\n", + " text-decoration: none;\n", + " display: inline-block;\n", + " font-family: Arial;\n", + " font-size: 16px;\n", + " margin: 4px 2px;\n", + " cursor: pointer;\n", + "}\n", + "\n", + " .text-normal-black{\n", + " color: #000;font-weight: 200; font-size: 10pt;\n", + " font-family: Arial;\n", + " }\n", + " .div_band_dos{\n", + " box-sizing: border-box;\n", + " width: 100%;\n", + " height: 600px;\n", + " font-weight: 100;\n", + " font-family: Arial;\n", + " padding-left: 20px;\n", + " padding-top: 10px;\n", + " padding-right: 1em;\n", + " margin: 0;\n", + " border: 0;\n", + " }\n", + " .div_band_dos_compare{\n", + " box-sizing: border-box;\n", + " width: 1600px;\n", + " height: 600px;\n", + " color: #00AEFF;\n", + " font-weight: 100;\n", + " font-family: Arial;\n", + " padding-left: 20px;\n", + " padding-top: 10px;\n", + " padding-right: 1em;\n", + " margin: 0;\n", + " border: 0;\n", + " }\n", + " .div_band{\n", + " font-family: Arial;\n", + " font-size: 0.875em;\n", + " width: 37%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " float:left;\n", + " }\n", + " .div_dos{\n", + " font-family: Arial;\n", + " font-size: 0.875em;\n", + " width: 13%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " float:left;\n", + " }\n", + " .div_tools{\n", + " color: #20335d;font-weight: 150; font-size: 13pt;\n", + " width: 35%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " margin-left:20pt;\n", + " float:left;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .div_checkbox_compare{\n", + " color: #888;font-weight: 150; font-size: 12pt;\n", + " width: 10%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " border: solid #fff 1px;\n", + " float:right;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .div_overview{\n", + " width: 300px;\n", + " height: 200px;\n", + " background-color: #fff;\n", + " margin-left:10px; \n", + " margin-top: 20px;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .button_tools {\n", + " background-color: #F0F0F0;\n", + " border: 0.5px solid #A4A4A4;\n", + " color: black;\n", + " padding: 10px 15px;\n", + " text-align: center;\n", + " text-decoration: none;\n", + " display: inline-block;\n", + " font-size: 16px;\n", + " margin: 4px 2px;\n", + " cursor: pointer;\n", + " font-family: Arial;\n", + "\n", + " }\n", + "\n", + " \n", + " .g-before-after{position:relative;overflow:hidden;width:500px}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%}\n", + "</style>\n", + "\n", + "<script>\n", + " //Search for certain keyword: https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\n", + " //FjiYy5-ETRCrs5ktzJA55w/bOY0cPkBvvNAY7pZdbginlKXJ2kF\n", + " //\"upload_id\"/\"calc_id\"\n", + " \n", + " //Global variables\n", + " var paths_section_k_band_segment = []; \n", + " var paths_section_dos = [];\n", + " var band_obj_all = [];\n", + " var dos_obj_all = [];\n", + " var info_obj_all = [];\n", + " \n", + " var band_paths = [];\n", + " var dos_paths = [];\n", + " var N_materials = 0; //Number of materials that have both band and DOS in the same calculation \n", + " \n", + " \n", + " function getJSON(url) {\n", + " var resp ;\n", + " var xmlHttp ;\n", + "\n", + " resp = '' ;\n", + " xmlHttp = new XMLHttpRequest();\n", + "\n", + " if(xmlHttp != null)\n", + " {\n", + " xmlHttp.open( \"GET\", url, false );\n", + " xmlHttp.send( null );\n", + " resp = xmlHttp.responseText;\n", + " }\n", + "\n", + " return resp;\n", + " }\n", + " function match_band_dos()\n", + " {\n", + " //TMP for local tests\n", + " /*\n", + " paths_section_k_band_segment = [\"data/kOJR-AlPSgiNG9AdZoxd4g_9mxjIU0edrPosfsTc4uyDG9H_UXr.json\",\"data/kOJR-AlPSgiNG9AdZoxd4g_lfkGCmWozYENeiGhu5W7dJUqLTkj.json\"];\n", + " paths_section_dos = [\"data/kOJR-AlPSgiNG9AdZoxd4g_8tEGnaz0yY91eSyysKZkIUH9qx8J.json\", \"data/kOJR-AlPSgiNG9AdZoxd4g_lxUT3viRZcC_1IsH_KvO5tChAtV1.json\"];\n", + " */\n", + "\n", + " //band_paths = [];\n", + " //dos_paths = [];\n", + " //N_materials = 0; \n", + " \n", + " var data_k_band = [];\n", + " for(var i_path_k_band = 0; i_path_k_band < paths_section_k_band_segment.length; i_path_k_band ++)\n", + " {\n", + " var i_data_k_band_json = JSON.parse(getJSON(paths_section_k_band_segment[i_path_k_band]));\n", + " var i_data_k_band = {};\n", + " i_data_k_band[\"program_name\"] = i_data_k_band_json[\"section_run\"][\"program_name\"];\n", + " i_data_k_band[\"k_mesh_points\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n", + " i_data_k_band[\"simulation_cell\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n", + " i_data_k_band[\"atom_positions\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n", + " i_data_k_band[\"atom_labels\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " i_data_k_band[\"XC_functional_name\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n", + " i_data_k_band[\"path\"] = paths_section_k_band_segment[i_path_k_band];\n", + " data_k_band.push(i_data_k_band);\n", + " }\n", + "\n", + " var data_dos = [];\n", + " for(var i_path_dos = 0; i_path_dos < paths_section_dos.length; i_path_dos ++)\n", + " {\n", + " var i_data_dos_json = JSON.parse(getJSON(paths_section_dos[i_path_dos]));\n", + " var i_data_dos = {};\n", + " i_data_dos[\"program_name\"] = i_data_dos_json[\"section_run\"][\"program_name\"];\n", + " i_data_dos[\"k_mesh_points\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n", + " i_data_dos[\"simulation_cell\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n", + " i_data_dos[\"atom_positions\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n", + " i_data_dos[\"atom_labels\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " i_data_dos[\"XC_functional_name\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n", + " i_data_dos[\"path\"] = paths_section_dos[i_path_dos];\n", + " data_dos.push(i_data_dos); \n", + " }\n", + "\n", + " //Matching: band[i] ~ dos[i] (the same systems are arranged with the same index)\n", + " band_paths = [];\n", + " dos_paths = [];\n", + " N_materials = 0;\n", + " for(var i_k_band = 0; i_k_band < data_k_band.length; i_k_band ++)\n", + " {\n", + " for(var i_dos = 0; i_dos < data_dos.length; i_dos ++)\n", + " {\n", + " if(data_k_band[i_k_band][\"program_name\"] != data_dos[i_dos][\"program_name\"])\n", + " continue; \n", + " //if(data_k_band[i_k_band][\"k_mesh_points\"].join() != data_dos[i_dos][\"k_mesh_points\"].join())\n", + " // continue;\n", + " if(data_k_band[i_k_band][\"simulation_cell\"].join() != data_dos[i_dos][\"simulation_cell\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"atom_positions\"].join() != data_dos[i_dos][\"atom_positions\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"atom_labels\"].join() != data_dos[i_dos][\"atom_labels\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"XC_functional_name\"] != data_dos[i_dos][\"XC_functional_name\"])\n", + " continue;\n", + " band_paths.push(data_k_band[i_k_band][\"path\"]);\n", + " dos_paths.push(data_dos[i_dos][\"path\"]);\n", + " N_materials ++;\n", + " }\n", + " }\n", + " //Pass the arrays to python\n", + "\n", + " var command = \"N_materials = \" + N_materials + \";\"\n", + " var kernel = IPython.notebook.kernel;\n", + " command += \"band_paths = \" + \"[\\'\" + band_paths.join(\"\\',\\'\") + \"\\'];\";\n", + " command += \"dos_paths = \" + \"[\\'\" + dos_paths.join(\"\\',\\'\") + \"\\'];\";\n", + " kernel.execute(command);\n", + " \n", + " \n", + " }\n", + "\n", + " function get_paths_from_search_results(result_json, div_id_search_results,div_head)\n", + " {\n", + " paths = [];\n", + " search_results_content = [div_head, '<table>', '<tr><th>Chemical formula</th><th>Spacegroup</th><th>Code</th><th>XC functional</th><th>Upload ID</th><th>Calculation ID</th><th>URL</th></tr>'];\n", + " for(var i_key in result_json)\n", + " {\n", + " if(i_key == \"results\")\n", + " {\n", + " for(var system in result_json[i_key])\n", + " {\n", + " //Get the path to the data files (json): https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/upload_id/calc_id \n", + " path = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/\" + result_json[i_key][system][\"upload_id\"] + \"/\" + result_json[i_key][system][\"calc_id\"]\n", + " paths.push(path);\n", + " \n", + " //Show the results in div\n", + " // \"formula\" \"spacegroup_symbol\" \"code_name\" \"xc_functional\"\n", + " content = '<tr>';\n", + " content += '<td>' + result_json[i_key][system][\"formula\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"spacegroup_symbol\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"code_name\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"xc_functional\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"upload_id\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"calc_id\"] + '</td>'; \n", + " content += '<td>' + path + '</td>';\n", + " content += '</tr>';\n", + " search_results_content.push(content);\n", + " }\n", + " }\n", + " }\n", + " search_results_content.push('</table>');\n", + " document.getElementById(div_id_search_results).innerHTML = search_results_content.join('');\n", + " return paths\n", + " }\n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " function submit_search()\n", + " {\n", + " \n", + " var result;\n", + " var formula = document.getElementById(\"keyword_chemical_formula\").value;\n", + " var query_command_k_band = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_k_band_segment\";\n", + " var query_command_dos = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_dos\";\n", + " //result = getJSON(\"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\");\n", + " var result_k_band = getJSON(query_command_k_band);\n", + " var result_dos = getJSON(query_command_dos);\n", + " var result_json_k_band = JSON.parse(result_k_band);//parse the searching results to json from URL\n", + " var result_json_dos = JSON.parse(result_dos);\n", + " paths_section_k_band_segment = []; \n", + " paths_section_dos = [];\n", + " paths_section_k_band_segment = get_paths_from_search_results(result_json_k_band, \"search_results_section_k_band_segment\", \"<br><br><font size=4em>Calculations containing band structures:</font><br>\");\n", + " paths_section_dos = get_paths_from_search_results(result_json_dos, \"search_results_section_dos\", \"<br><font size=4em>Calculations containing DOS:</font><br>\");\n", + " \n", + " var promise = Promise.resolve();\n", + " promise\n", + " .then(match_band_dos())\n", + " .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')))\n", + " .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')));\n", + " \n", + " //match_band_dos();\n", + " \n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')); //Read the json files, and prepare data for plot\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')); //Prepare for plot\n", + " }\n", + " function reset_search()\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('search_materials'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot'));\n", + " }\n", + " \n", + " \n", + "</script>\n", + "<font size=4em>Please input the chemical formula:</font>\n", + "<input type=\"text\" id=\"keyword_chemical_formula\" value=\"AlInO3\"> \n", + "<button class=\"button\" onclick=\"submit_search()\">Search</button>\n", + "<button class=\"button\" onclick=\"reset_search()\">Reset</button>\n", + "<br><br><br>\n", + "<div id=\"search_results_section_k_band_segment\"></div>\n", + "<div id=\"search_results_section_dos\"></div>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%html\n", + "<br><br>\n", + "\n", + "<p style=\"color: #20335d;font-weight: 450; font-size: 14pt;font-family: Arial;\"> This tutorial visulizes the band structures and density of states (DOS) of the NOMAD materials.</p>\n", + "<br><br>\n", + "\n", + "<style>\n", + ".button {\n", + " background-color: #e7e7e7;\n", + " border: 0.5px solid #A4A4A4;\n", + " color: black;\n", + " padding: 15px 32px;\n", + " text-align: center;\n", + " text-decoration: none;\n", + " display: inline-block;\n", + " font-family: Arial;\n", + " font-size: 16px;\n", + " margin: 4px 2px;\n", + " cursor: pointer;\n", + "}\n", + "\n", + " .text-normal-black{\n", + " color: #000;font-weight: 200; font-size: 10pt;\n", + " font-family: Arial;\n", + " }\n", + " .div_band_dos{\n", + " box-sizing: border-box;\n", + " width: 100%;\n", + " height: 600px;\n", + " font-weight: 100;\n", + " font-family: Arial;\n", + " padding-left: 20px;\n", + " padding-top: 10px;\n", + " padding-right: 1em;\n", + " margin: 0;\n", + " border: 0;\n", + " }\n", + " .div_band_dos_compare{\n", + " box-sizing: border-box;\n", + " width: 1600px;\n", + " height: 600px;\n", + " color: #00AEFF;\n", + " font-weight: 100;\n", + " font-family: Arial;\n", + " padding-left: 20px;\n", + " padding-top: 10px;\n", + " padding-right: 1em;\n", + " margin: 0;\n", + " border: 0;\n", + " }\n", + " .div_band{\n", + " font-family: Arial;\n", + " font-size: 0.875em;\n", + " width: 37%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " float:left;\n", + " }\n", + " .div_dos{\n", + " font-family: Arial;\n", + " font-size: 0.875em;\n", + " width: 13%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " float:left;\n", + " }\n", + " .div_tools{\n", + " color: #20335d;font-weight: 150; font-size: 13pt;\n", + " width: 35%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " margin-left:20pt;\n", + " float:left;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .div_checkbox_compare{\n", + " color: #888;font-weight: 150; font-size: 12pt;\n", + " width: 10%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " border: solid #fff 1px;\n", + " float:right;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .div_overview{\n", + " width: 300px;\n", + " height: 200px;\n", + " background-color: #fff;\n", + " margin-left:10px; \n", + " margin-top: 20px;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .button_tools {\n", + " background-color: #F0F0F0;\n", + " border: 0.5px solid #A4A4A4;\n", + " color: black;\n", + " padding: 10px 15px;\n", + " text-align: center;\n", + " text-decoration: none;\n", + " display: inline-block;\n", + " font-size: 16px;\n", + " margin: 4px 2px;\n", + " cursor: pointer;\n", + " font-family: Arial;\n", + "\n", + " }\n", + "\n", + " \n", + " .g-before-after{position:relative;overflow:hidden;width:500px}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%}\n", + "</style>\n", + "\n", + "<script>\n", + " //Search for certain keyword: https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\n", + " //FjiYy5-ETRCrs5ktzJA55w/bOY0cPkBvvNAY7pZdbginlKXJ2kF\n", + " //\"upload_id\"/\"calc_id\"\n", + " \n", + " //Global variables\n", + " var paths_section_k_band_segment = []; \n", + " var paths_section_dos = [];\n", + " var band_obj_all = [];\n", + " var dos_obj_all = [];\n", + " var info_obj_all = [];\n", + " \n", + " var band_paths = [];\n", + " var dos_paths = [];\n", + " var N_materials = 0; //Number of materials that have both band and DOS in the same calculation \n", + " \n", + " \n", + " function getJSON(url) {\n", + " var resp ;\n", + " var xmlHttp ;\n", + "\n", + " resp = '' ;\n", + " xmlHttp = new XMLHttpRequest();\n", + "\n", + " if(xmlHttp != null)\n", + " {\n", + " xmlHttp.open( \"GET\", url, false );\n", + " xmlHttp.send( null );\n", + " resp = xmlHttp.responseText;\n", + " }\n", + "\n", + " return resp;\n", + " }\n", + " function match_band_dos()\n", + " {\n", + " //TMP for local tests\n", + " /*\n", + " paths_section_k_band_segment = [\"data/kOJR-AlPSgiNG9AdZoxd4g_9mxjIU0edrPosfsTc4uyDG9H_UXr.json\",\"data/kOJR-AlPSgiNG9AdZoxd4g_lfkGCmWozYENeiGhu5W7dJUqLTkj.json\"];\n", + " paths_section_dos = [\"data/kOJR-AlPSgiNG9AdZoxd4g_8tEGnaz0yY91eSyysKZkIUH9qx8J.json\", \"data/kOJR-AlPSgiNG9AdZoxd4g_lxUT3viRZcC_1IsH_KvO5tChAtV1.json\"];\n", + " */\n", + "\n", + " //band_paths = [];\n", + " //dos_paths = [];\n", + " //N_materials = 0; \n", + " \n", + " var data_k_band = [];\n", + " for(var i_path_k_band = 0; i_path_k_band < paths_section_k_band_segment.length; i_path_k_band ++)\n", + " {\n", + " var i_data_k_band_json = JSON.parse(getJSON(paths_section_k_band_segment[i_path_k_band]));\n", + " var i_data_k_band = {};\n", + " i_data_k_band[\"program_name\"] = i_data_k_band_json[\"section_run\"][\"program_name\"];\n", + " i_data_k_band[\"k_mesh_points\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n", + " i_data_k_band[\"simulation_cell\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n", + " i_data_k_band[\"atom_positions\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n", + " i_data_k_band[\"atom_labels\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " i_data_k_band[\"XC_functional_name\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n", + " i_data_k_band[\"path\"] = paths_section_k_band_segment[i_path_k_band];\n", + " data_k_band.push(i_data_k_band);\n", + " }\n", + "\n", + " var data_dos = [];\n", + " for(var i_path_dos = 0; i_path_dos < paths_section_dos.length; i_path_dos ++)\n", + " {\n", + " var i_data_dos_json = JSON.parse(getJSON(paths_section_dos[i_path_dos]));\n", + " var i_data_dos = {};\n", + " i_data_dos[\"program_name\"] = i_data_dos_json[\"section_run\"][\"program_name\"];\n", + " i_data_dos[\"k_mesh_points\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n", + " i_data_dos[\"simulation_cell\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n", + " i_data_dos[\"atom_positions\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n", + " i_data_dos[\"atom_labels\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " i_data_dos[\"XC_functional_name\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n", + " i_data_dos[\"path\"] = paths_section_dos[i_path_dos];\n", + " data_dos.push(i_data_dos); \n", + " }\n", + "\n", + " //Matching: band[i] ~ dos[i] (the same systems are arranged with the same index)\n", + " band_paths = [];\n", + " dos_paths = [];\n", + " N_materials = 0;\n", + " for(var i_k_band = 0; i_k_band < data_k_band.length; i_k_band ++)\n", + " {\n", + " for(var i_dos = 0; i_dos < data_dos.length; i_dos ++)\n", + " {\n", + " if(data_k_band[i_k_band][\"program_name\"] != data_dos[i_dos][\"program_name\"])\n", + " continue; \n", + " //if(data_k_band[i_k_band][\"k_mesh_points\"].join() != data_dos[i_dos][\"k_mesh_points\"].join())\n", + " // continue;\n", + " if(data_k_band[i_k_band][\"simulation_cell\"].join() != data_dos[i_dos][\"simulation_cell\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"atom_positions\"].join() != data_dos[i_dos][\"atom_positions\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"atom_labels\"].join() != data_dos[i_dos][\"atom_labels\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"XC_functional_name\"] != data_dos[i_dos][\"XC_functional_name\"])\n", + " continue;\n", + " band_paths.push(data_k_band[i_k_band][\"path\"]);\n", + " dos_paths.push(data_dos[i_dos][\"path\"]);\n", + " N_materials ++;\n", + " }\n", + " }\n", + " //Pass the arrays to python\n", + "\n", + " var command = \"N_materials = \" + N_materials + \";\"\n", + " var kernel = IPython.notebook.kernel;\n", + " command += \"band_paths = \" + \"[\\'\" + band_paths.join(\"\\',\\'\") + \"\\'];\";\n", + " command += \"dos_paths = \" + \"[\\'\" + dos_paths.join(\"\\',\\'\") + \"\\'];\";\n", + " kernel.execute(command);\n", + " \n", + " \n", + " }\n", + "\n", + " function get_paths_from_search_results(result_json, div_id_search_results,div_head)\n", + " {\n", + " paths = [];\n", + " search_results_content = [div_head, '<table>', '<tr><th>Chemical formula</th><th>Spacegroup</th><th>Code</th><th>XC functional</th><th>Upload ID</th><th>Calculation ID</th><th>URL</th></tr>'];\n", + " for(var i_key in result_json)\n", + " {\n", + " if(i_key == \"results\")\n", + " {\n", + " for(var system in result_json[i_key])\n", + " {\n", + " //Get the path to the data files (json): https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/upload_id/calc_id \n", + " path = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/\" + result_json[i_key][system][\"upload_id\"] + \"/\" + result_json[i_key][system][\"calc_id\"]\n", + " paths.push(path);\n", + " \n", + " //Show the results in div\n", + " // \"formula\" \"spacegroup_symbol\" \"code_name\" \"xc_functional\"\n", + " content = '<tr>';\n", + " content += '<td>' + result_json[i_key][system][\"formula\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"spacegroup_symbol\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"code_name\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"xc_functional\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"upload_id\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"calc_id\"] + '</td>'; \n", + " content += '<td>' + path + '</td>';\n", + " content += '</tr>';\n", + " search_results_content.push(content);\n", + " }\n", + " }\n", + " }\n", + " search_results_content.push('</table>');\n", + " document.getElementById(div_id_search_results).innerHTML = search_results_content.join('');\n", + " return paths\n", + " }\n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " function submit_search()\n", + " {\n", + " \n", + " var result;\n", + " var formula = document.getElementById(\"keyword_chemical_formula\").value;\n", + " var query_command_k_band = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_k_band_segment\";\n", + " var query_command_dos = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_dos\";\n", + " //result = getJSON(\"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\");\n", + " var result_k_band = getJSON(query_command_k_band);\n", + " var result_dos = getJSON(query_command_dos);\n", + " var result_json_k_band = JSON.parse(result_k_band);//parse the searching results to json from URL\n", + " var result_json_dos = JSON.parse(result_dos);\n", + " paths_section_k_band_segment = []; \n", + " paths_section_dos = [];\n", + " paths_section_k_band_segment = get_paths_from_search_results(result_json_k_band, \"search_results_section_k_band_segment\", \"<br><br><font size=4em>Calculations containing band structures:</font><br>\");\n", + " paths_section_dos = get_paths_from_search_results(result_json_dos, \"search_results_section_dos\", \"<br><font size=4em>Calculations containing DOS:</font><br>\");\n", + " \n", + " var promise = Promise.resolve();\n", + " promise\n", + " .then(match_band_dos())\n", + " .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')))\n", + " .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')));\n", + " \n", + " //match_band_dos();\n", + " \n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')); //Read the json files, and prepare data for plot\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')); //Prepare for plot\n", + " }\n", + " function reset_search()\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('search_materials'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot'));\n", + " }\n", + " \n", + " \n", + "</script>\n", + "<font size=4em>Please input the chemical formula:</font>\n", + "<input type=\"text\" id=\"keyword_chemical_formula\" value=\"AlInO3\"> \n", + "<button class=\"button\" onclick=\"submit_search()\">Search</button>\n", + "<button class=\"button\" onclick=\"reset_search()\">Reset</button>\n", + "<br><br><br>\n", + "<div id=\"search_results_section_k_band_segment\"></div>\n", + "<div id=\"search_results_section_dos\"></div>\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "tags": [ + "process_band_dos_data" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script>\n", + " var band_obj_all = [];\n", + " var dos_obj_all = [];\n", + " var info_obj_all = [];\n", + " //alert(\"process_band_dos_data: \" +band_paths)\n", + " //alert(\"process_band_dos_data: \" +info_obj_all)\n", + " function get_label_flag(coor_array)\n", + " {\n", + " var coor = coor_array.sort().join();\n", + " if(coor == '0,0.5,0.5')\n", + " return \"X\";\n", + " if(coor == '0,0,0.5')\n", + " return \"M\";\n", + " else if(coor == '0.5,0.5,0.5')\n", + " return \"L\";\n", + " else if(coor == '0.375,0.375,0.75')\n", + " return \"K\";\n", + " else if(coor == '0.25,0.5,0.75')\n", + " return \"W\";\n", + " else if(coor == '0,0,0')\n", + " return \"\\u0393\";\n", + " else if(coor == '0.25,0.625,0.625')\n", + " return \"U\";\n", + " else\n", + " {\n", + " //alert(\"k label not found: \" + coor);\n", + " return \"?\";\n", + " }\n", + " }\n", + "\n", + "\n", + " //============Process the band structure data============\n", + " function get_band_obj(band_path, dos_fermi_energy)\n", + " {\n", + " var band_data = JSON.parse(getJSON(band_path));\n", + "\n", + " //---------Read section_k_band_segment------------\n", + " var section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n", + "\n", + " //--------Get the number of k band segments-------------\n", + " var N_k_band_segments = section_k_band_segment.length;\n", + "\n", + "\n", + " //----------Get the total number of k points in all segments---------\n", + " var N_k_points_all = 0;\n", + " for(var i = 0; i < N_k_band_segments; i++)\n", + " N_k_points_all = N_k_points_all + section_k_band_segment[i]['band_k_points'].length;\n", + "\n", + "\n", + " //--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n", + " // store in k_coor_1D[N_k_points_total]-----------------\n", + "\n", + " var band_distance_segments = [];\n", + " for(i = 0; i < N_k_band_segments; i++)\n", + " {\n", + " var x1, x2, y1, y2, z1, z2;\n", + " [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end']; //\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n", + " band_distance_segments.push(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2) + Math.pow((z1-z2), 2));\n", + " }\n", + "\n", + "\n", + " var band_distance_total = band_distance_segments.reduce((x,y) => x+y); //sum of band_distance_segments\n", + "\n", + " var average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total;\n", + "\n", + " //Prepare the parameters to rescale the k coordinates into [0,1]\n", + " var step_k_point = 1.0 / N_k_points_all;\n", + " var step_k_point = (1.0 + step_k_point) / N_k_points_all;\n", + "\n", + " var k_coor_1D = [];\n", + " for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points ++)\n", + " {\n", + " k_coor_1D.push(step_k_point * i_k_points)\n", + " }\n", + "\n", + "\n", + " //--------Get the eigenvalues of each band trajectory--------------\n", + " /*\n", + " N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n", + " N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n", + " band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n", + " N_k_points_all = 0\n", + " for i_segments in range(N_k_band_segments):\n", + " band_energies = section_k_band_segment[i_segments]['band_energies']\n", + " N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n", + " N_k_points_per_segment = len(band_energies[0])\n", + " for i_k_points in range(N_k_points_per_segment):\n", + " for i_bands in range(N_bands):\n", + " band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n", + " N_k_points_all = N_k_points_all + 1\n", + " */\n", + " //var N_k_points_per_segment = section_k_band_segment[0]['band_energies'][0].length; //suppose the numebr of k points in all the segments are the same\n", + " var N_bands = section_k_band_segment[0]['band_energies'][0][0].length;\n", + " var band_energies_all = new Array(N_bands);\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " band_energies_all[i_bands] = new Array(N_k_points_all);// new Array(N_bands, N_k_points_all); //store the eigenvalues\n", + "\n", + " var i_k_points_all = 0;\n", + "\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " var band_energies = section_k_band_segment[i_segments]['band_energies'];\n", + " var N_spin_channel = band_energies.length; //Number of the spin channel --FIXME: no spin polarized\n", + " var N_k_points_per_segment = band_energies[0].length;\n", + " for(var i_k_points = 0; i_k_points < N_k_points_per_segment; i_k_points ++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " band_energies_all[i_bands][i_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * Math.pow(10, -19)) - dos_fermi_energy;\n", + " }\n", + " i_k_points_all = i_k_points_all + 1 ;\n", + "\n", + " }\n", + " }\n", + "\n", + "\n", + "\n", + " var N_labels = 0\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " for(var j = 0; j < 2; j++)\n", + " //labels_tmp = section_k_band_segment[i_segments]['band_segm_start_end'][j];\n", + " N_labels = N_labels + 1\n", + " }\n", + " var label_flag = [];//[\"\" for i in range(N_labels)] //stores the flags of the labels (X, W, G, etc)\n", + "\n", + "\n", + " var i_label = 0;\n", + " var label_flag_last_final = \"\";\n", + " var label_flag_current_initial = \"\";\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " var labels_coor_0 = section_k_band_segment[i_segments]['band_segm_start_end'][0].sort();\n", + " var labels_coor_1 = section_k_band_segment[i_segments]['band_segm_start_end'][1].sort();\n", + "\n", + " var label_flag_0 = get_label_flag(labels_coor_0);\n", + " var label_flag_1 = get_label_flag(labels_coor_1);\n", + "\n", + " var label_flag_current_initial = label_flag_0;\n", + " if(label_flag_last_final == \"\")\n", + " label_flag_last_final = label_flag_0;\n", + "\n", + " if(label_flag_last_final == label_flag_current_initial)\n", + " label_flag[i_label] = label_flag_current_initial;\n", + " else\n", + " label_flag[i_label] = label_flag_last_final + '|' + label_flag_current_initial;\n", + " label_flag_last_final = label_flag_1\n", + "\n", + "\n", + " i_label = i_label + 1;\n", + " if(i_segments == N_k_band_segments - 1)\n", + " {\n", + " label_flag[i_label] = label_flag_1;\n", + " i_label = i_label + 1;\n", + " }\n", + " }\n", + " N_labels = i_label;\n", + "\n", + " //------------Get the coordinates for the labels------------\n", + " //label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n", + " var label_coor_relative = [];//np.zeros((N_labels))\n", + " for(i_label = 0; i_label < N_labels; i_label ++)\n", + " {\n", + " //Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n", + " //x = labels_coor_0[0]\n", + " //y = labels_coor_0[1]\n", + " //z = labels_coor_0[2]\n", + " //label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n", + " label_coor_relative.push(step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all));\n", + " }\n", + " //----Store the label-----------\n", + " var label_obj = [];//[['' for i in range(2)] for j in range(N_labels)]\n", + " for(i_label = 0; i_label < N_labels; i_label ++)\n", + " {\n", + " label_obj.push([label_coor_relative[i_label], label_flag[i_label]]);\n", + " }\n", + "\n", + "\n", + " //-------Get VBM, CBM----------------\n", + "\n", + " var HOMO = -1000;\n", + " var LUMO = 1000;\n", + " var coor_k_point_HOMO = []; //the coordinate of k point that stores HOMO\n", + " var coor_k_point_LUMO = [];//np.zeros((3)) #the coordinate of k point that stores LUMO\n", + " //band_gap_direct = 0.0\n", + " var band_gap_indirect = 0.0;\n", + "\n", + "\n", + " //band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " //band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " var band_energy_max = 10;\n", + " var band_energy_min = -10;\n", + " //N_band_energy_index = 10000\n", + " //band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n", + " //N_allowed_states = np.zeros(N_band_energy_index + 1)\n", + " //i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n", + "\n", + "\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " for(var i_k_points_all = 0; i_k_points_all< N_k_points_all; i_k_points_all ++)\n", + " {\n", + " //i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n", + " //N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n", + " var band_energy = band_energies_all[i_bands][i_k_points_all];\n", + " if(band_energy > 0)\n", + " {\n", + " if(band_energy < LUMO)\n", + " LUMO = band_energy;\n", + " }\n", + " else\n", + " {\n", + " if(band_energy > HOMO)\n", + " HOMO = band_energy;\n", + " }\n", + "\n", + " }\n", + " }\n", + "\n", + "\n", + " //#for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n", + " // if(N_allowed_states[i_band_index] > 0):\n", + " // LUMO = band_energy_min + band_energy_step * i_band_index\n", + " //print('HOMO, LUMO: ',HOMO, LUMO)\n", + " band_gap_indirect = Math.abs(LUMO - HOMO);\n", + "\n", + " if(band_gap_indirect < 0.5) //VBM and CBM has to be found in another way for metals/charged system:\n", + " {\n", + " HOMO = -1000.0;\n", + " LUMO = 1000.0;\n", + " band_energy_max = 10.0;\n", + " band_energy_min = 0.0;\n", + " var N_band_energy_index = 10000;\n", + " var band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index;\n", + " var N_allowed_states = [];\n", + " for(var i_state = 0; i_state < N_band_energy_index+1; i_state++)\n", + " N_allowed_states.push(0);\n", + "\n", + "\n", + " //get the DOS and store in N_allowed_states[]\n", + " for(var i_k_points_all = 0; i_k_points_all < N_k_points_all; i_k_points_all ++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " var band_energy = band_energies_all[i_bands][i_k_points_all];\n", + " if((band_energy_min < band_energy)&&(band_energy < band_energy_max))\n", + " {\n", + " var i_band_index = Math.floor((band_energy - band_energy_min) / band_energy_step);\n", + " N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1;\n", + " }\n", + " }\n", + " }\n", + "\n", + "\n", + " var if_gapped = 0;\n", + " for(var i_band_index = 0; i_band_index < N_band_energy_index; i_band_index ++)//go through the energy levels from the bottom\n", + " {\n", + " var band_energy = band_energy_min + band_energy_step * i_band_index\n", + " if(N_allowed_states[i_band_index] == 0)\n", + " if_gapped = if_gapped + 1;\n", + " if((band_energy > band_energy_max - 0.5) && (if_gapped == 0))\n", + " {\n", + " //alert(\"No gap found in this system. It seems to be a metal.\");\n", + " HOMO = 1000;\n", + " LUMO = 1000;\n", + " break;\n", + " }\n", + " //print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n", + "\n", + " if(N_allowed_states[i_band_index] > 0)\n", + " {\n", + " if(if_gapped * band_energy_step > 0.3 )//above VBM-CBM gap: LUMO\n", + " {\n", + " if(band_energy < LUMO)\n", + " {\n", + " //print(\"LUMO got!\")\n", + " LUMO = band_energy;\n", + " break; //break before touching another gap that is above the band gap\n", + " }\n", + " }\n", + "\n", + " if(if_gapped * band_energy_step < 0.3) //below VBM-CBM gap: HOMO\n", + " {\n", + " if(band_energy > HOMO)\n", + " {\n", + " //print(\"HOMO got!\")\n", + " HOMO = band_energy;\n", + " }\n", + " } \n", + " if_gapped = 0;\n", + " }\n", + " }\n", + " //alert('HOMO, LUMO for metal/charged system: '+ HOMO +\",\"+LUMO)\n", + "\n", + " }\n", + "\n", + "\n", + "\n", + "\n", + " //Find the position of HOMO, LUMO\n", + " var coor_k_point_HOMO = 0, coor_k_point_LUMO = 0;\n", + " for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " if(Math.abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001)\n", + " coor_k_point_HOMO = k_coor_1D[i_k_points];\n", + " if(Math.abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001)\n", + " coor_k_point_LUMO = k_coor_1D[i_k_points]; \n", + " }\n", + " }\n", + "\n", + " //alert(coor_k_point_HOMO +\",\" + coor_k_point_LUMO);\n", + "\n", + "\n", + " //Store the band data to band_obj\n", + "\n", + " var band_obj = {};\n", + " band_obj[\"band_x_axis\"] = k_coor_1D;\n", + " band_obj[\"band_y_axis\"] = band_energies_all\n", + " band_obj[\"labels\"] = label_obj;\n", + " band_obj[\"HOMO_energy\"] = HOMO;\n", + " band_obj[\"HOMO_coor\"] = coor_k_point_HOMO;\n", + " band_obj[\"LUMO_energy\"] = LUMO;\n", + " band_obj[\"LUMO_coor\"] = coor_k_point_LUMO;\n", + " band_obj[\"average_N_k_points_per_inverse_distance\"] = average_N_k_points_per_inverse_distance;\n", + "\n", + "\n", + " return band_obj\n", + "\n", + " }\n", + "\n", + "\n", + " function get_dos_obj(dos_path)\n", + " {\n", + "\n", + " var dos_data = JSON.parse(getJSON(dos_path));\n", + "\n", + " var N_dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'].length;\n", + "\n", + " //in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n", + "\n", + " //dos_energies = new Array(N_dos_values).fill(0.0);\n", + " //dos_energies_tmp = new Array(N_dos_values).fill(0.0) #tmp array for unit convertion\n", + " //dos_values = new Array(N_dos_values).fill(0.0)\n", + "\n", + " var dos_energies = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'];\n", + " var dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_integrated_values'];//[0]\n", + "\n", + " //To do: check if every section_dos has 'dos_fermi_energy'\n", + " var dos_fermi_energy = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_fermi_energy'];\n", + " dos_fermi_energy = dos_fermi_energy / (1.60217656535 * Math.pow(10,-19));\n", + " \n", + " for(var i = 0; i < N_dos_values; i++)\n", + " {\n", + " dos_energies[i] = dos_energies[i] / (1.60217656535 * Math.pow(10,-19)) - dos_fermi_energy;\n", + " }\n", + " \n", + " dos_obj = {}\n", + " dos_obj[\"dos_x_axis\"] = dos_energies;\n", + " dos_obj[\"dos_y_axis\"] = dos_values;\n", + " dos_obj[\"dos_fermi_energy\"] = dos_fermi_energy;\n", + " return dos_obj\n", + " }\n", + " function get_info_obj(band_path)\n", + " {\n", + "\n", + " var band_data = JSON.parse(getJSON(band_path));\n", + " var info_obj = {};\n", + " //---------Read the information of the calculation--------\n", + " info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n", + " info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n", + " info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n", + "\n", + " //----------Get the space group information----------\n", + " /*\n", + " [space_group_symbol, lattice_constant] = get_space_group(band_data);\n", + " info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist();\n", + " info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist();\n", + " */\n", + "\n", + " return info_obj\n", + " }\n", + " function process_band_dos_data()\n", + " {\n", + " info_all = [];\n", + " band_obj_all = [];\n", + " dos_obj_all = [];\n", + "\n", + " for(var i = 0; i < N_materials; i++)\n", + " {\n", + " var band_path = band_paths[i];\n", + " var dos_path = dos_paths[i];\n", + "\n", + "\n", + " var dos_obj = get_dos_obj(dos_path);\n", + " var dos_fermi_energy = dos_obj[\"dos_fermi_energy\"];\n", + " band_obj = get_band_obj(band_path, dos_fermi_energy);\n", + " var info_obj = get_info_obj(band_path);\n", + "\n", + " band_obj_all.push(band_obj);\n", + " dos_obj_all.push(dos_obj);\n", + " info_obj_all.push(info_obj);\n", + " }\n", + " }\n", + " process_band_dos_data();\n", + " //alert(\"process_band_dos_data: info_obj_all: \"+JSON.stringify(info_obj_all));\n", + "</script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script>\n", + " var band_obj_all = [];\n", + " var dos_obj_all = [];\n", + " var info_obj_all = [];\n", + " //alert(\"process_band_dos_data: \" +band_paths)\n", + " //alert(\"process_band_dos_data: \" +info_obj_all)\n", + " function get_label_flag(coor_array)\n", + " {\n", + " var coor = coor_array.sort().join();\n", + " if(coor == '0,0.5,0.5')\n", + " return \"X\";\n", + " if(coor == '0,0,0.5')\n", + " return \"M\";\n", + " else if(coor == '0.5,0.5,0.5')\n", + " return \"L\";\n", + " else if(coor == '0.375,0.375,0.75')\n", + " return \"K\";\n", + " else if(coor == '0.25,0.5,0.75')\n", + " return \"W\";\n", + " else if(coor == '0,0,0')\n", + " return \"\\u0393\";\n", + " else if(coor == '0.25,0.625,0.625')\n", + " return \"U\";\n", + " else\n", + " {\n", + " //alert(\"k label not found: \" + coor);\n", + " return \"?\";\n", + " }\n", + " }\n", + "\n", + "\n", + " //============Process the band structure data============\n", + " function get_band_obj(band_path, dos_fermi_energy)\n", + " {\n", + " var band_data = JSON.parse(getJSON(band_path));\n", + "\n", + " //---------Read section_k_band_segment------------\n", + " var section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n", + "\n", + " //--------Get the number of k band segments-------------\n", + " var N_k_band_segments = section_k_band_segment.length;\n", + "\n", + "\n", + " //----------Get the total number of k points in all segments---------\n", + " var N_k_points_all = 0;\n", + " for(var i = 0; i < N_k_band_segments; i++)\n", + " N_k_points_all = N_k_points_all + section_k_band_segment[i]['band_k_points'].length;\n", + "\n", + "\n", + " //--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n", + " // store in k_coor_1D[N_k_points_total]-----------------\n", + "\n", + " var band_distance_segments = [];\n", + " for(i = 0; i < N_k_band_segments; i++)\n", + " {\n", + " var x1, x2, y1, y2, z1, z2;\n", + " [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end']; //\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n", + " band_distance_segments.push(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2) + Math.pow((z1-z2), 2));\n", + " }\n", + "\n", + "\n", + " var band_distance_total = band_distance_segments.reduce((x,y) => x+y); //sum of band_distance_segments\n", + "\n", + " var average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total;\n", + "\n", + " //Prepare the parameters to rescale the k coordinates into [0,1]\n", + " var step_k_point = 1.0 / N_k_points_all;\n", + " var step_k_point = (1.0 + step_k_point) / N_k_points_all;\n", + "\n", + " var k_coor_1D = [];\n", + " for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points ++)\n", + " {\n", + " k_coor_1D.push(step_k_point * i_k_points)\n", + " }\n", + "\n", + "\n", + " //--------Get the eigenvalues of each band trajectory--------------\n", + " /*\n", + " N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n", + " N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n", + " band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n", + " N_k_points_all = 0\n", + " for i_segments in range(N_k_band_segments):\n", + " band_energies = section_k_band_segment[i_segments]['band_energies']\n", + " N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n", + " N_k_points_per_segment = len(band_energies[0])\n", + " for i_k_points in range(N_k_points_per_segment):\n", + " for i_bands in range(N_bands):\n", + " band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n", + " N_k_points_all = N_k_points_all + 1\n", + " */\n", + " //var N_k_points_per_segment = section_k_band_segment[0]['band_energies'][0].length; //suppose the numebr of k points in all the segments are the same\n", + " var N_bands = section_k_band_segment[0]['band_energies'][0][0].length;\n", + " var band_energies_all = new Array(N_bands);\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " band_energies_all[i_bands] = new Array(N_k_points_all);// new Array(N_bands, N_k_points_all); //store the eigenvalues\n", + "\n", + " var i_k_points_all = 0;\n", + "\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " var band_energies = section_k_band_segment[i_segments]['band_energies'];\n", + " var N_spin_channel = band_energies.length; //Number of the spin channel --FIXME: no spin polarized\n", + " var N_k_points_per_segment = band_energies[0].length;\n", + " for(var i_k_points = 0; i_k_points < N_k_points_per_segment; i_k_points ++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " band_energies_all[i_bands][i_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * Math.pow(10, -19)) - dos_fermi_energy;\n", + " }\n", + " i_k_points_all = i_k_points_all + 1 ;\n", + "\n", + " }\n", + " }\n", + "\n", + "\n", + "\n", + " var N_labels = 0\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " for(var j = 0; j < 2; j++)\n", + " //labels_tmp = section_k_band_segment[i_segments]['band_segm_start_end'][j];\n", + " N_labels = N_labels + 1\n", + " }\n", + " var label_flag = [];//[\"\" for i in range(N_labels)] //stores the flags of the labels (X, W, G, etc)\n", + "\n", + "\n", + " var i_label = 0;\n", + " var label_flag_last_final = \"\";\n", + " var label_flag_current_initial = \"\";\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " var labels_coor_0 = section_k_band_segment[i_segments]['band_segm_start_end'][0].sort();\n", + " var labels_coor_1 = section_k_band_segment[i_segments]['band_segm_start_end'][1].sort();\n", + "\n", + " var label_flag_0 = get_label_flag(labels_coor_0);\n", + " var label_flag_1 = get_label_flag(labels_coor_1);\n", + "\n", + " var label_flag_current_initial = label_flag_0;\n", + " if(label_flag_last_final == \"\")\n", + " label_flag_last_final = label_flag_0;\n", + "\n", + " if(label_flag_last_final == label_flag_current_initial)\n", + " label_flag[i_label] = label_flag_current_initial;\n", + " else\n", + " label_flag[i_label] = label_flag_last_final + '|' + label_flag_current_initial;\n", + " label_flag_last_final = label_flag_1\n", + "\n", + "\n", + " i_label = i_label + 1;\n", + " if(i_segments == N_k_band_segments - 1)\n", + " {\n", + " label_flag[i_label] = label_flag_1;\n", + " i_label = i_label + 1;\n", + " }\n", + " }\n", + " N_labels = i_label;\n", + "\n", + " //------------Get the coordinates for the labels------------\n", + " //label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n", + " var label_coor_relative = [];//np.zeros((N_labels))\n", + " for(i_label = 0; i_label < N_labels; i_label ++)\n", + " {\n", + " //Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n", + " //x = labels_coor_0[0]\n", + " //y = labels_coor_0[1]\n", + " //z = labels_coor_0[2]\n", + " //label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n", + " label_coor_relative.push(step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all));\n", + " }\n", + " //----Store the label-----------\n", + " var label_obj = [];//[['' for i in range(2)] for j in range(N_labels)]\n", + " for(i_label = 0; i_label < N_labels; i_label ++)\n", + " {\n", + " label_obj.push([label_coor_relative[i_label], label_flag[i_label]]);\n", + " }\n", + "\n", + "\n", + " //-------Get VBM, CBM----------------\n", + "\n", + " var HOMO = -1000;\n", + " var LUMO = 1000;\n", + " var coor_k_point_HOMO = []; //the coordinate of k point that stores HOMO\n", + " var coor_k_point_LUMO = [];//np.zeros((3)) #the coordinate of k point that stores LUMO\n", + " //band_gap_direct = 0.0\n", + " var band_gap_indirect = 0.0;\n", + "\n", + "\n", + " //band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " //band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " var band_energy_max = 10;\n", + " var band_energy_min = -10;\n", + " //N_band_energy_index = 10000\n", + " //band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n", + " //N_allowed_states = np.zeros(N_band_energy_index + 1)\n", + " //i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n", + "\n", + "\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " for(var i_k_points_all = 0; i_k_points_all< N_k_points_all; i_k_points_all ++)\n", + " {\n", + " //i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n", + " //N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n", + " var band_energy = band_energies_all[i_bands][i_k_points_all];\n", + " if(band_energy > 0)\n", + " {\n", + " if(band_energy < LUMO)\n", + " LUMO = band_energy;\n", + " }\n", + " else\n", + " {\n", + " if(band_energy > HOMO)\n", + " HOMO = band_energy;\n", + " }\n", + "\n", + " }\n", + " }\n", + "\n", + "\n", + " //#for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n", + " // if(N_allowed_states[i_band_index] > 0):\n", + " // LUMO = band_energy_min + band_energy_step * i_band_index\n", + " //print('HOMO, LUMO: ',HOMO, LUMO)\n", + " band_gap_indirect = Math.abs(LUMO - HOMO);\n", + "\n", + " if(band_gap_indirect < 0.5) //VBM and CBM has to be found in another way for metals/charged system:\n", + " {\n", + " HOMO = -1000.0;\n", + " LUMO = 1000.0;\n", + " band_energy_max = 10.0;\n", + " band_energy_min = 0.0;\n", + " var N_band_energy_index = 10000;\n", + " var band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index;\n", + " var N_allowed_states = [];\n", + " for(var i_state = 0; i_state < N_band_energy_index+1; i_state++)\n", + " N_allowed_states.push(0);\n", + "\n", + "\n", + " //get the DOS and store in N_allowed_states[]\n", + " for(var i_k_points_all = 0; i_k_points_all < N_k_points_all; i_k_points_all ++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " var band_energy = band_energies_all[i_bands][i_k_points_all];\n", + " if((band_energy_min < band_energy)&&(band_energy < band_energy_max))\n", + " {\n", + " var i_band_index = Math.floor((band_energy - band_energy_min) / band_energy_step);\n", + " N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1;\n", + " }\n", + " }\n", + " }\n", + "\n", + "\n", + " var if_gapped = 0;\n", + " for(var i_band_index = 0; i_band_index < N_band_energy_index; i_band_index ++)//go through the energy levels from the bottom\n", + " {\n", + " var band_energy = band_energy_min + band_energy_step * i_band_index\n", + " if(N_allowed_states[i_band_index] == 0)\n", + " if_gapped = if_gapped + 1;\n", + " if((band_energy > band_energy_max - 0.5) && (if_gapped == 0))\n", + " {\n", + " //alert(\"No gap found in this system. It seems to be a metal.\");\n", + " HOMO = 1000;\n", + " LUMO = 1000;\n", + " break;\n", + " }\n", + " //print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n", + "\n", + " if(N_allowed_states[i_band_index] > 0)\n", + " {\n", + " if(if_gapped * band_energy_step > 0.3 )//above VBM-CBM gap: LUMO\n", + " {\n", + " if(band_energy < LUMO)\n", + " {\n", + " //print(\"LUMO got!\")\n", + " LUMO = band_energy;\n", + " break; //break before touching another gap that is above the band gap\n", + " }\n", + " }\n", + "\n", + " if(if_gapped * band_energy_step < 0.3) //below VBM-CBM gap: HOMO\n", + " {\n", + " if(band_energy > HOMO)\n", + " {\n", + " //print(\"HOMO got!\")\n", + " HOMO = band_energy;\n", + " }\n", + " } \n", + " if_gapped = 0;\n", + " }\n", + " }\n", + " //alert('HOMO, LUMO for metal/charged system: '+ HOMO +\",\"+LUMO)\n", + "\n", + " }\n", + "\n", + "\n", + "\n", + "\n", + " //Find the position of HOMO, LUMO\n", + " var coor_k_point_HOMO = 0, coor_k_point_LUMO = 0;\n", + " for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " if(Math.abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001)\n", + " coor_k_point_HOMO = k_coor_1D[i_k_points];\n", + " if(Math.abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001)\n", + " coor_k_point_LUMO = k_coor_1D[i_k_points]; \n", + " }\n", + " }\n", + "\n", + " //alert(coor_k_point_HOMO +\",\" + coor_k_point_LUMO);\n", + "\n", + "\n", + " //Store the band data to band_obj\n", + "\n", + " var band_obj = {};\n", + " band_obj[\"band_x_axis\"] = k_coor_1D;\n", + " band_obj[\"band_y_axis\"] = band_energies_all\n", + " band_obj[\"labels\"] = label_obj;\n", + " band_obj[\"HOMO_energy\"] = HOMO;\n", + " band_obj[\"HOMO_coor\"] = coor_k_point_HOMO;\n", + " band_obj[\"LUMO_energy\"] = LUMO;\n", + " band_obj[\"LUMO_coor\"] = coor_k_point_LUMO;\n", + " band_obj[\"average_N_k_points_per_inverse_distance\"] = average_N_k_points_per_inverse_distance;\n", + "\n", + "\n", + " return band_obj\n", + "\n", + " }\n", + "\n", + "\n", + " function get_dos_obj(dos_path)\n", + " {\n", + "\n", + " var dos_data = JSON.parse(getJSON(dos_path));\n", + "\n", + " var N_dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'].length;\n", + "\n", + " //in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n", + "\n", + " //dos_energies = new Array(N_dos_values).fill(0.0);\n", + " //dos_energies_tmp = new Array(N_dos_values).fill(0.0) #tmp array for unit convertion\n", + " //dos_values = new Array(N_dos_values).fill(0.0)\n", + "\n", + " var dos_energies = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'];\n", + " var dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_integrated_values'];//[0]\n", + "\n", + " //To do: check if every section_dos has 'dos_fermi_energy'\n", + " var dos_fermi_energy = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_fermi_energy'];\n", + " dos_fermi_energy = dos_fermi_energy / (1.60217656535 * Math.pow(10,-19));\n", + " \n", + " for(var i = 0; i < N_dos_values; i++)\n", + " {\n", + " dos_energies[i] = dos_energies[i] / (1.60217656535 * Math.pow(10,-19)) - dos_fermi_energy;\n", + " }\n", + " \n", + " dos_obj = {}\n", + " dos_obj[\"dos_x_axis\"] = dos_energies;\n", + " dos_obj[\"dos_y_axis\"] = dos_values;\n", + " dos_obj[\"dos_fermi_energy\"] = dos_fermi_energy;\n", + " return dos_obj\n", + " }\n", + " function get_info_obj(band_path)\n", + " {\n", + "\n", + " var band_data = JSON.parse(getJSON(band_path));\n", + " var info_obj = {};\n", + " //---------Read the information of the calculation--------\n", + " info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n", + " info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n", + " info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n", + "\n", + " //----------Get the space group information----------\n", + " /*\n", + " [space_group_symbol, lattice_constant] = get_space_group(band_data);\n", + " info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist();\n", + " info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist();\n", + " */\n", + "\n", + " return info_obj\n", + " }\n", + " function process_band_dos_data()\n", + " {\n", + " info_all = [];\n", + " band_obj_all = [];\n", + " dos_obj_all = [];\n", + "\n", + " for(var i = 0; i < N_materials; i++)\n", + " {\n", + " var band_path = band_paths[i];\n", + " var dos_path = dos_paths[i];\n", + "\n", + "\n", + " var dos_obj = get_dos_obj(dos_path);\n", + " var dos_fermi_energy = dos_obj[\"dos_fermi_energy\"];\n", + " band_obj = get_band_obj(band_path, dos_fermi_energy);\n", + " var info_obj = get_info_obj(band_path);\n", + "\n", + " band_obj_all.push(band_obj);\n", + " dos_obj_all.push(dos_obj);\n", + " info_obj_all.push(info_obj);\n", + " }\n", + " }\n", + " process_band_dos_data();\n", + " //alert(\"process_band_dos_data: info_obj_all: \"+JSON.stringify(info_obj_all));\n", + "</script>" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "scrolled": false, + "tags": [ + "show_results_and_plot" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script>\n", + " var N_max_show = 10; //Number of results to be shown by default\n", + "\n", + " function show_materials_submitted_info()\n", + " {\n", + " //alert(\"N_materials=\" + N_materials)\n", + " //\"table_materials_submitted_info\"\n", + " //alert(\"show_materials_submitted_info: info_obj_all: \"+JSON.stringify(info_obj_all))\n", + " var table_content = new Array(); \n", + " str = '<tr>';\n", + " str += '<th width=\"5%\"></th>'\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Atom labels</b></font></p></th>';\n", + " //str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Space group</b></font></p></th>';\n", + " //str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Lattice constants (in Ang)</b></font></p></th>';\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Program name</b></font></p></th>';\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Basis set type</b></font></p></th>';\n", + " str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Functional</b></font></p></th>';\n", + " //str += '<th width=\"20%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Number of <i>k</i> points per inverse distance</b></font></p></th>';\n", + " str += '</tr>'; //first row: head\n", + " table_content.push(str);\n", + "\n", + " for(var i = 0; i < N_materials; i++) //add info of each material\n", + " {\n", + " //alert(\"show_materials_submitted_info: material \"+ i); \n", + " table_content.push('<tr>');\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<input type = \\\"checkbox\\\" name = \"checkbox_material\" id = \\\"checkbox_material' + i.toString() + '\\\" unchecked onclick=\\\"checkbox_material(this.id)\\\">';\n", + " str += \"<b>  #\" + (i+1).toString() + \"</b>\";\n", + " table_content.push(str);\n", + " table_content.push('</td>');\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"atom_labels\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got atom_labels\");\n", + "\n", + " /*\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"space_group_symbol\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got space_group_symbol\");\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"lattice_constant\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got lattice_constant\");\n", + " */\n", + " \n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"program_name\"].toUpperCase() + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got program_name\");\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"program_basis_set_type\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got program_basis_set_type\");\n", + "\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"XC_functional_name\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got XC_functional_name\");\n", + "\n", + " /*\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got average_N_k_points_per_inverse_distance\");\n", + " */\n", + " table_content.push('</tr>');\n", + "\n", + " }\n", + " \n", + " document.getElementById(\"table_materials_submitted_info\").innerHTML = table_content.join('');\n", + " }\n", + "\n", + " function clean_materials_selection()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_material\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"\";\n", + " }\n", + " }\n", + "\n", + " function select_all()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_material\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"checked\";\n", + " }\n", + " }\n", + "\n", + "\n", + "\n", + " function process()\n", + " {\n", + " //alert(\"Process:\"+band_paths)\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_js_plot'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_materials_submitted_info'));\n", + " show_materials_submitted_info();\n", + " document.getElementById(\"table_visualize\").innerHTML = \"\";\n", + " str = N_materials.toString();\n", + " document.getElementById(\"n_materials\").innerHTML = \"Number of materials submitted: \" + str + \"<font size = 1px color = #C0C0C0 >   Please press \\'Visualize\\' to visualize the band structure. </font>\";\n", + " document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n", + " }\n", + " \n", + "\n", + " var image_band = '';\n", + " var image_dos = '';\n", + " var image_band_links = new Array(N_materials); //store the URL of each band figure -> used to compare 2 figures\n", + " var image_band_links_selected = [];\n", + " var image_band_selected_Number = []; //record which i_material has been selected\n", + "\n", + "\n", + "\n", + " function prepare(N_materials_show)\n", + " {\n", + " document.getElementById(\"table_visualize\").innerHTML = \"\";\n", + " var table_content = new Array(); \n", + " //document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n", + " //-----Generate the html tables for each material--------\n", + " for(var i = 0; i < N_materials_show; i++)\n", + " {\n", + " checkbox_material_id = \"checkbox_material\" + i.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + "\n", + " table_content.push('<tr>');\n", + " div_string = '<div style = \\\"height: 20px\\\"></div>';\n", + " table_content.push(div_string);\n", + " table_content.push('<th>');\n", + "\n", + " //add main container div\n", + " div_string = '<div id = \\\"div_band_dos' + i.toString() + '\\\" class = \\\"div_band_dos\\\" >';\n", + " table_content.push(div_string);\n", + "\n", + " //show No. of the material\n", + " i_material = i + 1;\n", + " div_string = '<div style = \\\"height:30px\\; font-size: 15pt;\">' + '#' + i_material.toString() + '</div>';\n", + " table_content.push(div_string);\n", + "\n", + " //show band_path/dos info\n", + " div_string = '<div style = \\\"height:30px\\\">' + 'Band:   ' + band_paths[i] + ',    DOS:   ' + dos_paths[i] + '</div>';\n", + " table_content.push(div_string);\n", + "\n", + " //add div_band\n", + " div_string = '<div id = \\\"div_band' + i.toString() + '\\\" class = \\\"div_band\\\" ></div>';\n", + " table_content.push(div_string);\n", + "\n", + " //add div_dos\n", + " div_string = '<div id = \\\"div_dos' + i.toString() + '\\\" class = \\\"div_dos\\\" ></div>'; \n", + " table_content.push(div_string);\n", + "\n", + " //add div_tools\n", + " div_string = '<div id = \\\"div_tools' + i.toString() + '\\\" class = \\\"div_tools\\\" >'; \n", + " table_content.push(div_string);\n", + "\n", + " //add: infomation\n", + " div_string = '<div id = \\\"div_info' + i.toString() + '\\\">atom_labels<br>program_name</div>'; \n", + " table_content.push(div_string);\n", + "\n", + " //add: custom scale\n", + " div_string = '<br><p style=\\\"color: #000;font-weight: 100; font-size: 10pt; align:left\\\"> Set the lower and upper limit of energy scale (in eV): <br><br><font color=\\\"black\\\" size = 3px> Lower limit:    </font><textarea id=\\\"lowerlimit' + i.toString() + '\\\" rows=\\\"1\\\" style = \\\"width: 70px;\\\">-10</textarea> <font color=\\\"black\\\" size = 3px>   eV</font>    <font color=\\\"black\\\" size = 3px> Upper limit:    </font><textarea id=\\\"upperlimit' + i.toString() + '\\\" rows=\\\"1\\\" style = \\\"width: 70px;\\\">10</textarea> <font color=\\\"black\\\" size = 3px>   eV   </font></p>';\n", + " table_content.push(div_string);\n", + " div_string = '<br><button class = \\\"button_tools\\\" id = \\\"button_customscale' + i.toString() + '\\\" onclick = \\\"customscale(this.id)\\\"> Rescale </button>'; \n", + " table_content.push(div_string);\n", + "\n", + "\n", + " //add button:autoscale\n", + " div_string = '<button class = \\\"button_tools\\\" id = \\\"button_autoscale' + i.toString() + '\\\" onclick = \\\"autoscale(this.id)\\\" title = \\\"(-10 eV, 10 eV)\\\"> Autoscale </button>'; \n", + " table_content.push(div_string);\n", + " //add button:fullscale\n", + " div_string = '<button class = \\\"button_tools\\\" id = \\\"button_fullscale' + i.toString() + '\\\" onclick = \\\"fullscale(this.id)\\\" title = \\\"(-100 eV, 100 eV)\\\"> Full scale </button><br><br>'; \n", + " table_content.push(div_string);\n", + "\n", + " //table_content.push(\"Select and zoom:\");\n", + "\n", + " /*//overview for select and zoom\n", + " div_string = '<div id = \\\"div_overview' + i.toString() + '\\\" class = \\\"div_overview\\\" ></div>'; // <div id=\"overview\" style=\"width:300px;height:200px; margin-left:10px; margin-top: 50px; padding-top: 0px\"></div>\n", + " table_content.push(div_string);\n", + " div_string = '<p id = \\\"overviewLegend' + i.toString() + '\\\" ></p>'; // <p id=\"overviewLegend\" style=\"margin-left:10px\"></p>\n", + " table_content.push(div_string);*/\n", + "\n", + " //download figures as png\n", + " div_string = '<a id = \\\"img_band' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download band </a>';\n", + " table_content.push(div_string); \n", + " div_string = '<a id = \\\"img_dos' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download DOS </a>';\n", + " table_content.push(div_string);\n", + "\n", + " //add show VBM & CBM\n", + " div_string = '<br><br><p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_VBM' + i.toString() + '\\\" unchecked onclick=\\\"show_VBM(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Show VBM </font> (<font color=\\\"blue\\\">\\•</font>) <font color=\\\"black\\\" size = 3px> and CBM </font>(<font color=\\\"red\\\">\\•</font>) </p>';\n", + " table_content.push(div_string);\n", + "\n", + "\n", + " table_content.push('</div>');//div_tools\n", + "\n", + " //checkbox for comparison\n", + " div_string = '<div id = \\\"div_checkbox_compare' + i.toString() + '\\\" class = \\\"div_checkbox_compare\\\" >';\n", + " table_content.push(div_string);\n", + " //div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n", + " div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" checked = \\\"unchecked\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n", + " table_content.push(div_string);\n", + " table_content.push('</div>');//div_checkbox_compare\n", + "\n", + "\n", + " table_content.push('</div>');//div_band_dos\n", + " table_content.push('</th>');\n", + " table_content.push('</tr>'); \n", + " }\n", + "\n", + " document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n", + " }\n", + "\n", + "\n", + " function visualize_band_dos()\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_jquery'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_axislabels'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_dashes'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_navigate'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_selection'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_flot_legendoncanvas'));\n", + " document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n", + " document.getElementById(\"div_compare_buttons\").style.visibility=\"\";\n", + "\n", + "\n", + "\n", + " if(N_materials > N_max_show)\n", + " {\n", + " document.getElementById(\"div_showall\").style.visibility=\"visible\";\n", + " document.getElementById(\"checkbox_showall\").checked = \"\";\n", + " } \n", + "\n", + " N_materials_show = Math.min(N_max_show, N_materials);\n", + "\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + "\n", + " }\n", + "\n", + " function show_all(id)//\"plot_placeholder\"\n", + " {\n", + " var if_showall=0;\n", + " if_showall = check_show_VBM(id);\n", + " if(if_showall == 1)\n", + " {\n", + " N_materials_show = N_materials;\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + " }\n", + " else\n", + " {\n", + " N_materials_show = Math.min(N_max_show, N_materials);\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + " }\n", + "\n", + " }\n", + "\n", + " \n", + " //------------------Tool used to get the content from textarea---------------------\n", + " function get_text(textarea_id)\n", + " {\n", + " var text = document.getElementById(textarea_id).value;\n", + " return text;\n", + " }\n", + "\n", + "\n", + "\n", + " //-------------------Compare 2 band figures----------------------------------------\n", + "\n", + "\n", + " function check_compare(id)//checkbox_compare' + i.toString() + '\\\" unchecked onclick=\\\"check_compare(this.id)\n", + " {\n", + " var x = document.getElementById(id);\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " var N_chosen = 0;\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " if(choices_compare[i].checked)\n", + " {\n", + " N_chosen ++;\n", + " }\n", + " }\n", + " if(N_chosen == 2) // In max. only 2 figures could be selected and compared.\n", + " {\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " if(!choices_compare[i].checked)\n", + " {\n", + " choices_compare[i].disabled = 'disabled';\n", + " }\n", + " }\n", + " }\n", + " else\n", + " {\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " choices_compare[i].removeAttribute('disabled');\n", + " }\n", + " }\n", + "\n", + " }\n", + "\n", + " function compare()\n", + " {\n", + " $(\"#div_compare\").fadeIn(600);//show div for comparison\n", + " //check_compare(-100);\n", + "\n", + " var compare_list = [];\n", + " compare_list = make_compare_list();\n", + " //[i_material_1, i_material_2] = make_compare_list();\n", + " i_material_1 = compare_list[0];\n", + " i_material_2 = compare_list[1];\n", + " //document.getElementById(\"demo\").innerHTML = \"In add info compare:\" + i_material_1.toString() + i_material_2.toString();\n", + " compare_figures(i_material_1, i_material_2); \n", + " }\n", + " function make_compare_list()\n", + " {\n", + " //get the links to the images\n", + " images_selected_links = []; //store the links to the figures for comparison\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " var N_chosen = 0;\n", + " var str = ''; //tmp str for debug\n", + " var figure_selected = new Array(2);\n", + " for(var i=0; i<choices_compare.length; i++) //check which figures are selected\n", + " {\n", + " if(choices_compare[i].checked)\n", + " {\n", + " id_chosen = choices_compare[i].id;\n", + " i_chosen = Math.round(id_chosen.substring(16));\n", + " var tmp_str = image_band_links[i_chosen];\n", + " images_selected_links.push(tmp_str);\n", + " figure_selected[N_chosen] = i_chosen;\n", + " N_chosen ++;\n", + " //str += beakerx.image_band_links[i];\n", + " }\n", + " }\n", + " var i_material_1 = 0;\n", + " var i_material_2 = 0;\n", + " //document.getElementById(\"demo\").innerHTML = 'In making comare list';\n", + " image_band_links_selected = images_selected_links;\n", + " //document.getElementById(\"demo\").innerHTML = 'In making comare list: next';\n", + " if(N_chosen == 2)\n", + " {\n", + " i_material_1 = figure_selected[0];\n", + " i_material_2 = figure_selected[1];\n", + " }\n", + " //document.getElementById(\"demo\").innerHTML = 'Compare_list: ' +i_material_1.toString() + ' ' + i_material_2.toString();\n", + "\n", + " return [i_material_1, i_material_2];\n", + " }\n", + "\n", + " function check_compare_scale(i_material_1, i_material_2)\n", + " {\n", + " lowerlimit_id_1 = \"lowerlimit\" + i_material_1.toString();\n", + " lowerlimit_id_2 = \"lowerlimit\" + i_material_2.toString();\n", + " upperlimit_id_1 = \"upperlimit\" + i_material_1.toString();\n", + " upperlimit_id_2 = \"upperlimit\" + i_material_2.toString();\n", + "\n", + " lowerlimit_1 = parseFloat(document.getElementById(lowerlimit_id_1).innerHTML);\n", + " lowerlimit_2 = parseFloat(document.getElementById(lowerlimit_id_2).innerHTML);\n", + " upperlimit_1 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n", + " upperlimit_2 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n", + " if((lowerlimit_1 != lowerlimit_2) || (upperlimit_1 != upperlimit_2))\n", + " return -1;\n", + " else\n", + " return 1;\n", + " }\n", + "\n", + " function compare_figures(i_material_1, i_material_2)\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_query_beforeafter'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_compare_slide'));\n", + " add_info_compare(i_material_1, i_material_2);\n", + " document.getElementById(\"div_compare_container\").scrollIntoView({ behavior: 'smooth' }); \n", + " document.getElementById(\"div_compare_container\").scrollTop += 50;\n", + "\n", + " }\n", + "\n", + "\n", + " function clean_compare_list()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"\";\n", + " choices_compare[i].removeAttribute('disabled');\n", + " }\n", + " }\n", + "\n", + " //-----------Add information about the calculation to \"div_tools\"---------------\n", + " function add_info(i)\n", + " {\n", + " \n", + " //document.getElementById(\"demoa\").innerHTML = i.toString() + div_info_id;\n", + " //for(var i = 0; i < beakerx.N_materials; i++)\n", + " //{\n", + " div_info_id = \"div_info\" + i.toString();\n", + "\n", + " var str = '';\n", + " str += \"<br> <p style=\\\"text-align:left\\\"><font size = 3pt><b>Atom labels:</b>     \" + info_obj_all[i][\"atom_labels\"] + '</font></p>';\n", + " //str += \"<font size = 3pt><b>Space group:</b>     \" + info_obj_all[i][\"space_group_symbol\"] + '</font>';\n", + " //str += \"<font size = 3pt><b>Lattice constants (in Ang):</b>     \" + info_obj_all[i][\"lattice_constant\"] + '</font>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Program name:</b>    \" + info_obj_all[i][\"program_name\"].toUpperCase() + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Basis set type:</b>    \" + info_obj_all[i][\"program_basis_set_type\"] + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Functional:</b>    \" + info_obj_all[i][\"XC_functional_name\"] + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3) + '</font></p>';\n", + " document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n", + " //document.getElementById('program_name_1').innerHTML = \"<b>Code:</b>    \" + origData[\"program_name\"];\n", + " //document.getElementById('program_basis_set_type_1').innerHTML = \"<b>Basis set type:</b>    \" + origData[\"program_basis_set_type\"];\n", + " //document.getElementById('XC_functional_name_1').innerHTML = \"<b>Functional:</b>    \" + origData[\"XC_functional_name\"]; \n", + " //}\n", + " \n", + " }\n", + " function add_info_compare(i,j)\n", + " {\n", + "\n", + " div_info_id = \"div_compare_info\";\n", + " var str = '';\n", + "\n", + " if_same_scale = check_compare_scale(i_material_1, i_material_2);\n", + " if(if_same_scale == -1)\n", + " {\n", + " str = '<b><font size = \"15pt\" color=\"#940000\">Error: Different lower/upper limits.</font></b><br>';\n", + " document.getElementById(\"div_compare_container\").innerHTML = str;\n", + " document.getElementById(div_info_id).innerHTML = '';\n", + " return;\n", + " }\n", + "\n", + " str += \"<br><b><font-size:15pt>Information of the first calculation (left):</font></b> <br>\";\n", + " str += \"<br> <b>Atom labels:</b>     \" + info_obj_all[i][\"atom_labels\"];\n", + " //str += \"<br> <b>Space group:</b>     \" + info_obj_all[i][\"space_group_symbol\"];\n", + " //str += \"<br> <b>Lattice constants (in Ang):</b>     \" + info_obj_all[i][\"lattice_constant\"];\n", + " str += \"<br> <b>Program name:</b>    \" + info_obj_all[i][\"program_name\"].toUpperCase();\n", + " str += \"<br> <b>Basis set type:</b>    \" + info_obj_all[i][\"program_basis_set_type\"];\n", + " str += \"<br> <b>Functional:</b>    \" + info_obj_all[i][\"XC_functional_name\"];\n", + " str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " str += \"<br><br><br><b><font-size:15pt>Information of the second calculation (right):</font></b><br>\";\n", + " str += \"<br> <b>Atom labels:</b>     \" + info_obj_all[j][\"atom_labels\"];\n", + " //str += \"<br> <b>Space group:</b>     \" + info_obj_all[j][\"space_group_symbol\"];\n", + " //str += \"<br> <b>Lattice constants (in Ang):</b>     \" + info_obj_all[j][\"lattice_constant\"];\n", + " str += \"<br> <b>Program name:</b>    \" + info_obj_all[j][\"program_name\"].toUpperCase();\n", + " str += \"<br> <b>Basis set type:</b>    \" + info_obj_all[j][\"program_basis_set_type\"]; \n", + " str += \"<br> <b>Functional:</b>    \" + info_obj_all[j][\"XC_functional_name\"];\n", + " str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n", + " }\n", + "\n", + "\n", + "\n", + " //-----------------------Show/hide VBM, CBM-------------------------\n", + " function check_show_VBM(checkbox_VBM_id)\n", + " {\n", + " var x = document.getElementById(checkbox_VBM_id);\n", + " var if_checked = 0;\n", + " if(x.checked)//== \"checked\")\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"checked!\";\n", + " if_checked = 1;\n", + " }\n", + " else if (x.unchecked)// == \"unchecked\")\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"unchecked!\";\n", + " if_checked = -1;\n", + " }\n", + " else\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"nothing detected!\";\n", + " }\n", + " return if_checked;\n", + " }\n", + "\n", + " function check_if_in_compare_list(i) // check if the current material i is to be compared\n", + " {\n", + "\n", + " var checkbox_compare_id = \"checkbox_compare\" + i.toString();\n", + " var if_compare = check_show_VBM(checkbox_compare_id);\n", + " //document.getElementById(\"demo\").innerHTML = 'if_compare of ' + i.toString() + ' : ' + if_compare.toString();\n", + " var i_compare_material_1, i_compare_material_2;\n", + " [i_compare_material_1, i_compare_material_2] = make_compare_list();\n", + " var i_in_compare_list = -1;\n", + " if(i_compare_material_1 == i)\n", + " {\n", + " i_in_compare_list = 1;\n", + " }\n", + " else if (i_compare_material_2 == i)\n", + " {\n", + " i_in_compare_list = 2;\n", + " }\n", + " else\n", + " {\n", + " i_in_compare_list = 0;\n", + " }\n", + " //document.getElementById(\"demo\").innerHTML = 'Checking ' + i.toString() + ' in Compare_list: ' + i_in_compare_list.toString();\n", + " return [if_compare, i_in_compare_list];\n", + " }\n", + "\n", + " function show_VBM(id)\n", + " {\n", + " //prepare(\"new\");\n", + " //var if_show_VBM = -1;\n", + " var len_id = id.length;\n", + " var i_material = id.substring(12);\n", + " var i = Math.round(i_material);\n", + "\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + " //document.getElementById(\"demo\").innerHTML = i.toString() + ' in Compare_list: ' + i_in_compare_list.toString();\n", + "\n", + " plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + "\n", + " //---------------------Functions to rescale-------------------------------------------\n", + " function autoscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(16);\n", + " var i = Math.round(i_material);\n", + "\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " document.getElementById(upperlim_id).innerHTML =\"10.0\";\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " document.getElementById(lowerlim_id).innerHTML =\"-10.0\";\n", + "\n", + "\n", + " //document.getElementById(\"demoa\").innerHTML =i_material;\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + " plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + " function fullscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(16);\n", + " var i = Math.round(i_material);\n", + "\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " document.getElementById(upperlim_id).innerHTML =\"100.0\";\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " document.getElementById(lowerlim_id).innerHTML =\"-100.0\";\n", + "\n", + " //document.getElementById(\"demoa\").innerHTML =i_material;\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + "\n", + " plot_band_dos_i(i, -100, 100, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + " function customscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(18);\n", + " var i = Math.round(i_material);\n", + " //\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " upperlim = document.getElementById(upperlim_id).value;\n", + " upperlim_float = Math.round(upperlim);\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " lowerlim = document.getElementById(lowerlim_id).value;\n", + " lowerlim_float = Math.round(lowerlim);\n", + "\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + "\n", + " plot_band_dos_i(i, lowerlim_float, upperlim_float, if_show_VBM, if_compare, i_in_compare_list); \n", + " }\n", + "\n", + "\n", + " function plot_band_dos(lowerLim, upperLim, N_materials_show)\n", + " {\n", + " placeholder_band = \"#div_band1\";\n", + " placeholder_dos = \"#div_dos1\";\n", + " // lowerLim = -10.01\n", + " //upperLim = 10.01\n", + "\n", + "\n", + "\n", + " //alert(\"plot_band_dos\");\n", + " //prepare();\n", + " for(var i = 0; i < N_materials_show; i++)\n", + " {\n", + " \n", + " var checkbox_material_id = \"checkbox_material\" + i.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + " add_info(i);\n", + " }\n", + "\n", + " //------Plot----------------\n", + " /*\n", + " for(var i_material = 0; i_material < N_materials_show; i_material++)\n", + " {\n", + "\n", + " //alert(\"Material \"+i);\n", + " var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + "\n", + " plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n", + " }\n", + " */\n", + " //alert(\"next:for\")\n", + " for (let i_material = 0, p = Promise.resolve(); i_material < N_materials_show; i_material++) {\n", + " p = p.then(_ => new Promise(resolve =>\n", + " setTimeout(function () {\n", + " //alert(i_material)\n", + " var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected == 1)\n", + " {\n", + " plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n", + " }\n", + " resolve();\n", + " }, 0)\n", + " ));\n", + " }\n", + "\n", + "\n", + " return 1;\n", + " }\n", + "\n", + " var i = 0\n", + " var lowerLim = -10\n", + " var upperLim = 10\n", + " var if_show_VBM = 0\n", + " var if_compare = 0\n", + " var i_in_compare_list = -1\n", + "\n", + "\n", + " \n", + " function plot_band_dos_i(i_material, lowerLim_material, upperLim_material, if_show_VBM_material, if_compare_material, i_in_compare_list_material)\n", + " {\n", + " //alert(\"plot_band_dos_i\")\n", + "\n", + " i = i_material;\n", + " lowerLim = lowerLim_material;\n", + " upperLim = upperLim_material;\n", + " if_show_VBM = if_show_VBM_material;\n", + " if_compare = if_compare_material;\n", + " i_in_compare_list = i_in_compare_list_material;\n", + " //alert(\"plot_band_dos_i: i_material: \"+i)\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_band'));\n", + " //alert('i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list')\n", + " //plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_dos'));\n", + " } \n", + "</script>\n", + "\n", + " \n", + " \n", + "<br><br>\n", + "<button class=\"button\" onclick=\"process()\">Process data</button>\n", + "<br><br>\n", + "<div id = \"n_materials\" style = \"font-size: 18px; font-weight: 100; height: 60px; width: 100%;\"> Number of materials submitted: 0</div>\n", + "<div id = \"show_materials_submitted\" style = \"font-size: 20px; font-color: black;\"> </div>\n", + "\n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "<p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select materials to visualize the band structure and DOS:</p>\n", + "<div style = \"width :100%; height: 10px;\"></div> \n", + "<button class = \"button\" onclick = \"clean_materials_selection()\"> Clean selections </button> \n", + "<button class = \"button\" onclick = \"select_all()\"> Select all </button> \n", + "<button class = \"button\" onclick = \"visualize_band_dos()\"> Visualize </button> \n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "\n", + "<div id = \"show_materials_submitted_info\" style = \"width: 100%; font-size: 20px; font-color: black;\"> \n", + " <table id = \"table_materials_submitted_info\" style=\"width:100%\"> </table>\n", + "</div>\n", + "\n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "\n", + "\n", + "\n", + "\n", + "<div id=\"div_compare_buttons\" style=\"visibility:hidden\">\n", + " <br><br><br>\n", + " <p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select two materials in the checkbox on the right for comparison:</p>\n", + " <p style=\"color: #000;font-weight: 1000; font-size: 8pt;\"></p>\n", + " <button class = \"button\" onclick = \"clean_compare_list()\"> Clean selections </button> \n", + " <button class = \"button\" onclick = \"compare();compare()\" title = \"Select 2 materials in the checkbox below and compare: please make sure that the upper/lower limits are the same (using Rescale/Autoscale buttons).\" > Compare</button>\n", + "</div>\n", + "\n", + "\n", + "\n", + "<div id = \"div_showall\" style = \"width: 100%; visibility:hidden\">\n", + " <div style = \"width: 100%; height: 30px; \"></div>\n", + " <input type = \"checkbox\" id = \"checkbox_showall\" unchecked onclick=\"show_all(this.id)\"/> <font color=\"black\" size = 3px> Show all results </font><font size = 2px color = \"#666\"> (By default only the first 10 results are shown.) </font> \n", + " <div style = \"width: 100%; height: 30px; \"></div>\n", + "</div>\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "<div id = \"div_compare\" style = \"position: fixed; top: 20%; left: 10%; width: 1200px; height: 600px; z-index: 999999; border: 1px solid #555; background-color: #fff; display: none\" onclick = \"$(this).fadeOut(500)\"> \n", + " \n", + " <div style = \"float: right; width: 80px; height: 25px; margin-top: 10px; margin-right: 10px; z-index: 1000000; border: 1px solid #555; text-align: center; vertical-align: middle; background-color: #f9f9f9; font-size:12pt; font-color: #000; cursor:pointer;\" > CLOSE </div> <!--button to close the div-->\n", + " <div id = \"div_compare_info\" style = \" width: 350px; height: 500px; float: right; margin-top: 50px; margin-right: 10px; z-index: 10000000;\"></div>\n", + " <div id = \"div_compare_container\" style = \"margin-top: 50px; margin-left: 100px; width: 600px; height: 300px;\">\n", + " <div class=\"g-before-after\" id = \"div_compare_containerx\"></div>\n", + " </div>\n", + "</div>\n", + "\n", + "\n", + "<div id = \"demo\"></div>\n", + "\n", + "<div id = \"plot_placeholder\">\n", + " <div><br></div>\n", + " <table id = \"table_visualize\"> </table>\n", + "</div>\n", + "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script>\n", + " var N_max_show = 10; //Number of results to be shown by default\n", + "\n", + " function show_materials_submitted_info()\n", + " {\n", + " //alert(\"N_materials=\" + N_materials)\n", + " //\"table_materials_submitted_info\"\n", + " //alert(\"show_materials_submitted_info: info_obj_all: \"+JSON.stringify(info_obj_all))\n", + " var table_content = new Array(); \n", + " str = '<tr>';\n", + " str += '<th width=\"5%\"></th>'\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Atom labels</b></font></p></th>';\n", + " //str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Space group</b></font></p></th>';\n", + " //str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Lattice constants (in Ang)</b></font></p></th>';\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Program name</b></font></p></th>';\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Basis set type</b></font></p></th>';\n", + " str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Functional</b></font></p></th>';\n", + " //str += '<th width=\"20%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Number of <i>k</i> points per inverse distance</b></font></p></th>';\n", + " str += '</tr>'; //first row: head\n", + " table_content.push(str);\n", + "\n", + " for(var i = 0; i < N_materials; i++) //add info of each material\n", + " {\n", + " //alert(\"show_materials_submitted_info: material \"+ i); \n", + " table_content.push('<tr>');\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<input type = \\\"checkbox\\\" name = \"checkbox_material\" id = \\\"checkbox_material' + i.toString() + '\\\" unchecked onclick=\\\"checkbox_material(this.id)\\\">';\n", + " str += \"<b>  #\" + (i+1).toString() + \"</b>\";\n", + " table_content.push(str);\n", + " table_content.push('</td>');\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"atom_labels\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got atom_labels\");\n", + "\n", + " /*\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"space_group_symbol\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got space_group_symbol\");\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"lattice_constant\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got lattice_constant\");\n", + " */\n", + " \n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"program_name\"].toUpperCase() + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got program_name\");\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"program_basis_set_type\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got program_basis_set_type\");\n", + "\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"XC_functional_name\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got XC_functional_name\");\n", + "\n", + " /*\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got average_N_k_points_per_inverse_distance\");\n", + " */\n", + " table_content.push('</tr>');\n", + "\n", + " }\n", + " \n", + " document.getElementById(\"table_materials_submitted_info\").innerHTML = table_content.join('');\n", + " }\n", + "\n", + " function clean_materials_selection()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_material\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"\";\n", + " }\n", + " }\n", + "\n", + " function select_all()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_material\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"checked\";\n", + " }\n", + " }\n", + "\n", + "\n", + "\n", + " function process()\n", + " {\n", + " //alert(\"Process:\"+band_paths)\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_js_plot'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_materials_submitted_info'));\n", + " show_materials_submitted_info();\n", + " document.getElementById(\"table_visualize\").innerHTML = \"\";\n", + " str = N_materials.toString();\n", + " document.getElementById(\"n_materials\").innerHTML = \"Number of materials submitted: \" + str + \"<font size = 1px color = #C0C0C0 >   Please press \\'Visualize\\' to visualize the band structure. </font>\";\n", + " document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n", + " }\n", + " \n", + "\n", + " var image_band = '';\n", + " var image_dos = '';\n", + " var image_band_links = new Array(N_materials); //store the URL of each band figure -> used to compare 2 figures\n", + " var image_band_links_selected = [];\n", + " var image_band_selected_Number = []; //record which i_material has been selected\n", + "\n", + "\n", + "\n", + " function prepare(N_materials_show)\n", + " {\n", + " document.getElementById(\"table_visualize\").innerHTML = \"\";\n", + " var table_content = new Array(); \n", + " //document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n", + " //-----Generate the html tables for each material--------\n", + " for(var i = 0; i < N_materials_show; i++)\n", + " {\n", + " checkbox_material_id = \"checkbox_material\" + i.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + "\n", + " table_content.push('<tr>');\n", + " div_string = '<div style = \\\"height: 20px\\\"></div>';\n", + " table_content.push(div_string);\n", + " table_content.push('<th>');\n", + "\n", + " //add main container div\n", + " div_string = '<div id = \\\"div_band_dos' + i.toString() + '\\\" class = \\\"div_band_dos\\\" >';\n", + " table_content.push(div_string);\n", + "\n", + " //show No. of the material\n", + " i_material = i + 1;\n", + " div_string = '<div style = \\\"height:30px\\; font-size: 15pt;\">' + '#' + i_material.toString() + '</div>';\n", + " table_content.push(div_string);\n", + "\n", + " //show band_path/dos info\n", + " div_string = '<div style = \\\"height:30px\\\">' + 'Band:   ' + band_paths[i] + ',    DOS:   ' + dos_paths[i] + '</div>';\n", + " table_content.push(div_string);\n", + "\n", + " //add div_band\n", + " div_string = '<div id = \\\"div_band' + i.toString() + '\\\" class = \\\"div_band\\\" ></div>';\n", + " table_content.push(div_string);\n", + "\n", + " //add div_dos\n", + " div_string = '<div id = \\\"div_dos' + i.toString() + '\\\" class = \\\"div_dos\\\" ></div>'; \n", + " table_content.push(div_string);\n", + "\n", + " //add div_tools\n", + " div_string = '<div id = \\\"div_tools' + i.toString() + '\\\" class = \\\"div_tools\\\" >'; \n", + " table_content.push(div_string);\n", + "\n", + " //add: infomation\n", + " div_string = '<div id = \\\"div_info' + i.toString() + '\\\">atom_labels<br>program_name</div>'; \n", + " table_content.push(div_string);\n", + "\n", + " //add: custom scale\n", + " div_string = '<br><p style=\\\"color: #000;font-weight: 100; font-size: 10pt; align:left\\\"> Set the lower and upper limit of energy scale (in eV): <br><br><font color=\\\"black\\\" size = 3px> Lower limit:    </font><textarea id=\\\"lowerlimit' + i.toString() + '\\\" rows=\\\"1\\\" style = \\\"width: 70px;\\\">-10</textarea> <font color=\\\"black\\\" size = 3px>   eV</font>    <font color=\\\"black\\\" size = 3px> Upper limit:    </font><textarea id=\\\"upperlimit' + i.toString() + '\\\" rows=\\\"1\\\" style = \\\"width: 70px;\\\">10</textarea> <font color=\\\"black\\\" size = 3px>   eV   </font></p>';\n", + " table_content.push(div_string);\n", + " div_string = '<br><button class = \\\"button_tools\\\" id = \\\"button_customscale' + i.toString() + '\\\" onclick = \\\"customscale(this.id)\\\"> Rescale </button>'; \n", + " table_content.push(div_string);\n", + "\n", + "\n", + " //add button:autoscale\n", + " div_string = '<button class = \\\"button_tools\\\" id = \\\"button_autoscale' + i.toString() + '\\\" onclick = \\\"autoscale(this.id)\\\" title = \\\"(-10 eV, 10 eV)\\\"> Autoscale </button>'; \n", + " table_content.push(div_string);\n", + " //add button:fullscale\n", + " div_string = '<button class = \\\"button_tools\\\" id = \\\"button_fullscale' + i.toString() + '\\\" onclick = \\\"fullscale(this.id)\\\" title = \\\"(-100 eV, 100 eV)\\\"> Full scale </button><br><br>'; \n", + " table_content.push(div_string);\n", + "\n", + " //table_content.push(\"Select and zoom:\");\n", + "\n", + " /*//overview for select and zoom\n", + " div_string = '<div id = \\\"div_overview' + i.toString() + '\\\" class = \\\"div_overview\\\" ></div>'; // <div id=\"overview\" style=\"width:300px;height:200px; margin-left:10px; margin-top: 50px; padding-top: 0px\"></div>\n", + " table_content.push(div_string);\n", + " div_string = '<p id = \\\"overviewLegend' + i.toString() + '\\\" ></p>'; // <p id=\"overviewLegend\" style=\"margin-left:10px\"></p>\n", + " table_content.push(div_string);*/\n", + "\n", + " //download figures as png\n", + " div_string = '<a id = \\\"img_band' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download band </a>';\n", + " table_content.push(div_string); \n", + " div_string = '<a id = \\\"img_dos' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download DOS </a>';\n", + " table_content.push(div_string);\n", + "\n", + " //add show VBM & CBM\n", + " div_string = '<br><br><p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_VBM' + i.toString() + '\\\" unchecked onclick=\\\"show_VBM(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Show VBM </font> (<font color=\\\"blue\\\">\\•</font>) <font color=\\\"black\\\" size = 3px> and CBM </font>(<font color=\\\"red\\\">\\•</font>) </p>';\n", + " table_content.push(div_string);\n", + "\n", + "\n", + " table_content.push('</div>');//div_tools\n", + "\n", + " //checkbox for comparison\n", + " div_string = '<div id = \\\"div_checkbox_compare' + i.toString() + '\\\" class = \\\"div_checkbox_compare\\\" >';\n", + " table_content.push(div_string);\n", + " //div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n", + " div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" checked = \\\"unchecked\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n", + " table_content.push(div_string);\n", + " table_content.push('</div>');//div_checkbox_compare\n", + "\n", + "\n", + " table_content.push('</div>');//div_band_dos\n", + " table_content.push('</th>');\n", + " table_content.push('</tr>'); \n", + " }\n", + "\n", + " document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n", + " }\n", + "\n", + "\n", + " function visualize_band_dos()\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_jquery'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_axislabels'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_dashes'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_navigate'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_selection'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_flot_legendoncanvas'));\n", + " document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n", + " document.getElementById(\"div_compare_buttons\").style.visibility=\"\";\n", + "\n", + "\n", + "\n", + " if(N_materials > N_max_show)\n", + " {\n", + " document.getElementById(\"div_showall\").style.visibility=\"visible\";\n", + " document.getElementById(\"checkbox_showall\").checked = \"\";\n", + " } \n", + "\n", + " N_materials_show = Math.min(N_max_show, N_materials);\n", + "\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + "\n", + " }\n", + "\n", + " function show_all(id)//\"plot_placeholder\"\n", + " {\n", + " var if_showall=0;\n", + " if_showall = check_show_VBM(id);\n", + " if(if_showall == 1)\n", + " {\n", + " N_materials_show = N_materials;\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + " }\n", + " else\n", + " {\n", + " N_materials_show = Math.min(N_max_show, N_materials);\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + " }\n", + "\n", + " }\n", + "\n", + " \n", + " //------------------Tool used to get the content from textarea---------------------\n", + " function get_text(textarea_id)\n", + " {\n", + " var text = document.getElementById(textarea_id).value;\n", + " return text;\n", + " }\n", + "\n", + "\n", + "\n", + " //-------------------Compare 2 band figures----------------------------------------\n", + "\n", + "\n", + " function check_compare(id)//checkbox_compare' + i.toString() + '\\\" unchecked onclick=\\\"check_compare(this.id)\n", + " {\n", + " var x = document.getElementById(id);\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " var N_chosen = 0;\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " if(choices_compare[i].checked)\n", + " {\n", + " N_chosen ++;\n", + " }\n", + " }\n", + " if(N_chosen == 2) // In max. only 2 figures could be selected and compared.\n", + " {\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " if(!choices_compare[i].checked)\n", + " {\n", + " choices_compare[i].disabled = 'disabled';\n", + " }\n", + " }\n", + " }\n", + " else\n", + " {\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " choices_compare[i].removeAttribute('disabled');\n", + " }\n", + " }\n", + "\n", + " }\n", + "\n", + " function compare()\n", + " {\n", + " $(\"#div_compare\").fadeIn(600);//show div for comparison\n", + " //check_compare(-100);\n", + "\n", + " var compare_list = [];\n", + " compare_list = make_compare_list();\n", + " //[i_material_1, i_material_2] = make_compare_list();\n", + " i_material_1 = compare_list[0];\n", + " i_material_2 = compare_list[1];\n", + " //document.getElementById(\"demo\").innerHTML = \"In add info compare:\" + i_material_1.toString() + i_material_2.toString();\n", + " compare_figures(i_material_1, i_material_2); \n", + " }\n", + " function make_compare_list()\n", + " {\n", + " //get the links to the images\n", + " images_selected_links = []; //store the links to the figures for comparison\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " var N_chosen = 0;\n", + " var str = ''; //tmp str for debug\n", + " var figure_selected = new Array(2);\n", + " for(var i=0; i<choices_compare.length; i++) //check which figures are selected\n", + " {\n", + " if(choices_compare[i].checked)\n", + " {\n", + " id_chosen = choices_compare[i].id;\n", + " i_chosen = Math.round(id_chosen.substring(16));\n", + " var tmp_str = image_band_links[i_chosen];\n", + " images_selected_links.push(tmp_str);\n", + " figure_selected[N_chosen] = i_chosen;\n", + " N_chosen ++;\n", + " //str += beakerx.image_band_links[i];\n", + " }\n", + " }\n", + " var i_material_1 = 0;\n", + " var i_material_2 = 0;\n", + " //document.getElementById(\"demo\").innerHTML = 'In making comare list';\n", + " image_band_links_selected = images_selected_links;\n", + " //document.getElementById(\"demo\").innerHTML = 'In making comare list: next';\n", + " if(N_chosen == 2)\n", + " {\n", + " i_material_1 = figure_selected[0];\n", + " i_material_2 = figure_selected[1];\n", + " }\n", + " //document.getElementById(\"demo\").innerHTML = 'Compare_list: ' +i_material_1.toString() + ' ' + i_material_2.toString();\n", + "\n", + " return [i_material_1, i_material_2];\n", + " }\n", + "\n", + " function check_compare_scale(i_material_1, i_material_2)\n", + " {\n", + " lowerlimit_id_1 = \"lowerlimit\" + i_material_1.toString();\n", + " lowerlimit_id_2 = \"lowerlimit\" + i_material_2.toString();\n", + " upperlimit_id_1 = \"upperlimit\" + i_material_1.toString();\n", + " upperlimit_id_2 = \"upperlimit\" + i_material_2.toString();\n", + "\n", + " lowerlimit_1 = parseFloat(document.getElementById(lowerlimit_id_1).innerHTML);\n", + " lowerlimit_2 = parseFloat(document.getElementById(lowerlimit_id_2).innerHTML);\n", + " upperlimit_1 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n", + " upperlimit_2 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n", + " if((lowerlimit_1 != lowerlimit_2) || (upperlimit_1 != upperlimit_2))\n", + " return -1;\n", + " else\n", + " return 1;\n", + " }\n", + "\n", + " function compare_figures(i_material_1, i_material_2)\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_query_beforeafter'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_compare_slide'));\n", + " add_info_compare(i_material_1, i_material_2);\n", + " document.getElementById(\"div_compare_container\").scrollIntoView({ behavior: 'smooth' }); \n", + " document.getElementById(\"div_compare_container\").scrollTop += 50;\n", + "\n", + " }\n", + "\n", + "\n", + " function clean_compare_list()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"\";\n", + " choices_compare[i].removeAttribute('disabled');\n", + " }\n", + " }\n", + "\n", + " //-----------Add information about the calculation to \"div_tools\"---------------\n", + " function add_info(i)\n", + " {\n", + " \n", + " //document.getElementById(\"demoa\").innerHTML = i.toString() + div_info_id;\n", + " //for(var i = 0; i < beakerx.N_materials; i++)\n", + " //{\n", + " div_info_id = \"div_info\" + i.toString();\n", + "\n", + " var str = '';\n", + " str += \"<br> <p style=\\\"text-align:left\\\"><font size = 3pt><b>Atom labels:</b>     \" + info_obj_all[i][\"atom_labels\"] + '</font></p>';\n", + " //str += \"<font size = 3pt><b>Space group:</b>     \" + info_obj_all[i][\"space_group_symbol\"] + '</font>';\n", + " //str += \"<font size = 3pt><b>Lattice constants (in Ang):</b>     \" + info_obj_all[i][\"lattice_constant\"] + '</font>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Program name:</b>    \" + info_obj_all[i][\"program_name\"].toUpperCase() + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Basis set type:</b>    \" + info_obj_all[i][\"program_basis_set_type\"] + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Functional:</b>    \" + info_obj_all[i][\"XC_functional_name\"] + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3) + '</font></p>';\n", + " document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n", + " //document.getElementById('program_name_1').innerHTML = \"<b>Code:</b>    \" + origData[\"program_name\"];\n", + " //document.getElementById('program_basis_set_type_1').innerHTML = \"<b>Basis set type:</b>    \" + origData[\"program_basis_set_type\"];\n", + " //document.getElementById('XC_functional_name_1').innerHTML = \"<b>Functional:</b>    \" + origData[\"XC_functional_name\"]; \n", + " //}\n", + " \n", + " }\n", + " function add_info_compare(i,j)\n", + " {\n", + "\n", + " div_info_id = \"div_compare_info\";\n", + " var str = '';\n", + "\n", + " if_same_scale = check_compare_scale(i_material_1, i_material_2);\n", + " if(if_same_scale == -1)\n", + " {\n", + " str = '<b><font size = \"15pt\" color=\"#940000\">Error: Different lower/upper limits.</font></b><br>';\n", + " document.getElementById(\"div_compare_container\").innerHTML = str;\n", + " document.getElementById(div_info_id).innerHTML = '';\n", + " return;\n", + " }\n", + "\n", + " str += \"<br><b><font-size:15pt>Information of the first calculation (left):</font></b> <br>\";\n", + " str += \"<br> <b>Atom labels:</b>     \" + info_obj_all[i][\"atom_labels\"];\n", + " //str += \"<br> <b>Space group:</b>     \" + info_obj_all[i][\"space_group_symbol\"];\n", + " //str += \"<br> <b>Lattice constants (in Ang):</b>     \" + info_obj_all[i][\"lattice_constant\"];\n", + " str += \"<br> <b>Program name:</b>    \" + info_obj_all[i][\"program_name\"].toUpperCase();\n", + " str += \"<br> <b>Basis set type:</b>    \" + info_obj_all[i][\"program_basis_set_type\"];\n", + " str += \"<br> <b>Functional:</b>    \" + info_obj_all[i][\"XC_functional_name\"];\n", + " str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " str += \"<br><br><br><b><font-size:15pt>Information of the second calculation (right):</font></b><br>\";\n", + " str += \"<br> <b>Atom labels:</b>     \" + info_obj_all[j][\"atom_labels\"];\n", + " //str += \"<br> <b>Space group:</b>     \" + info_obj_all[j][\"space_group_symbol\"];\n", + " //str += \"<br> <b>Lattice constants (in Ang):</b>     \" + info_obj_all[j][\"lattice_constant\"];\n", + " str += \"<br> <b>Program name:</b>    \" + info_obj_all[j][\"program_name\"].toUpperCase();\n", + " str += \"<br> <b>Basis set type:</b>    \" + info_obj_all[j][\"program_basis_set_type\"]; \n", + " str += \"<br> <b>Functional:</b>    \" + info_obj_all[j][\"XC_functional_name\"];\n", + " str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n", + " }\n", + "\n", + "\n", + "\n", + " //-----------------------Show/hide VBM, CBM-------------------------\n", + " function check_show_VBM(checkbox_VBM_id)\n", + " {\n", + " var x = document.getElementById(checkbox_VBM_id);\n", + " var if_checked = 0;\n", + " if(x.checked)//== \"checked\")\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"checked!\";\n", + " if_checked = 1;\n", + " }\n", + " else if (x.unchecked)// == \"unchecked\")\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"unchecked!\";\n", + " if_checked = -1;\n", + " }\n", + " else\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"nothing detected!\";\n", + " }\n", + " return if_checked;\n", + " }\n", + "\n", + " function check_if_in_compare_list(i) // check if the current material i is to be compared\n", + " {\n", + "\n", + " var checkbox_compare_id = \"checkbox_compare\" + i.toString();\n", + " var if_compare = check_show_VBM(checkbox_compare_id);\n", + " //document.getElementById(\"demo\").innerHTML = 'if_compare of ' + i.toString() + ' : ' + if_compare.toString();\n", + " var i_compare_material_1, i_compare_material_2;\n", + " [i_compare_material_1, i_compare_material_2] = make_compare_list();\n", + " var i_in_compare_list = -1;\n", + " if(i_compare_material_1 == i)\n", + " {\n", + " i_in_compare_list = 1;\n", + " }\n", + " else if (i_compare_material_2 == i)\n", + " {\n", + " i_in_compare_list = 2;\n", + " }\n", + " else\n", + " {\n", + " i_in_compare_list = 0;\n", + " }\n", + " //document.getElementById(\"demo\").innerHTML = 'Checking ' + i.toString() + ' in Compare_list: ' + i_in_compare_list.toString();\n", + " return [if_compare, i_in_compare_list];\n", + " }\n", + "\n", + " function show_VBM(id)\n", + " {\n", + " //prepare(\"new\");\n", + " //var if_show_VBM = -1;\n", + " var len_id = id.length;\n", + " var i_material = id.substring(12);\n", + " var i = Math.round(i_material);\n", + "\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + " //document.getElementById(\"demo\").innerHTML = i.toString() + ' in Compare_list: ' + i_in_compare_list.toString();\n", + "\n", + " plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + "\n", + " //---------------------Functions to rescale-------------------------------------------\n", + " function autoscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(16);\n", + " var i = Math.round(i_material);\n", + "\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " document.getElementById(upperlim_id).innerHTML =\"10.0\";\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " document.getElementById(lowerlim_id).innerHTML =\"-10.0\";\n", + "\n", + "\n", + " //document.getElementById(\"demoa\").innerHTML =i_material;\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + " plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + " function fullscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(16);\n", + " var i = Math.round(i_material);\n", + "\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " document.getElementById(upperlim_id).innerHTML =\"100.0\";\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " document.getElementById(lowerlim_id).innerHTML =\"-100.0\";\n", + "\n", + " //document.getElementById(\"demoa\").innerHTML =i_material;\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + "\n", + " plot_band_dos_i(i, -100, 100, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + " function customscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(18);\n", + " var i = Math.round(i_material);\n", + " //\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " upperlim = document.getElementById(upperlim_id).value;\n", + " upperlim_float = Math.round(upperlim);\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " lowerlim = document.getElementById(lowerlim_id).value;\n", + " lowerlim_float = Math.round(lowerlim);\n", + "\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + "\n", + " plot_band_dos_i(i, lowerlim_float, upperlim_float, if_show_VBM, if_compare, i_in_compare_list); \n", + " }\n", + "\n", + "\n", + " function plot_band_dos(lowerLim, upperLim, N_materials_show)\n", + " {\n", + " placeholder_band = \"#div_band1\";\n", + " placeholder_dos = \"#div_dos1\";\n", + " // lowerLim = -10.01\n", + " //upperLim = 10.01\n", + "\n", + "\n", + "\n", + " //alert(\"plot_band_dos\");\n", + " //prepare();\n", + " for(var i = 0; i < N_materials_show; i++)\n", + " {\n", + " \n", + " var checkbox_material_id = \"checkbox_material\" + i.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + " add_info(i);\n", + " }\n", + "\n", + " //------Plot----------------\n", + " /*\n", + " for(var i_material = 0; i_material < N_materials_show; i_material++)\n", + " {\n", + "\n", + " //alert(\"Material \"+i);\n", + " var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + "\n", + " plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n", + " }\n", + " */\n", + " //alert(\"next:for\")\n", + " for (let i_material = 0, p = Promise.resolve(); i_material < N_materials_show; i_material++) {\n", + " p = p.then(_ => new Promise(resolve =>\n", + " setTimeout(function () {\n", + " //alert(i_material)\n", + " var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected == 1)\n", + " {\n", + " plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n", + " }\n", + " resolve();\n", + " }, 0)\n", + " ));\n", + " }\n", + "\n", + "\n", + " return 1;\n", + " }\n", + "\n", + " var i = 0\n", + " var lowerLim = -10\n", + " var upperLim = 10\n", + " var if_show_VBM = 0\n", + " var if_compare = 0\n", + " var i_in_compare_list = -1\n", + "\n", + "\n", + " \n", + " function plot_band_dos_i(i_material, lowerLim_material, upperLim_material, if_show_VBM_material, if_compare_material, i_in_compare_list_material)\n", + " {\n", + " //alert(\"plot_band_dos_i\")\n", + "\n", + " i = i_material;\n", + " lowerLim = lowerLim_material;\n", + " upperLim = upperLim_material;\n", + " if_show_VBM = if_show_VBM_material;\n", + " if_compare = if_compare_material;\n", + " i_in_compare_list = i_in_compare_list_material;\n", + " //alert(\"plot_band_dos_i: i_material: \"+i)\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_band'));\n", + " //alert('i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list')\n", + " //plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_dos'));\n", + " } \n", + "</script>\n", + "\n", + " \n", + " \n", + "<br><br>\n", + "<button class=\"button\" onclick=\"process()\">Process data</button>\n", + "<br><br>\n", + "<div id = \"n_materials\" style = \"font-size: 18px; font-weight: 100; height: 60px; width: 100%;\"> Number of materials submitted: 0</div>\n", + "<div id = \"show_materials_submitted\" style = \"font-size: 20px; font-color: black;\"> </div>\n", + "\n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "<p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select materials to visualize the band structure and DOS:</p>\n", + "<div style = \"width :100%; height: 10px;\"></div> \n", + "<button class = \"button\" onclick = \"clean_materials_selection()\"> Clean selections </button> \n", + "<button class = \"button\" onclick = \"select_all()\"> Select all </button> \n", + "<button class = \"button\" onclick = \"visualize_band_dos()\"> Visualize </button> \n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "\n", + "<div id = \"show_materials_submitted_info\" style = \"width: 100%; font-size: 20px; font-color: black;\"> \n", + " <table id = \"table_materials_submitted_info\" style=\"width:100%\"> </table>\n", + "</div>\n", + "\n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "\n", + "\n", + "\n", + "\n", + "<div id=\"div_compare_buttons\" style=\"visibility:hidden\">\n", + " <br><br><br>\n", + " <p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select two materials in the checkbox on the right for comparison:</p>\n", + " <p style=\"color: #000;font-weight: 1000; font-size: 8pt;\"></p>\n", + " <button class = \"button\" onclick = \"clean_compare_list()\"> Clean selections </button> \n", + " <button class = \"button\" onclick = \"compare();compare()\" title = \"Select 2 materials in the checkbox below and compare: please make sure that the upper/lower limits are the same (using Rescale/Autoscale buttons).\" > Compare</button>\n", + "</div>\n", + "\n", + "\n", + "\n", + "<div id = \"div_showall\" style = \"width: 100%; visibility:hidden\">\n", + " <div style = \"width: 100%; height: 30px; \"></div>\n", + " <input type = \"checkbox\" id = \"checkbox_showall\" unchecked onclick=\"show_all(this.id)\"/> <font color=\"black\" size = 3px> Show all results </font><font size = 2px color = \"#666\"> (By default only the first 10 results are shown.) </font> \n", + " <div style = \"width: 100%; height: 30px; \"></div>\n", + "</div>\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "<div id = \"div_compare\" style = \"position: fixed; top: 20%; left: 10%; width: 1200px; height: 600px; z-index: 999999; border: 1px solid #555; background-color: #fff; display: none\" onclick = \"$(this).fadeOut(500)\"> \n", + " \n", + " <div style = \"float: right; width: 80px; height: 25px; margin-top: 10px; margin-right: 10px; z-index: 1000000; border: 1px solid #555; text-align: center; vertical-align: middle; background-color: #f9f9f9; font-size:12pt; font-color: #000; cursor:pointer;\" > CLOSE </div> <!--button to close the div-->\n", + " <div id = \"div_compare_info\" style = \" width: 350px; height: 500px; float: right; margin-top: 50px; margin-right: 10px; z-index: 10000000;\"></div>\n", + " <div id = \"div_compare_container\" style = \"margin-top: 50px; margin-left: 100px; width: 600px; height: 300px;\">\n", + " <div class=\"g-before-after\" id = \"div_compare_containerx\"></div>\n", + " </div>\n", + "</div>\n", + "\n", + "\n", + "<div id = \"demo\"></div>\n", + "\n", + "<div id = \"plot_placeholder\">\n", + " <div><br></div>\n", + " <table id = \"table_visualize\"> </table>\n", + "</div>\n", + "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "tags": [ + "plot_band" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + " //alert(\"tag: plot_band\")\n", + "\n", + "plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + "function plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n", + "{\n", + " //i=0;\n", + " //alert(\"plot_band \"+ i)\n", + " var placeholder_band = \"#div_band\" + i.toString();\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var img_band_id = \"img_band\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + "\n", + " var placeholder_band_compare = \"\";\n", + "\n", + "\n", + " if(i_in_compare_list == 1)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\";\n", + " }\n", + " else if(i_in_compare_list == 2)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_2\";\n", + " }\n", + " else\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n", + " }\n", + "\n", + " Object.size = function(obj) {\n", + " var size = 0, key;\n", + " for (key in obj) \n", + " {\n", + " if (obj.hasOwnProperty(key)) size++;\n", + " }\n", + " return size;\n", + " };\n", + "\n", + " //Get the number of bands\n", + " //alert(\"Getting band\")\n", + " //alert(band_obj_all)\n", + " //alert(\"band_obj_all got!\")\n", + " var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n", + " var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n", + " //alert(band_obj_all[i][\"band_y_axis\"])\n", + " var band_plotdata = [];\n", + " \n", + " for(var i_band =0; i_band < N_bands; i_band++)\n", + " {\n", + " var tmp_data = [];\n", + " for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n", + " {\n", + " tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n", + " }\n", + " var plotData = { shadowSize: 0 , data: tmp_data, color: 'black', series: { lines: { show: true } , points: {show: false} } };\n", + " band_plotdata.push(plotData);\n", + " }\n", + "\n", + "\n", + " var tmp_data0 = [[0, 0], [1, 0]];\n", + " var plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n", + " band_plotdata.push(plotData0);\n", + "\n", + " var band_plotdata_overview = band_plotdata.slice(0);\n", + "\n", + " var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n", + " var HOMOlabel = [\"VBM\"];\n", + " var plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false}, showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n", + " var LUMOlabel = [\"CBM\"];\n", + " var plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false}, showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + " if (if_show_VBM == 1)\n", + " {\n", + " band_plotdata.push(plotHOMO);\n", + " band_plotdata.push(plotLUMO);\n", + " }\n", + "\n", + " \n", + " //alert(img_band_id + band_plotdata)\n", + " \n", + " //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n", + " //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\" }\n", + "\n", + " var canvas_band;\n", + " var options_band = {\n", + " canvas: true,\n", + " //legend:{ type: \"canvas\" },\n", + " series: { lines: { show: true, lineWidth: 2 }, \n", + " points: { show: false } }, \n", + " xaxis: { \n", + " ticks: band_obj_all[i][\"labels\"], \n", + " color:\"#000\", \n", + " font: {size: 20}, \n", + " zoomRange: false,\n", + " panRange: false \n", + " }, \n", + " yaxis: { \n", + " axisLabel: \"Energy (eV)\", \n", + " axisLabelUseCanvas: true,\n", + " //axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20, family:\"Arial\"},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " zoom: { \n", + " interactive: true\n", + " },\n", + "\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n", + "\n", + " grid: { \n", + " labelMargin: 15,\n", + " hoverable: true, \n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n", + " borderWidth: {\n", + " top: 2, \n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null } \n", + " }\n", + " }\n", + " //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n", + " //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n", + " var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n", + " var image_band = plot_band.toDataURL();\n", + " image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n", + " //beakerx.image_band = image_band;\n", + " document.getElementById(img_band_id).href= image_band;\n", + " image_band_links[i] = image_band;\n", + " //alert(\"band done\")\n", + "}\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + " //alert(\"tag: plot_band\")\n", + "\n", + "plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + "function plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n", + "{\n", + " //i=0;\n", + " //alert(\"plot_band \"+ i)\n", + " var placeholder_band = \"#div_band\" + i.toString();\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var img_band_id = \"img_band\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + "\n", + " var placeholder_band_compare = \"\";\n", + "\n", + "\n", + " if(i_in_compare_list == 1)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\";\n", + " }\n", + " else if(i_in_compare_list == 2)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_2\";\n", + " }\n", + " else\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n", + " }\n", + "\n", + " Object.size = function(obj) {\n", + " var size = 0, key;\n", + " for (key in obj) \n", + " {\n", + " if (obj.hasOwnProperty(key)) size++;\n", + " }\n", + " return size;\n", + " };\n", + "\n", + " //Get the number of bands\n", + " //alert(\"Getting band\")\n", + " //alert(band_obj_all)\n", + " //alert(\"band_obj_all got!\")\n", + " var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n", + " var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n", + " //alert(band_obj_all[i][\"band_y_axis\"])\n", + " var band_plotdata = [];\n", + " \n", + " for(var i_band =0; i_band < N_bands; i_band++)\n", + " {\n", + " var tmp_data = [];\n", + " for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n", + " {\n", + " tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n", + " }\n", + " var plotData = { shadowSize: 0 , data: tmp_data, color: 'black', series: { lines: { show: true } , points: {show: false} } };\n", + " band_plotdata.push(plotData);\n", + " }\n", + "\n", + "\n", + " var tmp_data0 = [[0, 0], [1, 0]];\n", + " var plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n", + " band_plotdata.push(plotData0);\n", + "\n", + " var band_plotdata_overview = band_plotdata.slice(0);\n", + "\n", + " var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n", + " var HOMOlabel = [\"VBM\"];\n", + " var plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false}, showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n", + " var LUMOlabel = [\"CBM\"];\n", + " var plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false}, showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + " if (if_show_VBM == 1)\n", + " {\n", + " band_plotdata.push(plotHOMO);\n", + " band_plotdata.push(plotLUMO);\n", + " }\n", + "\n", + " \n", + " //alert(img_band_id + band_plotdata)\n", + " \n", + " //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n", + " //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\" }\n", + "\n", + " var canvas_band;\n", + " var options_band = {\n", + " canvas: true,\n", + " //legend:{ type: \"canvas\" },\n", + " series: { lines: { show: true, lineWidth: 2 }, \n", + " points: { show: false } }, \n", + " xaxis: { \n", + " ticks: band_obj_all[i][\"labels\"], \n", + " color:\"#000\", \n", + " font: {size: 20}, \n", + " zoomRange: false,\n", + " panRange: false \n", + " }, \n", + " yaxis: { \n", + " axisLabel: \"Energy (eV)\", \n", + " axisLabelUseCanvas: true,\n", + " //axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20, family:\"Arial\"},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " zoom: { \n", + " interactive: true\n", + " },\n", + "\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n", + "\n", + " grid: { \n", + " labelMargin: 15,\n", + " hoverable: true, \n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n", + " borderWidth: {\n", + " top: 2, \n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null } \n", + " }\n", + " }\n", + " //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n", + " //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n", + " var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n", + " var image_band = plot_band.toDataURL();\n", + " image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n", + " //beakerx.image_band = image_band;\n", + " document.getElementById(img_band_id).href= image_band;\n", + " image_band_links[i] = image_band;\n", + " //alert(\"band done\")\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "tags": [ + "plot_dos" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + " //alert(\"tag: plot_dos \" + i)\n", + " //i=0;\n", + "\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + "\n", + "//----Plot DOS----------------------\n", + " var dos_plotdata = [];\n", + " //alert(\"dos:\"+dos_obj_all[i])\n", + " var xdos = dos_obj_all[i][\"dos_x_axis\"];\n", + " var ydos = dos_obj_all[i][\"dos_y_axis\"][0];\n", + " var dosLabelPos = Math.max.apply(Math, ydos)/2;\n", + " var d2 = [];\n", + " for (var ii = 0; ii < xdos.length; ii+=1) {\n", + " d2.push([ydos[ii],xdos[ii]]);\n", + " }\n", + " var plotData2={ shadowSize: 0, color: 'black' , data: d2};\n", + " dos_plotdata.push(plotData2);\n", + " //alert(\"dos_plotdata\"+JSON.stringify(dos_plotdata[0]));\n", + " \n", + " function find_xaxis_max_min(data, lowerbound, upperbound)\n", + " {\n", + " //data[xaxis,y] find the max and min value of x axis\n", + " //alert(\"dos[0]:\" + data[0][\"data\"]);\n", + " //alert(\"Bounds: \" + lowerbound + \" , \" + upperbound)\n", + " var n_data = data.length;\n", + " //alert(\"N dos: \" + n_data);\n", + " var data_min = 1000000;\n", + " var data_max = -1000000;\n", + " var data_current = 0;\n", + " for (var i = 0; i < n_data; i++)\n", + " {\n", + " if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n", + " {\n", + " data_current = data[i][0];\n", + " //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n", + " if(data_current >= data_max)\n", + " {\n", + " data_max = data_current;\n", + " }\n", + " if(data_current <= data_min)\n", + " {\n", + " data_min = data_current;\n", + " }\n", + " }\n", + " }\n", + " var data_max_min = [data_max, data_min];\n", + " //alert(\"data_max_min: \" + data_max_min);\n", + " return data_max_min;\n", + " }\n", + " var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n", + " var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n", + " //alert(\"dos_x_max_min:\"+dos_x_max_min+\", dosLabelPos:\"+dosLabelPos);\n", + " var options_dos ={\n", + " canvas: true,\n", + " series: {\n", + " lines: { show: true, lineWidth:2 },\n", + " points: { show: false }\n", + " },\n", + "\n", + " yaxis: { \n", + " axisLabel: \"\", \n", + " axisLabelUseCanvas: true,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " xaxis: {\n", + " axisLabel: \" \",\n", + " axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial',\n", + " axisLabelPadding: 3,\n", + " color:\"rgb(0, 0, 0)\",\n", + " font: {size: 20, family:\"Arial\"},\n", + " //ticks: 10,\n", + " tickLength:0,\n", + " min: dos_x_max_min[1],//0,\n", + " max: dos_x_max_min[0],//1,\n", + " tickDecimals: 0,\n", + " ticks: [[ dosLabelPos ,'DOS']],\n", + " //tickFormatter: MyFormatter\n", + " panRange: false\n", + " },\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " grid: {\n", + " labelMargin: 15,\n", + " hoverable: true,\n", + " //borderWidth : 1000,\n", + " //show : false,\n", + " // //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n", + " borderWidth: {\n", + " top: 2,\n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null\n", + " }\n", + " }\n", + " }\n", + " var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n", + " var image_dos = plot_dos.toDataURL();\n", + " image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n", + " image_dos = image_dos;\n", + " document.getElementById(img_dos_id).href= image_dos;\n", + " //alert(\"dos done.\")\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + " //alert(\"tag: plot_dos \" + i)\n", + " //i=0;\n", + "\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + "\n", + "//----Plot DOS----------------------\n", + " var dos_plotdata = [];\n", + " //alert(\"dos:\"+dos_obj_all[i])\n", + " var xdos = dos_obj_all[i][\"dos_x_axis\"];\n", + " var ydos = dos_obj_all[i][\"dos_y_axis\"][0];\n", + " var dosLabelPos = Math.max.apply(Math, ydos)/2;\n", + " var d2 = [];\n", + " for (var ii = 0; ii < xdos.length; ii+=1) {\n", + " d2.push([ydos[ii],xdos[ii]]);\n", + " }\n", + " var plotData2={ shadowSize: 0, color: 'black' , data: d2};\n", + " dos_plotdata.push(plotData2);\n", + " //alert(\"dos_plotdata\"+JSON.stringify(dos_plotdata[0]));\n", + " \n", + " function find_xaxis_max_min(data, lowerbound, upperbound)\n", + " {\n", + " //data[xaxis,y] find the max and min value of x axis\n", + " //alert(\"dos[0]:\" + data[0][\"data\"]);\n", + " //alert(\"Bounds: \" + lowerbound + \" , \" + upperbound)\n", + " var n_data = data.length;\n", + " //alert(\"N dos: \" + n_data);\n", + " var data_min = 1000000;\n", + " var data_max = -1000000;\n", + " var data_current = 0;\n", + " for (var i = 0; i < n_data; i++)\n", + " {\n", + " if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n", + " {\n", + " data_current = data[i][0];\n", + " //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n", + " if(data_current >= data_max)\n", + " {\n", + " data_max = data_current;\n", + " }\n", + " if(data_current <= data_min)\n", + " {\n", + " data_min = data_current;\n", + " }\n", + " }\n", + " }\n", + " var data_max_min = [data_max, data_min];\n", + " //alert(\"data_max_min: \" + data_max_min);\n", + " return data_max_min;\n", + " }\n", + " var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n", + " var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n", + " //alert(\"dos_x_max_min:\"+dos_x_max_min+\", dosLabelPos:\"+dosLabelPos);\n", + " var options_dos ={\n", + " canvas: true,\n", + " series: {\n", + " lines: { show: true, lineWidth:2 },\n", + " points: { show: false }\n", + " },\n", + "\n", + " yaxis: { \n", + " axisLabel: \"\", \n", + " axisLabelUseCanvas: true,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " xaxis: {\n", + " axisLabel: \" \",\n", + " axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial',\n", + " axisLabelPadding: 3,\n", + " color:\"rgb(0, 0, 0)\",\n", + " font: {size: 20, family:\"Arial\"},\n", + " //ticks: 10,\n", + " tickLength:0,\n", + " min: dos_x_max_min[1],//0,\n", + " max: dos_x_max_min[0],//1,\n", + " tickDecimals: 0,\n", + " ticks: [[ dosLabelPos ,'DOS']],\n", + " //tickFormatter: MyFormatter\n", + " panRange: false\n", + " },\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " grid: {\n", + " labelMargin: 15,\n", + " hoverable: true,\n", + " //borderWidth : 1000,\n", + " //show : false,\n", + " // //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n", + " borderWidth: {\n", + " top: 2,\n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null\n", + " }\n", + " }\n", + " }\n", + " var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n", + " var image_dos = plot_dos.toDataURL();\n", + " image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n", + " image_dos = image_dos;\n", + " document.getElementById(img_dos_id).href= image_dos;\n", + " //alert(\"dos done.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "tags": [ + "init_jquery" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"http://code.jquery.com/jquery-1.8.3.min.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"http://code.jquery.com/jquery-1.8.3.min.js\"></script>" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "tags": [ + "init_flot" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"js/jquery.flot.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"js/jquery.flot.js\"></script>\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "tags": [ + "init_flot_axislabels" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"js/jquery.flot.axislabels.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"js/jquery.flot.axislabels.js\"></script>" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "tags": [ + "init_flot_navigate" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"js/jquery.flot.navigate.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"js/jquery.flot.navigate.js\"></script>" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": { + "tags": [ + "init_flot_selection" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"js/jquery.flot.selection.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"js/jquery.flot.selection.js\"></script>" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "tags": [ + "js_query_beforeafter" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "//jquery.beforeafter.min.js\n", + "!function(e){e.fn.beforeafter=function(i){var t=e.extend({touch:!0,message:\"Slide\",hide_message:!0,reset:!0,reset_delay:3e3,drag_horizontal:!0,split_horizontal:!0\n", + "},i);return this.each(function(){var i=e(this),a=i.find(\"img\"),n=a.data(\"aftersrc\"),s=i.width(),d=0;a.after('<div class=\"g-img-after\"><img style=\"width: '+s+'px;\" src=\"'+n+'\"></div>'),\n", + "a.addClass(\"g-img-before\").width(s),i.append('<div class=\"g-img-divider\"><span>'+t.message+\"</span></div>\"),d=i.height(),t.split_horizontal||i.addClass(\"g-vertical\"),\n", + "i.on(\"mouseenter touchstart\",function(e){var t=i.data(\"reset-timer\");t&&(window.clearTimeout(t),i.data(\"reset-timer\",!1))}).on(\"mousemove touchmove\",function(a){\n", + "var n=0,o=0,r=i.find(\".g-img-divider span\");if(t.drag_horizontal)n=a.pageX-i.offset().left,o=n/s*100;else{var f=i.offset().top-e(window).scrollTop();n=a.clientY/f,\n", + "o=(a.clientY-f)/d*100}if(t.touch&&\"undefined\"!=typeof a.originalEvent.touches){var g=a.originalEvent.touches[0];o=t.drag_horizontal?(g.pageX-i.offset().left)/s*100:(g.pageY-i.offset().top)/d*100;\n", + "}t.split_horizontal?(i.find(\".g-img-after\").css(\"left\",o+\"%\"),i.find(\".g-img-divider\").css(\"left\",o+\"%\")):(i.find(\".g-img-after\").css(\"top\",o+\"%\"),i.find(\".g-img-divider\").css(\"top\",o+\"%\")),\n", + "t.hide_message&&r.is(\":visible\")&&r.fadeOut()}).on(\"mouseleave touchend touchcancel\",function(e){var a=i.data(\"reset-timer\"),n=i.find(\".g-img-divider span\");\n", + "t.reset&&(a||(a=window.setTimeout(function(){t.split_horizontal?(i.find(\".g-img-after\").animate({left:\"50%\"},500),i.find(\".g-img-divider\").animate({left:\"50%\"\n", + "},500,function(){n.fadeIn()})):(i.find(\".g-img-after\").animate({top:\"50%\"},500),i.find(\".g-img-divider\").animate({top:\"50%\"},500,function(){n.fadeIn()})),\n", + "i.data(\"reset-timer\",!1)},t.reset_delay),i.data(\"reset-timer\",a)))})}),this}}(jQuery);\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + "//jquery.beforeafter.min.js\n", + "!function(e){e.fn.beforeafter=function(i){var t=e.extend({touch:!0,message:\"Slide\",hide_message:!0,reset:!0,reset_delay:3e3,drag_horizontal:!0,split_horizontal:!0\n", + "},i);return this.each(function(){var i=e(this),a=i.find(\"img\"),n=a.data(\"aftersrc\"),s=i.width(),d=0;a.after('<div class=\"g-img-after\"><img style=\"width: '+s+'px;\" src=\"'+n+'\"></div>'),\n", + "a.addClass(\"g-img-before\").width(s),i.append('<div class=\"g-img-divider\"><span>'+t.message+\"</span></div>\"),d=i.height(),t.split_horizontal||i.addClass(\"g-vertical\"),\n", + "i.on(\"mouseenter touchstart\",function(e){var t=i.data(\"reset-timer\");t&&(window.clearTimeout(t),i.data(\"reset-timer\",!1))}).on(\"mousemove touchmove\",function(a){\n", + "var n=0,o=0,r=i.find(\".g-img-divider span\");if(t.drag_horizontal)n=a.pageX-i.offset().left,o=n/s*100;else{var f=i.offset().top-e(window).scrollTop();n=a.clientY/f,\n", + "o=(a.clientY-f)/d*100}if(t.touch&&\"undefined\"!=typeof a.originalEvent.touches){var g=a.originalEvent.touches[0];o=t.drag_horizontal?(g.pageX-i.offset().left)/s*100:(g.pageY-i.offset().top)/d*100;\n", + "}t.split_horizontal?(i.find(\".g-img-after\").css(\"left\",o+\"%\"),i.find(\".g-img-divider\").css(\"left\",o+\"%\")):(i.find(\".g-img-after\").css(\"top\",o+\"%\"),i.find(\".g-img-divider\").css(\"top\",o+\"%\")),\n", + "t.hide_message&&r.is(\":visible\")&&r.fadeOut()}).on(\"mouseleave touchend touchcancel\",function(e){var a=i.data(\"reset-timer\"),n=i.find(\".g-img-divider span\");\n", + "t.reset&&(a||(a=window.setTimeout(function(){t.split_horizontal?(i.find(\".g-img-after\").animate({left:\"50%\"},500),i.find(\".g-img-divider\").animate({left:\"50%\"\n", + "},500,function(){n.fadeIn()})):(i.find(\".g-img-after\").animate({top:\"50%\"},500),i.find(\".g-img-divider\").animate({top:\"50%\"},500,function(){n.fadeIn()})),\n", + "i.data(\"reset-timer\",!1)},t.reset_delay),i.data(\"reset-timer\",a)))})}),this}}(jQuery);" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "tags": [ + "js_compare_slide" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "var div_str = '';\n", + "//div_str = '<style> .g-before-after{position:relative;overflow:hidden}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%} </style>'\n", + "//div_str += '<script>$(\\'#div_compare_containerx\\').beforeafter(); </script>';\n", + "//div_str +='<script type=\\\"text/javascript\\\" src=\\\"https://github.com/jquery/jquery/blob/master/src/jquery.js\\\"></script> '\n", + "//div_str += '<div class=\\\"g-before-after\\\" id=\\\"div_compare_containerx\\\">';\n", + "div_str +='<img src = \\\"'\n", + "\n", + "var src1 = image_band_links_selected[0];\n", + "var src2 = image_band_links_selected[1];\n", + "var tmp_src1 = src1;\n", + "var tmp_src2 = src2;\n", + "//src1 = \"https://images4.alphacoders.com/640/640956.jpg\";\n", + "//src2 = \"http://imgmr.com/wp-content/uploads/2016/06/SAO-anime.jpg\";\n", + "div_str +=src1;\n", + "div_str += '\\\" data-aftersrc=\\\"'\n", + "div_str +=src2;\n", + "//div_str += '\\\"></div>';\n", + "div_str += '\\\"/>';\n", + "//#div_compare_containerx\n", + "document.getElementById(\"div_compare_containerx\").innerHTML = div_str;\n", + "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n", + "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n", + "//beakerx.image_band_links[i]\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + "var div_str = '';\n", + "//div_str = '<style> .g-before-after{position:relative;overflow:hidden}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%} </style>'\n", + "//div_str += '<script>$(\\'#div_compare_containerx\\').beforeafter(); </script>';\n", + "//div_str +='<script type=\\\"text/javascript\\\" src=\\\"https://github.com/jquery/jquery/blob/master/src/jquery.js\\\"></script> '\n", + "//div_str += '<div class=\\\"g-before-after\\\" id=\\\"div_compare_containerx\\\">';\n", + "div_str +='<img src = \\\"'\n", + "\n", + "var src1 = image_band_links_selected[0];\n", + "var src2 = image_band_links_selected[1];\n", + "var tmp_src1 = src1;\n", + "var tmp_src2 = src2;\n", + "//src1 = \"https://images4.alphacoders.com/640/640956.jpg\";\n", + "//src2 = \"http://imgmr.com/wp-content/uploads/2016/06/SAO-anime.jpg\";\n", + "div_str +=src1;\n", + "div_str += '\\\" data-aftersrc=\\\"'\n", + "div_str +=src2;\n", + "//div_str += '\\\"></div>';\n", + "div_str += '\\\"/>';\n", + "//#div_compare_containerx\n", + "document.getElementById(\"div_compare_containerx\").innerHTML = div_str;\n", + "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n", + "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n", + "//beakerx.image_band_links[i]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false, + "tags": [ + "process_band_dos_data_python" + ] + }, + "outputs": [], + "source": [ + "#tag:python_2\n", + "import urllib.request, json\n", + "import numpy as np\n", + "import math\n", + "\n", + "#======Define global objs============\n", + "info_all = []\n", + "band_obj_all = []\n", + "dos_obj_all = []\n", + "\n", + "def load_jsonfile(path):\n", + " #with open(path, encoding='utf-8') as band_file: \n", + " # return json.load(band_file)\n", + "\n", + " \n", + " with urllib.request.urlopen(path) as url:\n", + " data = json.loads(url.read().decode())\n", + " return data\n", + "\n", + "#-----Get the labels for x axis---------------\n", + "def get_label_flag(coor_array):\n", + " #np.sort(coor_array)\n", + " x = coor_array[0]\n", + " y = coor_array[1]\n", + " z = coor_array[2]\n", + " coor =np.sort([x,y,z])\n", + " xx = coor[0]\n", + " yy = coor[1]\n", + " zz = coor[2]\n", + " coor = [xx, yy, zz]\n", + " #pprint(coor)\n", + " if (coor == [0, 0.5, 0.5]):\n", + " return \"X\"\n", + " if (coor == [0, 0.0, 0.5]):\n", + " return \"M\"\n", + " elif (coor == [0.5, 0.5, 0.5]):\n", + " return \"L\"\n", + " elif (coor == [0.375, 0.375, 0.75]):\n", + " return \"K\"\n", + " elif (coor == [0.25, 0.5, 0.75]):\n", + " return \"W\"\n", + " elif (coor == [0, 0, 0]):\n", + " return \"\\u0393\"\n", + " elif (coor == [0.25, 0.625, 0.625]):\n", + " return \"U\"\n", + " else:\n", + " return \"?\"\n", + "\n", + "#============Process the band structure data============\n", + "def get_band_obj(band_path, dos_fermi_energy):\n", + "\n", + " #band_data: read from json file \n", + " #Load the data files for band\n", + " band_data = load_jsonfile(band_path)\n", + " \n", + " #---------Read section_k_band_segment------------\n", + " section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n", + " \n", + " #--------Get the number of k band segments-------------\n", + " N_k_band_segments = len(section_k_band_segment)\n", + " \n", + " #----------Get the total number of k points in all segments---------\n", + " N_k_points_all = 0\n", + " for i in range(N_k_band_segments):\n", + " band_k_points = section_k_band_segment[i]['band_k_points']\n", + " N_k_points_all = N_k_points_all + len(band_k_points)\n", + " \n", + " #--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n", + " # store in k_coor_1D[N_k_points_total]-----------------\n", + "\n", + " band_distance_segments = np.zeros(N_k_band_segments)\n", + " for i in range(N_k_band_segments):\n", + " [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end'] #\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n", + " band_distance_segments[i] = math.pow((x1-x2), 2) + math.pow((y1-y2), 2) + math.pow((z1-z2), 2)\n", + "\n", + " \n", + " band_distance_total = math.fsum(band_distance_segments)\n", + " #print(band_distance_segments)\n", + " average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total\n", + " \n", + " #Prepare the parameters to rescale the k coordinates into [0,1]\n", + " step_k_point = 1.0 / N_k_points_all\n", + " step_k_point = (1.0 + step_k_point) / N_k_points_all\n", + " \n", + " # \n", + " k_coor_1D = np.zeros((N_k_points_all))\n", + " for i_k_points in range(N_k_points_all):\n", + " k_coor_1D[i_k_points] = round( step_k_point * i_k_points, 3)\n", + " #for i in range(N_k_band_segments):\n", + " # ki[i] = \n", + " \n", + "\n", + " #--------Get the eigenvalues of each band trajectory--------------\n", + " N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n", + " N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n", + " band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n", + " N_k_points_all = 0\n", + " for i_segments in range(N_k_band_segments):\n", + " band_energies = section_k_band_segment[i_segments]['band_energies']\n", + " N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n", + " N_k_points_per_segment = len(band_energies[0])\n", + " for i_k_points in range(N_k_points_per_segment):\n", + " for i_bands in range(N_bands):\n", + " band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n", + " N_k_points_all = N_k_points_all + 1\n", + " \n", + " \n", + " N_labels = 0\n", + " for i_segments in range(N_k_band_segments):\n", + " for j in range(2):\n", + " labels_tmp = section_k_band_segment[i_segments]['band_segm_start_end'][j];\n", + " N_labels = N_labels + 1\n", + "\n", + " label_flag = [\"\" for i in range(N_labels)] #stores the flags of the labels (X, W, G, etc)\n", + "\n", + " i_label = 0\n", + " label_flag_last_final = \"\"\n", + " label_flag_current_initial = \"\"\n", + " for i_segments in range(N_k_band_segments):\n", + " labels_coor_0 = section_k_band_segment[i_segments]['band_segm_start_end'][0];\n", + " labels_coor_1 = section_k_band_segment[i_segments]['band_segm_start_end'][1];\n", + " np.sort(labels_coor_0)\n", + " np.sort(labels_coor_1)\n", + " label_flag_0 = get_label_flag(labels_coor_0)\n", + " label_flag_1 = get_label_flag(labels_coor_1)\n", + " label_flag_current_initial = label_flag_0\n", + " if(label_flag_last_final == \"\"):\n", + " label_flag_last_final = label_flag_0\n", + "\n", + " if(label_flag_last_final == label_flag_current_initial):\n", + " label_flag[i_label] = label_flag_current_initial\n", + " else:\n", + " label_flag[i_label] = \"\".join([label_flag_last_final, '|', label_flag_current_initial])\n", + " label_flag_last_final = label_flag_1\n", + " \n", + "\n", + " i_label = i_label + 1\n", + " if(i_segments == N_k_band_segments - 1):\n", + " label_flag[i_label] = label_flag_1\n", + " i_label = i_label + 1\n", + "\n", + " N_labels = i_label\n", + " \n", + " #------------Get the coordinates for the labels------------\n", + " #label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n", + " label_coor_relative = np.zeros((N_labels))\n", + " for i_label in range(N_labels):\n", + " #Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n", + " #x = labels_coor_0[0]\n", + " #y = labels_coor_0[1]\n", + " #z = labels_coor_0[2]\n", + " #label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n", + " label_coor_relative[i_label] = step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all);\n", + "\n", + " #----Store the label-----------\n", + " label_obj =[['' for i in range(2)] for j in range(N_labels)]\n", + " for i_label in range(N_labels):\n", + " label_obj[i_label][0] = label_coor_relative[i_label]\n", + " label_obj[i_label][1] = label_flag[i_label]\n", + " \n", + " #print(label_obj)\n", + " \n", + " \n", + " #Rescal the energies with respect to dos_fermi_energy\n", + " for i_k_points in range(N_k_points_all):\n", + " for i_bands in range(N_bands):\n", + " band_energies_all[i_bands][i_k_points] = band_energies_all[i_bands][i_k_points] - dos_fermi_energy\n", + "\n", + " #-------Get VBM, CBM----------------\n", + "\n", + " HOMO = -1000\n", + " LUMO = 1000\n", + " coor_k_point_HOMO = np.zeros((3)) #the coordinate of k point that stores HOMO\n", + " coor_k_point_LUMO = np.zeros((3)) #the coordinate of k point that stores LUMO\n", + " #band_gap_direct = 0.0\n", + " band_gap_indirect = 0.0\n", + " \n", + " \n", + " #band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " #band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " band_energy_max = 10\n", + " band_energy_min = -10\n", + " #N_band_energy_index = 10000\n", + " #band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n", + " #N_allowed_states = np.zeros(N_band_energy_index + 1)\n", + " #i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n", + "\n", + " for i_k_points_all in range(N_k_points_all):\n", + " for i_bands in range(N_bands):\n", + " #i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n", + " #N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n", + " band_energy = band_energies_all[i_bands][i_k_points_all]\n", + " if(band_energy > 0):\n", + " if(band_energy < LUMO):\n", + " LUMO = band_energy\n", + " else:\n", + " if(band_energy > HOMO):\n", + " HOMO = band_energy\n", + " #for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n", + " # if(N_allowed_states[i_band_index] > 0):\n", + " # LUMO = band_energy_min + band_energy_step * i_band_index\n", + " print('HOMO, LUMO: ',HOMO, LUMO)\n", + " band_gap_indirect = abs(LUMO - HOMO)\n", + " \n", + " if(band_gap_indirect < 0.5): #VBM and CBM has to be found in another way for metals/charged system:\n", + " HOMO = -1000\n", + " LUMO = 1000\n", + " band_energy_max = 10\n", + " band_energy_min = 0\n", + " N_band_energy_index = 10000\n", + " band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n", + " N_allowed_states = np.zeros(N_band_energy_index + 1)\n", + " \n", + " #get the DOS and store in N_allowed_states[]\n", + " for i_k_points_all in range(N_k_points_all):\n", + " for i_bands in range(N_bands):\n", + " band_energy = band_energies_all[i_bands][i_k_points_all]\n", + " if(band_energy_min < band_energy < band_energy_max):\n", + " i_band_index = math.floor((band_energy - band_energy_min) / band_energy_step)\n", + " N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1\n", + " if_gapped = 0\n", + " for i_band_index in range(N_band_energy_index): #go through the energy levels from the bottom\n", + " band_energy = band_energy_min + band_energy_step * i_band_index\n", + " if(N_allowed_states[i_band_index] == 0):\n", + " if_gapped = if_gapped + 1\n", + " if(band_energy > band_energy_max - 0.5) and (if_gapped == 0):\n", + " print(\"No gap found in this system. It seems to be a metal.\")\n", + " HOMO = 1000\n", + " LUMO = 1000\n", + " break\n", + " #print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n", + " \n", + " if(N_allowed_states[i_band_index] > 0):\n", + " if(if_gapped * band_energy_step> 0.3 ): #above VBM-CBM gap: LUMO\n", + " if(band_energy < LUMO):\n", + " #print(\"LUMO got!\")\n", + " LUMO = band_energy\n", + " break #break before touching another gap that is above the band gap\n", + " if(if_gapped * band_energy_step < 0.3): #below VBM-CBM gap: HOMO\n", + " if(band_energy > HOMO):\n", + " #print(\"HOMO got!\")\n", + " HOMO = band_energy\n", + " \n", + " if_gapped = 0\n", + " \n", + " print('HOMO, LUMO for metal/charged system: ',HOMO, LUMO)\n", + " \n", + " '''\n", + "\n", + "# print('HOMO: ',tmp_HOMO_max)\n", + " HOMO_global = tmp_HOMO_max\n", + " LUMO_global = tmp_LUMO_min\n", + " band_gap_indirect = LUMO_global - HOMO_global\n", + " E_top_valence = HOMO_global\n", + " if(band_gap_indirect < 0):\n", + " band_gap_indirect = 0\n", + "\n", + " #Rescal HOMO and LUMO with respect to HOMO\n", + " HOMO_global = round((HOMO_global - E_top_valence), 3)\n", + " LUMO_global = round((LUMO_global - E_top_valence), 3)\n", + " '''\n", + " \n", + " \n", + " \n", + " #Find the position of HOMO, LUMO\n", + "\n", + " for i_k_points in range(N_k_points_all):\n", + " for i_bands in range(N_bands):\n", + " if(abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001):\n", + " coor_k_point_HOMO = k_coor_1D[i_k_points]\n", + " if(abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001):\n", + " coor_k_point_LUMO = k_coor_1D[i_k_points] \n", + "\n", + "\n", + " \n", + " \n", + " #Store the band data to band_obj\n", + "\n", + " band_obj = {}\n", + " band_obj[\"band_x_axis\"] = np.array(k_coor_1D).tolist()\n", + " band_obj[\"band_y_axis\"] = np.array(band_energies_all).tolist()\n", + " band_obj[\"labels\"] = np.array(label_obj).tolist()\n", + " band_obj[\"HOMO_energy\"] = np.array(HOMO).tolist()\n", + " band_obj[\"HOMO_coor\"] = np.array(coor_k_point_HOMO).tolist()\n", + " band_obj[\"LUMO_energy\"] = np.array(LUMO).tolist()\n", + " band_obj[\"LUMO_coor\"] = np.array(coor_k_point_LUMO).tolist()\n", + " band_obj[\"average_N_k_points_per_inverse_distance\"] = np.array(average_N_k_points_per_inverse_distance).tolist()\n", + " \n", + "\n", + " \n", + " return band_obj\n", + "\n", + "\n", + "#===============Get the space group information===========\n", + "def get_space_group(band_data):\n", + " import pymatgen as mg\n", + " from pymatgen.symmetry.analyzer import SpacegroupAnalyzer\n", + "\n", + " simulation_cell = np.array(band_data[\"section_run\"][\"section_system\"][0].get('simulation_cell',\"empty\")) * 10000000000\n", + " atom_positions = np.array(band_data[\"section_run\"][\"section_system\"][0].get('atom_positions',\"empty\")) * 10000000000\n", + " atom_labels = np.array(band_data[\"section_run\"][\"section_system\"][0].get('atom_labels',\"empty\"))\n", + " structure = mg.Structure(simulation_cell,atom_labels, atom_positions, coords_are_cartesian = True)\n", + " \n", + " finder = SpacegroupAnalyzer(structure, symprec=1e-3, angle_tolerance=5)\n", + " space_group_symbol = finder.get_space_group_symbol()\n", + " lattice_constant = []\n", + " for item in structure.lattice.abc:\n", + " lattice_constant.append(item)\n", + " for i in range(len(lattice_constant)):\n", + " item = str(round(lattice_constant[i], 3))\n", + " lattice_constant[i] = item\n", + " \n", + " return [space_group_symbol, lattice_constant]\n", + "\n", + "#================Get the DOS data==============================\n", + "def get_dos_obj(dos_path):\n", + " #dos_data: read from json file \n", + " #Load the data files for dos\n", + " dos_data = load_jsonfile(dos_path)\n", + "\n", + " print(dos_path)\n", + " #N_dos_values = len(dos_data['sections']['section_run-0']['sections']['section_single_configuration_calculation-0']['section_dos'][0]['dos_energies'])\n", + " N_dos_values = len(dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'])\n", + " #in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n", + "\n", + " dos_energies = np.zeros((N_dos_values))\n", + " dos_energies_tmp = np.zeros((N_dos_values)) #tmp array for unit convertion\n", + " dos_values = np.zeros((N_dos_values))\n", + "\n", + " dos_energies_tmp = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies']\n", + " dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_values'][0]\n", + " \n", + "\n", + " dos_fermi_energy= dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0].get('dos_fermi_energy',\"empty\")\n", + " if(dos_fermi_energy == \"empty\"): #dos_fermi_energy is not available in EXCITING\n", + " dos_fermi_energy_exciting = dos_data['section_run']['section_single_configuration_calculation'].get('x_exciting_dos_fermi',\"empty\")\n", + " if(dos_fermi_energy_exciting == \"empty\"):\n", + " dos_fermi_energy = 0\n", + " else:\n", + " dos_fermi_energy = dos_fermi_energy_exciting / (1.60217656535 * pow(10,-19))\n", + " else:\n", + " dos_fermi_energy = dos_fermi_energy / (1.60217656535 * pow(10,-19))\n", + " print(\"dos_fermi_energy:\", dos_fermi_energy)\n", + " \n", + " for i_dos_values in range(N_dos_values):\n", + " dos_energies[i_dos_values] = 0.0\n", + " dos_energies[i_dos_values] = dos_energies_tmp[i_dos_values] / (1.60217656535 * pow(10,-19))\n", + " dos_energies[i_dos_values] = round((dos_energies[i_dos_values] - dos_fermi_energy), 3) #reference with the fermi level\n", + "\n", + " dos_obj = {}\n", + " dos_obj[\"dos_x_axis\"] = np.array(dos_energies).tolist()\n", + " dos_obj[\"dos_y_axis\"] = np.array(dos_values).tolist()\n", + " dos_obj[\"dos_fermi_energy\"] = np.array(dos_fermi_energy).tolist()\n", + "\n", + " return dos_obj\n", + "\n", + "\n", + "def get_info_obj(band_path):\n", + "\n", + " #band_data: read from json file \n", + " #Load the data files for band\n", + " band_data = load_jsonfile(band_path)\n", + " info_obj = {}\n", + " #---------Read the information of the calculation--------\n", + " info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n", + " info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n", + " info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n", + " \n", + " #----------Get the space group information----------\n", + " \n", + " [space_group_symbol, lattice_constant] = get_space_group(band_data)\n", + " info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist()\n", + " info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist()\n", + " print(\"space group:\", info_obj[\"space_group_symbol\"])\n", + " print(\"lattice_constant:\", lattice_constant)\n", + " \n", + " return info_obj\n", + "\n", + "\n", + "#============main===========================================\n", + "\n", + "#import matplotlib.pyplot as plt\n", + "band_obj_all = []\n", + "dos_obj_all = []\n", + "info_obj_all = []\n", + "print(\"Number of materials: \", N_materials)\n", + "\n", + "for i in range (N_materials):\n", + " print(\"Material: \", i)\n", + " band_path = band_paths[i]\n", + " dos_path = dos_paths[i]\n", + " \n", + " \n", + " dos_obj = get_dos_obj(dos_path)\n", + " dos_fermi_energy = dos_obj[\"dos_fermi_energy\"]\n", + " band_obj = get_band_obj(band_path, dos_fermi_energy)\n", + " info_obj = get_info_obj(band_path)\n", + " \n", + " band_obj_all.append(band_obj)\n", + " dos_obj_all.append(dos_obj)\n", + " info_obj_all.append(info_obj)\n", + " \n", + " \n", + " print(\"average_N_k_points_per_inverse_distance: \", band_obj[\"average_N_k_points_per_inverse_distance\"])\n", + "\n", + "print(\"Finish processing data.\")\n", + "\n", + "#run_cell_by_tag('save_data_to_js')\n", + "\n", + "print(\"Initialization of visulization finished.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 331, + "metadata": { + "tags": [ + "js_plot" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + " \n", + "var N_max_show = 10; //Number of results to be shown by default\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + " \n", + "var N_max_show = 10; //Number of results to be shown by default\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%javascript\n", + "// BACKUP!\n", + "/*\n", + "//Main plot function for given material:\n", + " function plot_band_dos_i_backup(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n", + " {\n", + " //alert(\"plot_band_dos_i\")\n", + " //i=0;\n", + " lowerLim = -10\n", + " upperLim = 10\n", + " if_show_VBM = 0\n", + " if_compare = 0\n", + " i_in_compare_list = -1\n", + " //i=0;\n", + " var placeholder_band = \"#div_band\" + i.toString();\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var img_band_id = \"img_band\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + " var placeholder_band_compare = \"\";\n", + "\n", + " if(i_in_compare_list == 1)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\";\n", + " }\n", + " else if(i_in_compare_list == 2)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_2\";\n", + " }\n", + " else\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n", + " }\n", + "\n", + " Object.size = function(obj) {\n", + " var size = 0, key;\n", + " for (key in obj) \n", + " {\n", + " if (obj.hasOwnProperty(key)) size++;\n", + " }\n", + " return size;\n", + " };\n", + "\n", + " //Get the number of bands\n", + " //alert(\"Getting band\")\n", + " //alert(band_obj_all)\n", + " //alert(\"band_obj_all got!\")\n", + " var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n", + " var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n", + " alert(band_obj_all[i][\"band_y_axis\"])\n", + " band_plotdata = [];\n", + "\n", + " for(var i_band =0; i_band < N_bands; i_band++)\n", + " {\n", + " var tmp_data = [];\n", + " for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n", + " {\n", + " tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n", + " }\n", + " plotData = { shadowSize: 0 , data: tmp_data, color: 'black', series: { lines: { show: true } , points: {show: false} } };\n", + " band_plotdata.push(plotData);\n", + " }\n", + "\n", + "\n", + " var tmp_data0 = [[0, 0], [1, 0]];\n", + " plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n", + " band_plotdata.push(plotData0);\n", + "\n", + " band_plotdata_overview = band_plotdata.slice(0);\n", + "\n", + " var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n", + " HOMOlabel = [\"VBM\"];\n", + " plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false}, showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n", + " LUMOlabel = [\"CBM\"];\n", + " plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false}, showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + " if (if_show_VBM == 1)\n", + " {\n", + " band_plotdata.push(plotHOMO);\n", + " band_plotdata.push(plotLUMO);\n", + " }\n", + "\n", + " \n", + " alert(img_band_id + band_plotdata)\n", + " \n", + " //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n", + " //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\" }\n", + "\n", + " var canvas_band;\n", + " var options_band = {\n", + " canvas: true,\n", + " //legend:{ type: \"canvas\" },\n", + " series: { lines: { show: true, lineWidth: 2 }, \n", + " points: { show: false } }, \n", + " xaxis: { \n", + " ticks: band_obj_all[i][\"labels\"], \n", + " color:\"#000\", \n", + " font: {size: 20}, \n", + " zoomRange: false,\n", + " panRange: false \n", + " }, \n", + " yaxis: { \n", + " axisLabel: \"Energy (eV)\", \n", + " axisLabelUseCanvas: true,\n", + " //axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20, family:\"Arial\"},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " zoom: { \n", + " interactive: true\n", + " },\n", + "\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n", + "\n", + " grid: { \n", + " labelMargin: 15,\n", + " hoverable: true, \n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n", + " borderWidth: {\n", + " top: 2, \n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null } \n", + " }\n", + " }\n", + " //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n", + " //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n", + " var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n", + " image_band = plot_band.toDataURL();\n", + " image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n", + " //beakerx.image_band = image_band;\n", + " document.getElementById(img_band_id).href= image_band;\n", + " image_band_links[i] = image_band;\n", + " alert(\"band plot done.\")\n", + "\n", + "\n", + " //----Plot DOS----------------------\n", + " var dos_plotdata = [];\n", + " alert(\"dos:\"+dos_obj_all[i])\n", + " var xdos = dos_obj_all[i][\"dos_x_axis\"];\n", + " var ydos = dos_obj_all[i][\"dos_y_axis\"];\n", + " var dosLabelPos = Math.max.apply(Math, ydos)/2;\n", + " var d2 = [];\n", + " for (var ii = 0; ii < xdos.length; ii+=1) {\n", + " d2.push([ydos[ii],xdos[ii]]);\n", + " }\n", + " var plotData2={ shadowSize: 0, color: 'black' , data: d2}\n", + " dos_plotdata.push(plotData2)\n", + "\n", + " function find_xaxis_max_min(data, lowerbound, upperbound)\n", + " {\n", + " //data[xaxis,y] find the max and min value of x axis\n", + " //alert(\"dos[0]:\" + data[0][\"data\"]);\n", + " //alert(\"Bounds: \" + lowerbound + \" , \" + upperbound)\n", + " var n_data = data.length;\n", + " //alert(\"N dos: \" + n_data);\n", + " var data_min = 1000000;\n", + " var data_max = -1000000;\n", + " var data_current = 0;\n", + " for (var i = 0; i < n_data; i++)\n", + " {\n", + " if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n", + " {\n", + " data_current = data[i][0];\n", + " //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n", + " if(data_current >= data_max)\n", + " {\n", + " data_max = data_current;\n", + " }\n", + " if(data_current <= data_min)\n", + " {\n", + " data_min = data_current;\n", + " }\n", + " }\n", + " }\n", + " var data_max_min = [data_max, data_min];\n", + " //alert(\"data_max_min: \" + data_max_min);\n", + " return data_max_min;\n", + " }\n", + " var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n", + " var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n", + "\n", + " var options_dos ={\n", + " canvas: true,\n", + " series: {\n", + " lines: { show: true, lineWidth:2 },\n", + " points: { show: false }\n", + " },\n", + "\n", + " yaxis: { \n", + " axisLabel: \"\", \n", + " axisLabelUseCanvas: true,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " xaxis: {\n", + " axisLabel: \" \",\n", + " axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial',\n", + " axisLabelPadding: 3,\n", + " color:\"rgb(0, 0, 0)\",\n", + " font: {size: 20, family:\"Arial\"},\n", + " //ticks: 10,\n", + " tickLength:0,\n", + " min: dos_x_max_min[1],//0,\n", + " max: dos_x_max_min[0],//1,\n", + " tickDecimals: 0,\n", + " ticks: [[ dosLabelPos ,'DOS']],\n", + " //tickFormatter: MyFormatter\n", + " panRange: false\n", + " },\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " grid: {\n", + " labelMargin: 15,\n", + " hoverable: true,\n", + " //borderWidth : 1000,\n", + " //show : false,\n", + " // //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n", + " borderWidth: {\n", + " top: 2,\n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null\n", + " }\n", + " }\n", + " }\n", + " var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n", + " var image_dos = plot_dos.toDataURL();\n", + " image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n", + " image_dos = image_dos;\n", + " document.getElementById(img_dos_id).href= image_dos;\n", + " \n", + " }\n", + "*/" + ] + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.7" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": false, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Nomad_tutorial_head.png b/Nomad_tutorial_head.png new file mode 100644 index 0000000000000000000000000000000000000000..c31c475de3e3e8df2e858a511b924b65d14a32ee GIT binary patch literal 52856 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 HB{Ts5c2)~Y literal 0 HcmV?d00001 diff --git a/band_structure_visualization.ipynb b/band_structure_visualization.ipynb new file mode 100644 index 0000000..b2c4549 --- /dev/null +++ b/band_structure_visualization.ipynb @@ -0,0 +1,4968 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "init_cell": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "<style>.container { width:100% !important; }</style>" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.core.display import display, HTML\n", + "display(HTML(\"<style>.container { width:100% !important; }</style>\"))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "init_cell": true + }, + "outputs": [], + "source": [ + "from IPython.core.display import Javascript\n", + "from IPython.display import display\n", + "\n", + "def run_cell_by_tag(tags):\n", + " display(Javascript(\"window.runCells('\"+tags+\"')\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "init_cell": true, + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script>\n", + " code_show=true; \n", + " function code_toggle() {\n", + " if (code_show)\n", + " {\n", + " $('div.input').hide();\n", + " } \n", + " else \n", + " {\n", + " $('div.input').show();\n", + " }\n", + " code_show = !code_show\n", + " } \n", + " $( document ).ready(code_toggle);\n", + "</script>\n", + "The raw code for this notebook is by default hidden for easier reading.\n", + "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>.\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script>\n", + " code_show=true; \n", + " function code_toggle() {\n", + " if (code_show)\n", + " {\n", + " $('div.input').hide();\n", + " } \n", + " else \n", + " {\n", + " $('div.input').show();\n", + " }\n", + " code_show = !code_show\n", + " } \n", + " $( document ).ready(code_toggle);\n", + "</script>\n", + "The raw code for this notebook is by default hidden for easier reading.\n", + "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "init_cell": true, + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "<div align=\"left\" style=\"background-color: rgba(149,170,79, 1.0); width: 100%; height: 390px; overflow: hidden;\">\n", + " <div >\n", + " <table>\n", + " <tr></tr>\n", + " <tr>\n", + " <td><img src=\"Nomad_tutorial_head.png\"></td>\n", + " </tr>\n", + " </table>\n", + " </div>\n", + "\n", + " <br><br>\n", + " <div style=\"position:relative; left:3%\"><font size=6em color=\"#20335d\" ><b> - Visualization of the band structure of materials </b></font></div>\n", + " <p style=\"position:relative;left:10%; \">\n", + " <br>\n", + " Created by:\n", + "\n", + " Xiangyue Liu<sup>1</sup>(<a href=\"mailto:xyliu@fhi-berlin.mpg.de\">email</a>),\n", + " \n", + " Fawzi Mohamed<sup>1</sup>,\n", + " \n", + " and Luca M. Ghiringhelli<sup>1</sup>(<a href=\"mailto:ghiringhelli@fhi-berlin.mpg.de\">email</a>), <br>\n", + "\n", + " <br><br>\n", + " <sup>1</sup> Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n", + " <br>\n", + "\n", + "\n", + " </p>\n", + " <br>\n", + " <div style=\"position:relative;bottom:3%\">\n", + " <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#999999\" size=\"10em\">v2.0.0</font></div>\n", + " <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#666666\" size=\"2.7em\">[Last updated: August 5, 2019]</font></div>\n", + " </div>\n", + "\n", + "</div>\n", + "\n", + "\n", + "<div style='text-align: right;'>\n", + " <a href=\"https://analytics-toolkit.nomad-coe.eu/home/\" class=\"btn btn-primary\" style=\"font-size:larger;\">Back to Analytics Home</a> \n", + " <a href=\"https://www.nomad-coe.eu/\" class=\"btn btn-primary\" style=\"font-size:larger; \">Back to nomad-coe</a> \n", + "</div>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "\n", + "\n", + "<div align=\"left\" style=\"background-color: rgba(149,170,79, 1.0); width: 100%; height: 390px; overflow: hidden;\">\n", + " <div >\n", + " <table>\n", + " <tr></tr>\n", + " <tr>\n", + " <td><img src=\"Nomad_tutorial_head.png\"></td>\n", + " </tr>\n", + " </table>\n", + " </div>\n", + "\n", + " <br><br>\n", + " <div style=\"position:relative; left:3%\"><font size=6em color=\"#20335d\" ><b> - Visualization of the band structure of materials </b></font></div>\n", + " <p style=\"position:relative;left:10%; \">\n", + " <br>\n", + " Created by:\n", + "\n", + " Xiangyue Liu<sup>1</sup>(<a href=\"mailto:xyliu@fhi-berlin.mpg.de\">email</a>),\n", + " \n", + " Fawzi Mohamed<sup>1</sup>,\n", + " \n", + " and Luca M. Ghiringhelli<sup>1</sup>(<a href=\"mailto:ghiringhelli@fhi-berlin.mpg.de\">email</a>), <br>\n", + "\n", + " <br><br>\n", + " <sup>1</sup> Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n", + " <br>\n", + "\n", + "\n", + " </p>\n", + " <br>\n", + " <div style=\"position:relative;bottom:3%\">\n", + " <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#999999\" size=\"10em\">v2.0.0</font></div>\n", + " <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#666666\" size=\"2.7em\">[Last updated: August 5, 2019]</font></div>\n", + " </div>\n", + "\n", + "</div>\n", + "\n", + "\n", + "<div style='text-align: right;'>\n", + " <a href=\"https://analytics-toolkit.nomad-coe.eu/home/\" class=\"btn btn-primary\" style=\"font-size:larger;\">Back to Analytics Home</a> \n", + " <a href=\"https://www.nomad-coe.eu/\" class=\"btn btn-primary\" style=\"font-size:larger; \">Back to nomad-coe</a> \n", + "</div>\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "init_cell": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script>\n", + " window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n", + " return (Jupyter.notebook.get_cells()\n", + " .filter(\n", + " ({metadata: {tags}}) => tags && tags.includes(tagName)\n", + " )\n", + " .map((cell) => Jupyter.notebook.find_cell_index(cell))\n", + " );\n", + " };\n", + "\n", + "\n", + " window.runCells = function runPlotCells(tags) {\n", + " var c = window.findCellIndicesByTag(tags);\n", + " Jupyter.notebook.execute_cells(c);\n", + " };\n", + "</script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script>\n", + " window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n", + " return (Jupyter.notebook.get_cells()\n", + " .filter(\n", + " ({metadata: {tags}}) => tags && tags.includes(tagName)\n", + " )\n", + " .map((cell) => Jupyter.notebook.find_cell_index(cell))\n", + " );\n", + " };\n", + "\n", + "\n", + " window.runCells = function runPlotCells(tags) {\n", + " var c = window.findCellIndicesByTag(tags);\n", + " Jupyter.notebook.execute_cells(c);\n", + " };\n", + "</script>" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "init_cell": true, + "tags": [ + "search_materials" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<br><br>\n", + "\n", + "<p style=\"color: #20335d;font-weight: 450; font-size: 14pt;font-family: Arial;\"> This tutorial visulizes the band structures and density of states (DOS) of the NOMAD materials.</p>\n", + "<br><br>\n", + "\n", + "<style>\n", + ".button {\n", + " background-color: #e7e7e7;\n", + " border: 0.5px solid #A4A4A4;\n", + " color: black;\n", + " padding: 15px 32px;\n", + " text-align: center;\n", + " text-decoration: none;\n", + " display: inline-block;\n", + " font-family: Arial;\n", + " font-size: 16px;\n", + " margin: 4px 2px;\n", + " cursor: pointer;\n", + "}\n", + "\n", + " .text-normal-black{\n", + " color: #000;font-weight: 200; font-size: 10pt;\n", + " font-family: Arial;\n", + " }\n", + " .div_band_dos{\n", + " box-sizing: border-box;\n", + " width: 100%;\n", + " height: 600px;\n", + " font-weight: 100;\n", + " font-family: Arial;\n", + " padding-left: 20px;\n", + " padding-top: 10px;\n", + " padding-right: 1em;\n", + " margin: 0;\n", + " border: 0;\n", + " }\n", + " .div_band_dos_compare{\n", + " box-sizing: border-box;\n", + " width: 1600px;\n", + " height: 600px;\n", + " color: #00AEFF;\n", + " font-weight: 100;\n", + " font-family: Arial;\n", + " padding-left: 20px;\n", + " padding-top: 10px;\n", + " padding-right: 1em;\n", + " margin: 0;\n", + " border: 0;\n", + " }\n", + " .div_band{\n", + " font-family: Arial;\n", + " font-size: 0.875em;\n", + " width: 37%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " float:left;\n", + " }\n", + " .div_dos{\n", + " font-family: Arial;\n", + " font-size: 0.875em;\n", + " width: 13%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " float:left;\n", + " }\n", + " .div_tools{\n", + " color: #20335d;font-weight: 150; font-size: 13pt;\n", + " width: 35%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " margin-left:20pt;\n", + " float:left;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .div_checkbox_compare{\n", + " color: #888;font-weight: 150; font-size: 12pt;\n", + " width: 10%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " border: solid #fff 1px;\n", + " float:right;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .div_overview{\n", + " width: 300px;\n", + " height: 200px;\n", + " background-color: #fff;\n", + " margin-left:10px; \n", + " margin-top: 20px;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .button_tools {\n", + " background-color: #F0F0F0;\n", + " border: 0.5px solid #A4A4A4;\n", + " color: black;\n", + " padding: 10px 15px;\n", + " text-align: center;\n", + " text-decoration: none;\n", + " display: inline-block;\n", + " font-size: 16px;\n", + " margin: 4px 2px;\n", + " cursor: pointer;\n", + " font-family: Arial;\n", + "\n", + " }\n", + "\n", + " \n", + " .g-before-after{position:relative;overflow:hidden;width:500px}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%}\n", + "</style>\n", + "\n", + "<script>\n", + " //Search for certain keyword: https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\n", + " //FjiYy5-ETRCrs5ktzJA55w/bOY0cPkBvvNAY7pZdbginlKXJ2kF\n", + " //\"upload_id\"/\"calc_id\"\n", + " \n", + " //Global variables\n", + " var paths_section_k_band_segment = []; \n", + " var paths_section_dos = [];\n", + " var band_obj_all = [];\n", + " var dos_obj_all = [];\n", + " var info_obj_all = [];\n", + " \n", + " var band_paths = [];\n", + " var dos_paths = [];\n", + " var N_materials = 0; //Number of materials that have both band and DOS in the same calculation \n", + " \n", + " \n", + " function getJSON(url) {\n", + " var resp ;\n", + " var xmlHttp ;\n", + "\n", + " resp = '' ;\n", + " xmlHttp = new XMLHttpRequest();\n", + "\n", + " if(xmlHttp != null)\n", + " {\n", + " xmlHttp.open( \"GET\", url, false );\n", + " xmlHttp.send( null );\n", + " resp = xmlHttp.responseText;\n", + " }\n", + "\n", + " return resp;\n", + " }\n", + " function match_band_dos()\n", + " {\n", + " //TMP for local tests\n", + " /*\n", + " paths_section_k_band_segment = [\"data/kOJR-AlPSgiNG9AdZoxd4g_9mxjIU0edrPosfsTc4uyDG9H_UXr.json\",\"data/kOJR-AlPSgiNG9AdZoxd4g_lfkGCmWozYENeiGhu5W7dJUqLTkj.json\"];\n", + " paths_section_dos = [\"data/kOJR-AlPSgiNG9AdZoxd4g_8tEGnaz0yY91eSyysKZkIUH9qx8J.json\", \"data/kOJR-AlPSgiNG9AdZoxd4g_lxUT3viRZcC_1IsH_KvO5tChAtV1.json\"];\n", + " */\n", + "\n", + " //band_paths = [];\n", + " //dos_paths = [];\n", + " //N_materials = 0; \n", + " \n", + " var data_k_band = [];\n", + " for(var i_path_k_band = 0; i_path_k_band < paths_section_k_band_segment.length; i_path_k_band ++)\n", + " {\n", + " var i_data_k_band_json = JSON.parse(getJSON(paths_section_k_band_segment[i_path_k_band]));\n", + " var i_data_k_band = {};\n", + " i_data_k_band[\"program_name\"] = i_data_k_band_json[\"section_run\"][\"program_name\"];\n", + " i_data_k_band[\"k_mesh_points\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n", + " i_data_k_band[\"simulation_cell\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n", + " i_data_k_band[\"atom_positions\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n", + " i_data_k_band[\"atom_labels\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " i_data_k_band[\"XC_functional_name\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n", + " i_data_k_band[\"path\"] = paths_section_k_band_segment[i_path_k_band];\n", + " data_k_band.push(i_data_k_band);\n", + " }\n", + "\n", + " var data_dos = [];\n", + " for(var i_path_dos = 0; i_path_dos < paths_section_dos.length; i_path_dos ++)\n", + " {\n", + " var i_data_dos_json = JSON.parse(getJSON(paths_section_dos[i_path_dos]));\n", + " var i_data_dos = {};\n", + " i_data_dos[\"program_name\"] = i_data_dos_json[\"section_run\"][\"program_name\"];\n", + " i_data_dos[\"k_mesh_points\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n", + " i_data_dos[\"simulation_cell\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n", + " i_data_dos[\"atom_positions\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n", + " i_data_dos[\"atom_labels\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " i_data_dos[\"XC_functional_name\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n", + " i_data_dos[\"path\"] = paths_section_dos[i_path_dos];\n", + " data_dos.push(i_data_dos); \n", + " }\n", + "\n", + " //Matching: band[i] ~ dos[i] (the same systems are arranged with the same index)\n", + " band_paths = [];\n", + " dos_paths = [];\n", + " N_materials = 0;\n", + " for(var i_k_band = 0; i_k_band < data_k_band.length; i_k_band ++)\n", + " {\n", + " for(var i_dos = 0; i_dos < data_dos.length; i_dos ++)\n", + " {\n", + " if(data_k_band[i_k_band][\"program_name\"] != data_dos[i_dos][\"program_name\"])\n", + " continue; \n", + " //if(data_k_band[i_k_band][\"k_mesh_points\"].join() != data_dos[i_dos][\"k_mesh_points\"].join())\n", + " // continue;\n", + " if(data_k_band[i_k_band][\"simulation_cell\"].join() != data_dos[i_dos][\"simulation_cell\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"atom_positions\"].join() != data_dos[i_dos][\"atom_positions\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"atom_labels\"].join() != data_dos[i_dos][\"atom_labels\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"XC_functional_name\"] != data_dos[i_dos][\"XC_functional_name\"])\n", + " continue;\n", + " band_paths.push(data_k_band[i_k_band][\"path\"]);\n", + " dos_paths.push(data_dos[i_dos][\"path\"]);\n", + " N_materials ++;\n", + " }\n", + " }\n", + " //Pass the arrays to python\n", + "\n", + " var command = \"N_materials = \" + N_materials + \";\"\n", + " var kernel = IPython.notebook.kernel;\n", + " command += \"band_paths = \" + \"[\\'\" + band_paths.join(\"\\',\\'\") + \"\\'];\";\n", + " command += \"dos_paths = \" + \"[\\'\" + dos_paths.join(\"\\',\\'\") + \"\\'];\";\n", + " kernel.execute(command);\n", + " \n", + " \n", + " }\n", + "\n", + " function get_paths_from_search_results(result_json, div_id_search_results,div_head)\n", + " {\n", + " paths = [];\n", + " search_results_content = [div_head, '<table>', '<tr><th>Chemical formula</th><th>Spacegroup</th><th>Code</th><th>XC functional</th><th>Upload ID</th><th>Calculation ID</th><th>URL</th></tr>'];\n", + " for(var i_key in result_json)\n", + " {\n", + " if(i_key == \"results\")\n", + " {\n", + " for(var system in result_json[i_key])\n", + " {\n", + " //Get the path to the data files (json): https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/upload_id/calc_id \n", + " path = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/\" + result_json[i_key][system][\"upload_id\"] + \"/\" + result_json[i_key][system][\"calc_id\"]\n", + " paths.push(path);\n", + " \n", + " //Show the results in div\n", + " // \"formula\" \"spacegroup_symbol\" \"code_name\" \"xc_functional\"\n", + " content = '<tr>';\n", + " content += '<td>' + result_json[i_key][system][\"formula\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"spacegroup_symbol\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"code_name\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"xc_functional\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"upload_id\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"calc_id\"] + '</td>'; \n", + " content += '<td>' + path + '</td>';\n", + " content += '</tr>';\n", + " search_results_content.push(content);\n", + " }\n", + " }\n", + " }\n", + " search_results_content.push('</table>');\n", + " document.getElementById(div_id_search_results).innerHTML = search_results_content.join('');\n", + " return paths\n", + " }\n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " function submit_search()\n", + " {\n", + " \n", + " var result;\n", + " var formula = document.getElementById(\"keyword_chemical_formula\").value;\n", + " var query_command_k_band = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_k_band_segment\";\n", + " var query_command_dos = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_dos\";\n", + " //result = getJSON(\"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\");\n", + " var result_k_band = getJSON(query_command_k_band);\n", + " var result_dos = getJSON(query_command_dos);\n", + " var result_json_k_band = JSON.parse(result_k_band);//parse the searching results to json from URL\n", + " var result_json_dos = JSON.parse(result_dos);\n", + " paths_section_k_band_segment = []; \n", + " paths_section_dos = [];\n", + " paths_section_k_band_segment = get_paths_from_search_results(result_json_k_band, \"search_results_section_k_band_segment\", \"<br><br><font size=4em>Calculations containing band structures:</font><br>\");\n", + " paths_section_dos = get_paths_from_search_results(result_json_dos, \"search_results_section_dos\", \"<br><font size=4em>Calculations containing DOS:</font><br>\");\n", + " \n", + " var promise = Promise.resolve();\n", + " promise\n", + " .then(match_band_dos())\n", + " .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')))\n", + " .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')));\n", + " \n", + " //match_band_dos();\n", + " \n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')); //Read the json files, and prepare data for plot\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')); //Prepare for plot\n", + " }\n", + " function reset_search()\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('search_materials'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot'));\n", + " }\n", + " \n", + " \n", + "</script>\n", + "<font size=4em>Please input the chemical formula:</font>\n", + "<input type=\"text\" id=\"keyword_chemical_formula\" value=\"AlInO3\"> \n", + "<button class=\"button\" onclick=\"submit_search()\">Search</button>\n", + "<button class=\"button\" onclick=\"reset_search()\">Reset</button>\n", + "<br><br><br>\n", + "<div id=\"search_results_section_k_band_segment\"></div>\n", + "<div id=\"search_results_section_dos\"></div>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%html\n", + "<br><br>\n", + "\n", + "<p style=\"color: #20335d;font-weight: 450; font-size: 14pt;font-family: Arial;\"> This tutorial visulizes the band structures and density of states (DOS) of the NOMAD materials.</p>\n", + "<br><br>\n", + "\n", + "<style>\n", + ".button {\n", + " background-color: #e7e7e7;\n", + " border: 0.5px solid #A4A4A4;\n", + " color: black;\n", + " padding: 15px 32px;\n", + " text-align: center;\n", + " text-decoration: none;\n", + " display: inline-block;\n", + " font-family: Arial;\n", + " font-size: 16px;\n", + " margin: 4px 2px;\n", + " cursor: pointer;\n", + "}\n", + "\n", + " .text-normal-black{\n", + " color: #000;font-weight: 200; font-size: 10pt;\n", + " font-family: Arial;\n", + " }\n", + " .div_band_dos{\n", + " box-sizing: border-box;\n", + " width: 100%;\n", + " height: 600px;\n", + " font-weight: 100;\n", + " font-family: Arial;\n", + " padding-left: 20px;\n", + " padding-top: 10px;\n", + " padding-right: 1em;\n", + " margin: 0;\n", + " border: 0;\n", + " }\n", + " .div_band_dos_compare{\n", + " box-sizing: border-box;\n", + " width: 1600px;\n", + " height: 600px;\n", + " color: #00AEFF;\n", + " font-weight: 100;\n", + " font-family: Arial;\n", + " padding-left: 20px;\n", + " padding-top: 10px;\n", + " padding-right: 1em;\n", + " margin: 0;\n", + " border: 0;\n", + " }\n", + " .div_band{\n", + " font-family: Arial;\n", + " font-size: 0.875em;\n", + " width: 37%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " float:left;\n", + " }\n", + " .div_dos{\n", + " font-family: Arial;\n", + " font-size: 0.875em;\n", + " width: 13%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " float:left;\n", + " }\n", + " .div_tools{\n", + " color: #20335d;font-weight: 150; font-size: 13pt;\n", + " width: 35%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " margin-left:20pt;\n", + " float:left;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .div_checkbox_compare{\n", + " color: #888;font-weight: 150; font-size: 12pt;\n", + " width: 10%;\n", + " height: 80%;\n", + " background-color: #fff;\n", + " border: solid #fff 1px;\n", + " float:right;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .div_overview{\n", + " width: 300px;\n", + " height: 200px;\n", + " background-color: #fff;\n", + " margin-left:10px; \n", + " margin-top: 20px;\n", + " font-family: Arial;\n", + "\n", + " }\n", + " .button_tools {\n", + " background-color: #F0F0F0;\n", + " border: 0.5px solid #A4A4A4;\n", + " color: black;\n", + " padding: 10px 15px;\n", + " text-align: center;\n", + " text-decoration: none;\n", + " display: inline-block;\n", + " font-size: 16px;\n", + " margin: 4px 2px;\n", + " cursor: pointer;\n", + " font-family: Arial;\n", + "\n", + " }\n", + "\n", + " \n", + " .g-before-after{position:relative;overflow:hidden;width:500px}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%}\n", + "</style>\n", + "\n", + "<script>\n", + " //Search for certain keyword: https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\n", + " //FjiYy5-ETRCrs5ktzJA55w/bOY0cPkBvvNAY7pZdbginlKXJ2kF\n", + " //\"upload_id\"/\"calc_id\"\n", + " \n", + " //Global variables\n", + " var paths_section_k_band_segment = []; \n", + " var paths_section_dos = [];\n", + " var band_obj_all = [];\n", + " var dos_obj_all = [];\n", + " var info_obj_all = [];\n", + " \n", + " var band_paths = [];\n", + " var dos_paths = [];\n", + " var N_materials = 0; //Number of materials that have both band and DOS in the same calculation \n", + " \n", + " \n", + " function getJSON(url) {\n", + " var resp ;\n", + " var xmlHttp ;\n", + "\n", + " resp = '' ;\n", + " xmlHttp = new XMLHttpRequest();\n", + "\n", + " if(xmlHttp != null)\n", + " {\n", + " xmlHttp.open( \"GET\", url, false );\n", + " xmlHttp.send( null );\n", + " resp = xmlHttp.responseText;\n", + " }\n", + "\n", + " return resp;\n", + " }\n", + " function match_band_dos()\n", + " {\n", + " //TMP for local tests\n", + " /*\n", + " paths_section_k_band_segment = [\"data/kOJR-AlPSgiNG9AdZoxd4g_9mxjIU0edrPosfsTc4uyDG9H_UXr.json\",\"data/kOJR-AlPSgiNG9AdZoxd4g_lfkGCmWozYENeiGhu5W7dJUqLTkj.json\"];\n", + " paths_section_dos = [\"data/kOJR-AlPSgiNG9AdZoxd4g_8tEGnaz0yY91eSyysKZkIUH9qx8J.json\", \"data/kOJR-AlPSgiNG9AdZoxd4g_lxUT3viRZcC_1IsH_KvO5tChAtV1.json\"];\n", + " */\n", + "\n", + " //band_paths = [];\n", + " //dos_paths = [];\n", + " //N_materials = 0; \n", + " \n", + " var data_k_band = [];\n", + " for(var i_path_k_band = 0; i_path_k_band < paths_section_k_band_segment.length; i_path_k_band ++)\n", + " {\n", + " var i_data_k_band_json = JSON.parse(getJSON(paths_section_k_band_segment[i_path_k_band]));\n", + " var i_data_k_band = {};\n", + " i_data_k_band[\"program_name\"] = i_data_k_band_json[\"section_run\"][\"program_name\"];\n", + " i_data_k_band[\"k_mesh_points\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n", + " i_data_k_band[\"simulation_cell\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n", + " i_data_k_band[\"atom_positions\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n", + " i_data_k_band[\"atom_labels\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " i_data_k_band[\"XC_functional_name\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n", + " i_data_k_band[\"path\"] = paths_section_k_band_segment[i_path_k_band];\n", + " data_k_band.push(i_data_k_band);\n", + " }\n", + "\n", + " var data_dos = [];\n", + " for(var i_path_dos = 0; i_path_dos < paths_section_dos.length; i_path_dos ++)\n", + " {\n", + " var i_data_dos_json = JSON.parse(getJSON(paths_section_dos[i_path_dos]));\n", + " var i_data_dos = {};\n", + " i_data_dos[\"program_name\"] = i_data_dos_json[\"section_run\"][\"program_name\"];\n", + " i_data_dos[\"k_mesh_points\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n", + " i_data_dos[\"simulation_cell\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n", + " i_data_dos[\"atom_positions\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n", + " i_data_dos[\"atom_labels\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " i_data_dos[\"XC_functional_name\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n", + " i_data_dos[\"path\"] = paths_section_dos[i_path_dos];\n", + " data_dos.push(i_data_dos); \n", + " }\n", + "\n", + " //Matching: band[i] ~ dos[i] (the same systems are arranged with the same index)\n", + " band_paths = [];\n", + " dos_paths = [];\n", + " N_materials = 0;\n", + " for(var i_k_band = 0; i_k_band < data_k_band.length; i_k_band ++)\n", + " {\n", + " for(var i_dos = 0; i_dos < data_dos.length; i_dos ++)\n", + " {\n", + " if(data_k_band[i_k_band][\"program_name\"] != data_dos[i_dos][\"program_name\"])\n", + " continue; \n", + " //if(data_k_band[i_k_band][\"k_mesh_points\"].join() != data_dos[i_dos][\"k_mesh_points\"].join())\n", + " // continue;\n", + " if(data_k_band[i_k_band][\"simulation_cell\"].join() != data_dos[i_dos][\"simulation_cell\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"atom_positions\"].join() != data_dos[i_dos][\"atom_positions\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"atom_labels\"].join() != data_dos[i_dos][\"atom_labels\"].join())\n", + " continue;\n", + " if(data_k_band[i_k_band][\"XC_functional_name\"] != data_dos[i_dos][\"XC_functional_name\"])\n", + " continue;\n", + " band_paths.push(data_k_band[i_k_band][\"path\"]);\n", + " dos_paths.push(data_dos[i_dos][\"path\"]);\n", + " N_materials ++;\n", + " }\n", + " }\n", + " //Pass the arrays to python\n", + "\n", + " var command = \"N_materials = \" + N_materials + \";\"\n", + " var kernel = IPython.notebook.kernel;\n", + " command += \"band_paths = \" + \"[\\'\" + band_paths.join(\"\\',\\'\") + \"\\'];\";\n", + " command += \"dos_paths = \" + \"[\\'\" + dos_paths.join(\"\\',\\'\") + \"\\'];\";\n", + " kernel.execute(command);\n", + " \n", + " \n", + " }\n", + "\n", + " function get_paths_from_search_results(result_json, div_id_search_results,div_head)\n", + " {\n", + " paths = [];\n", + " search_results_content = [div_head, '<table>', '<tr><th>Chemical formula</th><th>Spacegroup</th><th>Code</th><th>XC functional</th><th>Upload ID</th><th>Calculation ID</th><th>URL</th></tr>'];\n", + " for(var i_key in result_json)\n", + " {\n", + " if(i_key == \"results\")\n", + " {\n", + " for(var system in result_json[i_key])\n", + " {\n", + " //Get the path to the data files (json): https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/upload_id/calc_id \n", + " path = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/\" + result_json[i_key][system][\"upload_id\"] + \"/\" + result_json[i_key][system][\"calc_id\"]\n", + " paths.push(path);\n", + " \n", + " //Show the results in div\n", + " // \"formula\" \"spacegroup_symbol\" \"code_name\" \"xc_functional\"\n", + " content = '<tr>';\n", + " content += '<td>' + result_json[i_key][system][\"formula\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"spacegroup_symbol\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"code_name\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"xc_functional\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"upload_id\"] + '</td>';\n", + " content += '<td>' + result_json[i_key][system][\"calc_id\"] + '</td>'; \n", + " content += '<td>' + path + '</td>';\n", + " content += '</tr>';\n", + " search_results_content.push(content);\n", + " }\n", + " }\n", + " }\n", + " search_results_content.push('</table>');\n", + " document.getElementById(div_id_search_results).innerHTML = search_results_content.join('');\n", + " return paths\n", + " }\n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " function submit_search()\n", + " {\n", + " \n", + " var result;\n", + " var formula = document.getElementById(\"keyword_chemical_formula\").value;\n", + " var query_command_k_band = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_k_band_segment\";\n", + " var query_command_dos = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_dos\";\n", + " //result = getJSON(\"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\");\n", + " var result_k_band = getJSON(query_command_k_band);\n", + " var result_dos = getJSON(query_command_dos);\n", + " var result_json_k_band = JSON.parse(result_k_band);//parse the searching results to json from URL\n", + " var result_json_dos = JSON.parse(result_dos);\n", + " paths_section_k_band_segment = []; \n", + " paths_section_dos = [];\n", + " paths_section_k_band_segment = get_paths_from_search_results(result_json_k_band, \"search_results_section_k_band_segment\", \"<br><br><font size=4em>Calculations containing band structures:</font><br>\");\n", + " paths_section_dos = get_paths_from_search_results(result_json_dos, \"search_results_section_dos\", \"<br><font size=4em>Calculations containing DOS:</font><br>\");\n", + " \n", + " var promise = Promise.resolve();\n", + " promise\n", + " .then(match_band_dos())\n", + " .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')))\n", + " .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')));\n", + " \n", + " //match_band_dos();\n", + " \n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')); //Read the json files, and prepare data for plot\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')); //Prepare for plot\n", + " }\n", + " function reset_search()\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('search_materials'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot'));\n", + " }\n", + " \n", + " \n", + "</script>\n", + "<font size=4em>Please input the chemical formula:</font>\n", + "<input type=\"text\" id=\"keyword_chemical_formula\" value=\"AlInO3\"> \n", + "<button class=\"button\" onclick=\"submit_search()\">Search</button>\n", + "<button class=\"button\" onclick=\"reset_search()\">Reset</button>\n", + "<br><br><br>\n", + "<div id=\"search_results_section_k_band_segment\"></div>\n", + "<div id=\"search_results_section_dos\"></div>\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "tags": [ + "process_band_dos_data" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script>\n", + " var band_obj_all = [];\n", + " var dos_obj_all = [];\n", + " var info_obj_all = [];\n", + " //alert(\"process_band_dos_data: \" +band_paths)\n", + " //alert(\"process_band_dos_data: \" +info_obj_all)\n", + " function get_label_flag(coor_array)\n", + " {\n", + " var coor = coor_array.sort().join();\n", + " if(coor == '0,0.5,0.5')\n", + " return \"X\";\n", + " if(coor == '0,0,0.5')\n", + " return \"M\";\n", + " else if(coor == '0.5,0.5,0.5')\n", + " return \"L\";\n", + " else if(coor == '0.375,0.375,0.75')\n", + " return \"K\";\n", + " else if(coor == '0.25,0.5,0.75')\n", + " return \"W\";\n", + " else if(coor == '0,0,0')\n", + " return \"\\u0393\";\n", + " else if(coor == '0.25,0.625,0.625')\n", + " return \"U\";\n", + " else\n", + " {\n", + " //alert(\"k label not found: \" + coor);\n", + " return \"?\";\n", + " }\n", + " }\n", + "\n", + "\n", + " //============Process the band structure data============\n", + " function get_band_obj(band_path, dos_fermi_energy)\n", + " {\n", + " var band_data = JSON.parse(getJSON(band_path));\n", + "\n", + " //---------Read section_k_band_segment------------\n", + " var section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n", + "\n", + " //--------Get the number of k band segments-------------\n", + " var N_k_band_segments = section_k_band_segment.length;\n", + "\n", + "\n", + " //----------Get the total number of k points in all segments---------\n", + " var N_k_points_all = 0;\n", + " for(var i = 0; i < N_k_band_segments; i++)\n", + " N_k_points_all = N_k_points_all + section_k_band_segment[i]['band_k_points'].length;\n", + "\n", + "\n", + " //--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n", + " // store in k_coor_1D[N_k_points_total]-----------------\n", + "\n", + " var band_distance_segments = [];\n", + " for(i = 0; i < N_k_band_segments; i++)\n", + " {\n", + " var x1, x2, y1, y2, z1, z2;\n", + " [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end']; //\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n", + " band_distance_segments.push(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2) + Math.pow((z1-z2), 2));\n", + " }\n", + "\n", + "\n", + " var band_distance_total = band_distance_segments.reduce((x,y) => x+y); //sum of band_distance_segments\n", + "\n", + " var average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total;\n", + "\n", + " //Prepare the parameters to rescale the k coordinates into [0,1]\n", + " var step_k_point = 1.0 / N_k_points_all;\n", + " var step_k_point = (1.0 + step_k_point) / N_k_points_all;\n", + "\n", + " var k_coor_1D = [];\n", + " for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points ++)\n", + " {\n", + " k_coor_1D.push(step_k_point * i_k_points)\n", + " }\n", + "\n", + "\n", + " //--------Get the eigenvalues of each band trajectory--------------\n", + " /*\n", + " N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n", + " N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n", + " band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n", + " N_k_points_all = 0\n", + " for i_segments in range(N_k_band_segments):\n", + " band_energies = section_k_band_segment[i_segments]['band_energies']\n", + " N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n", + " N_k_points_per_segment = len(band_energies[0])\n", + " for i_k_points in range(N_k_points_per_segment):\n", + " for i_bands in range(N_bands):\n", + " band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n", + " N_k_points_all = N_k_points_all + 1\n", + " */\n", + " //var N_k_points_per_segment = section_k_band_segment[0]['band_energies'][0].length; //suppose the numebr of k points in all the segments are the same\n", + " var N_bands = section_k_band_segment[0]['band_energies'][0][0].length;\n", + " var band_energies_all = new Array(N_bands);\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " band_energies_all[i_bands] = new Array(N_k_points_all);// new Array(N_bands, N_k_points_all); //store the eigenvalues\n", + "\n", + " var i_k_points_all = 0;\n", + "\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " var band_energies = section_k_band_segment[i_segments]['band_energies'];\n", + " var N_spin_channel = band_energies.length; //Number of the spin channel --FIXME: no spin polarized\n", + " var N_k_points_per_segment = band_energies[0].length;\n", + " for(var i_k_points = 0; i_k_points < N_k_points_per_segment; i_k_points ++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " band_energies_all[i_bands][i_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * Math.pow(10, -19)) - dos_fermi_energy;\n", + " }\n", + " i_k_points_all = i_k_points_all + 1 ;\n", + "\n", + " }\n", + " }\n", + "\n", + "\n", + "\n", + " var N_labels = 0\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " for(var j = 0; j < 2; j++)\n", + " //labels_tmp = section_k_band_segment[i_segments]['band_segm_start_end'][j];\n", + " N_labels = N_labels + 1\n", + " }\n", + " var label_flag = [];//[\"\" for i in range(N_labels)] //stores the flags of the labels (X, W, G, etc)\n", + "\n", + "\n", + " var i_label = 0;\n", + " var label_flag_last_final = \"\";\n", + " var label_flag_current_initial = \"\";\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " var labels_coor_0 = section_k_band_segment[i_segments]['band_segm_start_end'][0].sort();\n", + " var labels_coor_1 = section_k_band_segment[i_segments]['band_segm_start_end'][1].sort();\n", + "\n", + " var label_flag_0 = get_label_flag(labels_coor_0);\n", + " var label_flag_1 = get_label_flag(labels_coor_1);\n", + "\n", + " var label_flag_current_initial = label_flag_0;\n", + " if(label_flag_last_final == \"\")\n", + " label_flag_last_final = label_flag_0;\n", + "\n", + " if(label_flag_last_final == label_flag_current_initial)\n", + " label_flag[i_label] = label_flag_current_initial;\n", + " else\n", + " label_flag[i_label] = label_flag_last_final + '|' + label_flag_current_initial;\n", + " label_flag_last_final = label_flag_1\n", + "\n", + "\n", + " i_label = i_label + 1;\n", + " if(i_segments == N_k_band_segments - 1)\n", + " {\n", + " label_flag[i_label] = label_flag_1;\n", + " i_label = i_label + 1;\n", + " }\n", + " }\n", + " N_labels = i_label;\n", + "\n", + " //------------Get the coordinates for the labels------------\n", + " //label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n", + " var label_coor_relative = [];//np.zeros((N_labels))\n", + " for(i_label = 0; i_label < N_labels; i_label ++)\n", + " {\n", + " //Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n", + " //x = labels_coor_0[0]\n", + " //y = labels_coor_0[1]\n", + " //z = labels_coor_0[2]\n", + " //label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n", + " label_coor_relative.push(step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all));\n", + " }\n", + " //----Store the label-----------\n", + " var label_obj = [];//[['' for i in range(2)] for j in range(N_labels)]\n", + " for(i_label = 0; i_label < N_labels; i_label ++)\n", + " {\n", + " label_obj.push([label_coor_relative[i_label], label_flag[i_label]]);\n", + " }\n", + "\n", + "\n", + " //-------Get VBM, CBM----------------\n", + "\n", + " var HOMO = -1000;\n", + " var LUMO = 1000;\n", + " var coor_k_point_HOMO = []; //the coordinate of k point that stores HOMO\n", + " var coor_k_point_LUMO = [];//np.zeros((3)) #the coordinate of k point that stores LUMO\n", + " //band_gap_direct = 0.0\n", + " var band_gap_indirect = 0.0;\n", + "\n", + "\n", + " //band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " //band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " var band_energy_max = 10;\n", + " var band_energy_min = -10;\n", + " //N_band_energy_index = 10000\n", + " //band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n", + " //N_allowed_states = np.zeros(N_band_energy_index + 1)\n", + " //i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n", + "\n", + "\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " for(var i_k_points_all = 0; i_k_points_all< N_k_points_all; i_k_points_all ++)\n", + " {\n", + " //i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n", + " //N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n", + " var band_energy = band_energies_all[i_bands][i_k_points_all];\n", + " if(band_energy > 0)\n", + " {\n", + " if(band_energy < LUMO)\n", + " LUMO = band_energy;\n", + " }\n", + " else\n", + " {\n", + " if(band_energy > HOMO)\n", + " HOMO = band_energy;\n", + " }\n", + "\n", + " }\n", + " }\n", + "\n", + "\n", + " //#for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n", + " // if(N_allowed_states[i_band_index] > 0):\n", + " // LUMO = band_energy_min + band_energy_step * i_band_index\n", + " //print('HOMO, LUMO: ',HOMO, LUMO)\n", + " band_gap_indirect = Math.abs(LUMO - HOMO);\n", + "\n", + " if(band_gap_indirect < 0.5) //VBM and CBM has to be found in another way for metals/charged system:\n", + " {\n", + " HOMO = -1000.0;\n", + " LUMO = 1000.0;\n", + " band_energy_max = 10.0;\n", + " band_energy_min = 0.0;\n", + " var N_band_energy_index = 10000;\n", + " var band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index;\n", + " var N_allowed_states = [];\n", + " for(var i_state = 0; i_state < N_band_energy_index+1; i_state++)\n", + " N_allowed_states.push(0);\n", + "\n", + "\n", + " //get the DOS and store in N_allowed_states[]\n", + " for(var i_k_points_all = 0; i_k_points_all < N_k_points_all; i_k_points_all ++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " var band_energy = band_energies_all[i_bands][i_k_points_all];\n", + " if((band_energy_min < band_energy)&&(band_energy < band_energy_max))\n", + " {\n", + " var i_band_index = Math.floor((band_energy - band_energy_min) / band_energy_step);\n", + " N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1;\n", + " }\n", + " }\n", + " }\n", + "\n", + "\n", + " var if_gapped = 0;\n", + " for(var i_band_index = 0; i_band_index < N_band_energy_index; i_band_index ++)//go through the energy levels from the bottom\n", + " {\n", + " var band_energy = band_energy_min + band_energy_step * i_band_index\n", + " if(N_allowed_states[i_band_index] == 0)\n", + " if_gapped = if_gapped + 1;\n", + " if((band_energy > band_energy_max - 0.5) && (if_gapped == 0))\n", + " {\n", + " //alert(\"No gap found in this system. It seems to be a metal.\");\n", + " HOMO = 1000;\n", + " LUMO = 1000;\n", + " break;\n", + " }\n", + " //print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n", + "\n", + " if(N_allowed_states[i_band_index] > 0)\n", + " {\n", + " if(if_gapped * band_energy_step > 0.3 )//above VBM-CBM gap: LUMO\n", + " {\n", + " if(band_energy < LUMO)\n", + " {\n", + " //print(\"LUMO got!\")\n", + " LUMO = band_energy;\n", + " break; //break before touching another gap that is above the band gap\n", + " }\n", + " }\n", + "\n", + " if(if_gapped * band_energy_step < 0.3) //below VBM-CBM gap: HOMO\n", + " {\n", + " if(band_energy > HOMO)\n", + " {\n", + " //print(\"HOMO got!\")\n", + " HOMO = band_energy;\n", + " }\n", + " } \n", + " if_gapped = 0;\n", + " }\n", + " }\n", + " //alert('HOMO, LUMO for metal/charged system: '+ HOMO +\",\"+LUMO)\n", + "\n", + " }\n", + "\n", + "\n", + "\n", + "\n", + " //Find the position of HOMO, LUMO\n", + " var coor_k_point_HOMO = 0, coor_k_point_LUMO = 0;\n", + " for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " if(Math.abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001)\n", + " coor_k_point_HOMO = k_coor_1D[i_k_points];\n", + " if(Math.abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001)\n", + " coor_k_point_LUMO = k_coor_1D[i_k_points]; \n", + " }\n", + " }\n", + "\n", + " //alert(coor_k_point_HOMO +\",\" + coor_k_point_LUMO);\n", + "\n", + "\n", + " //Store the band data to band_obj\n", + "\n", + " var band_obj = {};\n", + " band_obj[\"band_x_axis\"] = k_coor_1D;\n", + " band_obj[\"band_y_axis\"] = band_energies_all\n", + " band_obj[\"labels\"] = label_obj;\n", + " band_obj[\"HOMO_energy\"] = HOMO;\n", + " band_obj[\"HOMO_coor\"] = coor_k_point_HOMO;\n", + " band_obj[\"LUMO_energy\"] = LUMO;\n", + " band_obj[\"LUMO_coor\"] = coor_k_point_LUMO;\n", + " band_obj[\"average_N_k_points_per_inverse_distance\"] = average_N_k_points_per_inverse_distance;\n", + "\n", + "\n", + " return band_obj\n", + "\n", + " }\n", + "\n", + "\n", + " function get_dos_obj(dos_path)\n", + " {\n", + "\n", + " var dos_data = JSON.parse(getJSON(dos_path));\n", + "\n", + " var N_dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'].length;\n", + "\n", + " //in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n", + "\n", + " //dos_energies = new Array(N_dos_values).fill(0.0);\n", + " //dos_energies_tmp = new Array(N_dos_values).fill(0.0) #tmp array for unit convertion\n", + " //dos_values = new Array(N_dos_values).fill(0.0)\n", + "\n", + " var dos_energies = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'];\n", + " var dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_integrated_values'];//[0]\n", + "\n", + " //To do: check if every section_dos has 'dos_fermi_energy'\n", + " var dos_fermi_energy = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_fermi_energy'];\n", + " dos_fermi_energy = dos_fermi_energy / (1.60217656535 * Math.pow(10,-19));\n", + " \n", + " for(var i = 0; i < N_dos_values; i++)\n", + " {\n", + " dos_energies[i] = dos_energies[i] / (1.60217656535 * Math.pow(10,-19)) - dos_fermi_energy;\n", + " }\n", + " \n", + " dos_obj = {}\n", + " dos_obj[\"dos_x_axis\"] = dos_energies;\n", + " dos_obj[\"dos_y_axis\"] = dos_values;\n", + " dos_obj[\"dos_fermi_energy\"] = dos_fermi_energy;\n", + " return dos_obj\n", + " }\n", + " function get_info_obj(band_path)\n", + " {\n", + "\n", + " var band_data = JSON.parse(getJSON(band_path));\n", + " var info_obj = {};\n", + " //---------Read the information of the calculation--------\n", + " info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n", + " info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n", + " info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n", + "\n", + " //----------Get the space group information----------\n", + " /*\n", + " [space_group_symbol, lattice_constant] = get_space_group(band_data);\n", + " info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist();\n", + " info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist();\n", + " */\n", + "\n", + " return info_obj\n", + " }\n", + " function process_band_dos_data()\n", + " {\n", + " info_all = [];\n", + " band_obj_all = [];\n", + " dos_obj_all = [];\n", + "\n", + " for(var i = 0; i < N_materials; i++)\n", + " {\n", + " var band_path = band_paths[i];\n", + " var dos_path = dos_paths[i];\n", + "\n", + "\n", + " var dos_obj = get_dos_obj(dos_path);\n", + " var dos_fermi_energy = dos_obj[\"dos_fermi_energy\"];\n", + " band_obj = get_band_obj(band_path, dos_fermi_energy);\n", + " var info_obj = get_info_obj(band_path);\n", + "\n", + " band_obj_all.push(band_obj);\n", + " dos_obj_all.push(dos_obj);\n", + " info_obj_all.push(info_obj);\n", + " }\n", + " }\n", + " process_band_dos_data();\n", + " //alert(\"process_band_dos_data: info_obj_all: \"+JSON.stringify(info_obj_all));\n", + "</script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script>\n", + " var band_obj_all = [];\n", + " var dos_obj_all = [];\n", + " var info_obj_all = [];\n", + " //alert(\"process_band_dos_data: \" +band_paths)\n", + " //alert(\"process_band_dos_data: \" +info_obj_all)\n", + " function get_label_flag(coor_array)\n", + " {\n", + " var coor = coor_array.sort().join();\n", + " if(coor == '0,0.5,0.5')\n", + " return \"X\";\n", + " if(coor == '0,0,0.5')\n", + " return \"M\";\n", + " else if(coor == '0.5,0.5,0.5')\n", + " return \"L\";\n", + " else if(coor == '0.375,0.375,0.75')\n", + " return \"K\";\n", + " else if(coor == '0.25,0.5,0.75')\n", + " return \"W\";\n", + " else if(coor == '0,0,0')\n", + " return \"\\u0393\";\n", + " else if(coor == '0.25,0.625,0.625')\n", + " return \"U\";\n", + " else\n", + " {\n", + " //alert(\"k label not found: \" + coor);\n", + " return \"?\";\n", + " }\n", + " }\n", + "\n", + "\n", + " //============Process the band structure data============\n", + " function get_band_obj(band_path, dos_fermi_energy)\n", + " {\n", + " var band_data = JSON.parse(getJSON(band_path));\n", + "\n", + " //---------Read section_k_band_segment------------\n", + " var section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n", + "\n", + " //--------Get the number of k band segments-------------\n", + " var N_k_band_segments = section_k_band_segment.length;\n", + "\n", + "\n", + " //----------Get the total number of k points in all segments---------\n", + " var N_k_points_all = 0;\n", + " for(var i = 0; i < N_k_band_segments; i++)\n", + " N_k_points_all = N_k_points_all + section_k_band_segment[i]['band_k_points'].length;\n", + "\n", + "\n", + " //--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n", + " // store in k_coor_1D[N_k_points_total]-----------------\n", + "\n", + " var band_distance_segments = [];\n", + " for(i = 0; i < N_k_band_segments; i++)\n", + " {\n", + " var x1, x2, y1, y2, z1, z2;\n", + " [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end']; //\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n", + " band_distance_segments.push(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2) + Math.pow((z1-z2), 2));\n", + " }\n", + "\n", + "\n", + " var band_distance_total = band_distance_segments.reduce((x,y) => x+y); //sum of band_distance_segments\n", + "\n", + " var average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total;\n", + "\n", + " //Prepare the parameters to rescale the k coordinates into [0,1]\n", + " var step_k_point = 1.0 / N_k_points_all;\n", + " var step_k_point = (1.0 + step_k_point) / N_k_points_all;\n", + "\n", + " var k_coor_1D = [];\n", + " for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points ++)\n", + " {\n", + " k_coor_1D.push(step_k_point * i_k_points)\n", + " }\n", + "\n", + "\n", + " //--------Get the eigenvalues of each band trajectory--------------\n", + " /*\n", + " N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n", + " N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n", + " band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n", + " N_k_points_all = 0\n", + " for i_segments in range(N_k_band_segments):\n", + " band_energies = section_k_band_segment[i_segments]['band_energies']\n", + " N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n", + " N_k_points_per_segment = len(band_energies[0])\n", + " for i_k_points in range(N_k_points_per_segment):\n", + " for i_bands in range(N_bands):\n", + " band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n", + " N_k_points_all = N_k_points_all + 1\n", + " */\n", + " //var N_k_points_per_segment = section_k_band_segment[0]['band_energies'][0].length; //suppose the numebr of k points in all the segments are the same\n", + " var N_bands = section_k_band_segment[0]['band_energies'][0][0].length;\n", + " var band_energies_all = new Array(N_bands);\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " band_energies_all[i_bands] = new Array(N_k_points_all);// new Array(N_bands, N_k_points_all); //store the eigenvalues\n", + "\n", + " var i_k_points_all = 0;\n", + "\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " var band_energies = section_k_band_segment[i_segments]['band_energies'];\n", + " var N_spin_channel = band_energies.length; //Number of the spin channel --FIXME: no spin polarized\n", + " var N_k_points_per_segment = band_energies[0].length;\n", + " for(var i_k_points = 0; i_k_points < N_k_points_per_segment; i_k_points ++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " band_energies_all[i_bands][i_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * Math.pow(10, -19)) - dos_fermi_energy;\n", + " }\n", + " i_k_points_all = i_k_points_all + 1 ;\n", + "\n", + " }\n", + " }\n", + "\n", + "\n", + "\n", + " var N_labels = 0\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " for(var j = 0; j < 2; j++)\n", + " //labels_tmp = section_k_band_segment[i_segments]['band_segm_start_end'][j];\n", + " N_labels = N_labels + 1\n", + " }\n", + " var label_flag = [];//[\"\" for i in range(N_labels)] //stores the flags of the labels (X, W, G, etc)\n", + "\n", + "\n", + " var i_label = 0;\n", + " var label_flag_last_final = \"\";\n", + " var label_flag_current_initial = \"\";\n", + " for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n", + " {\n", + " var labels_coor_0 = section_k_band_segment[i_segments]['band_segm_start_end'][0].sort();\n", + " var labels_coor_1 = section_k_band_segment[i_segments]['band_segm_start_end'][1].sort();\n", + "\n", + " var label_flag_0 = get_label_flag(labels_coor_0);\n", + " var label_flag_1 = get_label_flag(labels_coor_1);\n", + "\n", + " var label_flag_current_initial = label_flag_0;\n", + " if(label_flag_last_final == \"\")\n", + " label_flag_last_final = label_flag_0;\n", + "\n", + " if(label_flag_last_final == label_flag_current_initial)\n", + " label_flag[i_label] = label_flag_current_initial;\n", + " else\n", + " label_flag[i_label] = label_flag_last_final + '|' + label_flag_current_initial;\n", + " label_flag_last_final = label_flag_1\n", + "\n", + "\n", + " i_label = i_label + 1;\n", + " if(i_segments == N_k_band_segments - 1)\n", + " {\n", + " label_flag[i_label] = label_flag_1;\n", + " i_label = i_label + 1;\n", + " }\n", + " }\n", + " N_labels = i_label;\n", + "\n", + " //------------Get the coordinates for the labels------------\n", + " //label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n", + " var label_coor_relative = [];//np.zeros((N_labels))\n", + " for(i_label = 0; i_label < N_labels; i_label ++)\n", + " {\n", + " //Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n", + " //x = labels_coor_0[0]\n", + " //y = labels_coor_0[1]\n", + " //z = labels_coor_0[2]\n", + " //label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n", + " label_coor_relative.push(step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all));\n", + " }\n", + " //----Store the label-----------\n", + " var label_obj = [];//[['' for i in range(2)] for j in range(N_labels)]\n", + " for(i_label = 0; i_label < N_labels; i_label ++)\n", + " {\n", + " label_obj.push([label_coor_relative[i_label], label_flag[i_label]]);\n", + " }\n", + "\n", + "\n", + " //-------Get VBM, CBM----------------\n", + "\n", + " var HOMO = -1000;\n", + " var LUMO = 1000;\n", + " var coor_k_point_HOMO = []; //the coordinate of k point that stores HOMO\n", + " var coor_k_point_LUMO = [];//np.zeros((3)) #the coordinate of k point that stores LUMO\n", + " //band_gap_direct = 0.0\n", + " var band_gap_indirect = 0.0;\n", + "\n", + "\n", + " //band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " //band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " var band_energy_max = 10;\n", + " var band_energy_min = -10;\n", + " //N_band_energy_index = 10000\n", + " //band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n", + " //N_allowed_states = np.zeros(N_band_energy_index + 1)\n", + " //i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n", + "\n", + "\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " for(var i_k_points_all = 0; i_k_points_all< N_k_points_all; i_k_points_all ++)\n", + " {\n", + " //i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n", + " //N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n", + " var band_energy = band_energies_all[i_bands][i_k_points_all];\n", + " if(band_energy > 0)\n", + " {\n", + " if(band_energy < LUMO)\n", + " LUMO = band_energy;\n", + " }\n", + " else\n", + " {\n", + " if(band_energy > HOMO)\n", + " HOMO = band_energy;\n", + " }\n", + "\n", + " }\n", + " }\n", + "\n", + "\n", + " //#for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n", + " // if(N_allowed_states[i_band_index] > 0):\n", + " // LUMO = band_energy_min + band_energy_step * i_band_index\n", + " //print('HOMO, LUMO: ',HOMO, LUMO)\n", + " band_gap_indirect = Math.abs(LUMO - HOMO);\n", + "\n", + " if(band_gap_indirect < 0.5) //VBM and CBM has to be found in another way for metals/charged system:\n", + " {\n", + " HOMO = -1000.0;\n", + " LUMO = 1000.0;\n", + " band_energy_max = 10.0;\n", + " band_energy_min = 0.0;\n", + " var N_band_energy_index = 10000;\n", + " var band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index;\n", + " var N_allowed_states = [];\n", + " for(var i_state = 0; i_state < N_band_energy_index+1; i_state++)\n", + " N_allowed_states.push(0);\n", + "\n", + "\n", + " //get the DOS and store in N_allowed_states[]\n", + " for(var i_k_points_all = 0; i_k_points_all < N_k_points_all; i_k_points_all ++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " var band_energy = band_energies_all[i_bands][i_k_points_all];\n", + " if((band_energy_min < band_energy)&&(band_energy < band_energy_max))\n", + " {\n", + " var i_band_index = Math.floor((band_energy - band_energy_min) / band_energy_step);\n", + " N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1;\n", + " }\n", + " }\n", + " }\n", + "\n", + "\n", + " var if_gapped = 0;\n", + " for(var i_band_index = 0; i_band_index < N_band_energy_index; i_band_index ++)//go through the energy levels from the bottom\n", + " {\n", + " var band_energy = band_energy_min + band_energy_step * i_band_index\n", + " if(N_allowed_states[i_band_index] == 0)\n", + " if_gapped = if_gapped + 1;\n", + " if((band_energy > band_energy_max - 0.5) && (if_gapped == 0))\n", + " {\n", + " //alert(\"No gap found in this system. It seems to be a metal.\");\n", + " HOMO = 1000;\n", + " LUMO = 1000;\n", + " break;\n", + " }\n", + " //print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n", + "\n", + " if(N_allowed_states[i_band_index] > 0)\n", + " {\n", + " if(if_gapped * band_energy_step > 0.3 )//above VBM-CBM gap: LUMO\n", + " {\n", + " if(band_energy < LUMO)\n", + " {\n", + " //print(\"LUMO got!\")\n", + " LUMO = band_energy;\n", + " break; //break before touching another gap that is above the band gap\n", + " }\n", + " }\n", + "\n", + " if(if_gapped * band_energy_step < 0.3) //below VBM-CBM gap: HOMO\n", + " {\n", + " if(band_energy > HOMO)\n", + " {\n", + " //print(\"HOMO got!\")\n", + " HOMO = band_energy;\n", + " }\n", + " } \n", + " if_gapped = 0;\n", + " }\n", + " }\n", + " //alert('HOMO, LUMO for metal/charged system: '+ HOMO +\",\"+LUMO)\n", + "\n", + " }\n", + "\n", + "\n", + "\n", + "\n", + " //Find the position of HOMO, LUMO\n", + " var coor_k_point_HOMO = 0, coor_k_point_LUMO = 0;\n", + " for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points++)\n", + " {\n", + " for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n", + " {\n", + " if(Math.abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001)\n", + " coor_k_point_HOMO = k_coor_1D[i_k_points];\n", + " if(Math.abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001)\n", + " coor_k_point_LUMO = k_coor_1D[i_k_points]; \n", + " }\n", + " }\n", + "\n", + " //alert(coor_k_point_HOMO +\",\" + coor_k_point_LUMO);\n", + "\n", + "\n", + " //Store the band data to band_obj\n", + "\n", + " var band_obj = {};\n", + " band_obj[\"band_x_axis\"] = k_coor_1D;\n", + " band_obj[\"band_y_axis\"] = band_energies_all\n", + " band_obj[\"labels\"] = label_obj;\n", + " band_obj[\"HOMO_energy\"] = HOMO;\n", + " band_obj[\"HOMO_coor\"] = coor_k_point_HOMO;\n", + " band_obj[\"LUMO_energy\"] = LUMO;\n", + " band_obj[\"LUMO_coor\"] = coor_k_point_LUMO;\n", + " band_obj[\"average_N_k_points_per_inverse_distance\"] = average_N_k_points_per_inverse_distance;\n", + "\n", + "\n", + " return band_obj\n", + "\n", + " }\n", + "\n", + "\n", + " function get_dos_obj(dos_path)\n", + " {\n", + "\n", + " var dos_data = JSON.parse(getJSON(dos_path));\n", + "\n", + " var N_dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'].length;\n", + "\n", + " //in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n", + "\n", + " //dos_energies = new Array(N_dos_values).fill(0.0);\n", + " //dos_energies_tmp = new Array(N_dos_values).fill(0.0) #tmp array for unit convertion\n", + " //dos_values = new Array(N_dos_values).fill(0.0)\n", + "\n", + " var dos_energies = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'];\n", + " var dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_integrated_values'];//[0]\n", + "\n", + " //To do: check if every section_dos has 'dos_fermi_energy'\n", + " var dos_fermi_energy = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_fermi_energy'];\n", + " dos_fermi_energy = dos_fermi_energy / (1.60217656535 * Math.pow(10,-19));\n", + " \n", + " for(var i = 0; i < N_dos_values; i++)\n", + " {\n", + " dos_energies[i] = dos_energies[i] / (1.60217656535 * Math.pow(10,-19)) - dos_fermi_energy;\n", + " }\n", + " \n", + " dos_obj = {}\n", + " dos_obj[\"dos_x_axis\"] = dos_energies;\n", + " dos_obj[\"dos_y_axis\"] = dos_values;\n", + " dos_obj[\"dos_fermi_energy\"] = dos_fermi_energy;\n", + " return dos_obj\n", + " }\n", + " function get_info_obj(band_path)\n", + " {\n", + "\n", + " var band_data = JSON.parse(getJSON(band_path));\n", + " var info_obj = {};\n", + " //---------Read the information of the calculation--------\n", + " info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n", + " info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n", + " info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n", + "\n", + " //----------Get the space group information----------\n", + " /*\n", + " [space_group_symbol, lattice_constant] = get_space_group(band_data);\n", + " info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist();\n", + " info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist();\n", + " */\n", + "\n", + " return info_obj\n", + " }\n", + " function process_band_dos_data()\n", + " {\n", + " info_all = [];\n", + " band_obj_all = [];\n", + " dos_obj_all = [];\n", + "\n", + " for(var i = 0; i < N_materials; i++)\n", + " {\n", + " var band_path = band_paths[i];\n", + " var dos_path = dos_paths[i];\n", + "\n", + "\n", + " var dos_obj = get_dos_obj(dos_path);\n", + " var dos_fermi_energy = dos_obj[\"dos_fermi_energy\"];\n", + " band_obj = get_band_obj(band_path, dos_fermi_energy);\n", + " var info_obj = get_info_obj(band_path);\n", + "\n", + " band_obj_all.push(band_obj);\n", + " dos_obj_all.push(dos_obj);\n", + " info_obj_all.push(info_obj);\n", + " }\n", + " }\n", + " process_band_dos_data();\n", + " //alert(\"process_band_dos_data: info_obj_all: \"+JSON.stringify(info_obj_all));\n", + "</script>" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "scrolled": false, + "tags": [ + "show_results_and_plot" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script>\n", + " var N_max_show = 10; //Number of results to be shown by default\n", + "\n", + " function show_materials_submitted_info()\n", + " {\n", + " //alert(\"N_materials=\" + N_materials)\n", + " //\"table_materials_submitted_info\"\n", + " //alert(\"show_materials_submitted_info: info_obj_all: \"+JSON.stringify(info_obj_all))\n", + " var table_content = new Array(); \n", + " str = '<tr>';\n", + " str += '<th width=\"5%\"></th>'\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Atom labels</b></font></p></th>';\n", + " //str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Space group</b></font></p></th>';\n", + " //str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Lattice constants (in Ang)</b></font></p></th>';\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Program name</b></font></p></th>';\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Basis set type</b></font></p></th>';\n", + " str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Functional</b></font></p></th>';\n", + " //str += '<th width=\"20%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Number of <i>k</i> points per inverse distance</b></font></p></th>';\n", + " str += '</tr>'; //first row: head\n", + " table_content.push(str);\n", + "\n", + " for(var i = 0; i < N_materials; i++) //add info of each material\n", + " {\n", + " //alert(\"show_materials_submitted_info: material \"+ i); \n", + " table_content.push('<tr>');\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<input type = \\\"checkbox\\\" name = \"checkbox_material\" id = \\\"checkbox_material' + i.toString() + '\\\" unchecked onclick=\\\"checkbox_material(this.id)\\\">';\n", + " str += \"<b>  #\" + (i+1).toString() + \"</b>\";\n", + " table_content.push(str);\n", + " table_content.push('</td>');\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"atom_labels\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got atom_labels\");\n", + "\n", + " /*\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"space_group_symbol\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got space_group_symbol\");\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"lattice_constant\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got lattice_constant\");\n", + " */\n", + " \n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"program_name\"].toUpperCase() + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got program_name\");\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"program_basis_set_type\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got program_basis_set_type\");\n", + "\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"XC_functional_name\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got XC_functional_name\");\n", + "\n", + " /*\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got average_N_k_points_per_inverse_distance\");\n", + " */\n", + " table_content.push('</tr>');\n", + "\n", + " }\n", + " \n", + " document.getElementById(\"table_materials_submitted_info\").innerHTML = table_content.join('');\n", + " }\n", + "\n", + " function clean_materials_selection()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_material\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"\";\n", + " }\n", + " }\n", + "\n", + " function select_all()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_material\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"checked\";\n", + " }\n", + " }\n", + "\n", + "\n", + "\n", + " function process()\n", + " {\n", + " //alert(\"Process:\"+band_paths)\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_js_plot'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_materials_submitted_info'));\n", + " show_materials_submitted_info();\n", + " document.getElementById(\"table_visualize\").innerHTML = \"\";\n", + " str = N_materials.toString();\n", + " document.getElementById(\"n_materials\").innerHTML = \"Number of materials submitted: \" + str + \"<font size = 1px color = #C0C0C0 >   Please press \\'Visualize\\' to visualize the band structure. </font>\";\n", + " document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n", + " }\n", + " \n", + "\n", + " var image_band = '';\n", + " var image_dos = '';\n", + " var image_band_links = new Array(N_materials); //store the URL of each band figure -> used to compare 2 figures\n", + " var image_band_links_selected = [];\n", + " var image_band_selected_Number = []; //record which i_material has been selected\n", + "\n", + "\n", + "\n", + " function prepare(N_materials_show)\n", + " {\n", + " document.getElementById(\"table_visualize\").innerHTML = \"\";\n", + " var table_content = new Array(); \n", + " //document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n", + " //-----Generate the html tables for each material--------\n", + " for(var i = 0; i < N_materials_show; i++)\n", + " {\n", + " checkbox_material_id = \"checkbox_material\" + i.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + "\n", + " table_content.push('<tr>');\n", + " div_string = '<div style = \\\"height: 20px\\\"></div>';\n", + " table_content.push(div_string);\n", + " table_content.push('<th>');\n", + "\n", + " //add main container div\n", + " div_string = '<div id = \\\"div_band_dos' + i.toString() + '\\\" class = \\\"div_band_dos\\\" >';\n", + " table_content.push(div_string);\n", + "\n", + " //show No. of the material\n", + " i_material = i + 1;\n", + " div_string = '<div style = \\\"height:30px\\; font-size: 15pt;\">' + '#' + i_material.toString() + '</div>';\n", + " table_content.push(div_string);\n", + "\n", + " //show band_path/dos info\n", + " div_string = '<div style = \\\"height:30px\\\">' + 'Band:   ' + band_paths[i] + ',    DOS:   ' + dos_paths[i] + '</div>';\n", + " table_content.push(div_string);\n", + "\n", + " //add div_band\n", + " div_string = '<div id = \\\"div_band' + i.toString() + '\\\" class = \\\"div_band\\\" ></div>';\n", + " table_content.push(div_string);\n", + "\n", + " //add div_dos\n", + " div_string = '<div id = \\\"div_dos' + i.toString() + '\\\" class = \\\"div_dos\\\" ></div>'; \n", + " table_content.push(div_string);\n", + "\n", + " //add div_tools\n", + " div_string = '<div id = \\\"div_tools' + i.toString() + '\\\" class = \\\"div_tools\\\" >'; \n", + " table_content.push(div_string);\n", + "\n", + " //add: infomation\n", + " div_string = '<div id = \\\"div_info' + i.toString() + '\\\">atom_labels<br>program_name</div>'; \n", + " table_content.push(div_string);\n", + "\n", + " //add: custom scale\n", + " div_string = '<br><p style=\\\"color: #000;font-weight: 100; font-size: 10pt; align:left\\\"> Set the lower and upper limit of energy scale (in eV): <br><br><font color=\\\"black\\\" size = 3px> Lower limit:    </font><textarea id=\\\"lowerlimit' + i.toString() + '\\\" rows=\\\"1\\\" style = \\\"width: 70px;\\\">-10</textarea> <font color=\\\"black\\\" size = 3px>   eV</font>    <font color=\\\"black\\\" size = 3px> Upper limit:    </font><textarea id=\\\"upperlimit' + i.toString() + '\\\" rows=\\\"1\\\" style = \\\"width: 70px;\\\">10</textarea> <font color=\\\"black\\\" size = 3px>   eV   </font></p>';\n", + " table_content.push(div_string);\n", + " div_string = '<br><button class = \\\"button_tools\\\" id = \\\"button_customscale' + i.toString() + '\\\" onclick = \\\"customscale(this.id)\\\"> Rescale </button>'; \n", + " table_content.push(div_string);\n", + "\n", + "\n", + " //add button:autoscale\n", + " div_string = '<button class = \\\"button_tools\\\" id = \\\"button_autoscale' + i.toString() + '\\\" onclick = \\\"autoscale(this.id)\\\" title = \\\"(-10 eV, 10 eV)\\\"> Autoscale </button>'; \n", + " table_content.push(div_string);\n", + " //add button:fullscale\n", + " div_string = '<button class = \\\"button_tools\\\" id = \\\"button_fullscale' + i.toString() + '\\\" onclick = \\\"fullscale(this.id)\\\" title = \\\"(-100 eV, 100 eV)\\\"> Full scale </button><br><br>'; \n", + " table_content.push(div_string);\n", + "\n", + " //table_content.push(\"Select and zoom:\");\n", + "\n", + " /*//overview for select and zoom\n", + " div_string = '<div id = \\\"div_overview' + i.toString() + '\\\" class = \\\"div_overview\\\" ></div>'; // <div id=\"overview\" style=\"width:300px;height:200px; margin-left:10px; margin-top: 50px; padding-top: 0px\"></div>\n", + " table_content.push(div_string);\n", + " div_string = '<p id = \\\"overviewLegend' + i.toString() + '\\\" ></p>'; // <p id=\"overviewLegend\" style=\"margin-left:10px\"></p>\n", + " table_content.push(div_string);*/\n", + "\n", + " //download figures as png\n", + " div_string = '<a id = \\\"img_band' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download band </a>';\n", + " table_content.push(div_string); \n", + " div_string = '<a id = \\\"img_dos' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download DOS </a>';\n", + " table_content.push(div_string);\n", + "\n", + " //add show VBM & CBM\n", + " div_string = '<br><br><p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_VBM' + i.toString() + '\\\" unchecked onclick=\\\"show_VBM(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Show VBM </font> (<font color=\\\"blue\\\">\\•</font>) <font color=\\\"black\\\" size = 3px> and CBM </font>(<font color=\\\"red\\\">\\•</font>) </p>';\n", + " table_content.push(div_string);\n", + "\n", + "\n", + " table_content.push('</div>');//div_tools\n", + "\n", + " //checkbox for comparison\n", + " div_string = '<div id = \\\"div_checkbox_compare' + i.toString() + '\\\" class = \\\"div_checkbox_compare\\\" >';\n", + " table_content.push(div_string);\n", + " //div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n", + " div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" checked = \\\"unchecked\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n", + " table_content.push(div_string);\n", + " table_content.push('</div>');//div_checkbox_compare\n", + "\n", + "\n", + " table_content.push('</div>');//div_band_dos\n", + " table_content.push('</th>');\n", + " table_content.push('</tr>'); \n", + " }\n", + "\n", + " document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n", + " }\n", + "\n", + "\n", + " function visualize_band_dos()\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_jquery'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_axislabels'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_dashes'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_navigate'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_selection'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_flot_legendoncanvas'));\n", + " document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n", + " document.getElementById(\"div_compare_buttons\").style.visibility=\"\";\n", + "\n", + "\n", + "\n", + " if(N_materials > N_max_show)\n", + " {\n", + " document.getElementById(\"div_showall\").style.visibility=\"visible\";\n", + " document.getElementById(\"checkbox_showall\").checked = \"\";\n", + " } \n", + "\n", + " N_materials_show = Math.min(N_max_show, N_materials);\n", + "\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + "\n", + " }\n", + "\n", + " function show_all(id)//\"plot_placeholder\"\n", + " {\n", + " var if_showall=0;\n", + " if_showall = check_show_VBM(id);\n", + " if(if_showall == 1)\n", + " {\n", + " N_materials_show = N_materials;\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + " }\n", + " else\n", + " {\n", + " N_materials_show = Math.min(N_max_show, N_materials);\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + " }\n", + "\n", + " }\n", + "\n", + " \n", + " //------------------Tool used to get the content from textarea---------------------\n", + " function get_text(textarea_id)\n", + " {\n", + " var text = document.getElementById(textarea_id).value;\n", + " return text;\n", + " }\n", + "\n", + "\n", + "\n", + " //-------------------Compare 2 band figures----------------------------------------\n", + "\n", + "\n", + " function check_compare(id)//checkbox_compare' + i.toString() + '\\\" unchecked onclick=\\\"check_compare(this.id)\n", + " {\n", + " var x = document.getElementById(id);\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " var N_chosen = 0;\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " if(choices_compare[i].checked)\n", + " {\n", + " N_chosen ++;\n", + " }\n", + " }\n", + " if(N_chosen == 2) // In max. only 2 figures could be selected and compared.\n", + " {\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " if(!choices_compare[i].checked)\n", + " {\n", + " choices_compare[i].disabled = 'disabled';\n", + " }\n", + " }\n", + " }\n", + " else\n", + " {\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " choices_compare[i].removeAttribute('disabled');\n", + " }\n", + " }\n", + "\n", + " }\n", + "\n", + " function compare()\n", + " {\n", + " $(\"#div_compare\").fadeIn(600);//show div for comparison\n", + " //check_compare(-100);\n", + "\n", + " var compare_list = [];\n", + " compare_list = make_compare_list();\n", + " //[i_material_1, i_material_2] = make_compare_list();\n", + " i_material_1 = compare_list[0];\n", + " i_material_2 = compare_list[1];\n", + " //document.getElementById(\"demo\").innerHTML = \"In add info compare:\" + i_material_1.toString() + i_material_2.toString();\n", + " compare_figures(i_material_1, i_material_2); \n", + " }\n", + " function make_compare_list()\n", + " {\n", + " //get the links to the images\n", + " images_selected_links = []; //store the links to the figures for comparison\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " var N_chosen = 0;\n", + " var str = ''; //tmp str for debug\n", + " var figure_selected = new Array(2);\n", + " for(var i=0; i<choices_compare.length; i++) //check which figures are selected\n", + " {\n", + " if(choices_compare[i].checked)\n", + " {\n", + " id_chosen = choices_compare[i].id;\n", + " i_chosen = Math.round(id_chosen.substring(16));\n", + " var tmp_str = image_band_links[i_chosen];\n", + " images_selected_links.push(tmp_str);\n", + " figure_selected[N_chosen] = i_chosen;\n", + " N_chosen ++;\n", + " //str += beakerx.image_band_links[i];\n", + " }\n", + " }\n", + " var i_material_1 = 0;\n", + " var i_material_2 = 0;\n", + " //document.getElementById(\"demo\").innerHTML = 'In making comare list';\n", + " image_band_links_selected = images_selected_links;\n", + " //document.getElementById(\"demo\").innerHTML = 'In making comare list: next';\n", + " if(N_chosen == 2)\n", + " {\n", + " i_material_1 = figure_selected[0];\n", + " i_material_2 = figure_selected[1];\n", + " }\n", + " //document.getElementById(\"demo\").innerHTML = 'Compare_list: ' +i_material_1.toString() + ' ' + i_material_2.toString();\n", + "\n", + " return [i_material_1, i_material_2];\n", + " }\n", + "\n", + " function check_compare_scale(i_material_1, i_material_2)\n", + " {\n", + " lowerlimit_id_1 = \"lowerlimit\" + i_material_1.toString();\n", + " lowerlimit_id_2 = \"lowerlimit\" + i_material_2.toString();\n", + " upperlimit_id_1 = \"upperlimit\" + i_material_1.toString();\n", + " upperlimit_id_2 = \"upperlimit\" + i_material_2.toString();\n", + "\n", + " lowerlimit_1 = parseFloat(document.getElementById(lowerlimit_id_1).innerHTML);\n", + " lowerlimit_2 = parseFloat(document.getElementById(lowerlimit_id_2).innerHTML);\n", + " upperlimit_1 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n", + " upperlimit_2 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n", + " if((lowerlimit_1 != lowerlimit_2) || (upperlimit_1 != upperlimit_2))\n", + " return -1;\n", + " else\n", + " return 1;\n", + " }\n", + "\n", + " function compare_figures(i_material_1, i_material_2)\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_query_beforeafter'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_compare_slide'));\n", + " add_info_compare(i_material_1, i_material_2);\n", + " document.getElementById(\"div_compare_container\").scrollIntoView({ behavior: 'smooth' }); \n", + " document.getElementById(\"div_compare_container\").scrollTop += 50;\n", + "\n", + " }\n", + "\n", + "\n", + " function clean_compare_list()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"\";\n", + " choices_compare[i].removeAttribute('disabled');\n", + " }\n", + " }\n", + "\n", + " //-----------Add information about the calculation to \"div_tools\"---------------\n", + " function add_info(i)\n", + " {\n", + " \n", + " //document.getElementById(\"demoa\").innerHTML = i.toString() + div_info_id;\n", + " //for(var i = 0; i < beakerx.N_materials; i++)\n", + " //{\n", + " div_info_id = \"div_info\" + i.toString();\n", + "\n", + " var str = '';\n", + " str += \"<br> <p style=\\\"text-align:left\\\"><font size = 3pt><b>Atom labels:</b>     \" + info_obj_all[i][\"atom_labels\"] + '</font></p>';\n", + " //str += \"<font size = 3pt><b>Space group:</b>     \" + info_obj_all[i][\"space_group_symbol\"] + '</font>';\n", + " //str += \"<font size = 3pt><b>Lattice constants (in Ang):</b>     \" + info_obj_all[i][\"lattice_constant\"] + '</font>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Program name:</b>    \" + info_obj_all[i][\"program_name\"].toUpperCase() + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Basis set type:</b>    \" + info_obj_all[i][\"program_basis_set_type\"] + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Functional:</b>    \" + info_obj_all[i][\"XC_functional_name\"] + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3) + '</font></p>';\n", + " document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n", + " //document.getElementById('program_name_1').innerHTML = \"<b>Code:</b>    \" + origData[\"program_name\"];\n", + " //document.getElementById('program_basis_set_type_1').innerHTML = \"<b>Basis set type:</b>    \" + origData[\"program_basis_set_type\"];\n", + " //document.getElementById('XC_functional_name_1').innerHTML = \"<b>Functional:</b>    \" + origData[\"XC_functional_name\"]; \n", + " //}\n", + " \n", + " }\n", + " function add_info_compare(i,j)\n", + " {\n", + "\n", + " div_info_id = \"div_compare_info\";\n", + " var str = '';\n", + "\n", + " if_same_scale = check_compare_scale(i_material_1, i_material_2);\n", + " if(if_same_scale == -1)\n", + " {\n", + " str = '<b><font size = \"15pt\" color=\"#940000\">Error: Different lower/upper limits.</font></b><br>';\n", + " document.getElementById(\"div_compare_container\").innerHTML = str;\n", + " document.getElementById(div_info_id).innerHTML = '';\n", + " return;\n", + " }\n", + "\n", + " str += \"<br><b><font-size:15pt>Information of the first calculation (left):</font></b> <br>\";\n", + " str += \"<br> <b>Atom labels:</b>     \" + info_obj_all[i][\"atom_labels\"];\n", + " //str += \"<br> <b>Space group:</b>     \" + info_obj_all[i][\"space_group_symbol\"];\n", + " //str += \"<br> <b>Lattice constants (in Ang):</b>     \" + info_obj_all[i][\"lattice_constant\"];\n", + " str += \"<br> <b>Program name:</b>    \" + info_obj_all[i][\"program_name\"].toUpperCase();\n", + " str += \"<br> <b>Basis set type:</b>    \" + info_obj_all[i][\"program_basis_set_type\"];\n", + " str += \"<br> <b>Functional:</b>    \" + info_obj_all[i][\"XC_functional_name\"];\n", + " str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " str += \"<br><br><br><b><font-size:15pt>Information of the second calculation (right):</font></b><br>\";\n", + " str += \"<br> <b>Atom labels:</b>     \" + info_obj_all[j][\"atom_labels\"];\n", + " //str += \"<br> <b>Space group:</b>     \" + info_obj_all[j][\"space_group_symbol\"];\n", + " //str += \"<br> <b>Lattice constants (in Ang):</b>     \" + info_obj_all[j][\"lattice_constant\"];\n", + " str += \"<br> <b>Program name:</b>    \" + info_obj_all[j][\"program_name\"].toUpperCase();\n", + " str += \"<br> <b>Basis set type:</b>    \" + info_obj_all[j][\"program_basis_set_type\"]; \n", + " str += \"<br> <b>Functional:</b>    \" + info_obj_all[j][\"XC_functional_name\"];\n", + " str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n", + " }\n", + "\n", + "\n", + "\n", + " //-----------------------Show/hide VBM, CBM-------------------------\n", + " function check_show_VBM(checkbox_VBM_id)\n", + " {\n", + " var x = document.getElementById(checkbox_VBM_id);\n", + " var if_checked = 0;\n", + " if(x.checked)//== \"checked\")\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"checked!\";\n", + " if_checked = 1;\n", + " }\n", + " else if (x.unchecked)// == \"unchecked\")\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"unchecked!\";\n", + " if_checked = -1;\n", + " }\n", + " else\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"nothing detected!\";\n", + " }\n", + " return if_checked;\n", + " }\n", + "\n", + " function check_if_in_compare_list(i) // check if the current material i is to be compared\n", + " {\n", + "\n", + " var checkbox_compare_id = \"checkbox_compare\" + i.toString();\n", + " var if_compare = check_show_VBM(checkbox_compare_id);\n", + " //document.getElementById(\"demo\").innerHTML = 'if_compare of ' + i.toString() + ' : ' + if_compare.toString();\n", + " var i_compare_material_1, i_compare_material_2;\n", + " [i_compare_material_1, i_compare_material_2] = make_compare_list();\n", + " var i_in_compare_list = -1;\n", + " if(i_compare_material_1 == i)\n", + " {\n", + " i_in_compare_list = 1;\n", + " }\n", + " else if (i_compare_material_2 == i)\n", + " {\n", + " i_in_compare_list = 2;\n", + " }\n", + " else\n", + " {\n", + " i_in_compare_list = 0;\n", + " }\n", + " //document.getElementById(\"demo\").innerHTML = 'Checking ' + i.toString() + ' in Compare_list: ' + i_in_compare_list.toString();\n", + " return [if_compare, i_in_compare_list];\n", + " }\n", + "\n", + " function show_VBM(id)\n", + " {\n", + " //prepare(\"new\");\n", + " //var if_show_VBM = -1;\n", + " var len_id = id.length;\n", + " var i_material = id.substring(12);\n", + " var i = Math.round(i_material);\n", + "\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + " //document.getElementById(\"demo\").innerHTML = i.toString() + ' in Compare_list: ' + i_in_compare_list.toString();\n", + "\n", + " plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + "\n", + " //---------------------Functions to rescale-------------------------------------------\n", + " function autoscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(16);\n", + " var i = Math.round(i_material);\n", + "\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " document.getElementById(upperlim_id).innerHTML =\"10.0\";\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " document.getElementById(lowerlim_id).innerHTML =\"-10.0\";\n", + "\n", + "\n", + " //document.getElementById(\"demoa\").innerHTML =i_material;\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + " plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + " function fullscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(16);\n", + " var i = Math.round(i_material);\n", + "\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " document.getElementById(upperlim_id).innerHTML =\"100.0\";\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " document.getElementById(lowerlim_id).innerHTML =\"-100.0\";\n", + "\n", + " //document.getElementById(\"demoa\").innerHTML =i_material;\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + "\n", + " plot_band_dos_i(i, -100, 100, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + " function customscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(18);\n", + " var i = Math.round(i_material);\n", + " //\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " upperlim = document.getElementById(upperlim_id).value;\n", + " upperlim_float = Math.round(upperlim);\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " lowerlim = document.getElementById(lowerlim_id).value;\n", + " lowerlim_float = Math.round(lowerlim);\n", + "\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + "\n", + " plot_band_dos_i(i, lowerlim_float, upperlim_float, if_show_VBM, if_compare, i_in_compare_list); \n", + " }\n", + "\n", + "\n", + " function plot_band_dos(lowerLim, upperLim, N_materials_show)\n", + " {\n", + " placeholder_band = \"#div_band1\";\n", + " placeholder_dos = \"#div_dos1\";\n", + " // lowerLim = -10.01\n", + " //upperLim = 10.01\n", + "\n", + "\n", + "\n", + " //alert(\"plot_band_dos\");\n", + " //prepare();\n", + " for(var i = 0; i < N_materials_show; i++)\n", + " {\n", + " \n", + " var checkbox_material_id = \"checkbox_material\" + i.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + " add_info(i);\n", + " }\n", + "\n", + " //------Plot----------------\n", + " /*\n", + " for(var i_material = 0; i_material < N_materials_show; i_material++)\n", + " {\n", + "\n", + " //alert(\"Material \"+i);\n", + " var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + "\n", + " plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n", + " }\n", + " */\n", + " //alert(\"next:for\")\n", + " for (let i_material = 0, p = Promise.resolve(); i_material < N_materials_show; i_material++) {\n", + " p = p.then(_ => new Promise(resolve =>\n", + " setTimeout(function () {\n", + " //alert(i_material)\n", + " var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected == 1)\n", + " {\n", + " plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n", + " }\n", + " resolve();\n", + " }, 0)\n", + " ));\n", + " }\n", + "\n", + "\n", + " return 1;\n", + " }\n", + "\n", + " var i = 0\n", + " var lowerLim = -10\n", + " var upperLim = 10\n", + " var if_show_VBM = 0\n", + " var if_compare = 0\n", + " var i_in_compare_list = -1\n", + "\n", + "\n", + " \n", + " function plot_band_dos_i(i_material, lowerLim_material, upperLim_material, if_show_VBM_material, if_compare_material, i_in_compare_list_material)\n", + " {\n", + " //alert(\"plot_band_dos_i\")\n", + "\n", + " i = i_material;\n", + " lowerLim = lowerLim_material;\n", + " upperLim = upperLim_material;\n", + " if_show_VBM = if_show_VBM_material;\n", + " if_compare = if_compare_material;\n", + " i_in_compare_list = i_in_compare_list_material;\n", + " //alert(\"plot_band_dos_i: i_material: \"+i)\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_band'));\n", + " //alert('i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list')\n", + " //plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_dos'));\n", + " } \n", + "</script>\n", + "\n", + " \n", + " \n", + "<br><br>\n", + "<button class=\"button\" onclick=\"process()\">Process data</button>\n", + "<br><br>\n", + "<div id = \"n_materials\" style = \"font-size: 18px; font-weight: 100; height: 60px; width: 100%;\"> Number of materials submitted: 0</div>\n", + "<div id = \"show_materials_submitted\" style = \"font-size: 20px; font-color: black;\"> </div>\n", + "\n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "<p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select materials to visualize the band structure and DOS:</p>\n", + "<div style = \"width :100%; height: 10px;\"></div> \n", + "<button class = \"button\" onclick = \"clean_materials_selection()\"> Clean selections </button> \n", + "<button class = \"button\" onclick = \"select_all()\"> Select all </button> \n", + "<button class = \"button\" onclick = \"visualize_band_dos()\"> Visualize </button> \n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "\n", + "<div id = \"show_materials_submitted_info\" style = \"width: 100%; font-size: 20px; font-color: black;\"> \n", + " <table id = \"table_materials_submitted_info\" style=\"width:100%\"> </table>\n", + "</div>\n", + "\n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "\n", + "\n", + "\n", + "\n", + "<div id=\"div_compare_buttons\" style=\"visibility:hidden\">\n", + " <br><br><br>\n", + " <p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select two materials in the checkbox on the right for comparison:</p>\n", + " <p style=\"color: #000;font-weight: 1000; font-size: 8pt;\"></p>\n", + " <button class = \"button\" onclick = \"clean_compare_list()\"> Clean selections </button> \n", + " <button class = \"button\" onclick = \"compare();compare()\" title = \"Select 2 materials in the checkbox below and compare: please make sure that the upper/lower limits are the same (using Rescale/Autoscale buttons).\" > Compare</button>\n", + "</div>\n", + "\n", + "\n", + "\n", + "<div id = \"div_showall\" style = \"width: 100%; visibility:hidden\">\n", + " <div style = \"width: 100%; height: 30px; \"></div>\n", + " <input type = \"checkbox\" id = \"checkbox_showall\" unchecked onclick=\"show_all(this.id)\"/> <font color=\"black\" size = 3px> Show all results </font><font size = 2px color = \"#666\"> (By default only the first 10 results are shown.) </font> \n", + " <div style = \"width: 100%; height: 30px; \"></div>\n", + "</div>\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "<div id = \"div_compare\" style = \"position: fixed; top: 20%; left: 10%; width: 1200px; height: 600px; z-index: 999999; border: 1px solid #555; background-color: #fff; display: none\" onclick = \"$(this).fadeOut(500)\"> \n", + " \n", + " <div style = \"float: right; width: 80px; height: 25px; margin-top: 10px; margin-right: 10px; z-index: 1000000; border: 1px solid #555; text-align: center; vertical-align: middle; background-color: #f9f9f9; font-size:12pt; font-color: #000; cursor:pointer;\" > CLOSE </div> <!--button to close the div-->\n", + " <div id = \"div_compare_info\" style = \" width: 350px; height: 500px; float: right; margin-top: 50px; margin-right: 10px; z-index: 10000000;\"></div>\n", + " <div id = \"div_compare_container\" style = \"margin-top: 50px; margin-left: 100px; width: 600px; height: 300px;\">\n", + " <div class=\"g-before-after\" id = \"div_compare_containerx\"></div>\n", + " </div>\n", + "</div>\n", + "\n", + "\n", + "<div id = \"demo\"></div>\n", + "\n", + "<div id = \"plot_placeholder\">\n", + " <div><br></div>\n", + " <table id = \"table_visualize\"> </table>\n", + "</div>\n", + "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script>\n", + " var N_max_show = 10; //Number of results to be shown by default\n", + "\n", + " function show_materials_submitted_info()\n", + " {\n", + " //alert(\"N_materials=\" + N_materials)\n", + " //\"table_materials_submitted_info\"\n", + " //alert(\"show_materials_submitted_info: info_obj_all: \"+JSON.stringify(info_obj_all))\n", + " var table_content = new Array(); \n", + " str = '<tr>';\n", + " str += '<th width=\"5%\"></th>'\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Atom labels</b></font></p></th>';\n", + " //str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Space group</b></font></p></th>';\n", + " //str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Lattice constants (in Ang)</b></font></p></th>';\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Program name</b></font></p></th>';\n", + " str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Basis set type</b></font></p></th>';\n", + " str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Functional</b></font></p></th>';\n", + " //str += '<th width=\"20%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Number of <i>k</i> points per inverse distance</b></font></p></th>';\n", + " str += '</tr>'; //first row: head\n", + " table_content.push(str);\n", + "\n", + " for(var i = 0; i < N_materials; i++) //add info of each material\n", + " {\n", + " //alert(\"show_materials_submitted_info: material \"+ i); \n", + " table_content.push('<tr>');\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<input type = \\\"checkbox\\\" name = \"checkbox_material\" id = \\\"checkbox_material' + i.toString() + '\\\" unchecked onclick=\\\"checkbox_material(this.id)\\\">';\n", + " str += \"<b>  #\" + (i+1).toString() + \"</b>\";\n", + " table_content.push(str);\n", + " table_content.push('</td>');\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"atom_labels\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got atom_labels\");\n", + "\n", + " /*\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"space_group_symbol\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got space_group_symbol\");\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"lattice_constant\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got lattice_constant\");\n", + " */\n", + " \n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"program_name\"].toUpperCase() + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got program_name\");\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"program_basis_set_type\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got program_basis_set_type\");\n", + "\n", + "\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += info_obj_all[i][\"XC_functional_name\"] + ';   ';\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got XC_functional_name\");\n", + "\n", + " /*\n", + " table_content.push('<td>'); \n", + " str = '<font size = \\\"3pt\\\">';\n", + " str += band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " str += \"</font>\"\n", + " table_content.push(str); \n", + " table_content.push('</td>');\n", + " //alert(\"got average_N_k_points_per_inverse_distance\");\n", + " */\n", + " table_content.push('</tr>');\n", + "\n", + " }\n", + " \n", + " document.getElementById(\"table_materials_submitted_info\").innerHTML = table_content.join('');\n", + " }\n", + "\n", + " function clean_materials_selection()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_material\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"\";\n", + " }\n", + " }\n", + "\n", + " function select_all()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_material\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"checked\";\n", + " }\n", + " }\n", + "\n", + "\n", + "\n", + " function process()\n", + " {\n", + " //alert(\"Process:\"+band_paths)\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_js_plot'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_materials_submitted_info'));\n", + " show_materials_submitted_info();\n", + " document.getElementById(\"table_visualize\").innerHTML = \"\";\n", + " str = N_materials.toString();\n", + " document.getElementById(\"n_materials\").innerHTML = \"Number of materials submitted: \" + str + \"<font size = 1px color = #C0C0C0 >   Please press \\'Visualize\\' to visualize the band structure. </font>\";\n", + " document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n", + " }\n", + " \n", + "\n", + " var image_band = '';\n", + " var image_dos = '';\n", + " var image_band_links = new Array(N_materials); //store the URL of each band figure -> used to compare 2 figures\n", + " var image_band_links_selected = [];\n", + " var image_band_selected_Number = []; //record which i_material has been selected\n", + "\n", + "\n", + "\n", + " function prepare(N_materials_show)\n", + " {\n", + " document.getElementById(\"table_visualize\").innerHTML = \"\";\n", + " var table_content = new Array(); \n", + " //document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n", + " //-----Generate the html tables for each material--------\n", + " for(var i = 0; i < N_materials_show; i++)\n", + " {\n", + " checkbox_material_id = \"checkbox_material\" + i.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + "\n", + " table_content.push('<tr>');\n", + " div_string = '<div style = \\\"height: 20px\\\"></div>';\n", + " table_content.push(div_string);\n", + " table_content.push('<th>');\n", + "\n", + " //add main container div\n", + " div_string = '<div id = \\\"div_band_dos' + i.toString() + '\\\" class = \\\"div_band_dos\\\" >';\n", + " table_content.push(div_string);\n", + "\n", + " //show No. of the material\n", + " i_material = i + 1;\n", + " div_string = '<div style = \\\"height:30px\\; font-size: 15pt;\">' + '#' + i_material.toString() + '</div>';\n", + " table_content.push(div_string);\n", + "\n", + " //show band_path/dos info\n", + " div_string = '<div style = \\\"height:30px\\\">' + 'Band:   ' + band_paths[i] + ',    DOS:   ' + dos_paths[i] + '</div>';\n", + " table_content.push(div_string);\n", + "\n", + " //add div_band\n", + " div_string = '<div id = \\\"div_band' + i.toString() + '\\\" class = \\\"div_band\\\" ></div>';\n", + " table_content.push(div_string);\n", + "\n", + " //add div_dos\n", + " div_string = '<div id = \\\"div_dos' + i.toString() + '\\\" class = \\\"div_dos\\\" ></div>'; \n", + " table_content.push(div_string);\n", + "\n", + " //add div_tools\n", + " div_string = '<div id = \\\"div_tools' + i.toString() + '\\\" class = \\\"div_tools\\\" >'; \n", + " table_content.push(div_string);\n", + "\n", + " //add: infomation\n", + " div_string = '<div id = \\\"div_info' + i.toString() + '\\\">atom_labels<br>program_name</div>'; \n", + " table_content.push(div_string);\n", + "\n", + " //add: custom scale\n", + " div_string = '<br><p style=\\\"color: #000;font-weight: 100; font-size: 10pt; align:left\\\"> Set the lower and upper limit of energy scale (in eV): <br><br><font color=\\\"black\\\" size = 3px> Lower limit:    </font><textarea id=\\\"lowerlimit' + i.toString() + '\\\" rows=\\\"1\\\" style = \\\"width: 70px;\\\">-10</textarea> <font color=\\\"black\\\" size = 3px>   eV</font>    <font color=\\\"black\\\" size = 3px> Upper limit:    </font><textarea id=\\\"upperlimit' + i.toString() + '\\\" rows=\\\"1\\\" style = \\\"width: 70px;\\\">10</textarea> <font color=\\\"black\\\" size = 3px>   eV   </font></p>';\n", + " table_content.push(div_string);\n", + " div_string = '<br><button class = \\\"button_tools\\\" id = \\\"button_customscale' + i.toString() + '\\\" onclick = \\\"customscale(this.id)\\\"> Rescale </button>'; \n", + " table_content.push(div_string);\n", + "\n", + "\n", + " //add button:autoscale\n", + " div_string = '<button class = \\\"button_tools\\\" id = \\\"button_autoscale' + i.toString() + '\\\" onclick = \\\"autoscale(this.id)\\\" title = \\\"(-10 eV, 10 eV)\\\"> Autoscale </button>'; \n", + " table_content.push(div_string);\n", + " //add button:fullscale\n", + " div_string = '<button class = \\\"button_tools\\\" id = \\\"button_fullscale' + i.toString() + '\\\" onclick = \\\"fullscale(this.id)\\\" title = \\\"(-100 eV, 100 eV)\\\"> Full scale </button><br><br>'; \n", + " table_content.push(div_string);\n", + "\n", + " //table_content.push(\"Select and zoom:\");\n", + "\n", + " /*//overview for select and zoom\n", + " div_string = '<div id = \\\"div_overview' + i.toString() + '\\\" class = \\\"div_overview\\\" ></div>'; // <div id=\"overview\" style=\"width:300px;height:200px; margin-left:10px; margin-top: 50px; padding-top: 0px\"></div>\n", + " table_content.push(div_string);\n", + " div_string = '<p id = \\\"overviewLegend' + i.toString() + '\\\" ></p>'; // <p id=\"overviewLegend\" style=\"margin-left:10px\"></p>\n", + " table_content.push(div_string);*/\n", + "\n", + " //download figures as png\n", + " div_string = '<a id = \\\"img_band' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download band </a>';\n", + " table_content.push(div_string); \n", + " div_string = '<a id = \\\"img_dos' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download DOS </a>';\n", + " table_content.push(div_string);\n", + "\n", + " //add show VBM & CBM\n", + " div_string = '<br><br><p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_VBM' + i.toString() + '\\\" unchecked onclick=\\\"show_VBM(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Show VBM </font> (<font color=\\\"blue\\\">\\•</font>) <font color=\\\"black\\\" size = 3px> and CBM </font>(<font color=\\\"red\\\">\\•</font>) </p>';\n", + " table_content.push(div_string);\n", + "\n", + "\n", + " table_content.push('</div>');//div_tools\n", + "\n", + " //checkbox for comparison\n", + " div_string = '<div id = \\\"div_checkbox_compare' + i.toString() + '\\\" class = \\\"div_checkbox_compare\\\" >';\n", + " table_content.push(div_string);\n", + " //div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n", + " div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" checked = \\\"unchecked\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n", + " table_content.push(div_string);\n", + " table_content.push('</div>');//div_checkbox_compare\n", + "\n", + "\n", + " table_content.push('</div>');//div_band_dos\n", + " table_content.push('</th>');\n", + " table_content.push('</tr>'); \n", + " }\n", + "\n", + " document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n", + " }\n", + "\n", + "\n", + " function visualize_band_dos()\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_jquery'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_axislabels'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_dashes'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_navigate'));\n", + " //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_selection'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_flot_legendoncanvas'));\n", + " document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n", + " document.getElementById(\"div_compare_buttons\").style.visibility=\"\";\n", + "\n", + "\n", + "\n", + " if(N_materials > N_max_show)\n", + " {\n", + " document.getElementById(\"div_showall\").style.visibility=\"visible\";\n", + " document.getElementById(\"checkbox_showall\").checked = \"\";\n", + " } \n", + "\n", + " N_materials_show = Math.min(N_max_show, N_materials);\n", + "\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + "\n", + " }\n", + "\n", + " function show_all(id)//\"plot_placeholder\"\n", + " {\n", + " var if_showall=0;\n", + " if_showall = check_show_VBM(id);\n", + " if(if_showall == 1)\n", + " {\n", + " N_materials_show = N_materials;\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + " }\n", + " else\n", + " {\n", + " N_materials_show = Math.min(N_max_show, N_materials);\n", + " prepare(N_materials_show);\n", + " clean_compare_list();\n", + " plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n", + " }\n", + "\n", + " }\n", + "\n", + " \n", + " //------------------Tool used to get the content from textarea---------------------\n", + " function get_text(textarea_id)\n", + " {\n", + " var text = document.getElementById(textarea_id).value;\n", + " return text;\n", + " }\n", + "\n", + "\n", + "\n", + " //-------------------Compare 2 band figures----------------------------------------\n", + "\n", + "\n", + " function check_compare(id)//checkbox_compare' + i.toString() + '\\\" unchecked onclick=\\\"check_compare(this.id)\n", + " {\n", + " var x = document.getElementById(id);\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " var N_chosen = 0;\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " if(choices_compare[i].checked)\n", + " {\n", + " N_chosen ++;\n", + " }\n", + " }\n", + " if(N_chosen == 2) // In max. only 2 figures could be selected and compared.\n", + " {\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " if(!choices_compare[i].checked)\n", + " {\n", + " choices_compare[i].disabled = 'disabled';\n", + " }\n", + " }\n", + " }\n", + " else\n", + " {\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " choices_compare[i].removeAttribute('disabled');\n", + " }\n", + " }\n", + "\n", + " }\n", + "\n", + " function compare()\n", + " {\n", + " $(\"#div_compare\").fadeIn(600);//show div for comparison\n", + " //check_compare(-100);\n", + "\n", + " var compare_list = [];\n", + " compare_list = make_compare_list();\n", + " //[i_material_1, i_material_2] = make_compare_list();\n", + " i_material_1 = compare_list[0];\n", + " i_material_2 = compare_list[1];\n", + " //document.getElementById(\"demo\").innerHTML = \"In add info compare:\" + i_material_1.toString() + i_material_2.toString();\n", + " compare_figures(i_material_1, i_material_2); \n", + " }\n", + " function make_compare_list()\n", + " {\n", + " //get the links to the images\n", + " images_selected_links = []; //store the links to the figures for comparison\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " var N_chosen = 0;\n", + " var str = ''; //tmp str for debug\n", + " var figure_selected = new Array(2);\n", + " for(var i=0; i<choices_compare.length; i++) //check which figures are selected\n", + " {\n", + " if(choices_compare[i].checked)\n", + " {\n", + " id_chosen = choices_compare[i].id;\n", + " i_chosen = Math.round(id_chosen.substring(16));\n", + " var tmp_str = image_band_links[i_chosen];\n", + " images_selected_links.push(tmp_str);\n", + " figure_selected[N_chosen] = i_chosen;\n", + " N_chosen ++;\n", + " //str += beakerx.image_band_links[i];\n", + " }\n", + " }\n", + " var i_material_1 = 0;\n", + " var i_material_2 = 0;\n", + " //document.getElementById(\"demo\").innerHTML = 'In making comare list';\n", + " image_band_links_selected = images_selected_links;\n", + " //document.getElementById(\"demo\").innerHTML = 'In making comare list: next';\n", + " if(N_chosen == 2)\n", + " {\n", + " i_material_1 = figure_selected[0];\n", + " i_material_2 = figure_selected[1];\n", + " }\n", + " //document.getElementById(\"demo\").innerHTML = 'Compare_list: ' +i_material_1.toString() + ' ' + i_material_2.toString();\n", + "\n", + " return [i_material_1, i_material_2];\n", + " }\n", + "\n", + " function check_compare_scale(i_material_1, i_material_2)\n", + " {\n", + " lowerlimit_id_1 = \"lowerlimit\" + i_material_1.toString();\n", + " lowerlimit_id_2 = \"lowerlimit\" + i_material_2.toString();\n", + " upperlimit_id_1 = \"upperlimit\" + i_material_1.toString();\n", + " upperlimit_id_2 = \"upperlimit\" + i_material_2.toString();\n", + "\n", + " lowerlimit_1 = parseFloat(document.getElementById(lowerlimit_id_1).innerHTML);\n", + " lowerlimit_2 = parseFloat(document.getElementById(lowerlimit_id_2).innerHTML);\n", + " upperlimit_1 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n", + " upperlimit_2 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n", + " if((lowerlimit_1 != lowerlimit_2) || (upperlimit_1 != upperlimit_2))\n", + " return -1;\n", + " else\n", + " return 1;\n", + " }\n", + "\n", + " function compare_figures(i_material_1, i_material_2)\n", + " {\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_query_beforeafter'));\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_compare_slide'));\n", + " add_info_compare(i_material_1, i_material_2);\n", + " document.getElementById(\"div_compare_container\").scrollIntoView({ behavior: 'smooth' }); \n", + " document.getElementById(\"div_compare_container\").scrollTop += 50;\n", + "\n", + " }\n", + "\n", + "\n", + " function clean_compare_list()\n", + " {\n", + " var choices_compare = document.getElementsByName(\"checkbox_compare\");\n", + " for(var i=0; i<choices_compare.length; i++)\n", + " {\n", + " //choices_compare[i].removeAttribute('checked');\n", + " //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n", + " choices_compare[i].checked = \"\";\n", + " choices_compare[i].removeAttribute('disabled');\n", + " }\n", + " }\n", + "\n", + " //-----------Add information about the calculation to \"div_tools\"---------------\n", + " function add_info(i)\n", + " {\n", + " \n", + " //document.getElementById(\"demoa\").innerHTML = i.toString() + div_info_id;\n", + " //for(var i = 0; i < beakerx.N_materials; i++)\n", + " //{\n", + " div_info_id = \"div_info\" + i.toString();\n", + "\n", + " var str = '';\n", + " str += \"<br> <p style=\\\"text-align:left\\\"><font size = 3pt><b>Atom labels:</b>     \" + info_obj_all[i][\"atom_labels\"] + '</font></p>';\n", + " //str += \"<font size = 3pt><b>Space group:</b>     \" + info_obj_all[i][\"space_group_symbol\"] + '</font>';\n", + " //str += \"<font size = 3pt><b>Lattice constants (in Ang):</b>     \" + info_obj_all[i][\"lattice_constant\"] + '</font>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Program name:</b>    \" + info_obj_all[i][\"program_name\"].toUpperCase() + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Basis set type:</b>    \" + info_obj_all[i][\"program_basis_set_type\"] + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Functional:</b>    \" + info_obj_all[i][\"XC_functional_name\"] + '</font></p>';\n", + " str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3) + '</font></p>';\n", + " document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n", + " //document.getElementById('program_name_1').innerHTML = \"<b>Code:</b>    \" + origData[\"program_name\"];\n", + " //document.getElementById('program_basis_set_type_1').innerHTML = \"<b>Basis set type:</b>    \" + origData[\"program_basis_set_type\"];\n", + " //document.getElementById('XC_functional_name_1').innerHTML = \"<b>Functional:</b>    \" + origData[\"XC_functional_name\"]; \n", + " //}\n", + " \n", + " }\n", + " function add_info_compare(i,j)\n", + " {\n", + "\n", + " div_info_id = \"div_compare_info\";\n", + " var str = '';\n", + "\n", + " if_same_scale = check_compare_scale(i_material_1, i_material_2);\n", + " if(if_same_scale == -1)\n", + " {\n", + " str = '<b><font size = \"15pt\" color=\"#940000\">Error: Different lower/upper limits.</font></b><br>';\n", + " document.getElementById(\"div_compare_container\").innerHTML = str;\n", + " document.getElementById(div_info_id).innerHTML = '';\n", + " return;\n", + " }\n", + "\n", + " str += \"<br><b><font-size:15pt>Information of the first calculation (left):</font></b> <br>\";\n", + " str += \"<br> <b>Atom labels:</b>     \" + info_obj_all[i][\"atom_labels\"];\n", + " //str += \"<br> <b>Space group:</b>     \" + info_obj_all[i][\"space_group_symbol\"];\n", + " //str += \"<br> <b>Lattice constants (in Ang):</b>     \" + info_obj_all[i][\"lattice_constant\"];\n", + " str += \"<br> <b>Program name:</b>    \" + info_obj_all[i][\"program_name\"].toUpperCase();\n", + " str += \"<br> <b>Basis set type:</b>    \" + info_obj_all[i][\"program_basis_set_type\"];\n", + " str += \"<br> <b>Functional:</b>    \" + info_obj_all[i][\"XC_functional_name\"];\n", + " str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " str += \"<br><br><br><b><font-size:15pt>Information of the second calculation (right):</font></b><br>\";\n", + " str += \"<br> <b>Atom labels:</b>     \" + info_obj_all[j][\"atom_labels\"];\n", + " //str += \"<br> <b>Space group:</b>     \" + info_obj_all[j][\"space_group_symbol\"];\n", + " //str += \"<br> <b>Lattice constants (in Ang):</b>     \" + info_obj_all[j][\"lattice_constant\"];\n", + " str += \"<br> <b>Program name:</b>    \" + info_obj_all[j][\"program_name\"].toUpperCase();\n", + " str += \"<br> <b>Basis set type:</b>    \" + info_obj_all[j][\"program_basis_set_type\"]; \n", + " str += \"<br> <b>Functional:</b>    \" + info_obj_all[j][\"XC_functional_name\"];\n", + " str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>    \" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n", + " document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n", + " }\n", + "\n", + "\n", + "\n", + " //-----------------------Show/hide VBM, CBM-------------------------\n", + " function check_show_VBM(checkbox_VBM_id)\n", + " {\n", + " var x = document.getElementById(checkbox_VBM_id);\n", + " var if_checked = 0;\n", + " if(x.checked)//== \"checked\")\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"checked!\";\n", + " if_checked = 1;\n", + " }\n", + " else if (x.unchecked)// == \"unchecked\")\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"unchecked!\";\n", + " if_checked = -1;\n", + " }\n", + " else\n", + " {\n", + " //document.getElementById(\"demoa\").innerHTML = \"nothing detected!\";\n", + " }\n", + " return if_checked;\n", + " }\n", + "\n", + " function check_if_in_compare_list(i) // check if the current material i is to be compared\n", + " {\n", + "\n", + " var checkbox_compare_id = \"checkbox_compare\" + i.toString();\n", + " var if_compare = check_show_VBM(checkbox_compare_id);\n", + " //document.getElementById(\"demo\").innerHTML = 'if_compare of ' + i.toString() + ' : ' + if_compare.toString();\n", + " var i_compare_material_1, i_compare_material_2;\n", + " [i_compare_material_1, i_compare_material_2] = make_compare_list();\n", + " var i_in_compare_list = -1;\n", + " if(i_compare_material_1 == i)\n", + " {\n", + " i_in_compare_list = 1;\n", + " }\n", + " else if (i_compare_material_2 == i)\n", + " {\n", + " i_in_compare_list = 2;\n", + " }\n", + " else\n", + " {\n", + " i_in_compare_list = 0;\n", + " }\n", + " //document.getElementById(\"demo\").innerHTML = 'Checking ' + i.toString() + ' in Compare_list: ' + i_in_compare_list.toString();\n", + " return [if_compare, i_in_compare_list];\n", + " }\n", + "\n", + " function show_VBM(id)\n", + " {\n", + " //prepare(\"new\");\n", + " //var if_show_VBM = -1;\n", + " var len_id = id.length;\n", + " var i_material = id.substring(12);\n", + " var i = Math.round(i_material);\n", + "\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + " //document.getElementById(\"demo\").innerHTML = i.toString() + ' in Compare_list: ' + i_in_compare_list.toString();\n", + "\n", + " plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + "\n", + " //---------------------Functions to rescale-------------------------------------------\n", + " function autoscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(16);\n", + " var i = Math.round(i_material);\n", + "\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " document.getElementById(upperlim_id).innerHTML =\"10.0\";\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " document.getElementById(lowerlim_id).innerHTML =\"-10.0\";\n", + "\n", + "\n", + " //document.getElementById(\"demoa\").innerHTML =i_material;\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + " plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + " function fullscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(16);\n", + " var i = Math.round(i_material);\n", + "\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " document.getElementById(upperlim_id).innerHTML =\"100.0\";\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " document.getElementById(lowerlim_id).innerHTML =\"-100.0\";\n", + "\n", + " //document.getElementById(\"demoa\").innerHTML =i_material;\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + "\n", + " plot_band_dos_i(i, -100, 100, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + " }\n", + "\n", + " function customscale(id)\n", + " {\n", + " var len_id = id.length;\n", + " var i_material = id.substring(18);\n", + " var i = Math.round(i_material);\n", + " //\n", + " upperlim_id = \"upperlimit\" + i_material;\n", + " upperlim = document.getElementById(upperlim_id).value;\n", + " upperlim_float = Math.round(upperlim);\n", + " lowerlim_id = \"lowerlimit\" + i_material;\n", + " lowerlim = document.getElementById(lowerlim_id).value;\n", + " lowerlim_float = Math.round(lowerlim);\n", + "\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + "\n", + " var if_compare, i_in_compare_list;\n", + " [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n", + "\n", + "\n", + "\n", + " plot_band_dos_i(i, lowerlim_float, upperlim_float, if_show_VBM, if_compare, i_in_compare_list); \n", + " }\n", + "\n", + "\n", + " function plot_band_dos(lowerLim, upperLim, N_materials_show)\n", + " {\n", + " placeholder_band = \"#div_band1\";\n", + " placeholder_dos = \"#div_dos1\";\n", + " // lowerLim = -10.01\n", + " //upperLim = 10.01\n", + "\n", + "\n", + "\n", + " //alert(\"plot_band_dos\");\n", + " //prepare();\n", + " for(var i = 0; i < N_materials_show; i++)\n", + " {\n", + " \n", + " var checkbox_material_id = \"checkbox_material\" + i.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + " add_info(i);\n", + " }\n", + "\n", + " //------Plot----------------\n", + " /*\n", + " for(var i_material = 0; i_material < N_materials_show; i_material++)\n", + " {\n", + "\n", + " //alert(\"Material \"+i);\n", + " var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected != 1)\n", + " {\n", + " continue;\n", + " }\n", + "\n", + " plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n", + " }\n", + " */\n", + " //alert(\"next:for\")\n", + " for (let i_material = 0, p = Promise.resolve(); i_material < N_materials_show; i_material++) {\n", + " p = p.then(_ => new Promise(resolve =>\n", + " setTimeout(function () {\n", + " //alert(i_material)\n", + " var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n", + " var if_selected = check_show_VBM(checkbox_material_id);\n", + " if(if_selected == 1)\n", + " {\n", + " plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n", + " }\n", + " resolve();\n", + " }, 0)\n", + " ));\n", + " }\n", + "\n", + "\n", + " return 1;\n", + " }\n", + "\n", + " var i = 0\n", + " var lowerLim = -10\n", + " var upperLim = 10\n", + " var if_show_VBM = 0\n", + " var if_compare = 0\n", + " var i_in_compare_list = -1\n", + "\n", + "\n", + " \n", + " function plot_band_dos_i(i_material, lowerLim_material, upperLim_material, if_show_VBM_material, if_compare_material, i_in_compare_list_material)\n", + " {\n", + " //alert(\"plot_band_dos_i\")\n", + "\n", + " i = i_material;\n", + " lowerLim = lowerLim_material;\n", + " upperLim = upperLim_material;\n", + " if_show_VBM = if_show_VBM_material;\n", + " if_compare = if_compare_material;\n", + " i_in_compare_list = i_in_compare_list_material;\n", + " //alert(\"plot_band_dos_i: i_material: \"+i)\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_band'));\n", + " //alert('i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list')\n", + " //plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n", + " Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_dos'));\n", + " } \n", + "</script>\n", + "\n", + " \n", + " \n", + "<br><br>\n", + "<button class=\"button\" onclick=\"process()\">Process data</button>\n", + "<br><br>\n", + "<div id = \"n_materials\" style = \"font-size: 18px; font-weight: 100; height: 60px; width: 100%;\"> Number of materials submitted: 0</div>\n", + "<div id = \"show_materials_submitted\" style = \"font-size: 20px; font-color: black;\"> </div>\n", + "\n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "<p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select materials to visualize the band structure and DOS:</p>\n", + "<div style = \"width :100%; height: 10px;\"></div> \n", + "<button class = \"button\" onclick = \"clean_materials_selection()\"> Clean selections </button> \n", + "<button class = \"button\" onclick = \"select_all()\"> Select all </button> \n", + "<button class = \"button\" onclick = \"visualize_band_dos()\"> Visualize </button> \n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "\n", + "<div id = \"show_materials_submitted_info\" style = \"width: 100%; font-size: 20px; font-color: black;\"> \n", + " <table id = \"table_materials_submitted_info\" style=\"width:100%\"> </table>\n", + "</div>\n", + "\n", + "<div style = \"width :100%; height: 30px;\"></div> \n", + "\n", + "\n", + "\n", + "\n", + "<div id=\"div_compare_buttons\" style=\"visibility:hidden\">\n", + " <br><br><br>\n", + " <p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select two materials in the checkbox on the right for comparison:</p>\n", + " <p style=\"color: #000;font-weight: 1000; font-size: 8pt;\"></p>\n", + " <button class = \"button\" onclick = \"clean_compare_list()\"> Clean selections </button> \n", + " <button class = \"button\" onclick = \"compare();compare()\" title = \"Select 2 materials in the checkbox below and compare: please make sure that the upper/lower limits are the same (using Rescale/Autoscale buttons).\" > Compare</button>\n", + "</div>\n", + "\n", + "\n", + "\n", + "<div id = \"div_showall\" style = \"width: 100%; visibility:hidden\">\n", + " <div style = \"width: 100%; height: 30px; \"></div>\n", + " <input type = \"checkbox\" id = \"checkbox_showall\" unchecked onclick=\"show_all(this.id)\"/> <font color=\"black\" size = 3px> Show all results </font><font size = 2px color = \"#666\"> (By default only the first 10 results are shown.) </font> \n", + " <div style = \"width: 100%; height: 30px; \"></div>\n", + "</div>\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "<div id = \"div_compare\" style = \"position: fixed; top: 20%; left: 10%; width: 1200px; height: 600px; z-index: 999999; border: 1px solid #555; background-color: #fff; display: none\" onclick = \"$(this).fadeOut(500)\"> \n", + " \n", + " <div style = \"float: right; width: 80px; height: 25px; margin-top: 10px; margin-right: 10px; z-index: 1000000; border: 1px solid #555; text-align: center; vertical-align: middle; background-color: #f9f9f9; font-size:12pt; font-color: #000; cursor:pointer;\" > CLOSE </div> <!--button to close the div-->\n", + " <div id = \"div_compare_info\" style = \" width: 350px; height: 500px; float: right; margin-top: 50px; margin-right: 10px; z-index: 10000000;\"></div>\n", + " <div id = \"div_compare_container\" style = \"margin-top: 50px; margin-left: 100px; width: 600px; height: 300px;\">\n", + " <div class=\"g-before-after\" id = \"div_compare_containerx\"></div>\n", + " </div>\n", + "</div>\n", + "\n", + "\n", + "<div id = \"demo\"></div>\n", + "\n", + "<div id = \"plot_placeholder\">\n", + " <div><br></div>\n", + " <table id = \"table_visualize\"> </table>\n", + "</div>\n", + "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "tags": [ + "plot_band" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + " //alert(\"tag: plot_band\")\n", + "\n", + "plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + "function plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n", + "{\n", + " //i=0;\n", + " //alert(\"plot_band \"+ i)\n", + " var placeholder_band = \"#div_band\" + i.toString();\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var img_band_id = \"img_band\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + "\n", + " var placeholder_band_compare = \"\";\n", + "\n", + "\n", + " if(i_in_compare_list == 1)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\";\n", + " }\n", + " else if(i_in_compare_list == 2)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_2\";\n", + " }\n", + " else\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n", + " }\n", + "\n", + " Object.size = function(obj) {\n", + " var size = 0, key;\n", + " for (key in obj) \n", + " {\n", + " if (obj.hasOwnProperty(key)) size++;\n", + " }\n", + " return size;\n", + " };\n", + "\n", + " //Get the number of bands\n", + " //alert(\"Getting band\")\n", + " //alert(band_obj_all)\n", + " //alert(\"band_obj_all got!\")\n", + " var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n", + " var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n", + " //alert(band_obj_all[i][\"band_y_axis\"])\n", + " var band_plotdata = [];\n", + " \n", + " for(var i_band =0; i_band < N_bands; i_band++)\n", + " {\n", + " var tmp_data = [];\n", + " for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n", + " {\n", + " tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n", + " }\n", + " var plotData = { shadowSize: 0 , data: tmp_data, color: 'black', series: { lines: { show: true } , points: {show: false} } };\n", + " band_plotdata.push(plotData);\n", + " }\n", + "\n", + "\n", + " var tmp_data0 = [[0, 0], [1, 0]];\n", + " var plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n", + " band_plotdata.push(plotData0);\n", + "\n", + " var band_plotdata_overview = band_plotdata.slice(0);\n", + "\n", + " var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n", + " var HOMOlabel = [\"VBM\"];\n", + " var plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false}, showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n", + " var LUMOlabel = [\"CBM\"];\n", + " var plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false}, showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + " if (if_show_VBM == 1)\n", + " {\n", + " band_plotdata.push(plotHOMO);\n", + " band_plotdata.push(plotLUMO);\n", + " }\n", + "\n", + " \n", + " //alert(img_band_id + band_plotdata)\n", + " \n", + " //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n", + " //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\" }\n", + "\n", + " var canvas_band;\n", + " var options_band = {\n", + " canvas: true,\n", + " //legend:{ type: \"canvas\" },\n", + " series: { lines: { show: true, lineWidth: 2 }, \n", + " points: { show: false } }, \n", + " xaxis: { \n", + " ticks: band_obj_all[i][\"labels\"], \n", + " color:\"#000\", \n", + " font: {size: 20}, \n", + " zoomRange: false,\n", + " panRange: false \n", + " }, \n", + " yaxis: { \n", + " axisLabel: \"Energy (eV)\", \n", + " axisLabelUseCanvas: true,\n", + " //axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20, family:\"Arial\"},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " zoom: { \n", + " interactive: true\n", + " },\n", + "\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n", + "\n", + " grid: { \n", + " labelMargin: 15,\n", + " hoverable: true, \n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n", + " borderWidth: {\n", + " top: 2, \n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null } \n", + " }\n", + " }\n", + " //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n", + " //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n", + " var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n", + " var image_band = plot_band.toDataURL();\n", + " image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n", + " //beakerx.image_band = image_band;\n", + " document.getElementById(img_band_id).href= image_band;\n", + " image_band_links[i] = image_band;\n", + " //alert(\"band done\")\n", + "}\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + " //alert(\"tag: plot_band\")\n", + "\n", + "plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n", + "\n", + "function plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n", + "{\n", + " //i=0;\n", + " //alert(\"plot_band \"+ i)\n", + " var placeholder_band = \"#div_band\" + i.toString();\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var img_band_id = \"img_band\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + "\n", + " var placeholder_band_compare = \"\";\n", + "\n", + "\n", + " if(i_in_compare_list == 1)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\";\n", + " }\n", + " else if(i_in_compare_list == 2)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_2\";\n", + " }\n", + " else\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n", + " }\n", + "\n", + " Object.size = function(obj) {\n", + " var size = 0, key;\n", + " for (key in obj) \n", + " {\n", + " if (obj.hasOwnProperty(key)) size++;\n", + " }\n", + " return size;\n", + " };\n", + "\n", + " //Get the number of bands\n", + " //alert(\"Getting band\")\n", + " //alert(band_obj_all)\n", + " //alert(\"band_obj_all got!\")\n", + " var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n", + " var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n", + " //alert(band_obj_all[i][\"band_y_axis\"])\n", + " var band_plotdata = [];\n", + " \n", + " for(var i_band =0; i_band < N_bands; i_band++)\n", + " {\n", + " var tmp_data = [];\n", + " for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n", + " {\n", + " tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n", + " }\n", + " var plotData = { shadowSize: 0 , data: tmp_data, color: 'black', series: { lines: { show: true } , points: {show: false} } };\n", + " band_plotdata.push(plotData);\n", + " }\n", + "\n", + "\n", + " var tmp_data0 = [[0, 0], [1, 0]];\n", + " var plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n", + " band_plotdata.push(plotData0);\n", + "\n", + " var band_plotdata_overview = band_plotdata.slice(0);\n", + "\n", + " var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n", + " var HOMOlabel = [\"VBM\"];\n", + " var plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false}, showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n", + " var LUMOlabel = [\"CBM\"];\n", + " var plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false}, showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + " if (if_show_VBM == 1)\n", + " {\n", + " band_plotdata.push(plotHOMO);\n", + " band_plotdata.push(plotLUMO);\n", + " }\n", + "\n", + " \n", + " //alert(img_band_id + band_plotdata)\n", + " \n", + " //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n", + " //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\" }\n", + "\n", + " var canvas_band;\n", + " var options_band = {\n", + " canvas: true,\n", + " //legend:{ type: \"canvas\" },\n", + " series: { lines: { show: true, lineWidth: 2 }, \n", + " points: { show: false } }, \n", + " xaxis: { \n", + " ticks: band_obj_all[i][\"labels\"], \n", + " color:\"#000\", \n", + " font: {size: 20}, \n", + " zoomRange: false,\n", + " panRange: false \n", + " }, \n", + " yaxis: { \n", + " axisLabel: \"Energy (eV)\", \n", + " axisLabelUseCanvas: true,\n", + " //axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20, family:\"Arial\"},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " zoom: { \n", + " interactive: true\n", + " },\n", + "\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n", + "\n", + " grid: { \n", + " labelMargin: 15,\n", + " hoverable: true, \n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n", + " borderWidth: {\n", + " top: 2, \n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null } \n", + " }\n", + " }\n", + " //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n", + " //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n", + " var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n", + " var image_band = plot_band.toDataURL();\n", + " image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n", + " //beakerx.image_band = image_band;\n", + " document.getElementById(img_band_id).href= image_band;\n", + " image_band_links[i] = image_band;\n", + " //alert(\"band done\")\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "tags": [ + "plot_dos" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + " //alert(\"tag: plot_dos \" + i)\n", + " //i=0;\n", + "\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + "\n", + "//----Plot DOS----------------------\n", + " var dos_plotdata = [];\n", + " //alert(\"dos:\"+dos_obj_all[i])\n", + " var xdos = dos_obj_all[i][\"dos_x_axis\"];\n", + " var ydos = dos_obj_all[i][\"dos_y_axis\"][0];\n", + " var dosLabelPos = Math.max.apply(Math, ydos)/2;\n", + " var d2 = [];\n", + " for (var ii = 0; ii < xdos.length; ii+=1) {\n", + " d2.push([ydos[ii],xdos[ii]]);\n", + " }\n", + " var plotData2={ shadowSize: 0, color: 'black' , data: d2};\n", + " dos_plotdata.push(plotData2);\n", + " //alert(\"dos_plotdata\"+JSON.stringify(dos_plotdata[0]));\n", + " \n", + " function find_xaxis_max_min(data, lowerbound, upperbound)\n", + " {\n", + " //data[xaxis,y] find the max and min value of x axis\n", + " //alert(\"dos[0]:\" + data[0][\"data\"]);\n", + " //alert(\"Bounds: \" + lowerbound + \" , \" + upperbound)\n", + " var n_data = data.length;\n", + " //alert(\"N dos: \" + n_data);\n", + " var data_min = 1000000;\n", + " var data_max = -1000000;\n", + " var data_current = 0;\n", + " for (var i = 0; i < n_data; i++)\n", + " {\n", + " if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n", + " {\n", + " data_current = data[i][0];\n", + " //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n", + " if(data_current >= data_max)\n", + " {\n", + " data_max = data_current;\n", + " }\n", + " if(data_current <= data_min)\n", + " {\n", + " data_min = data_current;\n", + " }\n", + " }\n", + " }\n", + " var data_max_min = [data_max, data_min];\n", + " //alert(\"data_max_min: \" + data_max_min);\n", + " return data_max_min;\n", + " }\n", + " var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n", + " var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n", + " //alert(\"dos_x_max_min:\"+dos_x_max_min+\", dosLabelPos:\"+dosLabelPos);\n", + " var options_dos ={\n", + " canvas: true,\n", + " series: {\n", + " lines: { show: true, lineWidth:2 },\n", + " points: { show: false }\n", + " },\n", + "\n", + " yaxis: { \n", + " axisLabel: \"\", \n", + " axisLabelUseCanvas: true,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " xaxis: {\n", + " axisLabel: \" \",\n", + " axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial',\n", + " axisLabelPadding: 3,\n", + " color:\"rgb(0, 0, 0)\",\n", + " font: {size: 20, family:\"Arial\"},\n", + " //ticks: 10,\n", + " tickLength:0,\n", + " min: dos_x_max_min[1],//0,\n", + " max: dos_x_max_min[0],//1,\n", + " tickDecimals: 0,\n", + " ticks: [[ dosLabelPos ,'DOS']],\n", + " //tickFormatter: MyFormatter\n", + " panRange: false\n", + " },\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " grid: {\n", + " labelMargin: 15,\n", + " hoverable: true,\n", + " //borderWidth : 1000,\n", + " //show : false,\n", + " // //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n", + " borderWidth: {\n", + " top: 2,\n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null\n", + " }\n", + " }\n", + " }\n", + " var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n", + " var image_dos = plot_dos.toDataURL();\n", + " image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n", + " image_dos = image_dos;\n", + " document.getElementById(img_dos_id).href= image_dos;\n", + " //alert(\"dos done.\")\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + " //alert(\"tag: plot_dos \" + i)\n", + " //i=0;\n", + "\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + "\n", + "//----Plot DOS----------------------\n", + " var dos_plotdata = [];\n", + " //alert(\"dos:\"+dos_obj_all[i])\n", + " var xdos = dos_obj_all[i][\"dos_x_axis\"];\n", + " var ydos = dos_obj_all[i][\"dos_y_axis\"][0];\n", + " var dosLabelPos = Math.max.apply(Math, ydos)/2;\n", + " var d2 = [];\n", + " for (var ii = 0; ii < xdos.length; ii+=1) {\n", + " d2.push([ydos[ii],xdos[ii]]);\n", + " }\n", + " var plotData2={ shadowSize: 0, color: 'black' , data: d2};\n", + " dos_plotdata.push(plotData2);\n", + " //alert(\"dos_plotdata\"+JSON.stringify(dos_plotdata[0]));\n", + " \n", + " function find_xaxis_max_min(data, lowerbound, upperbound)\n", + " {\n", + " //data[xaxis,y] find the max and min value of x axis\n", + " //alert(\"dos[0]:\" + data[0][\"data\"]);\n", + " //alert(\"Bounds: \" + lowerbound + \" , \" + upperbound)\n", + " var n_data = data.length;\n", + " //alert(\"N dos: \" + n_data);\n", + " var data_min = 1000000;\n", + " var data_max = -1000000;\n", + " var data_current = 0;\n", + " for (var i = 0; i < n_data; i++)\n", + " {\n", + " if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n", + " {\n", + " data_current = data[i][0];\n", + " //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n", + " if(data_current >= data_max)\n", + " {\n", + " data_max = data_current;\n", + " }\n", + " if(data_current <= data_min)\n", + " {\n", + " data_min = data_current;\n", + " }\n", + " }\n", + " }\n", + " var data_max_min = [data_max, data_min];\n", + " //alert(\"data_max_min: \" + data_max_min);\n", + " return data_max_min;\n", + " }\n", + " var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n", + " var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n", + " //alert(\"dos_x_max_min:\"+dos_x_max_min+\", dosLabelPos:\"+dosLabelPos);\n", + " var options_dos ={\n", + " canvas: true,\n", + " series: {\n", + " lines: { show: true, lineWidth:2 },\n", + " points: { show: false }\n", + " },\n", + "\n", + " yaxis: { \n", + " axisLabel: \"\", \n", + " axisLabelUseCanvas: true,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " xaxis: {\n", + " axisLabel: \" \",\n", + " axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial',\n", + " axisLabelPadding: 3,\n", + " color:\"rgb(0, 0, 0)\",\n", + " font: {size: 20, family:\"Arial\"},\n", + " //ticks: 10,\n", + " tickLength:0,\n", + " min: dos_x_max_min[1],//0,\n", + " max: dos_x_max_min[0],//1,\n", + " tickDecimals: 0,\n", + " ticks: [[ dosLabelPos ,'DOS']],\n", + " //tickFormatter: MyFormatter\n", + " panRange: false\n", + " },\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " grid: {\n", + " labelMargin: 15,\n", + " hoverable: true,\n", + " //borderWidth : 1000,\n", + " //show : false,\n", + " // //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n", + " borderWidth: {\n", + " top: 2,\n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null\n", + " }\n", + " }\n", + " }\n", + " var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n", + " var image_dos = plot_dos.toDataURL();\n", + " image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n", + " image_dos = image_dos;\n", + " document.getElementById(img_dos_id).href= image_dos;\n", + " //alert(\"dos done.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "tags": [ + "init_jquery" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"http://code.jquery.com/jquery-1.8.3.min.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"http://code.jquery.com/jquery-1.8.3.min.js\"></script>" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "tags": [ + "init_flot" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"js/jquery.flot.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"js/jquery.flot.js\"></script>\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "tags": [ + "init_flot_axislabels" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"js/jquery.flot.axislabels.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"js/jquery.flot.axislabels.js\"></script>" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "tags": [ + "init_flot_navigate" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"js/jquery.flot.navigate.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"js/jquery.flot.navigate.js\"></script>" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": { + "tags": [ + "init_flot_selection" + ] + }, + "outputs": [ + { + "data": { + "text/html": [ + "<script src=\"js/jquery.flot.selection.js\"></script>\n" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%HTML\n", + "<script src=\"js/jquery.flot.selection.js\"></script>" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "tags": [ + "js_query_beforeafter" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "//jquery.beforeafter.min.js\n", + "!function(e){e.fn.beforeafter=function(i){var t=e.extend({touch:!0,message:\"Slide\",hide_message:!0,reset:!0,reset_delay:3e3,drag_horizontal:!0,split_horizontal:!0\n", + "},i);return this.each(function(){var i=e(this),a=i.find(\"img\"),n=a.data(\"aftersrc\"),s=i.width(),d=0;a.after('<div class=\"g-img-after\"><img style=\"width: '+s+'px;\" src=\"'+n+'\"></div>'),\n", + "a.addClass(\"g-img-before\").width(s),i.append('<div class=\"g-img-divider\"><span>'+t.message+\"</span></div>\"),d=i.height(),t.split_horizontal||i.addClass(\"g-vertical\"),\n", + "i.on(\"mouseenter touchstart\",function(e){var t=i.data(\"reset-timer\");t&&(window.clearTimeout(t),i.data(\"reset-timer\",!1))}).on(\"mousemove touchmove\",function(a){\n", + "var n=0,o=0,r=i.find(\".g-img-divider span\");if(t.drag_horizontal)n=a.pageX-i.offset().left,o=n/s*100;else{var f=i.offset().top-e(window).scrollTop();n=a.clientY/f,\n", + "o=(a.clientY-f)/d*100}if(t.touch&&\"undefined\"!=typeof a.originalEvent.touches){var g=a.originalEvent.touches[0];o=t.drag_horizontal?(g.pageX-i.offset().left)/s*100:(g.pageY-i.offset().top)/d*100;\n", + "}t.split_horizontal?(i.find(\".g-img-after\").css(\"left\",o+\"%\"),i.find(\".g-img-divider\").css(\"left\",o+\"%\")):(i.find(\".g-img-after\").css(\"top\",o+\"%\"),i.find(\".g-img-divider\").css(\"top\",o+\"%\")),\n", + "t.hide_message&&r.is(\":visible\")&&r.fadeOut()}).on(\"mouseleave touchend touchcancel\",function(e){var a=i.data(\"reset-timer\"),n=i.find(\".g-img-divider span\");\n", + "t.reset&&(a||(a=window.setTimeout(function(){t.split_horizontal?(i.find(\".g-img-after\").animate({left:\"50%\"},500),i.find(\".g-img-divider\").animate({left:\"50%\"\n", + "},500,function(){n.fadeIn()})):(i.find(\".g-img-after\").animate({top:\"50%\"},500),i.find(\".g-img-divider\").animate({top:\"50%\"},500,function(){n.fadeIn()})),\n", + "i.data(\"reset-timer\",!1)},t.reset_delay),i.data(\"reset-timer\",a)))})}),this}}(jQuery);\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + "//jquery.beforeafter.min.js\n", + "!function(e){e.fn.beforeafter=function(i){var t=e.extend({touch:!0,message:\"Slide\",hide_message:!0,reset:!0,reset_delay:3e3,drag_horizontal:!0,split_horizontal:!0\n", + "},i);return this.each(function(){var i=e(this),a=i.find(\"img\"),n=a.data(\"aftersrc\"),s=i.width(),d=0;a.after('<div class=\"g-img-after\"><img style=\"width: '+s+'px;\" src=\"'+n+'\"></div>'),\n", + "a.addClass(\"g-img-before\").width(s),i.append('<div class=\"g-img-divider\"><span>'+t.message+\"</span></div>\"),d=i.height(),t.split_horizontal||i.addClass(\"g-vertical\"),\n", + "i.on(\"mouseenter touchstart\",function(e){var t=i.data(\"reset-timer\");t&&(window.clearTimeout(t),i.data(\"reset-timer\",!1))}).on(\"mousemove touchmove\",function(a){\n", + "var n=0,o=0,r=i.find(\".g-img-divider span\");if(t.drag_horizontal)n=a.pageX-i.offset().left,o=n/s*100;else{var f=i.offset().top-e(window).scrollTop();n=a.clientY/f,\n", + "o=(a.clientY-f)/d*100}if(t.touch&&\"undefined\"!=typeof a.originalEvent.touches){var g=a.originalEvent.touches[0];o=t.drag_horizontal?(g.pageX-i.offset().left)/s*100:(g.pageY-i.offset().top)/d*100;\n", + "}t.split_horizontal?(i.find(\".g-img-after\").css(\"left\",o+\"%\"),i.find(\".g-img-divider\").css(\"left\",o+\"%\")):(i.find(\".g-img-after\").css(\"top\",o+\"%\"),i.find(\".g-img-divider\").css(\"top\",o+\"%\")),\n", + "t.hide_message&&r.is(\":visible\")&&r.fadeOut()}).on(\"mouseleave touchend touchcancel\",function(e){var a=i.data(\"reset-timer\"),n=i.find(\".g-img-divider span\");\n", + "t.reset&&(a||(a=window.setTimeout(function(){t.split_horizontal?(i.find(\".g-img-after\").animate({left:\"50%\"},500),i.find(\".g-img-divider\").animate({left:\"50%\"\n", + "},500,function(){n.fadeIn()})):(i.find(\".g-img-after\").animate({top:\"50%\"},500),i.find(\".g-img-divider\").animate({top:\"50%\"},500,function(){n.fadeIn()})),\n", + "i.data(\"reset-timer\",!1)},t.reset_delay),i.data(\"reset-timer\",a)))})}),this}}(jQuery);" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "tags": [ + "js_compare_slide" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "var div_str = '';\n", + "//div_str = '<style> .g-before-after{position:relative;overflow:hidden}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%} </style>'\n", + "//div_str += '<script>$(\\'#div_compare_containerx\\').beforeafter(); </script>';\n", + "//div_str +='<script type=\\\"text/javascript\\\" src=\\\"https://github.com/jquery/jquery/blob/master/src/jquery.js\\\"></script> '\n", + "//div_str += '<div class=\\\"g-before-after\\\" id=\\\"div_compare_containerx\\\">';\n", + "div_str +='<img src = \\\"'\n", + "\n", + "var src1 = image_band_links_selected[0];\n", + "var src2 = image_band_links_selected[1];\n", + "var tmp_src1 = src1;\n", + "var tmp_src2 = src2;\n", + "//src1 = \"https://images4.alphacoders.com/640/640956.jpg\";\n", + "//src2 = \"http://imgmr.com/wp-content/uploads/2016/06/SAO-anime.jpg\";\n", + "div_str +=src1;\n", + "div_str += '\\\" data-aftersrc=\\\"'\n", + "div_str +=src2;\n", + "//div_str += '\\\"></div>';\n", + "div_str += '\\\"/>';\n", + "//#div_compare_containerx\n", + "document.getElementById(\"div_compare_containerx\").innerHTML = div_str;\n", + "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n", + "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n", + "//beakerx.image_band_links[i]\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + "var div_str = '';\n", + "//div_str = '<style> .g-before-after{position:relative;overflow:hidden}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%} </style>'\n", + "//div_str += '<script>$(\\'#div_compare_containerx\\').beforeafter(); </script>';\n", + "//div_str +='<script type=\\\"text/javascript\\\" src=\\\"https://github.com/jquery/jquery/blob/master/src/jquery.js\\\"></script> '\n", + "//div_str += '<div class=\\\"g-before-after\\\" id=\\\"div_compare_containerx\\\">';\n", + "div_str +='<img src = \\\"'\n", + "\n", + "var src1 = image_band_links_selected[0];\n", + "var src2 = image_band_links_selected[1];\n", + "var tmp_src1 = src1;\n", + "var tmp_src2 = src2;\n", + "//src1 = \"https://images4.alphacoders.com/640/640956.jpg\";\n", + "//src2 = \"http://imgmr.com/wp-content/uploads/2016/06/SAO-anime.jpg\";\n", + "div_str +=src1;\n", + "div_str += '\\\" data-aftersrc=\\\"'\n", + "div_str +=src2;\n", + "//div_str += '\\\"></div>';\n", + "div_str += '\\\"/>';\n", + "//#div_compare_containerx\n", + "document.getElementById(\"div_compare_containerx\").innerHTML = div_str;\n", + "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n", + "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n", + "//beakerx.image_band_links[i]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false, + "tags": [ + "process_band_dos_data_python" + ] + }, + "outputs": [], + "source": [ + "#tag:python_2\n", + "import urllib.request, json\n", + "import numpy as np\n", + "import math\n", + "\n", + "#======Define global objs============\n", + "info_all = []\n", + "band_obj_all = []\n", + "dos_obj_all = []\n", + "\n", + "def load_jsonfile(path):\n", + " #with open(path, encoding='utf-8') as band_file: \n", + " # return json.load(band_file)\n", + "\n", + " \n", + " with urllib.request.urlopen(path) as url:\n", + " data = json.loads(url.read().decode())\n", + " return data\n", + "\n", + "#-----Get the labels for x axis---------------\n", + "def get_label_flag(coor_array):\n", + " #np.sort(coor_array)\n", + " x = coor_array[0]\n", + " y = coor_array[1]\n", + " z = coor_array[2]\n", + " coor =np.sort([x,y,z])\n", + " xx = coor[0]\n", + " yy = coor[1]\n", + " zz = coor[2]\n", + " coor = [xx, yy, zz]\n", + " #pprint(coor)\n", + " if (coor == [0, 0.5, 0.5]):\n", + " return \"X\"\n", + " if (coor == [0, 0.0, 0.5]):\n", + " return \"M\"\n", + " elif (coor == [0.5, 0.5, 0.5]):\n", + " return \"L\"\n", + " elif (coor == [0.375, 0.375, 0.75]):\n", + " return \"K\"\n", + " elif (coor == [0.25, 0.5, 0.75]):\n", + " return \"W\"\n", + " elif (coor == [0, 0, 0]):\n", + " return \"\\u0393\"\n", + " elif (coor == [0.25, 0.625, 0.625]):\n", + " return \"U\"\n", + " else:\n", + " return \"?\"\n", + "\n", + "#============Process the band structure data============\n", + "def get_band_obj(band_path, dos_fermi_energy):\n", + "\n", + " #band_data: read from json file \n", + " #Load the data files for band\n", + " band_data = load_jsonfile(band_path)\n", + " \n", + " #---------Read section_k_band_segment------------\n", + " section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n", + " \n", + " #--------Get the number of k band segments-------------\n", + " N_k_band_segments = len(section_k_band_segment)\n", + " \n", + " #----------Get the total number of k points in all segments---------\n", + " N_k_points_all = 0\n", + " for i in range(N_k_band_segments):\n", + " band_k_points = section_k_band_segment[i]['band_k_points']\n", + " N_k_points_all = N_k_points_all + len(band_k_points)\n", + " \n", + " #--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n", + " # store in k_coor_1D[N_k_points_total]-----------------\n", + "\n", + " band_distance_segments = np.zeros(N_k_band_segments)\n", + " for i in range(N_k_band_segments):\n", + " [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end'] #\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n", + " band_distance_segments[i] = math.pow((x1-x2), 2) + math.pow((y1-y2), 2) + math.pow((z1-z2), 2)\n", + "\n", + " \n", + " band_distance_total = math.fsum(band_distance_segments)\n", + " #print(band_distance_segments)\n", + " average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total\n", + " \n", + " #Prepare the parameters to rescale the k coordinates into [0,1]\n", + " step_k_point = 1.0 / N_k_points_all\n", + " step_k_point = (1.0 + step_k_point) / N_k_points_all\n", + " \n", + " # \n", + " k_coor_1D = np.zeros((N_k_points_all))\n", + " for i_k_points in range(N_k_points_all):\n", + " k_coor_1D[i_k_points] = round( step_k_point * i_k_points, 3)\n", + " #for i in range(N_k_band_segments):\n", + " # ki[i] = \n", + " \n", + "\n", + " #--------Get the eigenvalues of each band trajectory--------------\n", + " N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n", + " N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n", + " band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n", + " N_k_points_all = 0\n", + " for i_segments in range(N_k_band_segments):\n", + " band_energies = section_k_band_segment[i_segments]['band_energies']\n", + " N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n", + " N_k_points_per_segment = len(band_energies[0])\n", + " for i_k_points in range(N_k_points_per_segment):\n", + " for i_bands in range(N_bands):\n", + " band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n", + " N_k_points_all = N_k_points_all + 1\n", + " \n", + " \n", + " N_labels = 0\n", + " for i_segments in range(N_k_band_segments):\n", + " for j in range(2):\n", + " labels_tmp = section_k_band_segment[i_segments]['band_segm_start_end'][j];\n", + " N_labels = N_labels + 1\n", + "\n", + " label_flag = [\"\" for i in range(N_labels)] #stores the flags of the labels (X, W, G, etc)\n", + "\n", + " i_label = 0\n", + " label_flag_last_final = \"\"\n", + " label_flag_current_initial = \"\"\n", + " for i_segments in range(N_k_band_segments):\n", + " labels_coor_0 = section_k_band_segment[i_segments]['band_segm_start_end'][0];\n", + " labels_coor_1 = section_k_band_segment[i_segments]['band_segm_start_end'][1];\n", + " np.sort(labels_coor_0)\n", + " np.sort(labels_coor_1)\n", + " label_flag_0 = get_label_flag(labels_coor_0)\n", + " label_flag_1 = get_label_flag(labels_coor_1)\n", + " label_flag_current_initial = label_flag_0\n", + " if(label_flag_last_final == \"\"):\n", + " label_flag_last_final = label_flag_0\n", + "\n", + " if(label_flag_last_final == label_flag_current_initial):\n", + " label_flag[i_label] = label_flag_current_initial\n", + " else:\n", + " label_flag[i_label] = \"\".join([label_flag_last_final, '|', label_flag_current_initial])\n", + " label_flag_last_final = label_flag_1\n", + " \n", + "\n", + " i_label = i_label + 1\n", + " if(i_segments == N_k_band_segments - 1):\n", + " label_flag[i_label] = label_flag_1\n", + " i_label = i_label + 1\n", + "\n", + " N_labels = i_label\n", + " \n", + " #------------Get the coordinates for the labels------------\n", + " #label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n", + " label_coor_relative = np.zeros((N_labels))\n", + " for i_label in range(N_labels):\n", + " #Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n", + " #x = labels_coor_0[0]\n", + " #y = labels_coor_0[1]\n", + " #z = labels_coor_0[2]\n", + " #label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n", + " label_coor_relative[i_label] = step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all);\n", + "\n", + " #----Store the label-----------\n", + " label_obj =[['' for i in range(2)] for j in range(N_labels)]\n", + " for i_label in range(N_labels):\n", + " label_obj[i_label][0] = label_coor_relative[i_label]\n", + " label_obj[i_label][1] = label_flag[i_label]\n", + " \n", + " #print(label_obj)\n", + " \n", + " \n", + " #Rescal the energies with respect to dos_fermi_energy\n", + " for i_k_points in range(N_k_points_all):\n", + " for i_bands in range(N_bands):\n", + " band_energies_all[i_bands][i_k_points] = band_energies_all[i_bands][i_k_points] - dos_fermi_energy\n", + "\n", + " #-------Get VBM, CBM----------------\n", + "\n", + " HOMO = -1000\n", + " LUMO = 1000\n", + " coor_k_point_HOMO = np.zeros((3)) #the coordinate of k point that stores HOMO\n", + " coor_k_point_LUMO = np.zeros((3)) #the coordinate of k point that stores LUMO\n", + " #band_gap_direct = 0.0\n", + " band_gap_indirect = 0.0\n", + " \n", + " \n", + " #band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " #band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n", + " band_energy_max = 10\n", + " band_energy_min = -10\n", + " #N_band_energy_index = 10000\n", + " #band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n", + " #N_allowed_states = np.zeros(N_band_energy_index + 1)\n", + " #i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n", + "\n", + " for i_k_points_all in range(N_k_points_all):\n", + " for i_bands in range(N_bands):\n", + " #i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n", + " #N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n", + " band_energy = band_energies_all[i_bands][i_k_points_all]\n", + " if(band_energy > 0):\n", + " if(band_energy < LUMO):\n", + " LUMO = band_energy\n", + " else:\n", + " if(band_energy > HOMO):\n", + " HOMO = band_energy\n", + " #for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n", + " # if(N_allowed_states[i_band_index] > 0):\n", + " # LUMO = band_energy_min + band_energy_step * i_band_index\n", + " print('HOMO, LUMO: ',HOMO, LUMO)\n", + " band_gap_indirect = abs(LUMO - HOMO)\n", + " \n", + " if(band_gap_indirect < 0.5): #VBM and CBM has to be found in another way for metals/charged system:\n", + " HOMO = -1000\n", + " LUMO = 1000\n", + " band_energy_max = 10\n", + " band_energy_min = 0\n", + " N_band_energy_index = 10000\n", + " band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n", + " N_allowed_states = np.zeros(N_band_energy_index + 1)\n", + " \n", + " #get the DOS and store in N_allowed_states[]\n", + " for i_k_points_all in range(N_k_points_all):\n", + " for i_bands in range(N_bands):\n", + " band_energy = band_energies_all[i_bands][i_k_points_all]\n", + " if(band_energy_min < band_energy < band_energy_max):\n", + " i_band_index = math.floor((band_energy - band_energy_min) / band_energy_step)\n", + " N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1\n", + " if_gapped = 0\n", + " for i_band_index in range(N_band_energy_index): #go through the energy levels from the bottom\n", + " band_energy = band_energy_min + band_energy_step * i_band_index\n", + " if(N_allowed_states[i_band_index] == 0):\n", + " if_gapped = if_gapped + 1\n", + " if(band_energy > band_energy_max - 0.5) and (if_gapped == 0):\n", + " print(\"No gap found in this system. It seems to be a metal.\")\n", + " HOMO = 1000\n", + " LUMO = 1000\n", + " break\n", + " #print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n", + " \n", + " if(N_allowed_states[i_band_index] > 0):\n", + " if(if_gapped * band_energy_step> 0.3 ): #above VBM-CBM gap: LUMO\n", + " if(band_energy < LUMO):\n", + " #print(\"LUMO got!\")\n", + " LUMO = band_energy\n", + " break #break before touching another gap that is above the band gap\n", + " if(if_gapped * band_energy_step < 0.3): #below VBM-CBM gap: HOMO\n", + " if(band_energy > HOMO):\n", + " #print(\"HOMO got!\")\n", + " HOMO = band_energy\n", + " \n", + " if_gapped = 0\n", + " \n", + " print('HOMO, LUMO for metal/charged system: ',HOMO, LUMO)\n", + " \n", + " '''\n", + "\n", + "# print('HOMO: ',tmp_HOMO_max)\n", + " HOMO_global = tmp_HOMO_max\n", + " LUMO_global = tmp_LUMO_min\n", + " band_gap_indirect = LUMO_global - HOMO_global\n", + " E_top_valence = HOMO_global\n", + " if(band_gap_indirect < 0):\n", + " band_gap_indirect = 0\n", + "\n", + " #Rescal HOMO and LUMO with respect to HOMO\n", + " HOMO_global = round((HOMO_global - E_top_valence), 3)\n", + " LUMO_global = round((LUMO_global - E_top_valence), 3)\n", + " '''\n", + " \n", + " \n", + " \n", + " #Find the position of HOMO, LUMO\n", + "\n", + " for i_k_points in range(N_k_points_all):\n", + " for i_bands in range(N_bands):\n", + " if(abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001):\n", + " coor_k_point_HOMO = k_coor_1D[i_k_points]\n", + " if(abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001):\n", + " coor_k_point_LUMO = k_coor_1D[i_k_points] \n", + "\n", + "\n", + " \n", + " \n", + " #Store the band data to band_obj\n", + "\n", + " band_obj = {}\n", + " band_obj[\"band_x_axis\"] = np.array(k_coor_1D).tolist()\n", + " band_obj[\"band_y_axis\"] = np.array(band_energies_all).tolist()\n", + " band_obj[\"labels\"] = np.array(label_obj).tolist()\n", + " band_obj[\"HOMO_energy\"] = np.array(HOMO).tolist()\n", + " band_obj[\"HOMO_coor\"] = np.array(coor_k_point_HOMO).tolist()\n", + " band_obj[\"LUMO_energy\"] = np.array(LUMO).tolist()\n", + " band_obj[\"LUMO_coor\"] = np.array(coor_k_point_LUMO).tolist()\n", + " band_obj[\"average_N_k_points_per_inverse_distance\"] = np.array(average_N_k_points_per_inverse_distance).tolist()\n", + " \n", + "\n", + " \n", + " return band_obj\n", + "\n", + "\n", + "#===============Get the space group information===========\n", + "def get_space_group(band_data):\n", + " import pymatgen as mg\n", + " from pymatgen.symmetry.analyzer import SpacegroupAnalyzer\n", + "\n", + " simulation_cell = np.array(band_data[\"section_run\"][\"section_system\"][0].get('simulation_cell',\"empty\")) * 10000000000\n", + " atom_positions = np.array(band_data[\"section_run\"][\"section_system\"][0].get('atom_positions',\"empty\")) * 10000000000\n", + " atom_labels = np.array(band_data[\"section_run\"][\"section_system\"][0].get('atom_labels',\"empty\"))\n", + " structure = mg.Structure(simulation_cell,atom_labels, atom_positions, coords_are_cartesian = True)\n", + " \n", + " finder = SpacegroupAnalyzer(structure, symprec=1e-3, angle_tolerance=5)\n", + " space_group_symbol = finder.get_space_group_symbol()\n", + " lattice_constant = []\n", + " for item in structure.lattice.abc:\n", + " lattice_constant.append(item)\n", + " for i in range(len(lattice_constant)):\n", + " item = str(round(lattice_constant[i], 3))\n", + " lattice_constant[i] = item\n", + " \n", + " return [space_group_symbol, lattice_constant]\n", + "\n", + "#================Get the DOS data==============================\n", + "def get_dos_obj(dos_path):\n", + " #dos_data: read from json file \n", + " #Load the data files for dos\n", + " dos_data = load_jsonfile(dos_path)\n", + "\n", + " print(dos_path)\n", + " #N_dos_values = len(dos_data['sections']['section_run-0']['sections']['section_single_configuration_calculation-0']['section_dos'][0]['dos_energies'])\n", + " N_dos_values = len(dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'])\n", + " #in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n", + "\n", + " dos_energies = np.zeros((N_dos_values))\n", + " dos_energies_tmp = np.zeros((N_dos_values)) #tmp array for unit convertion\n", + " dos_values = np.zeros((N_dos_values))\n", + "\n", + " dos_energies_tmp = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies']\n", + " dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_values'][0]\n", + " \n", + "\n", + " dos_fermi_energy= dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0].get('dos_fermi_energy',\"empty\")\n", + " if(dos_fermi_energy == \"empty\"): #dos_fermi_energy is not available in EXCITING\n", + " dos_fermi_energy_exciting = dos_data['section_run']['section_single_configuration_calculation'].get('x_exciting_dos_fermi',\"empty\")\n", + " if(dos_fermi_energy_exciting == \"empty\"):\n", + " dos_fermi_energy = 0\n", + " else:\n", + " dos_fermi_energy = dos_fermi_energy_exciting / (1.60217656535 * pow(10,-19))\n", + " else:\n", + " dos_fermi_energy = dos_fermi_energy / (1.60217656535 * pow(10,-19))\n", + " print(\"dos_fermi_energy:\", dos_fermi_energy)\n", + " \n", + " for i_dos_values in range(N_dos_values):\n", + " dos_energies[i_dos_values] = 0.0\n", + " dos_energies[i_dos_values] = dos_energies_tmp[i_dos_values] / (1.60217656535 * pow(10,-19))\n", + " dos_energies[i_dos_values] = round((dos_energies[i_dos_values] - dos_fermi_energy), 3) #reference with the fermi level\n", + "\n", + " dos_obj = {}\n", + " dos_obj[\"dos_x_axis\"] = np.array(dos_energies).tolist()\n", + " dos_obj[\"dos_y_axis\"] = np.array(dos_values).tolist()\n", + " dos_obj[\"dos_fermi_energy\"] = np.array(dos_fermi_energy).tolist()\n", + "\n", + " return dos_obj\n", + "\n", + "\n", + "def get_info_obj(band_path):\n", + "\n", + " #band_data: read from json file \n", + " #Load the data files for band\n", + " band_data = load_jsonfile(band_path)\n", + " info_obj = {}\n", + " #---------Read the information of the calculation--------\n", + " info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n", + " info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n", + " info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n", + " info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n", + " \n", + " #----------Get the space group information----------\n", + " \n", + " [space_group_symbol, lattice_constant] = get_space_group(band_data)\n", + " info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist()\n", + " info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist()\n", + " print(\"space group:\", info_obj[\"space_group_symbol\"])\n", + " print(\"lattice_constant:\", lattice_constant)\n", + " \n", + " return info_obj\n", + "\n", + "\n", + "#============main===========================================\n", + "\n", + "#import matplotlib.pyplot as plt\n", + "band_obj_all = []\n", + "dos_obj_all = []\n", + "info_obj_all = []\n", + "print(\"Number of materials: \", N_materials)\n", + "\n", + "for i in range (N_materials):\n", + " print(\"Material: \", i)\n", + " band_path = band_paths[i]\n", + " dos_path = dos_paths[i]\n", + " \n", + " \n", + " dos_obj = get_dos_obj(dos_path)\n", + " dos_fermi_energy = dos_obj[\"dos_fermi_energy\"]\n", + " band_obj = get_band_obj(band_path, dos_fermi_energy)\n", + " info_obj = get_info_obj(band_path)\n", + " \n", + " band_obj_all.append(band_obj)\n", + " dos_obj_all.append(dos_obj)\n", + " info_obj_all.append(info_obj)\n", + " \n", + " \n", + " print(\"average_N_k_points_per_inverse_distance: \", band_obj[\"average_N_k_points_per_inverse_distance\"])\n", + "\n", + "print(\"Finish processing data.\")\n", + "\n", + "#run_cell_by_tag('save_data_to_js')\n", + "\n", + "print(\"Initialization of visulization finished.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 331, + "metadata": { + "tags": [ + "js_plot" + ] + }, + "outputs": [ + { + "data": { + "application/javascript": [ + " \n", + "var N_max_show = 10; //Number of results to be shown by default\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%javascript\n", + " \n", + "var N_max_show = 10; //Number of results to be shown by default\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%javascript\n", + "// BACKUP!\n", + "/*\n", + "//Main plot function for given material:\n", + " function plot_band_dos_i_backup(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n", + " {\n", + " //alert(\"plot_band_dos_i\")\n", + " //i=0;\n", + " lowerLim = -10\n", + " upperLim = 10\n", + " if_show_VBM = 0\n", + " if_compare = 0\n", + " i_in_compare_list = -1\n", + " //i=0;\n", + " var placeholder_band = \"#div_band\" + i.toString();\n", + " var placeholder_dos = \"#div_dos\" + i.toString();\n", + " var placeholder_tools = \"#div_tools\" + i.toString();\n", + " var placeholder_overview = \"#div_overview\" + i.toString();\n", + " var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n", + " var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n", + " var img_band_id = \"img_band\" + i.toString();\n", + " var img_dos_id = \"img_dos\" + i.toString();\n", + " var placeholder_band_compare = \"\";\n", + "\n", + " if(i_in_compare_list == 1)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\";\n", + " }\n", + " else if(i_in_compare_list == 2)\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_2\";\n", + " }\n", + " else\n", + " {\n", + " placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n", + " }\n", + "\n", + " Object.size = function(obj) {\n", + " var size = 0, key;\n", + " for (key in obj) \n", + " {\n", + " if (obj.hasOwnProperty(key)) size++;\n", + " }\n", + " return size;\n", + " };\n", + "\n", + " //Get the number of bands\n", + " //alert(\"Getting band\")\n", + " //alert(band_obj_all)\n", + " //alert(\"band_obj_all got!\")\n", + " var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n", + " var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n", + " alert(band_obj_all[i][\"band_y_axis\"])\n", + " band_plotdata = [];\n", + "\n", + " for(var i_band =0; i_band < N_bands; i_band++)\n", + " {\n", + " var tmp_data = [];\n", + " for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n", + " {\n", + " tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n", + " }\n", + " plotData = { shadowSize: 0 , data: tmp_data, color: 'black', series: { lines: { show: true } , points: {show: false} } };\n", + " band_plotdata.push(plotData);\n", + " }\n", + "\n", + "\n", + " var tmp_data0 = [[0, 0], [1, 0]];\n", + " plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n", + " band_plotdata.push(plotData0);\n", + "\n", + " band_plotdata_overview = band_plotdata.slice(0);\n", + "\n", + " var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n", + " HOMOlabel = [\"VBM\"];\n", + " plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false}, showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n", + " LUMOlabel = [\"CBM\"];\n", + " plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false}, showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n", + "\n", + " //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n", + " if (if_show_VBM == 1)\n", + " {\n", + " band_plotdata.push(plotHOMO);\n", + " band_plotdata.push(plotLUMO);\n", + " }\n", + "\n", + " \n", + " alert(img_band_id + band_plotdata)\n", + " \n", + " //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n", + " //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\" }\n", + "\n", + " var canvas_band;\n", + " var options_band = {\n", + " canvas: true,\n", + " //legend:{ type: \"canvas\" },\n", + " series: { lines: { show: true, lineWidth: 2 }, \n", + " points: { show: false } }, \n", + " xaxis: { \n", + " ticks: band_obj_all[i][\"labels\"], \n", + " color:\"#000\", \n", + " font: {size: 20}, \n", + " zoomRange: false,\n", + " panRange: false \n", + " }, \n", + " yaxis: { \n", + " axisLabel: \"Energy (eV)\", \n", + " axisLabelUseCanvas: true,\n", + " //axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20, family:\"Arial\"},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " zoom: { \n", + " interactive: true\n", + " },\n", + "\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n", + "\n", + " grid: { \n", + " labelMargin: 15,\n", + " hoverable: true, \n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n", + " borderWidth: {\n", + " top: 2, \n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null } \n", + " }\n", + " }\n", + " //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n", + " //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n", + " var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n", + " image_band = plot_band.toDataURL();\n", + " image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n", + " //beakerx.image_band = image_band;\n", + " document.getElementById(img_band_id).href= image_band;\n", + " image_band_links[i] = image_band;\n", + " alert(\"band plot done.\")\n", + "\n", + "\n", + " //----Plot DOS----------------------\n", + " var dos_plotdata = [];\n", + " alert(\"dos:\"+dos_obj_all[i])\n", + " var xdos = dos_obj_all[i][\"dos_x_axis\"];\n", + " var ydos = dos_obj_all[i][\"dos_y_axis\"];\n", + " var dosLabelPos = Math.max.apply(Math, ydos)/2;\n", + " var d2 = [];\n", + " for (var ii = 0; ii < xdos.length; ii+=1) {\n", + " d2.push([ydos[ii],xdos[ii]]);\n", + " }\n", + " var plotData2={ shadowSize: 0, color: 'black' , data: d2}\n", + " dos_plotdata.push(plotData2)\n", + "\n", + " function find_xaxis_max_min(data, lowerbound, upperbound)\n", + " {\n", + " //data[xaxis,y] find the max and min value of x axis\n", + " //alert(\"dos[0]:\" + data[0][\"data\"]);\n", + " //alert(\"Bounds: \" + lowerbound + \" , \" + upperbound)\n", + " var n_data = data.length;\n", + " //alert(\"N dos: \" + n_data);\n", + " var data_min = 1000000;\n", + " var data_max = -1000000;\n", + " var data_current = 0;\n", + " for (var i = 0; i < n_data; i++)\n", + " {\n", + " if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n", + " {\n", + " data_current = data[i][0];\n", + " //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n", + " if(data_current >= data_max)\n", + " {\n", + " data_max = data_current;\n", + " }\n", + " if(data_current <= data_min)\n", + " {\n", + " data_min = data_current;\n", + " }\n", + " }\n", + " }\n", + " var data_max_min = [data_max, data_min];\n", + " //alert(\"data_max_min: \" + data_max_min);\n", + " return data_max_min;\n", + " }\n", + " var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n", + " var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n", + "\n", + " var options_dos ={\n", + " canvas: true,\n", + " series: {\n", + " lines: { show: true, lineWidth:2 },\n", + " points: { show: false }\n", + " },\n", + "\n", + " yaxis: { \n", + " axisLabel: \"\", \n", + " axisLabelUseCanvas: true,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial', \n", + " axisLabelPadding: 10, \n", + " color:\"#000\", \n", + " font: {size: 20},\n", + " tickLength:-5, \n", + " min: lowerLim, \n", + " max: upperLim,\n", + " tickDecimals: 0, \n", + " zoomRange: [0.001, 1000],\n", + " panRange: [-100, 100] \n", + " },\n", + "\n", + " xaxis: {\n", + " axisLabel: \" \",\n", + " axisLabelUseCanvas: false,\n", + " axisLabelFontSizePixels: 20,\n", + " axisLabelFontFamily: 'Arial',\n", + " axisLabelPadding: 3,\n", + " color:\"rgb(0, 0, 0)\",\n", + " font: {size: 20, family:\"Arial\"},\n", + " //ticks: 10,\n", + " tickLength:0,\n", + " min: dos_x_max_min[1],//0,\n", + " max: dos_x_max_min[0],//1,\n", + " tickDecimals: 0,\n", + " ticks: [[ dosLabelPos ,'DOS']],\n", + " //tickFormatter: MyFormatter\n", + " panRange: false\n", + " },\n", + " pan: {\n", + " interactive: true\n", + " }, \n", + "\n", + " grid: {\n", + " labelMargin: 15,\n", + " hoverable: true,\n", + " //borderWidth : 1000,\n", + " //show : false,\n", + " // //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n", + " backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n", + " borderWidth: {\n", + " top: 2,\n", + " right: 2,\n", + " bottom: 2,\n", + " left: 2,\n", + " color : null\n", + " }\n", + " }\n", + " }\n", + " var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n", + " var image_dos = plot_dos.toDataURL();\n", + " image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n", + " image_dos = image_dos;\n", + " document.getElementById(img_dos_id).href= image_dos;\n", + " \n", + " }\n", + "*/" + ] + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.7" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": false, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/js/jquery-3.2.1.min.js b/js/jquery-3.2.1.min.js new file mode 100644 index 0000000..644d35e --- /dev/null +++ b/js/jquery-3.2.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=Array.isArray(d)))?(e?(e=!1,f=c&&Array.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e);return!1}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}return!1}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,N,e),g(f,c,O,e)):(f++,j.call(a,g(f,c,N,e),g(f,c,O,e),g(f,c,N,c.notifyWith))):(d!==N&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), +a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},U=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function V(){this.expando=r.expando+V.uid++}V.uid=1,V.prototype={cache:function(a){var b=a[this.expando];return b||(b={},U(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){Array.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(L)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var W=new V,X=new V,Y=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function $(a){return"true"===a||"false"!==a&&("null"===a?null:a===+a+""?+a:Y.test(a)?JSON.parse(a):a)}function _(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Z,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c=$(c)}catch(e){}X.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return X.hasData(a)||W.hasData(a)},data:function(a,b,c){return X.access(a,b,c)},removeData:function(a,b){X.remove(a,b)},_data:function(a,b,c){return W.access(a,b,c)},_removeData:function(a,b){W.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=X.get(f),1===f.nodeType&&!W.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),_(f,d,e[d])));W.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){X.set(this,a)}):T(this,function(b){var c;if(f&&void 0===b){if(c=X.get(f,a),void 0!==c)return c;if(c=_(f,a),void 0!==c)return c}else this.each(function(){X.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=W.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var aa=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ba=new RegExp("^(?:([+-])=|)("+aa+")([a-z%]*)$","i"),ca=["Top","Right","Bottom","Left"],da=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ea=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function fa(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&ba.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ga={};function ha(a){var b,c=a.ownerDocument,d=a.nodeName,e=ga[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ga[d]=e,e)}function ia(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=W.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&da(d)&&(e[f]=ha(d))):"none"!==c&&(e[f]="none",W.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ia(this,!0)},hide:function(){return ia(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){da(this)?r(this).show():r(this).hide()})}});var ja=/^(?:checkbox|radio)$/i,ka=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c<d;c++)W.set(a[c],"globalEval",!b||W.get(b[c],"globalEval"))}var pa=/<|&#?\w+;/;function qa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(pa.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ka.exec(f)||["",""])[1].toLowerCase(),i=ma[h]||ma._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g,h=[],i=b.delegateCount,j=a.target;if(i&&j.nodeType&&!("click"===a.type&&a.button>=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c<i;c++)d=b[c],e=d.selector+" ",void 0===g[e]&&(g[e]=d.needsContext?r(e,this).index(j)>-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i<b.length&&h.push({elem:j,handlers:b.slice(i)}),h},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==xa()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===xa()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&B(this,"input"))return this.click(),!1},_default:function(a){return B(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?va:wa,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:wa,isPropagationStopped:wa,isImmediatePropagationStopped:wa,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=va,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=va,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=va,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&sa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ta.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return ya(this,a,b,c,d)},one:function(a,b,c,d){return ya(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=wa),this.each(function(){r.event.remove(this,a,c,b)})}});var za=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/<script|<style|<link/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,Ca=/^true\/(.*)/,Da=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}X.hasData(a)&&(h=X.access(a),i=r.extend({},h),X.set(b,i))}}function Ia(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ja.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ja(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,na(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ga),l=0;l<i;l++)j=h[l],la.test(j.type||"")&&!W.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Da,""),k))}return a}function Ka(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(na(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&oa(na(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(za,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d<e;d++)Ia(f[d],g[d]);if(b)if(c)for(f=f||na(a),g=g||na(h),d=0,e=f.length;d<e;d++)Ha(f[d],g[d]);else Ha(a,h);return g=na(h,"script"),g.length>0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(na(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ja(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(na(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var La=/^margin/,Ma=new RegExp("^("+aa+")(?!px)[a-z%]+$","i"),Na=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",ra.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,ra.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Oa(a,b,c){var d,e,f,g,h=a.style;return c=c||Na(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ma.test(g)&&La.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Pa(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Qa=/^(none|table(?!-c[ea]).+)/,Ra=/^--/,Sa={position:"absolute",visibility:"hidden",display:"block"},Ta={letterSpacing:"0",fontWeight:"400"},Ua=["Webkit","Moz","ms"],Va=d.createElement("div").style;function Wa(a){if(a in Va)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ua.length;while(c--)if(a=Ua[c]+b,a in Va)return a}function Xa(a){var b=r.cssProps[a];return b||(b=r.cssProps[a]=Wa(a)||a),b}function Ya(a,b,c){var d=ba.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Za(a,b,c,d,e){var f,g=0;for(f=c===(d?"border":"content")?4:"width"===b?1:0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+ca[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+ca[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+ca[f]+"Width",!0,e))):(g+=r.css(a,"padding"+ca[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+ca[f]+"Width",!0,e)));return g}function $a(a,b,c){var d,e=Na(a),f=Oa(a,b,e),g="border-box"===r.css(a,"boxSizing",!1,e);return Ma.test(f)?f:(d=g&&(o.boxSizingReliable()||f===a.style[b]),"auto"===f&&(f=a["offset"+b[0].toUpperCase()+b.slice(1)]),f=parseFloat(f)||0,f+Za(a,b,c||(g?"border":"content"),d,e)+"px")}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Oa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=Ra.test(b),j=a.style;return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:j[b]:(f=typeof c,"string"===f&&(e=ba.exec(c))&&e[1]&&(c=fa(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(j[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i?j.setProperty(b,c):j[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b),i=Ra.test(b);return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Oa(a,b,d)),"normal"===e&&b in Ta&&(e=Ta[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Qa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?$a(a,b,d):ea(a,Sa,function(){return $a(a,b,d)})},set:function(a,c,d){var e,f=d&&Na(a),g=d&&Za(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=ba.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ya(a,c,g)}}}),r.cssHooks.marginLeft=Pa(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Oa(a,"marginLeft"))||a.getBoundingClientRect().left-ea(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+ca[d]+b]=f[d]||f[d-2]||f[0];return e}},La.test(a)||(r.cssHooks[a+b].set=Ya)}),r.fn.extend({css:function(a,b){return T(this,function(a,b,c){var d,e,f={},g=0;if(Array.isArray(b)){for(d=Na(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&da(a),q=W.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],cb.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=W.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ia([a],!0),j=a.style.display||j,k=r.css(a,"display"),ia([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=W.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ia([a],!0),m.done(function(){p||ia([a]),W.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=hb(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],Array.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=kb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=ab||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(i||h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:ab||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);f<g;f++)if(d=kb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,hb,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j}r.Animation=r.extend(kb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return fa(c.elem,a,ba.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(L);for(var c,d=0,e=a.length;d<e;d++)c=a[d],kb.tweeners[c]=kb.tweeners[c]||[],kb.tweeners[c].unshift(b)},prefilters:[ib],prefilter:function(a,b){b?kb.prefilters.unshift(a):kb.prefilters.push(a)}}),r.speed=function(a,b,c){var d=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off?d.duration=0:"number"!=typeof d.duration&&(d.duration in r.fx.speeds?d.duration=r.fx.speeds[d.duration]:d.duration=r.fx.speeds._default),null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){r.isFunction(d.old)&&d.old.call(this),d.queue&&r.dequeue(this,d.queue)},d},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(da).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=kb(this,r.extend({},a),f);(e||W.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=W.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&db.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=W.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),r.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(ab=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),ab=void 0},r.fx.timer=function(a){r.timers.push(a),r.fx.start()},r.fx.interval=13,r.fx.start=function(){bb||(bb=!0,eb())},r.fx.stop=function(){bb=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var lb,mb=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), +null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d<i;d++)if(c=e[d],(c.selected||d===f)&&!c.disabled&&(!c.parentNode.disabled||!B(c.parentNode,"optgroup"))){if(b=r(c).val(),g)return b;h.push(b)}return h},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Tb=[],Ub=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Tb.pop()||r.expando+"_"+ub++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Ub.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ub.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Ub,"$1"+e):b.jsonp!==!1&&(b.url+=(vb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Tb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=C.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=qa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=pb(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length},r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),b=f.ownerDocument,c=b.documentElement,e=b.defaultView,{top:d.top+e.pageYOffset-c.clientTop,left:d.left+e.pageXOffset-c.clientLeft}):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),B(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||ra})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return T(this,function(a,d,e){var f;return r.isWindow(a)?f=a:9===a.nodeType&&(f=a.defaultView),void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Pa(o.pixelPosition,function(a,c){if(c)return c=Oa(a,b),Ma.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return T(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.holdReady=function(a){a?r.readyWait++:r.ready(!0)},r.isArray=Array.isArray,r.parseJSON=JSON.parse,r.nodeName=B,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Vb=a.jQuery,Wb=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Wb),b&&a.jQuery===r&&(a.jQuery=Vb),r},b||(a.jQuery=a.$=r),r}); diff --git a/js/jquery.event.move.js b/js/jquery.event.move.js new file mode 100644 index 0000000..a792b71 --- /dev/null +++ b/js/jquery.event.move.js @@ -0,0 +1,599 @@ +// DOM.event.move +// +// 2.0.0 +// +// Stephen Band +// +// Triggers 'movestart', 'move' and 'moveend' events after +// mousemoves following a mousedown cross a distance threshold, +// similar to the native 'dragstart', 'drag' and 'dragend' events. +// Move events are throttled to animation frames. Move event objects +// have the properties: +// +// pageX: +// pageY: Page coordinates of pointer. +// startX: +// startY: Page coordinates of pointer at movestart. +// distX: +// distY: Distance the pointer has moved since movestart. +// deltaX: +// deltaY: Distance the finger has moved since last event. +// velocityX: +// velocityY: Average velocity over last few events. + + +(function(fn) { + if (typeof define === 'function' && define.amd) { + define([], fn); + } else if ((typeof module !== "undefined" && module !== null) && module.exports) { + module.exports = fn; + } else { + fn(); + } +})(function(){ + var assign = Object.assign || window.jQuery && jQuery.extend; + + // Number of pixels a pressed pointer travels before movestart + // event is fired. + var threshold = 8; + + // Shim for requestAnimationFrame, falling back to timer. See: + // see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + var requestFrame = (function(){ + return ( + window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(fn, element){ + return window.setTimeout(function(){ + fn(); + }, 25); + } + ); + })(); + + // Shim for customEvent + // see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill + (function () { + if ( typeof window.CustomEvent === "function" ) return false; + function CustomEvent ( event, params ) { + params = params || { bubbles: false, cancelable: false, detail: undefined }; + var evt = document.createEvent( 'CustomEvent' ); + evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); + return evt; + } + + CustomEvent.prototype = window.Event.prototype; + window.CustomEvent = CustomEvent; + })(); + + var ignoreTags = { + textarea: true, + input: true, + select: true, + button: true + }; + + var mouseevents = { + move: 'mousemove', + cancel: 'mouseup dragstart', + end: 'mouseup' + }; + + var touchevents = { + move: 'touchmove', + cancel: 'touchend', + end: 'touchend' + }; + + var rspaces = /\s+/; + + + // DOM Events + + var eventOptions = { bubbles: true, cancelable: true }; + + var eventsSymbol = typeof Symbol === "function" ? Symbol('events') : {}; + + function createEvent(type) { + return new CustomEvent(type, eventOptions); + } + + function getEvents(node) { + return node[eventsSymbol] || (node[eventsSymbol] = {}); + } + + function on(node, types, fn, data, selector) { + types = types.split(rspaces); + + var events = getEvents(node); + var i = types.length; + var handlers, type; + + function handler(e) { fn(e, data); } + + while (i--) { + type = types[i]; + handlers = events[type] || (events[type] = []); + handlers.push([fn, handler]); + node.addEventListener(type, handler); + } + } + + function off(node, types, fn, selector) { + types = types.split(rspaces); + + var events = getEvents(node); + var i = types.length; + var type, handlers, k; + + if (!events) { return; } + + while (i--) { + type = types[i]; + handlers = events[type]; + if (!handlers) { continue; } + k = handlers.length; + while (k--) { + if (handlers[k][0] === fn) { + node.removeEventListener(type, handlers[k][1]); + handlers.splice(k, 1); + } + } + } + } + + function trigger(node, type, properties) { + // Don't cache events. It prevents you from triggering an event of a + // given type from inside the handler of another event of that type. + var event = createEvent(type); + if (properties) { assign(event, properties); } + node.dispatchEvent(event); + } + + + // Constructors + + function Timer(fn){ + var callback = fn, + active = false, + running = false; + + function trigger(time) { + if (active){ + callback(); + requestFrame(trigger); + running = true; + active = false; + } + else { + running = false; + } + } + + this.kick = function(fn) { + active = true; + if (!running) { trigger(); } + }; + + this.end = function(fn) { + var cb = callback; + + if (!fn) { return; } + + // If the timer is not running, simply call the end callback. + if (!running) { + fn(); + } + // If the timer is running, and has been kicked lately, then + // queue up the current callback and the end callback, otherwise + // just the end callback. + else { + callback = active ? + function(){ cb(); fn(); } : + fn ; + + active = true; + } + }; + } + + + // Functions + + function noop() {} + + function preventDefault(e) { + e.preventDefault(); + } + + function isIgnoreTag(e) { + return !!ignoreTags[e.target.tagName.toLowerCase()]; + } + + function isPrimaryButton(e) { + // Ignore mousedowns on any button other than the left (or primary) + // mouse button, or when a modifier key is pressed. + return (e.which === 1 && !e.ctrlKey && !e.altKey); + } + + function identifiedTouch(touchList, id) { + var i, l; + + if (touchList.identifiedTouch) { + return touchList.identifiedTouch(id); + } + + // touchList.identifiedTouch() does not exist in + // webkit yet… we must do the search ourselves... + + i = -1; + l = touchList.length; + + while (++i < l) { + if (touchList[i].identifier === id) { + return touchList[i]; + } + } + } + + function changedTouch(e, data) { + var touch = identifiedTouch(e.changedTouches, data.identifier); + + // This isn't the touch you're looking for. + if (!touch) { return; } + + // Chrome Android (at least) includes touches that have not + // changed in e.changedTouches. That's a bit annoying. Check + // that this touch has changed. + if (touch.pageX === data.pageX && touch.pageY === data.pageY) { return; } + + return touch; + } + + + // Handlers that decide when the first movestart is triggered + + function mousedown(e){ + // Ignore non-primary buttons + if (!isPrimaryButton(e)) { return; } + + // Ignore form and interactive elements + if (isIgnoreTag(e)) { return; } + + on(document, mouseevents.move, mousemove, e); + on(document, mouseevents.cancel, mouseend, e); + } + + function mousemove(e, data){ + checkThreshold(e, data, e, removeMouse); + } + + function mouseend(e, data) { + removeMouse(); + } + + function removeMouse() { + off(document, mouseevents.move, mousemove); + off(document, mouseevents.cancel, mouseend); + } + + function touchstart(e) { + // Don't get in the way of interaction with form elements + if (ignoreTags[e.target.tagName.toLowerCase()]) { return; } + + var touch = e.changedTouches[0]; + + // iOS live updates the touch objects whereas Android gives us copies. + // That means we can't trust the touchstart object to stay the same, + // so we must copy the data. This object acts as a template for + // movestart, move and moveend event objects. + var data = { + target: touch.target, + pageX: touch.pageX, + pageY: touch.pageY, + identifier: touch.identifier, + + // The only way to make handlers individually unbindable is by + // making them unique. + touchmove: function(e, data) { touchmove(e, data); }, + touchend: function(e, data) { touchend(e, data); } + }; + + on(document, touchevents.move, data.touchmove, data); + on(document, touchevents.cancel, data.touchend, data); + } + + function touchmove(e, data) { + var touch = changedTouch(e, data); + if (!touch) { return; } + checkThreshold(e, data, touch, removeTouch); + } + + function touchend(e, data) { + var touch = identifiedTouch(e.changedTouches, data.identifier); + if (!touch) { return; } + removeTouch(data); + } + + function removeTouch(data) { + off(document, touchevents.move, data.touchmove); + off(document, touchevents.cancel, data.touchend); + } + + function checkThreshold(e, data, touch, fn) { + var distX = touch.pageX - data.pageX; + var distY = touch.pageY - data.pageY; + + // Do nothing if the threshold has not been crossed. + if ((distX * distX) + (distY * distY) < (threshold * threshold)) { return; } + + triggerStart(e, data, touch, distX, distY, fn); + } + + function triggerStart(e, data, touch, distX, distY, fn) { + var touches = e.targetTouches; + var time = e.timeStamp - data.timeStamp; + + // Create a movestart object with some special properties that + // are passed only to the movestart handlers. + var template = { + altKey: e.altKey, + ctrlKey: e.ctrlKey, + shiftKey: e.shiftKey, + startX: data.pageX, + startY: data.pageY, + distX: distX, + distY: distY, + deltaX: distX, + deltaY: distY, + pageX: touch.pageX, + pageY: touch.pageY, + velocityX: distX / time, + velocityY: distY / time, + identifier: data.identifier, + targetTouches: touches, + finger: touches ? touches.length : 1, + enableMove: function() { + this.moveEnabled = true; + this.enableMove = noop; + e.preventDefault(); + } + }; + + // Trigger the movestart event. + trigger(data.target, 'movestart', template); + + // Unbind handlers that tracked the touch or mouse up till now. + fn(data); + } + + + // Handlers that control what happens following a movestart + + function activeMousemove(e, data) { + var timer = data.timer; + + data.touch = e; + data.timeStamp = e.timeStamp; + timer.kick(); + } + + function activeMouseend(e, data) { + var target = data.target; + var event = data.event; + var timer = data.timer; + + removeActiveMouse(); + + endEvent(target, event, timer, function() { + // Unbind the click suppressor, waiting until after mouseup + // has been handled. + setTimeout(function(){ + off(target, 'click', preventDefault); + }, 0); + }); + } + + function removeActiveMouse() { + off(document, mouseevents.move, activeMousemove); + off(document, mouseevents.end, activeMouseend); + } + + function activeTouchmove(e, data) { + var event = data.event; + var timer = data.timer; + var touch = changedTouch(e, event); + + if (!touch) { return; } + + // Stop the interface from gesturing + e.preventDefault(); + + event.targetTouches = e.targetTouches; + data.touch = touch; + data.timeStamp = e.timeStamp; + + timer.kick(); + } + + function activeTouchend(e, data) { + var target = data.target; + var event = data.event; + var timer = data.timer; + var touch = identifiedTouch(e.changedTouches, event.identifier); + + // This isn't the touch you're looking for. + if (!touch) { return; } + + removeActiveTouch(data); + endEvent(target, event, timer); + } + + function removeActiveTouch(data) { + off(document, touchevents.move, data.activeTouchmove); + off(document, touchevents.end, data.activeTouchend); + } + + + // Logic for triggering move and moveend events + + function updateEvent(event, touch, timeStamp) { + var time = timeStamp - event.timeStamp; + + event.distX = touch.pageX - event.startX; + event.distY = touch.pageY - event.startY; + event.deltaX = touch.pageX - event.pageX; + event.deltaY = touch.pageY - event.pageY; + + // Average the velocity of the last few events using a decay + // curve to even out spurious jumps in values. + event.velocityX = 0.3 * event.velocityX + 0.7 * event.deltaX / time; + event.velocityY = 0.3 * event.velocityY + 0.7 * event.deltaY / time; + event.pageX = touch.pageX; + event.pageY = touch.pageY; + } + + function endEvent(target, event, timer, fn) { + timer.end(function(){ + trigger(target, 'moveend', event); + return fn && fn(); + }); + } + + + // Set up the DOM + + function movestart(e) { + if (e.defaultPrevented) { return; } + if (!e.moveEnabled) { return; } + + var event = { + startX: e.startX, + startY: e.startY, + pageX: e.pageX, + pageY: e.pageY, + distX: e.distX, + distY: e.distY, + deltaX: e.deltaX, + deltaY: e.deltaY, + velocityX: e.velocityX, + velocityY: e.velocityY, + identifier: e.identifier, + targetTouches: e.targetTouches, + finger: e.finger + }; + + var data = { + target: e.target, + event: event, + timer: new Timer(update), + touch: undefined, + timeStamp: e.timeStamp + }; + + function update(time) { + updateEvent(event, data.touch, data.timeStamp); + trigger(data.target, 'move', event); + } + + if (e.identifier === undefined) { + // We're dealing with a mouse event. + // Stop clicks from propagating during a move + on(e.target, 'click', preventDefault); + on(document, mouseevents.move, activeMousemove, data); + on(document, mouseevents.end, activeMouseend, data); + } + else { + // In order to unbind correct handlers they have to be unique + data.activeTouchmove = function(e, data) { activeTouchmove(e, data); }; + data.activeTouchend = function(e, data) { activeTouchend(e, data); }; + + // We're dealing with a touch. + on(document, touchevents.move, data.activeTouchmove, data); + on(document, touchevents.end, data.activeTouchend, data); + } + } + + on(document, 'mousedown', mousedown); + on(document, 'touchstart', touchstart); + on(document, 'movestart', movestart); + + + // jQuery special events + // + // jQuery event objects are copies of DOM event objects. They need + // a little help copying the move properties across. + + if (!window.jQuery) { return; } + + var properties = ("startX startY pageX pageY distX distY deltaX deltaY velocityX velocityY").split(' '); + + function enableMove1(e) { e.enableMove(); } + function enableMove2(e) { e.enableMove(); } + function enableMove3(e) { e.enableMove(); } + + function add(handleObj) { + var handler = handleObj.handler; + + handleObj.handler = function(e) { + // Copy move properties across from originalEvent + var i = properties.length; + var property; + + while(i--) { + property = properties[i]; + e[property] = e.originalEvent[property]; + } + + handler.apply(this, arguments); + }; + } + + jQuery.event.special.movestart = { + setup: function() { + // Movestart must be enabled to allow other move events + on(this, 'movestart', enableMove1); + + // Do listen to DOM events + return false; + }, + + teardown: function() { + off(this, 'movestart', enableMove1); + return false; + }, + + add: add + }; + + jQuery.event.special.move = { + setup: function() { + on(this, 'movestart', enableMove2); + return false; + }, + + teardown: function() { + off(this, 'movestart', enableMove2); + return false; + }, + + add: add + }; + + jQuery.event.special.moveend = { + setup: function() { + on(this, 'movestart', enableMove3); + return false; + }, + + teardown: function() { + off(this, 'movestart', enableMove3); + return false; + }, + + add: add + }; +}); diff --git a/js/jquery.flot.axislabels.js b/js/jquery.flot.axislabels.js new file mode 100644 index 0000000..cda8038 --- /dev/null +++ b/js/jquery.flot.axislabels.js @@ -0,0 +1,462 @@ +/* +Axis Labels Plugin for flot. +http://github.com/markrcote/flot-axislabels +Original code is Copyright (c) 2010 Xuan Luo. +Original code was released under the GPLv3 license by Xuan Luo, September 2010. +Original code was rereleased under the MIT license by Xuan Luo, April 2012. +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +(function ($) { + var options = { + axisLabels: { + show: true + } + }; + + function canvasSupported() { + return !!document.createElement('canvas').getContext; + } + + function canvasTextSupported() { + if (!canvasSupported()) { + return false; + } + var dummy_canvas = document.createElement('canvas'); + var context = dummy_canvas.getContext('2d'); + return typeof context.fillText == 'function'; + } + + function css3TransitionSupported() { + var div = document.createElement('div'); + return typeof div.style.MozTransition != 'undefined' // Gecko + || typeof div.style.OTransition != 'undefined' // Opera + || typeof div.style.webkitTransition != 'undefined' // WebKit + || typeof div.style.transition != 'undefined'; + } + + + function AxisLabel(axisName, position, padding, plot, opts) { + this.axisName = axisName; + this.position = position; + this.padding = padding; + this.plot = plot; + this.opts = opts; + this.width = 0; + this.height = 0; + } + + AxisLabel.prototype.cleanup = function() { + }; + + + CanvasAxisLabel.prototype = new AxisLabel(); + CanvasAxisLabel.prototype.constructor = CanvasAxisLabel; + function CanvasAxisLabel(axisName, position, padding, plot, opts) { + AxisLabel.prototype.constructor.call(this, axisName, position, padding, + plot, opts); + } + + CanvasAxisLabel.prototype.calculateSize = function() { + if (!this.opts.axisLabelFontSizePixels) + this.opts.axisLabelFontSizePixels = 14; + if (!this.opts.axisLabelFontFamily) + this.opts.axisLabelFontFamily = 'sans-serif'; + + var textWidth = this.opts.axisLabelFontSizePixels + this.padding; + var textHeight = this.opts.axisLabelFontSizePixels + this.padding; + if (this.position == 'left' || this.position == 'right') { + this.width = this.opts.axisLabelFontSizePixels + this.padding; + this.height = 0; + } else { + this.width = 0; + this.height = this.opts.axisLabelFontSizePixels + this.padding; + } + }; + + CanvasAxisLabel.prototype.draw = function(box) { + if (!this.opts.axisLabelColour) + this.opts.axisLabelColour = 'black'; + var ctx = this.plot.getCanvas().getContext('2d'); + ctx.save(); + ctx.font = this.opts.axisLabelFontSizePixels + 'px ' + + this.opts.axisLabelFontFamily; + ctx.fillStyle = this.opts.axisLabelColour; + var width = ctx.measureText(this.opts.axisLabel).width; + var height = this.opts.axisLabelFontSizePixels; + var x, y, angle = 0; + if (this.position == 'top') { + x = box.left + box.width/2 - width/2; + y = box.top + height*0.72; + } else if (this.position == 'bottom') { + x = box.left + box.width/2 - width/2; + y = box.top + box.height - height*0.72; + } else if (this.position == 'left') { + x = box.left + height*0.72; + y = box.height/2 + box.top + width/2; + angle = -Math.PI/2; + } else if (this.position == 'right') { + x = box.left + box.width - height*0.72; + y = box.height/2 + box.top - width/2; + angle = Math.PI/2; + } + ctx.translate(x, y); + ctx.rotate(angle); + ctx.fillText(this.opts.axisLabel, 0, 0); + ctx.restore(); + }; + + + HtmlAxisLabel.prototype = new AxisLabel(); + HtmlAxisLabel.prototype.constructor = HtmlAxisLabel; + function HtmlAxisLabel(axisName, position, padding, plot, opts) { + AxisLabel.prototype.constructor.call(this, axisName, position, + padding, plot, opts); + this.elem = null; + } + + HtmlAxisLabel.prototype.calculateSize = function() { + var elem = $('<div class="axisLabels" style="position:absolute;">' + + this.opts.axisLabel + '</div>'); + this.plot.getPlaceholder().append(elem); + // store height and width of label itself, for use in draw() + this.labelWidth = elem.outerWidth(true); + this.labelHeight = elem.outerHeight(true); + elem.remove(); + + this.width = this.height = 0; + if (this.position == 'left' || this.position == 'right') { + this.width = this.labelWidth + this.padding; + } else { + this.height = this.labelHeight + this.padding; + } + }; + + HtmlAxisLabel.prototype.cleanup = function() { + if (this.elem) { + this.elem.remove(); + } + }; + + HtmlAxisLabel.prototype.draw = function(box) { + this.plot.getPlaceholder().find('#' + this.axisName + 'Label').remove(); + this.elem = $('<div id="' + this.axisName + + 'Label" " class="axisLabels" style="position:absolute;">' + + this.opts.axisLabel + '</div>'); + this.plot.getPlaceholder().append(this.elem); + if (this.position == 'top') { + this.elem.css('left', box.left + box.width/2 - this.labelWidth/2 + + 'px'); + this.elem.css('top', box.top + 'px'); + } else if (this.position == 'bottom') { + this.elem.css('left', box.left + box.width/2 - this.labelWidth/2 + + 'px'); + this.elem.css('top', box.top + box.height - this.labelHeight + + 'px'); + } else if (this.position == 'left') { + this.elem.css('top', box.top + box.height/2 - this.labelHeight/2 + + 'px'); + this.elem.css('left', box.left + 'px'); + } else if (this.position == 'right') { + this.elem.css('top', box.top + box.height/2 - this.labelHeight/2 + + 'px'); + this.elem.css('left', box.left + box.width - this.labelWidth + + 'px'); + } + }; + + + CssTransformAxisLabel.prototype = new HtmlAxisLabel(); + CssTransformAxisLabel.prototype.constructor = CssTransformAxisLabel; + function CssTransformAxisLabel(axisName, position, padding, plot, opts) { + HtmlAxisLabel.prototype.constructor.call(this, axisName, position, + padding, plot, opts); + } + + CssTransformAxisLabel.prototype.calculateSize = function() { + HtmlAxisLabel.prototype.calculateSize.call(this); + this.width = this.height = 0; + if (this.position == 'left' || this.position == 'right') { + this.width = this.labelHeight + this.padding; + } else { + this.height = this.labelHeight + this.padding; + } + }; + + CssTransformAxisLabel.prototype.transforms = function(degrees, x, y) { + var stransforms = { + '-moz-transform': '', + '-webkit-transform': '', + '-o-transform': '', + '-ms-transform': '' + }; + if (x != 0 || y != 0) { + var stdTranslate = ' translate(' + x + 'px, ' + y + 'px)'; + stransforms['-moz-transform'] += stdTranslate; + stransforms['-webkit-transform'] += stdTranslate; + stransforms['-o-transform'] += stdTranslate; + stransforms['-ms-transform'] += stdTranslate; + } + if (degrees != 0) { + var rotation = degrees / 90; + var stdRotate = ' rotate(' + degrees + 'deg)'; + stransforms['-moz-transform'] += stdRotate; + stransforms['-webkit-transform'] += stdRotate; + stransforms['-o-transform'] += stdRotate; + stransforms['-ms-transform'] += stdRotate; + } + var s = 'top: 0; left: 0; '; + for (var prop in stransforms) { + if (stransforms[prop]) { + s += prop + ':' + stransforms[prop] + ';'; + } + } + s += ';'; + return s; + }; + + CssTransformAxisLabel.prototype.calculateOffsets = function(box) { + var offsets = { x: 0, y: 0, degrees: 0 }; + if (this.position == 'bottom') { + offsets.x = box.left + box.width/2 - this.labelWidth/2; + offsets.y = box.top + box.height - this.labelHeight; + } else if (this.position == 'top') { + offsets.x = box.left + box.width/2 - this.labelWidth/2; + offsets.y = box.top; + } else if (this.position == 'left') { + offsets.degrees = -90; + offsets.x = box.left - this.labelWidth/2 + this.labelHeight/2; + offsets.y = box.height/2 + box.top; + } else if (this.position == 'right') { + offsets.degrees = 90; + offsets.x = box.left + box.width - this.labelWidth/2 + - this.labelHeight/2; + offsets.y = box.height/2 + box.top; + } + offsets.x = Math.round(offsets.x); + offsets.y = Math.round(offsets.y); + + return offsets; + }; + + CssTransformAxisLabel.prototype.draw = function(box) { + this.plot.getPlaceholder().find("." + this.axisName + "Label").remove(); + var offsets = this.calculateOffsets(box); + this.elem = $('<div class="axisLabels ' + this.axisName + + 'Label" style="position:absolute; ' + + this.transforms(offsets.degrees, offsets.x, offsets.y) + + '">' + this.opts.axisLabel + '</div>'); + this.plot.getPlaceholder().append(this.elem); + }; + + + IeTransformAxisLabel.prototype = new CssTransformAxisLabel(); + IeTransformAxisLabel.prototype.constructor = IeTransformAxisLabel; + function IeTransformAxisLabel(axisName, position, padding, plot, opts) { + CssTransformAxisLabel.prototype.constructor.call(this, axisName, + position, padding, + plot, opts); + this.requiresResize = false; + } + + IeTransformAxisLabel.prototype.transforms = function(degrees, x, y) { + // I didn't feel like learning the crazy Matrix stuff, so this uses + // a combination of the rotation transform and CSS positioning. + var s = ''; + if (degrees != 0) { + var rotation = degrees/90; + while (rotation < 0) { + rotation += 4; + } + s += ' filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=' + rotation + '); '; + // see below + this.requiresResize = (this.position == 'right'); + } + if (x != 0) { + s += 'left: ' + x + 'px; '; + } + if (y != 0) { + s += 'top: ' + y + 'px; '; + } + return s; + }; + + IeTransformAxisLabel.prototype.calculateOffsets = function(box) { + var offsets = CssTransformAxisLabel.prototype.calculateOffsets.call( + this, box); + // adjust some values to take into account differences between + // CSS and IE rotations. + if (this.position == 'top') { + // FIXME: not sure why, but placing this exactly at the top causes + // the top axis label to flip to the bottom... + offsets.y = box.top + 1; + } else if (this.position == 'left') { + offsets.x = box.left; + offsets.y = box.height/2 + box.top - this.labelWidth/2; + } else if (this.position == 'right') { + offsets.x = box.left + box.width - this.labelHeight; + offsets.y = box.height/2 + box.top - this.labelWidth/2; + } + return offsets; + }; + + IeTransformAxisLabel.prototype.draw = function(box) { + CssTransformAxisLabel.prototype.draw.call(this, box); + if (this.requiresResize) { + this.elem = this.plot.getPlaceholder().find("." + this.axisName + + "Label"); + // Since we used CSS positioning instead of transforms for + // translating the element, and since the positioning is done + // before any rotations, we have to reset the width and height + // in case the browser wrapped the text (specifically for the + // y2axis). + this.elem.css('width', this.labelWidth); + this.elem.css('height', this.labelHeight); + } + }; + + + function init(plot) { + plot.hooks.processOptions.push(function (plot, options) { + + if (!options.axisLabels.show) + return; + + // This is kind of a hack. There are no hooks in Flot between + // the creation and measuring of the ticks (setTicks, measureTickLabels + // in setupGrid() ) and the drawing of the ticks and plot box + // (insertAxisLabels in setupGrid() ). + // + // Therefore, we use a trick where we run the draw routine twice: + // the first time to get the tick measurements, so that we can change + // them, and then have it draw it again. + var secondPass = false; + + var axisLabels = {}; + var axisOffsetCounts = { left: 0, right: 0, top: 0, bottom: 0 }; + + var defaultPadding = 2; // padding between axis and tick labels + plot.hooks.draw.push(function (plot, ctx) { + var hasAxisLabels = false; + if (!secondPass) { + // MEASURE AND SET OPTIONS + $.each(plot.getAxes(), function(axisName, axis) { + var opts = axis.options // Flot 0.7 + || plot.getOptions()[axisName]; // Flot 0.6 + + // Handle redraws initiated outside of this plug-in. + if (axisName in axisLabels) { + axis.labelHeight = axis.labelHeight - + axisLabels[axisName].height; + axis.labelWidth = axis.labelWidth - + axisLabels[axisName].width; + opts.labelHeight = axis.labelHeight; + opts.labelWidth = axis.labelWidth; + axisLabels[axisName].cleanup(); + delete axisLabels[axisName]; + } + + if (!opts || !opts.axisLabel || !axis.show) + return; + + hasAxisLabels = true; + var renderer = null; + + if (!opts.axisLabelUseHtml && + navigator.appName == 'Microsoft Internet Explorer') { + var ua = navigator.userAgent; + var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); + if (re.exec(ua) != null) { + rv = parseFloat(RegExp.$1); + } + if (rv >= 9 && !opts.axisLabelUseCanvas && !opts.axisLabelUseHtml) { + renderer = CssTransformAxisLabel; + } else if (!opts.axisLabelUseCanvas && !opts.axisLabelUseHtml) { + renderer = IeTransformAxisLabel; + } else if (opts.axisLabelUseCanvas) { + renderer = CanvasAxisLabel; + } else { + renderer = HtmlAxisLabel; + } + } else { + if (opts.axisLabelUseHtml || (!css3TransitionSupported() && !canvasTextSupported()) && !opts.axisLabelUseCanvas) { + renderer = HtmlAxisLabel; + } else if (opts.axisLabelUseCanvas || !css3TransitionSupported()) { + renderer = CanvasAxisLabel; + } else { + renderer = CssTransformAxisLabel; + } + } + + var padding = opts.axisLabelPadding === undefined ? + defaultPadding : opts.axisLabelPadding; + + axisLabels[axisName] = new renderer(axisName, + axis.position, padding, + plot, opts); + + // flot interprets axis.labelHeight and .labelWidth as + // the height and width of the tick labels. We increase + // these values to make room for the axis label and + // padding. + + axisLabels[axisName].calculateSize(); + + // AxisLabel.height and .width are the size of the + // axis label and padding. + // Just set opts here because axis will be sorted out on + // the redraw. + + opts.labelHeight = axis.labelHeight + + axisLabels[axisName].height; + opts.labelWidth = axis.labelWidth + + axisLabels[axisName].width; + }); + + // If there are axis labels, re-draw with new label widths and + // heights. + + if (hasAxisLabels) { + secondPass = true; + plot.setupGrid(); + plot.draw(); + } + } else { + secondPass = false; + // DRAW + $.each(plot.getAxes(), function(axisName, axis) { + var opts = axis.options // Flot 0.7 + || plot.getOptions()[axisName]; // Flot 0.6 + if (!opts || !opts.axisLabel || !axis.show) + return; + + axisLabels[axisName].draw(axis.box); + }); + } + }); + }); + } + + + $.plot.plugins.push({ + init: init, + options: options, + name: 'axisLabels', + version: '2.0' + }); +})(jQuery); diff --git a/js/jquery.flot.js b/js/jquery.flot.js new file mode 100644 index 0000000..fd33fd2 --- /dev/null +++ b/js/jquery.flot.js @@ -0,0 +1,3175 @@ +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ + +// first an inline dependency, jquery.colorhelpers.js, we inline it here +// for convenience + +/* Plugin for jQuery for working with colors. + * + * Version 1.1. + * + * Inspiration from jQuery color animation plugin by John Resig. + * + * Released under the MIT license by Ole Laursen, October 2009. + * + * Examples: + * + * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString() + * var c = $.color.extract($("#mydiv"), 'background-color'); + * console.log(c.r, c.g, c.b, c.a); + * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)" + * + * Note that .scale() and .add() return the same modified object + * instead of making a new one. + * + * V. 1.1: Fix error handling so e.g. parsing an empty string does + * produce a color rather than just crashing. + */ +(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery); + +// the actual Flot code +(function($) { + + // Cache the prototype hasOwnProperty for faster access + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + // A shim to provide 'detach' to jQuery versions prior to 1.4. Using a DOM + // operation produces the same effect as detach, i.e. removing the element + // without touching its jQuery data. + + // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+. + + if (!$.fn.detach) { + $.fn.detach = function() { + return this.each(function() { + if (this.parentNode) { + this.parentNode.removeChild( this ); + } + }); + }; + } + + /////////////////////////////////////////////////////////////////////////// + // The Canvas object is a wrapper around an HTML5 <canvas> tag. + // + // @constructor + // @param {string} cls List of classes to apply to the canvas. + // @param {element} container Element onto which to append the canvas. + // + // Requiring a container is a little iffy, but unfortunately canvas + // operations don't work unless the canvas is attached to the DOM. + + function Canvas(cls, container) { + + var element = container.children("." + cls)[0]; + + if (element == null) { + + element = document.createElement("canvas"); + element.className = cls; + + $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 }) + .appendTo(container); + + // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas + + if (!element.getContext) { + if (window.G_vmlCanvasManager) { + element = window.G_vmlCanvasManager.initElement(element); + } else { + throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode."); + } + } + } + + this.element = element; + + var context = this.context = element.getContext("2d"); + + // Determine the screen's ratio of physical to device-independent + // pixels. This is the ratio between the canvas width that the browser + // advertises and the number of pixels actually present in that space. + + // The iPhone 4, for example, has a device-independent width of 320px, + // but its screen is actually 640px wide. It therefore has a pixel + // ratio of 2, while most normal devices have a ratio of 1. + + var devicePixelRatio = window.devicePixelRatio || 1, + backingStoreRatio = + context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + + this.pixelRatio = devicePixelRatio / backingStoreRatio; + + // Size the canvas to match the internal dimensions of its container + + this.resize(container.width(), container.height()); + + // Collection of HTML div layers for text overlaid onto the canvas + + this.textContainer = null; + this.text = {}; + + // Cache of text fragments and metrics, so we can avoid expensively + // re-calculating them when the plot is re-rendered in a loop. + + this._textCache = {}; + } + + // Resizes the canvas to the given dimensions. + // + // @param {number} width New width of the canvas, in pixels. + // @param {number} width New height of the canvas, in pixels. + + Canvas.prototype.resize = function(width, height) { + + if (width <= 0 || height <= 0) { + throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height); + } + + var element = this.element, + context = this.context, + pixelRatio = this.pixelRatio; + + // Resize the canvas, increasing its density based on the display's + // pixel ratio; basically giving it more pixels without increasing the + // size of its element, to take advantage of the fact that retina + // displays have that many more pixels in the same advertised space. + + // Resizing should reset the state (excanvas seems to be buggy though) + + if (this.width != width) { + element.width = width * pixelRatio; + element.style.width = width + "px"; + this.width = width; + } + + if (this.height != height) { + element.height = height * pixelRatio; + element.style.height = height + "px"; + this.height = height; + } + + // Save the context, so we can reset in case we get replotted. The + // restore ensure that we're really back at the initial state, and + // should be safe even if we haven't saved the initial state yet. + + context.restore(); + context.save(); + + // Scale the coordinate space to match the display density; so even though we + // may have twice as many pixels, we still want lines and other drawing to + // appear at the same size; the extra pixels will just make them crisper. + + context.scale(pixelRatio, pixelRatio); + }; + + // Clears the entire canvas area, not including any overlaid HTML text + + Canvas.prototype.clear = function() { + this.context.clearRect(0, 0, this.width, this.height); + }; + + // Finishes rendering the canvas, including managing the text overlay. + + Canvas.prototype.render = function() { + + var cache = this._textCache; + + // For each text layer, add elements marked as active that haven't + // already been rendered, and remove those that are no longer active. + + for (var layerKey in cache) { + if (hasOwnProperty.call(cache, layerKey)) { + + var layer = this.getTextLayer(layerKey), + layerCache = cache[layerKey]; + + layer.hide(); + + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + + var positions = styleCache[key].positions; + + for (var i = 0, position; position = positions[i]; i++) { + if (position.active) { + if (!position.rendered) { + layer.append(position.element); + position.rendered = true; + } + } else { + positions.splice(i--, 1); + if (position.rendered) { + position.element.detach(); + } + } + } + + if (positions.length == 0) { + delete styleCache[key]; + } + } + } + } + } + + layer.show(); + } + } + }; + + // Creates (if necessary) and returns the text overlay container. + // + // @param {string} classes String of space-separated CSS classes used to + // uniquely identify the text layer. + // @return {object} The jQuery-wrapped text-layer div. + + Canvas.prototype.getTextLayer = function(classes) { + + var layer = this.text[classes]; + + // Create the text layer if it doesn't exist + + if (layer == null) { + + // Create the text layer container, if it doesn't exist + + if (this.textContainer == null) { + this.textContainer = $("<div class='flot-text'></div>") + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0, + 'font-size': "smaller", + color: "#545454" + }) + .insertAfter(this.element); + } + + layer = this.text[classes] = $("<div></div>") + .addClass(classes) + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0 + }) + .appendTo(this.textContainer); + } + + return layer; + }; + + // Creates (if necessary) and returns a text info object. + // + // The object looks like this: + // + // { + // width: Width of the text's wrapper div. + // height: Height of the text's wrapper div. + // element: The jQuery-wrapped HTML div containing the text. + // positions: Array of positions at which this text is drawn. + // } + // + // The positions array contains objects that look like this: + // + // { + // active: Flag indicating whether the text should be visible. + // rendered: Flag indicating whether the text is currently visible. + // element: The jQuery-wrapped HTML div containing the text. + // x: X coordinate at which to draw the text. + // y: Y coordinate at which to draw the text. + // } + // + // Each position after the first receives a clone of the original element. + // + // The idea is that that the width, height, and general 'identity' of the + // text is constant no matter where it is placed; the placements are a + // secondary property. + // + // Canvas maintains a cache of recently-used text info objects; getTextInfo + // either returns the cached element or creates a new entry. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {string} text Text string to retrieve info for. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @return {object} a text info object. + + Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { + + var textStyle, layerCache, styleCache, info; + + // Cast the value to a string, in case we were given a number or such + + text = "" + text; + + // If the font is a font-spec object, generate a CSS font definition + + if (typeof font === "object") { + textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family; + } else { + textStyle = font; + } + + // Retrieve (or create) the cache for the text's layer and styles + + layerCache = this._textCache[layer]; + + if (layerCache == null) { + layerCache = this._textCache[layer] = {}; + } + + styleCache = layerCache[textStyle]; + + if (styleCache == null) { + styleCache = layerCache[textStyle] = {}; + } + + info = styleCache[text]; + + // If we can't find a matching element in our cache, create a new one + + if (info == null) { + + var element = $("<div></div>").html(text) + .css({ + position: "absolute", + 'max-width': width, + top: -9999 + }) + .appendTo(this.getTextLayer(layer)); + + if (typeof font === "object") { + element.css({ + font: textStyle, + color: font.color + }); + } else if (typeof font === "string") { + element.addClass(font); + } + + info = styleCache[text] = { + width: element.outerWidth(true), + height: element.outerHeight(true), + element: element, + positions: [] + }; + + element.detach(); + } + + return info; + }; + + // Adds a text string to the canvas text overlay. + // + // The text isn't drawn immediately; it is marked as rendering, which will + // result in its addition to the canvas on the next render pass. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number} x X coordinate at which to draw the text. + // @param {number} y Y coordinate at which to draw the text. + // @param {string} text Text string to draw. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @param {string=} halign Horizontal alignment of the text; either "left", + // "center" or "right". + // @param {string=} valign Vertical alignment of the text; either "top", + // "middle" or "bottom". + + Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) { + + var info = this.getTextInfo(layer, text, font, angle, width), + positions = info.positions; + + // Tweak the div's position to match the text's alignment + + if (halign == "center") { + x -= info.width / 2; + } else if (halign == "right") { + x -= info.width; + } + + if (valign == "middle") { + y -= info.height / 2; + } else if (valign == "bottom") { + y -= info.height; + } + + // Determine whether this text already exists at this position. + // If so, mark it for inclusion in the next render pass. + + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = true; + return; + } + } + + // If the text doesn't exist at this position, create a new entry + + // For the very first position we'll re-use the original element, + // while for subsequent ones we'll clone it. + + position = { + active: true, + rendered: false, + element: positions.length ? info.element.clone() : info.element, + x: x, + y: y + }; + + positions.push(position); + + // Move the element to its final position within the container + + position.element.css({ + top: Math.round(y), + left: Math.round(x), + 'text-align': halign // In case the text wraps + }); + }; + + // Removes one or more text strings from the canvas text overlay. + // + // If no parameters are given, all text within the layer is removed. + // + // Note that the text is not immediately removed; it is simply marked as + // inactive, which will result in its removal on the next render pass. + // This avoids the performance penalty for 'clear and redraw' behavior, + // where we potentially get rid of all text on a layer, but will likely + // add back most or all of it later, as when redrawing axes, for example. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number=} x X coordinate of the text. + // @param {number=} y Y coordinate of the text. + // @param {string=} text Text string to remove. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which the text is rotated, in degrees. + // Angle is currently unused, it will be implemented in the future. + + Canvas.prototype.removeText = function(layer, x, y, text, font, angle) { + if (text == null) { + var layerCache = this._textCache[layer]; + if (layerCache != null) { + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + var positions = styleCache[key].positions; + for (var i = 0, position; position = positions[i]; i++) { + position.active = false; + } + } + } + } + } + } + } else { + var positions = this.getTextInfo(layer, text, font, angle).positions; + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = false; + } + } + } + }; + + /////////////////////////////////////////////////////////////////////////// + // The top-level container for the entire plot. + + function Plot(placeholder, data_, options_, plugins) { + // data is on the form: + // [ series1, series2 ... ] + // where series is either just the data as [ [x1, y1], [x2, y2], ... ] + // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... } + + var series = [], + options = { + // the color theme used for graphs + colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"], + legend: { + show: true, + noColumns: 1, // number of colums in legend table + labelFormatter: null, // fn: string -> string + labelBoxBorderColor: "#ccc", // border color for the little label boxes + container: null, // container (as jQuery object) to put legend in, null means default on top of graph + position: "ne", // position of default legend container within plot + margin: 5, // distance from grid edge to default legend container within plot + backgroundColor: null, // null means auto-detect + backgroundOpacity: 0.85, // set to 0 to avoid background + sorted: null // default to no legend sorting + }, + xaxis: { + show: null, // null = auto-detect, true = always, false = never + position: "bottom", // or "top" + mode: null, // null or "time" + font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" } + color: null, // base color, labels, ticks + tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)" + transform: null, // null or f: number -> number to transform axis + inverseTransform: null, // if transform is set, this should be the inverse function + min: null, // min. value to show, null means set automatically + max: null, // max. value to show, null means set automatically + autoscaleMargin: null, // margin in % to add if auto-setting min/max + ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks + tickFormatter: null, // fn: number -> string + labelWidth: null, // size of tick labels in pixels + labelHeight: null, + reserveSpace: null, // whether to reserve space even if axis isn't shown + tickLength: null, // size in pixels of ticks, or "full" for whole line + alignTicksWithAxis: null, // axis number or null for no sync + tickDecimals: null, // no. of decimals, null means auto + tickSize: null, // number or [number, "unit"] + minTickSize: null // number or [number, "unit"] + }, + yaxis: { + autoscaleMargin: 0.02, + position: "left" // or "right" + }, + xaxes: [], + yaxes: [], + series: { + points: { + show: false, + radius: 3, + lineWidth: 2, // in pixels + fill: true, + fillColor: "#ffffff", + symbol: "circle" // or callback + }, + lines: { + // we don't put in show: false so we can see + // whether lines were actively disabled + lineWidth: 2, // in pixels + fill: false, + fillColor: null, + steps: false + // Omit 'zero', so we can later default its value to + // match that of the 'fill' option. + }, + bars: { + show: false, + lineWidth: 2, // in pixels + barWidth: 1, // in units of the x axis + fill: true, + fillColor: null, + align: "left", // "left", "right", or "center" + horizontal: false, + zero: true + }, + shadowSize: 3, + highlightColor: null + }, + grid: { + show: true, + aboveData: false, + color: "#545454", // primary color used for outline and labels + backgroundColor: null, // null for transparent, else color + borderColor: null, // set if different from the grid color + tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)" + margin: 0, // distance from the canvas edge to the grid + labelMargin: 5, // in pixels + axisMargin: 8, // in pixels + borderWidth: 2, // in pixels + minBorderMargin: null, // in pixels, null means taken from points radius + markings: null, // array of ranges or fn: axes -> array of ranges + markingsColor: "#f4f4f4", + markingsLineWidth: 2, + TickLineStyle: "dashed", + // interactive stuff + clickable: false, + hoverable: false, + autoHighlight: true, // highlight in case mouse is near + mouseActiveRadius: 10 // how far the mouse can be away to activate an item + }, + interaction: { + redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow + }, + hooks: {} + }, + surface = null, // the canvas for the plot itself + overlay = null, // canvas for interactive stuff on top of plot + eventHolder = null, // jQuery object that events should be bound to + ctx = null, octx = null, + xaxes = [], yaxes = [], + plotOffset = { left: 0, right: 0, top: 0, bottom: 0}, + plotWidth = 0, plotHeight = 0, + hooks = { + processOptions: [], + processRawData: [], + processDatapoints: [], + processOffset: [], + drawBackground: [], + drawSeries: [], + draw: [], + bindEvents: [], + drawOverlay: [], + shutdown: [] + }, + plot = this; + + // public functions + plot.setData = setData; + plot.setupGrid = setupGrid; + plot.draw = draw; + plot.getPlaceholder = function() { return placeholder; }; + plot.getCanvas = function() { return surface.element; }; + plot.getPlotOffset = function() { return plotOffset; }; + plot.width = function () { return plotWidth; }; + plot.height = function () { return plotHeight; }; + plot.offset = function () { + var o = eventHolder.offset(); + o.left += plotOffset.left; + o.top += plotOffset.top; + return o; + }; + plot.getData = function () { return series; }; + plot.getAxes = function () { + var res = {}, i; + $.each(xaxes.concat(yaxes), function (_, axis) { + if (axis) + res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis; + }); + return res; + }; + plot.getXAxes = function () { return xaxes; }; + plot.getYAxes = function () { return yaxes; }; + plot.c2p = canvasToAxisCoords; + plot.p2c = axisToCanvasCoords; + plot.getOptions = function () { return options; }; + plot.highlight = highlight; + plot.unhighlight = unhighlight; + plot.triggerRedrawOverlay = triggerRedrawOverlay; + plot.pointOffset = function(point) { + return { + left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10), + top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10) + }; + }; + plot.shutdown = shutdown; + plot.destroy = function () { + shutdown(); + placeholder.removeData("plot").empty(); + + series = []; + options = null; + surface = null; + overlay = null; + eventHolder = null; + ctx = null; + octx = null; + xaxes = []; + yaxes = []; + hooks = null; + highlights = []; + plot = null; + }; + plot.resize = function () { + var width = placeholder.width(), + height = placeholder.height(); + surface.resize(width, height); + overlay.resize(width, height); + }; + + // public attributes + plot.hooks = hooks; + + // initialize + initPlugins(plot); + parseOptions(options_); + setupCanvases(); + setData(data_); + setupGrid(); + draw(); + bindEvents(); + + + function executeHooks(hook, args) { + args = [plot].concat(args); + for (var i = 0; i < hook.length; ++i) + hook[i].apply(this, args); + } + + function initPlugins() { + + // References to key classes, allowing plugins to modify them + + var classes = { + Canvas: Canvas + }; + + for (var i = 0; i < plugins.length; ++i) { + var p = plugins[i]; + p.init(plot, classes); + if (p.options) + $.extend(true, options, p.options); + } + } + + function parseOptions(opts) { + + $.extend(true, options, opts); + + // $.extend merges arrays, rather than replacing them. When less + // colors are provided than the size of the default palette, we + // end up with those colors plus the remaining defaults, which is + // not expected behavior; avoid it by replacing them here. + + if (opts && opts.colors) { + options.colors = opts.colors; + } + + if (options.xaxis.color == null) + options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + if (options.yaxis.color == null) + options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + + if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility + options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color; + if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility + options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color; + + if (options.grid.borderColor == null) + options.grid.borderColor = options.grid.color; + if (options.grid.tickColor == null) + options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + + // Fill in defaults for axis options, including any unspecified + // font-spec fields, if a font-spec was provided. + + // If no x/y axis options were provided, create one of each anyway, + // since the rest of the code assumes that they exist. + + var i, axisOptions, axisCount, + fontSize = placeholder.css("font-size"), + fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 14, + fontDefaults = { + style: placeholder.css("font-style"), + size: Math.round(0.8 * fontSizeDefault), + variant: placeholder.css("font-variant"), + weight: placeholder.css("font-weight"), + family: placeholder.css("font-family") + }; + + axisCount = options.xaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + + axisOptions = options.xaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.xaxis, axisOptions); + options.xaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + axisCount = options.yaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + + axisOptions = options.yaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.yaxis, axisOptions); + options.yaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + // backwards compatibility, to be removed in future + if (options.xaxis.noTicks && options.xaxis.ticks == null) + options.xaxis.ticks = options.xaxis.noTicks; + if (options.yaxis.noTicks && options.yaxis.ticks == null) + options.yaxis.ticks = options.yaxis.noTicks; + if (options.x2axis) { + options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis); + options.xaxes[1].position = "top"; + // Override the inherit to allow the axis to auto-scale + if (options.x2axis.min == null) { + options.xaxes[1].min = null; + } + if (options.x2axis.max == null) { + options.xaxes[1].max = null; + } + } + if (options.y2axis) { + options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis); + options.yaxes[1].position = "right"; + // Override the inherit to allow the axis to auto-scale + if (options.y2axis.min == null) { + options.yaxes[1].min = null; + } + if (options.y2axis.max == null) { + options.yaxes[1].max = null; + } + } + if (options.grid.coloredAreas) + options.grid.markings = options.grid.coloredAreas; + if (options.grid.coloredAreasColor) + options.grid.markingsColor = options.grid.coloredAreasColor; + if (options.lines) + $.extend(true, options.series.lines, options.lines); + if (options.points) + $.extend(true, options.series.points, options.points); + if (options.bars) + $.extend(true, options.series.bars, options.bars); + if (options.shadowSize != null) + options.series.shadowSize = options.shadowSize; + if (options.highlightColor != null) + options.series.highlightColor = options.highlightColor; + + // save options on axes for future reference + for (i = 0; i < options.xaxes.length; ++i) + getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i]; + for (i = 0; i < options.yaxes.length; ++i) + getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i]; + + // add hooks from options + for (var n in hooks) + if (options.hooks[n] && options.hooks[n].length) + hooks[n] = hooks[n].concat(options.hooks[n]); + + executeHooks(hooks.processOptions, [options]); + } + + function setData(d) { + series = parseData(d); + fillInSeriesOptions(); + processData(); + } + + function parseData(d) { + var res = []; + for (var i = 0; i < d.length; ++i) { + var s = $.extend(true, {}, options.series); + + if (d[i].data != null) { + s.data = d[i].data; // move the data instead of deep-copy + delete d[i].data; + + $.extend(true, s, d[i]); + + d[i].data = s.data; + } + else + s.data = d[i]; + res.push(s); + } + + return res; + } + + function axisNumber(obj, coord) { + var a = obj[coord + "axis"]; + if (typeof a == "object") // if we got a real axis, extract number + a = a.n; + if (typeof a != "number") + a = 1; // default to first axis + return a; + } + + function allAxes() { + // return flat array without annoying null entries + return $.grep(xaxes.concat(yaxes), function (a) { return a; }); + } + + function canvasToAxisCoords(pos) { + // return an object with x/y corresponding to all used axes + var res = {}, i, axis; + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) + res["x" + axis.n] = axis.c2p(pos.left); + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) + res["y" + axis.n] = axis.c2p(pos.top); + } + + if (res.x1 !== undefined) + res.x = res.x1; + if (res.y1 !== undefined) + res.y = res.y1; + + return res; + } + + function axisToCanvasCoords(pos) { + // get canvas coords from the first pair of x/y found in pos + var res = {}, i, axis, key; + + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) { + key = "x" + axis.n; + if (pos[key] == null && axis.n == 1) + key = "x"; + + if (pos[key] != null) { + res.left = axis.p2c(pos[key]); + break; + } + } + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) { + key = "y" + axis.n; + if (pos[key] == null && axis.n == 1) + key = "y"; + + if (pos[key] != null) { + res.top = axis.p2c(pos[key]); + break; + } + } + } + + return res; + } + + function getOrCreateAxis(axes, number) { + if (!axes[number - 1]) + axes[number - 1] = { + n: number, // save the number for future reference + direction: axes == xaxes ? "x" : "y", + options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis) + }; + + return axes[number - 1]; + } + + function fillInSeriesOptions() { + + var neededColors = series.length, maxIndex = -1, i; + + // Subtract the number of series that already have fixed colors or + // color indexes from the number that we still need to generate. + + for (i = 0; i < series.length; ++i) { + var sc = series[i].color; + if (sc != null) { + neededColors--; + if (typeof sc == "number" && sc > maxIndex) { + maxIndex = sc; + } + } + } + + // If any of the series have fixed color indexes, then we need to + // generate at least as many colors as the highest index. + + if (neededColors <= maxIndex) { + neededColors = maxIndex + 1; + } + + // Generate all the colors, using first the option colors and then + // variations on those colors once they're exhausted. + + var c, colors = [], colorPool = options.colors, + colorPoolSize = colorPool.length, variation = 0; + + for (i = 0; i < neededColors; i++) { + + c = $.color.parse(colorPool[i % colorPoolSize] || "#666"); + + // Each time we exhaust the colors in the pool we adjust + // a scaling factor used to produce more variations on + // those colors. The factor alternates negative/positive + // to produce lighter/darker colors. + + // Reset the variation after every few cycles, or else + // it will end up producing only white or black colors. + + if (i % colorPoolSize == 0 && i) { + if (variation >= 0) { + if (variation < 0.5) { + variation = -variation - 0.2; + } else variation = 0; + } else variation = -variation; + } + + colors[i] = c.scale('rgb', 1 + variation); + } + + // Finalize the series options, filling in their colors + + var colori = 0, s; + for (i = 0; i < series.length; ++i) { + s = series[i]; + + // assign colors + if (s.color == null) { + s.color = colors[colori].toString(); + ++colori; + } + else if (typeof s.color == "number") + s.color = colors[s.color].toString(); + + // turn on lines automatically in case nothing is set + if (s.lines.show == null) { + var v, show = true; + for (v in s) + if (s[v] && s[v].show) { + show = false; + break; + } + if (show) + s.lines.show = true; + } + + // If nothing was provided for lines.zero, default it to match + // lines.fill, since areas by default should extend to zero. + + if (s.lines.zero == null) { + s.lines.zero = !!s.lines.fill; + } + + // setup axes + s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x")); + s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y")); + } + } + + function processData() { + var topSentry = Number.POSITIVE_INFINITY, + bottomSentry = Number.NEGATIVE_INFINITY, + fakeInfinity = Number.MAX_VALUE, + i, j, k, m, length, + s, points, ps, x, y, axis, val, f, p, + data, format; + + function updateAxis(axis, min, max) { + if (min < axis.datamin && min != -fakeInfinity) + axis.datamin = min; + if (max > axis.datamax && max != fakeInfinity) + axis.datamax = max; + } + + $.each(allAxes(), function (_, axis) { + // init axis + axis.datamin = topSentry; + axis.datamax = bottomSentry; + axis.used = false; + }); + + for (i = 0; i < series.length; ++i) { + s = series[i]; + s.datapoints = { points: [] }; + + executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]); + } + + // first pass: clean and copy data + for (i = 0; i < series.length; ++i) { + s = series[i]; + + data = s.data; + format = s.datapoints.format; + + if (!format) { + format = []; + // find out how to copy + format.push({ x: true, number: true, required: true }); + format.push({ y: true, number: true, required: true }); + + if (s.bars.show || (s.lines.show && s.lines.fill)) { + var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero)); + format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale }); + if (s.bars.horizontal) { + delete format[format.length - 1].y; + format[format.length - 1].x = true; + } + } + + s.datapoints.format = format; + } + + if (s.datapoints.pointsize != null) + continue; // already filled in + + s.datapoints.pointsize = format.length; + + ps = s.datapoints.pointsize; + points = s.datapoints.points; + + var insertSteps = s.lines.show && s.lines.steps; + s.xaxis.used = s.yaxis.used = true; + + for (j = k = 0; j < data.length; ++j, k += ps) { + p = data[j]; + + var nullify = p == null; + if (!nullify) { + for (m = 0; m < ps; ++m) { + val = p[m]; + f = format[m]; + + if (f) { + if (f.number && val != null) { + val = +val; // convert to number + if (isNaN(val)) + val = null; + else if (val == Infinity) + val = fakeInfinity; + else if (val == -Infinity) + val = -fakeInfinity; + } + + if (val == null) { + if (f.required) + nullify = true; + + if (f.defaultValue != null) + val = f.defaultValue; + } + } + + points[k + m] = val; + } + } + + if (nullify) { + for (m = 0; m < ps; ++m) { + val = points[k + m]; + if (val != null) { + f = format[m]; + // extract min/max info + if (f.autoscale !== false) { + if (f.x) { + updateAxis(s.xaxis, val, val); + } + if (f.y) { + updateAxis(s.yaxis, val, val); + } + } + } + points[k + m] = null; + } + } + else { + // a little bit of line specific stuff that + // perhaps shouldn't be here, but lacking + // better means... + if (insertSteps && k > 0 + && points[k - ps] != null + && points[k - ps] != points[k] + && points[k - ps + 1] != points[k + 1]) { + // copy the point to make room for a middle point + for (m = 0; m < ps; ++m) + points[k + ps + m] = points[k + m]; + + // middle point has same y + points[k + 1] = points[k - ps + 1]; + + // we've added a point, better reflect that + k += ps; + } + } + } + } + + // give the hooks a chance to run + for (i = 0; i < series.length; ++i) { + s = series[i]; + + executeHooks(hooks.processDatapoints, [ s, s.datapoints]); + } + + // second pass: find datamax/datamin for auto-scaling + for (i = 0; i < series.length; ++i) { + s = series[i]; + points = s.datapoints.points; + ps = s.datapoints.pointsize; + format = s.datapoints.format; + + var xmin = topSentry, ymin = topSentry, + xmax = bottomSentry, ymax = bottomSentry; + + for (j = 0; j < points.length; j += ps) { + if (points[j] == null) + continue; + + for (m = 0; m < ps; ++m) { + val = points[j + m]; + f = format[m]; + if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity) + continue; + + if (f.x) { + if (val < xmin) + xmin = val; + if (val > xmax) + xmax = val; + } + if (f.y) { + if (val < ymin) + ymin = val; + if (val > ymax) + ymax = val; + } + } + } + + if (s.bars.show) { + // make sure we got room for the bar on the dancing floor + var delta; + + switch (s.bars.align) { + case "left": + delta = 0; + break; + case "right": + delta = -s.bars.barWidth; + break; + default: + delta = -s.bars.barWidth / 2; + } + + if (s.bars.horizontal) { + ymin += delta; + ymax += delta + s.bars.barWidth; + } + else { + xmin += delta; + xmax += delta + s.bars.barWidth; + } + } + + updateAxis(s.xaxis, xmin, xmax); + updateAxis(s.yaxis, ymin, ymax); + } + + $.each(allAxes(), function (_, axis) { + if (axis.datamin == topSentry) + axis.datamin = null; + if (axis.datamax == bottomSentry) + axis.datamax = null; + }); + } + + function setupCanvases() { + + // Make sure the placeholder is clear of everything except canvases + // from a previous plot in this container that we'll try to re-use. + + placeholder.css("padding", 0) // padding messes up the positioning + .children().filter(function(){ + return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base'); + }).remove(); + + if (placeholder.css("position") == 'static') + placeholder.css("position", "relative"); // for positioning labels and overlay + + surface = new Canvas("flot-base", placeholder); + overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features + + ctx = surface.context; + octx = overlay.context; + + // define which element we're listening for events on + eventHolder = $(overlay.element).unbind(); + + // If we're re-using a plot object, shut down the old one + + var existing = placeholder.data("plot"); + + if (existing) { + existing.shutdown(); + overlay.clear(); + } + + // save in case we get replotted + placeholder.data("plot", plot); + } + + function bindEvents() { + // bind events + if (options.grid.hoverable) { + eventHolder.mousemove(onMouseMove); + + // Use bind, rather than .mouseleave, because we officially + // still support jQuery 1.2.6, which doesn't define a shortcut + // for mouseenter or mouseleave. This was a bug/oversight that + // was fixed somewhere around 1.3.x. We can return to using + // .mouseleave when we drop support for 1.2.6. + + eventHolder.bind("mouseleave", onMouseLeave); + } + + if (options.grid.clickable) + eventHolder.click(onClick); + + executeHooks(hooks.bindEvents, [eventHolder]); + } + + function shutdown() { + if (redrawTimeout) + clearTimeout(redrawTimeout); + + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mouseleave", onMouseLeave); + eventHolder.unbind("click", onClick); + + executeHooks(hooks.shutdown, [eventHolder]); + } + + function setTransformationHelpers(axis) { + // set helper functions on the axis, assumes plot area + // has been computed already + + function identity(x) { return x; } + + var s, m, t = axis.options.transform || identity, + it = axis.options.inverseTransform; + + // precompute how much the axis is scaling a point + // in canvas space + if (axis.direction == "x") { + s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min)); + m = Math.min(t(axis.max), t(axis.min)); + } + else { + s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min)); + s = -s; + m = Math.max(t(axis.max), t(axis.min)); + } + + // data point to canvas coordinate + if (t == identity) // slight optimization + axis.p2c = function (p) { return (p - m) * s; }; + else + axis.p2c = function (p) { return (t(p) - m) * s; }; + // canvas coordinate to data point + if (!it) + axis.c2p = function (c) { return m + c / s; }; + else + axis.c2p = function (c) { return it(m + c / s); }; + } + + function measureTickLabels(axis) { + + var opts = axis.options, + ticks = axis.ticks || [], + labelWidth = opts.labelWidth || 0, + labelHeight = opts.labelHeight || 0, + maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null), + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = opts.font || "flot-tick-label tickLabel"; + + for (var i = 0; i < ticks.length; ++i) { + + var t = ticks[i]; + + if (!t.label) + continue; + + var info = surface.getTextInfo(layer, t.label, font, null, maxWidth); + + labelWidth = Math.max(labelWidth, info.width); + labelHeight = Math.max(labelHeight, info.height); + } + + axis.labelWidth = opts.labelWidth || labelWidth; + axis.labelHeight = opts.labelHeight || labelHeight; + } + + function allocateAxisBoxFirstPhase(axis) { + // find the bounding box of the axis by looking at label + // widths/heights and ticks, make room by diminishing the + // plotOffset; this first phase only looks at one + // dimension per axis, the other dimension depends on the + // other axes so will have to wait + + var lw = axis.labelWidth, + lh = axis.labelHeight, + pos = axis.options.position, + isXAxis = axis.direction === "x", + tickLength = axis.options.tickLength, + axisMargin = options.grid.axisMargin, + padding = options.grid.labelMargin, + innermost = true, + outermost = true, + first = true, + found = false; + + // Determine the axis's position in its direction and on its side + + $.each(isXAxis ? xaxes : yaxes, function(i, a) { + if (a && (a.show || a.reserveSpace)) { + if (a === axis) { + found = true; + } else if (a.options.position === pos) { + if (found) { + outermost = false; + } else { + innermost = false; + } + } + if (!found) { + first = false; + } + } + }); + + // The outermost axis on each side has no margin + + if (outermost) { + axisMargin = 0; + } + + // The ticks for the first axis in each direction stretch across + + if (tickLength == null) { + tickLength = first ? "full" : 5; + } + + if (!isNaN(+tickLength)) + padding += +tickLength; + + if (isXAxis) { + lh += padding; + + if (pos == "bottom") { + plotOffset.bottom += lh + axisMargin; + axis.box = { top: surface.height - plotOffset.bottom, height: lh }; + } + else { + axis.box = { top: plotOffset.top + axisMargin, height: lh }; + plotOffset.top += lh + axisMargin; + } + } + else { + lw += padding; + + if (pos == "left") { + axis.box = { left: plotOffset.left + axisMargin, width: lw }; + plotOffset.left += lw + axisMargin; + } + else { + plotOffset.right += lw + axisMargin; + axis.box = { left: surface.width - plotOffset.right, width: lw }; + } + } + + // save for future reference + axis.position = pos; + axis.tickLength = tickLength; + axis.box.padding = padding; + axis.innermost = innermost; + } + + function allocateAxisBoxSecondPhase(axis) { + // now that all axis boxes have been placed in one + // dimension, we can set the remaining dimension coordinates + if (axis.direction == "x") { + axis.box.left = plotOffset.left - axis.labelWidth / 2; + axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth; + } + else { + axis.box.top = plotOffset.top - axis.labelHeight / 2; + axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight; + } + } + + function adjustLayoutForThingsStickingOut() { + // possibly adjust plot offset to ensure everything stays + // inside the canvas and isn't clipped off + + var minMargin = options.grid.minBorderMargin, + axis, i; + + // check stuff from the plot (FIXME: this should just read + // a value from the series, otherwise it's impossible to + // customize) + if (minMargin == null) { + minMargin = 0; + for (i = 0; i < series.length; ++i) + minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2)); + } + + var margins = { + left: minMargin, + right: minMargin, + top: minMargin, + bottom: minMargin + }; + + // check axis labels, note we don't check the actual + // labels but instead use the overall width/height to not + // jump as much around with replots + $.each(allAxes(), function (_, axis) { + if (axis.reserveSpace && axis.ticks && axis.ticks.length) { + if (axis.direction === "x") { + margins.left = Math.max(margins.left, axis.labelWidth / 2); + margins.right = Math.max(margins.right, axis.labelWidth / 2); + } else { + margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2); + margins.top = Math.max(margins.top, axis.labelHeight / 2); + } + } + }); + + plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left)); + plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right)); + plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top)); + plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom)); + } + + function setupGrid() { + var i, axes = allAxes(), showGrid = options.grid.show; + + // Initialize the plot's offset from the edge of the canvas + + for (var a in plotOffset) { + var margin = options.grid.margin || 0; + plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0; + } + + executeHooks(hooks.processOffset, [plotOffset]); + + // If the grid is visible, add its border width to the offset + + for (var a in plotOffset) { + if(typeof(options.grid.borderWidth) == "object") { + plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0; + } + else { + plotOffset[a] += showGrid ? options.grid.borderWidth : 0; + } + } + + $.each(axes, function (_, axis) { + var axisOpts = axis.options; + axis.show = axisOpts.show == null ? axis.used : axisOpts.show; + axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace; + setRange(axis); + }); + + if (showGrid) { + + var allocatedAxes = $.grep(axes, function (axis) { + return axis.show || axis.reserveSpace; + }); + + $.each(allocatedAxes, function (_, axis) { + // make the ticks + setupTickGeneration(axis); + setTicks(axis); + snapRangeToTicks(axis, axis.ticks); + // find labelWidth/Height for axis + measureTickLabels(axis); + }); + + // with all dimensions calculated, we can compute the + // axis bounding boxes, start from the outside + // (reverse order) + for (i = allocatedAxes.length - 1; i >= 0; --i) + allocateAxisBoxFirstPhase(allocatedAxes[i]); + + // make sure we've got enough space for things that + // might stick out + adjustLayoutForThingsStickingOut(); + + $.each(allocatedAxes, function (_, axis) { + allocateAxisBoxSecondPhase(axis); + }); + } + + plotWidth = surface.width - plotOffset.left - plotOffset.right; + plotHeight = surface.height - plotOffset.bottom - plotOffset.top; + + // now we got the proper plot dimensions, we can compute the scaling + $.each(axes, function (_, axis) { + setTransformationHelpers(axis); + }); + + if (showGrid) { + drawAxisLabels(); + } + + insertLegend(); + } + + function setRange(axis) { + var opts = axis.options, + min = +(opts.min != null ? opts.min : axis.datamin), + max = +(opts.max != null ? opts.max : axis.datamax), + delta = max - min; + + if (delta == 0.0) { + // degenerate case + var widen = max == 0 ? 1 : 0.01; + + if (opts.min == null) + min -= widen; + // always widen max if we couldn't widen min to ensure we + // don't fall into min == max which doesn't work + if (opts.max == null || opts.min != null) + max += widen; + } + else { + // consider autoscaling + var margin = opts.autoscaleMargin; + if (margin != null) { + if (opts.min == null) { + min -= delta * margin; + // make sure we don't go below zero if all values + // are positive + if (min < 0 && axis.datamin != null && axis.datamin >= 0) + min = 0; + } + if (opts.max == null) { + max += delta * margin; + if (max > 0 && axis.datamax != null && axis.datamax <= 0) + max = 0; + } + } + } + axis.min = min; + axis.max = max; + } + + function setupTickGeneration(axis) { + var opts = axis.options; + + // estimate number of ticks + var noTicks; + if (typeof opts.ticks == "number" && opts.ticks > 0) + noTicks = opts.ticks; + else + // heuristic based on the model a*sqrt(x) fitted to + // some data points that seemed reasonable + noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height); + + var delta = (axis.max - axis.min) / noTicks, + dec = -Math.floor(Math.log(delta) / Math.LN10), + maxDec = opts.tickDecimals; + + if (maxDec != null && dec > maxDec) { + dec = maxDec; + } + + var magn = Math.pow(10, -dec), + norm = delta / magn, // norm is between 1.0 and 10.0 + size; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + // special case for 2.5, requires an extra decimal + if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) { + size = 2.5; + ++dec; + } + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + + if (opts.minTickSize != null && size < opts.minTickSize) { + size = opts.minTickSize; + } + + axis.delta = delta; + axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec); + axis.tickSize = opts.tickSize || size; + + // Time mode was moved to a plug-in in 0.8, and since so many people use it + // we'll add an especially friendly reminder to make sure they included it. + + if (opts.mode == "time" && !axis.tickGenerator) { + throw new Error("Time mode requires the flot.time plugin."); + } + + // Flot supports base-10 axes; any other mode else is handled by a plug-in, + // like flot.time.js. + + if (!axis.tickGenerator) { + + axis.tickGenerator = function (axis) { + + var ticks = [], + start = floorInBase(axis.min, axis.tickSize), + i = 0, + v = Number.NaN, + prev; + + do { + prev = v; + v = start + i * axis.tickSize; + ticks.push(v); + ++i; + } while (v < axis.max && v != prev); + return ticks; + }; + + axis.tickFormatter = function (value, axis) { + + var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1; + var formatted = "" + Math.round(value * factor) / factor; + + // If tickDecimals was specified, ensure that we have exactly that + // much precision; otherwise default to the value's own precision. + + if (axis.tickDecimals != null) { + var decimal = formatted.indexOf("."); + var precision = decimal == -1 ? 0 : formatted.length - decimal - 1; + if (precision < axis.tickDecimals) { + return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision); + } + } + + return formatted; + }; + } + + if ($.isFunction(opts.tickFormatter)) + axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); }; + + if (opts.alignTicksWithAxis != null) { + var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1]; + if (otherAxis && otherAxis.used && otherAxis != axis) { + // consider snapping min/max to outermost nice ticks + var niceTicks = axis.tickGenerator(axis); + if (niceTicks.length > 0) { + if (opts.min == null) + axis.min = Math.min(axis.min, niceTicks[0]); + if (opts.max == null && niceTicks.length > 1) + axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]); + } + + axis.tickGenerator = function (axis) { + // copy ticks, scaled to this axis + var ticks = [], v, i; + for (i = 0; i < otherAxis.ticks.length; ++i) { + v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min); + v = axis.min + v * (axis.max - axis.min); + ticks.push(v); + } + return ticks; + }; + + // we might need an extra decimal since forced + // ticks don't necessarily fit naturally + if (!axis.mode && opts.tickDecimals == null) { + var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1), + ts = axis.tickGenerator(axis); + + // only proceed if the tick interval rounded + // with an extra decimal doesn't give us a + // zero at end + if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec)))) + axis.tickDecimals = extraDec; + } + } + } + } + + function setTicks(axis) { + var oticks = axis.options.ticks, ticks = []; + if (oticks == null || (typeof oticks == "number" && oticks > 0)) + ticks = axis.tickGenerator(axis); + else if (oticks) { + if ($.isFunction(oticks)) + // generate the ticks + ticks = oticks(axis); + else + ticks = oticks; + } + + // clean up/labelify the supplied ticks, copy them over + var i, v; + axis.ticks = []; + for (i = 0; i < ticks.length; ++i) { + var label = null; + var t = ticks[i]; + if (typeof t == "object") { + v = +t[0]; + if (t.length > 1) + label = t[1]; + } + else + v = +t; + if (label == null) + label = axis.tickFormatter(v, axis); + if (!isNaN(v)) + axis.ticks.push({ v: v, label: label }); + } + } + + function snapRangeToTicks(axis, ticks) { + if (axis.options.autoscaleMargin && ticks.length > 0) { + // snap to ticks + if (axis.options.min == null) + axis.min = Math.min(axis.min, ticks[0].v); + if (axis.options.max == null && ticks.length > 1) + axis.max = Math.max(axis.max, ticks[ticks.length - 1].v); + } + } + + function draw() { + + surface.clear(); + + executeHooks(hooks.drawBackground, [ctx]); + + var grid = options.grid; + + // draw background, if any + if (grid.show && grid.backgroundColor) + drawBackground(); + + if (grid.show && !grid.aboveData) { + drawGrid(); + } + + for (var i = 0; i < series.length; ++i) { + executeHooks(hooks.drawSeries, [ctx, series[i]]); + drawSeries(series[i]); + } + + executeHooks(hooks.draw, [ctx]); + + if (grid.show && grid.aboveData) { + drawGrid(); + } + + surface.render(); + + // A draw implies that either the axes or data have changed, so we + // should probably update the overlay highlights as well. + + triggerRedrawOverlay(); + } + + function extractRange(ranges, coord) { + var axis, from, to, key, axes = allAxes(); + + for (var i = 0; i < axes.length; ++i) { + axis = axes[i]; + if (axis.direction == coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n == 1) + key = coord + "axis"; // support x1axis as xaxis + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord == "x" ? xaxes[0] : yaxes[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function drawBackground() { + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)"); + ctx.fillRect(0, 0, plotWidth, plotHeight); + ctx.restore(); + } + + function drawGrid() { + var i, axes, bw, bc; + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + // draw markings + var markings = options.grid.markings; + if (markings) { + if ($.isFunction(markings)) { + axes = plot.getAxes(); + // xmin etc. is backwards compatibility, to be + // removed in the future + axes.xmin = axes.xaxis.min; + axes.xmax = axes.xaxis.max; + axes.ymin = axes.yaxis.min; + axes.ymax = axes.yaxis.max; + + markings = markings(axes); + } + + for (i = 0; i < markings.length; ++i) { + var m = markings[i], + xrange = extractRange(m, "x"), + yrange = extractRange(m, "y"); + + // fill in missing + if (xrange.from == null) + xrange.from = xrange.axis.min; + if (xrange.to == null) + xrange.to = xrange.axis.max; + if (yrange.from == null) + yrange.from = yrange.axis.min; + if (yrange.to == null) + yrange.to = yrange.axis.max; + + // clip + if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max || + yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) + continue; + + xrange.from = Math.max(xrange.from, xrange.axis.min); + xrange.to = Math.min(xrange.to, xrange.axis.max); + yrange.from = Math.max(yrange.from, yrange.axis.min); + yrange.to = Math.min(yrange.to, yrange.axis.max); + + var xequal = xrange.from === xrange.to, + yequal = yrange.from === yrange.to; + + if (xequal && yequal) { + continue; + } + + // then draw + xrange.from = Math.floor(xrange.axis.p2c(xrange.from)); + xrange.to = Math.floor(xrange.axis.p2c(xrange.to)); + yrange.from = Math.floor(yrange.axis.p2c(yrange.from)); + yrange.to = Math.floor(yrange.axis.p2c(yrange.to)); + + if (xequal || yequal) { + var lineWidth = m.lineWidth || options.grid.markingsLineWidth, + subPixel = lineWidth % 2 ? 0.5 : 0; + ctx.beginPath(); + ctx.strokeStyle = m.color || options.grid.markingsColor; + ctx.lineWidth = lineWidth; + if (xequal) { + ctx.moveTo(xrange.to + subPixel, yrange.from); + ctx.lineTo(xrange.to + subPixel, yrange.to); + } else { + ctx.moveTo(xrange.from, yrange.to + subPixel); + ctx.lineTo(xrange.to, yrange.to + subPixel); + } + ctx.stroke(); + } else { + ctx.fillStyle = m.color || options.grid.markingsColor; + ctx.fillRect(xrange.from, yrange.to, + xrange.to - xrange.from, + yrange.from - yrange.to); + } + } + } + + // draw the ticks + axes = allAxes(); + bw = options.grid.borderWidth; + + for (var j = 0; j < axes.length; ++j) { + var axis = axes[j], box = axis.box, + t = axis.tickLength, x, y, xoff, yoff; + if (!axis.show || axis.ticks.length == 0) + continue; + + ctx.lineWidth = 1; + + // find the edges + if (axis.direction == "x") { + x = 0; + if (t == "full") + y = (axis.position == "top" ? 0 : plotHeight); + else + y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0); + } + else { + y = 0; + if (t == "full") + x = (axis.position == "left" ? 0 : plotWidth); + else + x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0); + } + + // draw tick bar + if (!axis.innermost) { + ctx.strokeStyle = axis.options.color; + ctx.beginPath(); + xoff = yoff = 0; + if (axis.direction == "x") + xoff = plotWidth + 1; + else + yoff = plotHeight + 1; + + if (ctx.lineWidth == 1) { + if (axis.direction == "x") { + y = Math.floor(y) + 0.5; + } else { + x = Math.floor(x) + 0.5; + } + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + ctx.stroke(); + } + + // draw ticks + + ctx.strokeStyle = axis.options.tickColor; + + ctx.beginPath(); + for (i = 0; i < axis.ticks.length; ++i) { + var v = axis.ticks[i].v; + + xoff = yoff = 0; + + if (isNaN(v) || v < axis.min || v > axis.max + // skip those lying on the axes if we got a border + || (t == "full" + && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0) + && (v == axis.min || v == axis.max))) + continue; + + if (axis.direction == "x") { + x = axis.p2c(v); + yoff = t == "full" ? -plotHeight : t; + + if (axis.position == "top") + yoff = -yoff; + } + else { + y = axis.p2c(v); + xoff = t == "full" ? -plotWidth : t; + + if (axis.position == "left") + xoff = -xoff; + } + + if (ctx.lineWidth == 1) { + if (axis.direction == "x") + x = Math.floor(x) + 0.5; + else + y = Math.floor(y) + 0.5; + } + + + if( (options.grid.TickLineStyle == 'dashed') && (yoff < -5 ) ) + { for (var yadd = y-2.5 ; yadd > y+yoff+5; yadd++ ) + {ctx.moveTo(x, yadd); + ctx.lineTo(x + xoff, yadd - 5); + yadd = yadd-10} } + else + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff) + } + ctx.stroke(); + } + + + // draw border + if (bw) { + // If either borderWidth or borderColor is an object, then draw the border + // line by line instead of as one rectangle + bc = options.grid.borderColor; + if(typeof bw == "object" || typeof bc == "object") { + if (typeof bw !== "object") { + bw = {top: bw, right: bw, bottom: bw, left: bw}; + } + if (typeof bc !== "object") { + bc = {top: bc, right: bc, bottom: bc, left: bc}; + } + + if (bw.top > 0) { + ctx.strokeStyle = bc.top; + ctx.lineWidth = bw.top; + ctx.beginPath(); + ctx.moveTo(0 - bw.left, 0 - bw.top/2); + ctx.lineTo(plotWidth, 0 - bw.top/2); + ctx.stroke(); + } + + if (bw.right > 0) { + ctx.strokeStyle = bc.right; + ctx.lineWidth = bw.right; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top); + ctx.lineTo(plotWidth + bw.right / 2, plotHeight); + ctx.stroke(); + } + + if (bw.bottom > 0) { + ctx.strokeStyle = bc.bottom; + ctx.lineWidth = bw.bottom; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2); + ctx.lineTo(0, plotHeight + bw.bottom / 2); + ctx.stroke(); + } + + if (bw.left > 0) { + ctx.strokeStyle = bc.left; + ctx.lineWidth = bw.left; + ctx.beginPath(); + ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom); + ctx.lineTo(0- bw.left/2, 0); + ctx.stroke(); + } + } + else { + ctx.lineWidth = bw; + ctx.strokeStyle = options.grid.borderColor; + ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw); + } + } + + ctx.restore(); + } + + function drawAxisLabels() { + + $.each(allAxes(), function (_, axis) { + var box = axis.box, + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = axis.options.font || "flot-tick-label tickLabel", + tick, x, y, halign, valign; + + // Remove text before checking for axis.show and ticks.length; + // otherwise plugins, like flot-tickrotor, that draw their own + // tick labels will end up with both theirs and the defaults. + + surface.removeText(layer); + + if (!axis.show || axis.ticks.length == 0) + return; + + for (var i = 0; i < axis.ticks.length; ++i) { + + tick = axis.ticks[i]; + if (!tick.label || tick.v < axis.min || tick.v > axis.max) + continue; + + if (axis.direction == "x") { + halign = "center"; + x = plotOffset.left + axis.p2c(tick.v); + if (axis.position == "bottom") { + y = box.top + box.padding; + } else { + y = box.top + box.height - box.padding; + valign = "bottom"; + } + } else { + valign = "middle"; + y = plotOffset.top + axis.p2c(tick.v); + if (axis.position == "left") { + x = box.left + box.width - box.padding; + halign = "right"; + } else { + x = box.left + box.padding; + } + } + + surface.addText(layer, x, y, tick.label, font, null, null, halign, valign); + } + }); + } + + function drawSeries(series) { + if (series.lines.show) + drawSeriesLines(series); + if (series.bars.show) + drawSeriesBars(series); + if (series.points.show) + drawSeriesPoints(series); + } + + function drawSeriesLines(series) { + function plotLine(datapoints, xoffset, yoffset, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + prevx = null, prevy = null; + + ctx.beginPath(); + for (var i = ps; i < points.length; i += ps) { + var x1 = points[i - ps], y1 = points[i - ps + 1], + x2 = points[i], y2 = points[i + 1]; + + if (x1 == null || x2 == null) + continue; + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min) { + if (y2 < axisy.min) + continue; // line segment is outside + // compute new intersection point + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } + else if (y2 <= y1 && y2 < axisy.min) { + if (y1 < axisy.min) + continue; + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max) { + if (y2 > axisy.max) + continue; + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } + else if (y2 >= y1 && y2 > axisy.max) { + if (y1 > axisy.max) + continue; + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) + continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) + continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) + continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) + continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (x1 != prevx || y1 != prevy) + ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); + + prevx = x2; + prevy = y2; + ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset); + } + ctx.stroke(); + } + + function plotLineArea(datapoints, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + bottom = Math.min(Math.max(0, axisy.min), axisy.max), + i = 0, top, areaOpen = false, + ypos = 1, segmentStart = 0, segmentEnd = 0; + + // we process each segment in two turns, first forward + // direction to sketch out top, then once we hit the + // end we go backwards to sketch the bottom + while (true) { + if (ps > 0 && i > points.length + ps) + break; + + i += ps; // ps is negative if going backwards + + var x1 = points[i - ps], + y1 = points[i - ps + ypos], + x2 = points[i], y2 = points[i + ypos]; + + if (areaOpen) { + if (ps > 0 && x1 != null && x2 == null) { + // at turning point + segmentEnd = i; + ps = -ps; + ypos = 2; + continue; + } + + if (ps < 0 && i == segmentStart + ps) { + // done with the reverse sweep + ctx.fill(); + areaOpen = false; + ps = -ps; + ypos = 1; + i = segmentStart = segmentEnd + ps; + continue; + } + } + + if (x1 == null || x2 == null) + continue; + + // clip x values + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) + continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) + continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) + continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) + continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (!areaOpen) { + // open area + ctx.beginPath(); + ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom)); + areaOpen = true; + } + + // now first check the case where both is outside + if (y1 >= axisy.max && y2 >= axisy.max) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); + continue; + } + else if (y1 <= axisy.min && y2 <= axisy.min) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); + continue; + } + + // else it's a bit more complicated, there might + // be a flat maxed out rectangle first, then a + // triangular cutout or reverse; to find these + // keep track of the current x values + var x1old = x1, x2old = x2; + + // clip the y values, without shortcutting, we + // go through all cases in turn + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } + else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } + else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // if the x value was changed we got a rectangle + // to fill + if (x1 != x1old) { + ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)); + // it goes to (x1, y1), but we fill that below + } + + // fill triangular section, this sometimes result + // in redundant points if (x1, y1) hasn't changed + // from previous line to, but we just ignore that + ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + + // fill the other rectangle if it's there + if (x2 != x2old) { + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)); + } + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + ctx.lineJoin = "round"; + + var lw = series.lines.lineWidth, + sw = series.shadowSize; + // FIXME: consider another form of shadow when filling is turned on + if (lw > 0 && sw > 0) { + // draw shadow as a thick and thin line with transparency + ctx.lineWidth = sw; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + // position shadow at angle from the mid of line + var angle = Math.PI/18; + plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis); + ctx.lineWidth = sw/2; + plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight); + if (fillStyle) { + ctx.fillStyle = fillStyle; + plotLineArea(series.datapoints, series.xaxis, series.yaxis); + } + + if (lw > 0) + plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis); + ctx.restore(); + } + + function drawSeriesPoints(series) { + function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) { + var points = datapoints.points, ps = datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + var x = points[i], y = points[i + 1]; + if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) + continue; + + ctx.beginPath(); + x = axisx.p2c(x); + y = axisy.p2c(y) + offset; + if (symbol == "circle") + ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); + else + symbol(ctx, x, y, radius, shadow); + ctx.closePath(); + + if (fillStyle) { + ctx.fillStyle = fillStyle; + ctx.fill(); + } + ctx.stroke(); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var lw = series.points.lineWidth, + sw = series.shadowSize, + radius = series.points.radius, + symbol = series.points.symbol; + + // If the user sets the line width to 0, we change it to a very + // small value. A line width of 0 seems to force the default of 1. + // Doing the conditional here allows the shadow setting to still be + // optional even with a lineWidth of 0. + + if( lw == 0 ) + lw = 0.0001; + + if (lw > 0 && sw > 0) { + // draw shadow in two steps + var w = sw / 2; + ctx.lineWidth = w; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + plotPoints(series.datapoints, radius, null, w + w/2, true, + series.xaxis, series.yaxis, symbol); + + ctx.strokeStyle = "rgba(0,0,0,0.2)"; + plotPoints(series.datapoints, radius, null, w/2, true, + series.xaxis, series.yaxis, symbol); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + plotPoints(series.datapoints, radius, + getFillStyle(series.points, series.color), 0, false, + series.xaxis, series.yaxis, symbol); + ctx.restore(); + } + + function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { + var left, right, bottom, top, + drawLeft, drawRight, drawTop, drawBottom, + tmp; + + // in horizontal mode, we start the bar from the left + // instead of from the bottom so it appears to be + // horizontal rather than vertical + if (horizontal) { + drawBottom = drawRight = drawTop = true; + drawLeft = false; + left = b; + right = x; + top = y + barLeft; + bottom = y + barRight; + + // account for negative bars + if (right < left) { + tmp = right; + right = left; + left = tmp; + drawLeft = true; + drawRight = false; + } + } + else { + drawLeft = drawRight = drawTop = true; + drawBottom = false; + left = x + barLeft; + right = x + barRight; + bottom = b; + top = y; + + // account for negative bars + if (top < bottom) { + tmp = top; + top = bottom; + bottom = tmp; + drawBottom = true; + drawTop = false; + } + } + + // clip + if (right < axisx.min || left > axisx.max || + top < axisy.min || bottom > axisy.max) + return; + + if (left < axisx.min) { + left = axisx.min; + drawLeft = false; + } + + if (right > axisx.max) { + right = axisx.max; + drawRight = false; + } + + if (bottom < axisy.min) { + bottom = axisy.min; + drawBottom = false; + } + + if (top > axisy.max) { + top = axisy.max; + drawTop = false; + } + + left = axisx.p2c(left); + bottom = axisy.p2c(bottom); + right = axisx.p2c(right); + top = axisy.p2c(top); + + // fill the bar + if (fillStyleCallback) { + c.fillStyle = fillStyleCallback(bottom, top); + c.fillRect(left, top, right - left, bottom - top) + } + + // draw outline + if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) { + c.beginPath(); + + // FIXME: inline moveTo is buggy with excanvas + c.moveTo(left, bottom); + if (drawLeft) + c.lineTo(left, top); + else + c.moveTo(left, top); + if (drawTop) + c.lineTo(right, top); + else + c.moveTo(right, top); + if (drawRight) + c.lineTo(right, bottom); + else + c.moveTo(right, bottom); + if (drawBottom) + c.lineTo(left, bottom); + else + c.moveTo(left, bottom); + c.stroke(); + } + } + + function drawSeriesBars(series) { + function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { + var points = datapoints.points, ps = datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + if (points[i] == null) + continue; + drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + // FIXME: figure out a way to add shadows (for instance along the right edge) + ctx.lineWidth = series.bars.lineWidth; + ctx.strokeStyle = series.color; + + var barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } + + var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null; + plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis); + ctx.restore(); + } + + function getFillStyle(filloptions, seriesColor, bottom, top) { + var fill = filloptions.fill; + if (!fill) + return null; + + if (filloptions.fillColor) + return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); + + var c = $.color.parse(seriesColor); + c.a = typeof fill == "number" ? fill : 0.4; + c.normalize(); + return c.toString(); + } + + function insertLegend() { + + if (options.legend.container != null) { + $(options.legend.container).html(""); + } else { + placeholder.find(".legend").remove(); + } + + if (!options.legend.show) { + return; + } + + var fragments = [], entries = [], rowStarted = false, + lf = options.legend.labelFormatter, s, label; + + // Build a list of legend entries, with each having a label and a color + + for (var i = 0; i < series.length; ++i) { + s = series[i]; + if (s.label) { + label = lf ? lf(s.label, s) : s.label; + if (label) { + entries.push({ + label: label, + color: s.color + }); + } + } + } + + // Sort the legend using either the default or a custom comparator + + if (options.legend.sorted) { + if ($.isFunction(options.legend.sorted)) { + entries.sort(options.legend.sorted); + } else if (options.legend.sorted == "reverse") { + entries.reverse(); + } else { + var ascending = options.legend.sorted != "descending"; + entries.sort(function(a, b) { + return a.label == b.label ? 0 : ( + (a.label < b.label) != ascending ? 1 : -1 // Logical XOR + ); + }); + } + } + + // Generate markup for the list of entries, in their final order + + for (var i = 0; i < entries.length; ++i) { + + var entry = entries[i]; + + if (i % options.legend.noColumns == 0) { + if (rowStarted) + fragments.push('</tr>'); + fragments.push('<tr>'); + rowStarted = true; + } + + fragments.push( + '<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + entry.color + ';overflow:hidden"></div></div></td>' + + '<td class="legendLabel">' + entry.label + '</td>' + ); + } + + if (rowStarted) + fragments.push('</tr>'); + + if (fragments.length == 0) + return; + + var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>'; + if (options.legend.container != null) + $(options.legend.container).html(table); + else { + var pos = "", + p = options.legend.position, + m = options.legend.margin; + if (m[0] == null) + m = [m, m]; + if (p.charAt(0) == "n") + pos += 'top:' + (m[1] + plotOffset.top) + 'px;'; + else if (p.charAt(0) == "s") + pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;'; + if (p.charAt(1) == "e") + pos += 'right:' + (m[0] + plotOffset.right) + 'px;'; + else if (p.charAt(1) == "w") + pos += 'left:' + (m[0] + plotOffset.left) + 'px;'; + var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(placeholder); + if (options.legend.backgroundOpacity != 0.0) { + // put in the transparent background + // separately to avoid blended labels and + // label boxes + var c = options.legend.backgroundColor; + if (c == null) { + c = options.grid.backgroundColor; + if (c && typeof c == "string") + c = $.color.parse(c); + else + c = $.color.extract(legend, 'background-color'); + c.a = 1; + c = c.toString(); + } + var div = legend.children(); + $('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity); + } + } + } + + + // interactive features + + var highlights = [], + redrawTimeout = null; + + // returns the data item the mouse is over, or null if none is found + function findNearbyItem(mouseX, mouseY, seriesFilter) { + var maxDistance = options.grid.mouseActiveRadius, + smallestDistance = maxDistance * maxDistance + 1, + item = null, foundPoint = false, i, j, ps; + + for (i = series.length - 1; i >= 0; --i) { + if (!seriesFilter(series[i])) + continue; + + var s = series[i], + axisx = s.xaxis, + axisy = s.yaxis, + points = s.datapoints.points, + mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster + my = axisy.c2p(mouseY), + maxx = maxDistance / axisx.scale, + maxy = maxDistance / axisy.scale; + + ps = s.datapoints.pointsize; + // with inverse transforms, we can't use the maxx/maxy + // optimization, sadly + if (axisx.options.inverseTransform) + maxx = Number.MAX_VALUE; + if (axisy.options.inverseTransform) + maxy = Number.MAX_VALUE; + + if (s.lines.show || s.points.show) { + for (j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1]; + if (x == null) + continue; + + // For points and lines, the cursor must be within a + // certain distance to the data point + if (x - mx > maxx || x - mx < -maxx || + y - my > maxy || y - my < -maxy) + continue; + + // We have to calculate distances in pixels, not in + // data units, because the scales of the axes may be different + var dx = Math.abs(axisx.p2c(x) - mouseX), + dy = Math.abs(axisy.p2c(y) - mouseY), + dist = dx * dx + dy * dy; // we save the sqrt + + // use <= to ensure last point takes precedence + // (last generally means on top of) + if (dist < smallestDistance) { + smallestDistance = dist; + item = [i, j / ps]; + } + } + } + + if (s.bars.show && !item) { // no other point can be nearby + + var barLeft, barRight; + + switch (s.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -s.bars.barWidth; + break; + default: + barLeft = -s.bars.barWidth / 2; + } + + barRight = barLeft + s.bars.barWidth; + + for (j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1], b = points[j + 2]; + if (x == null) + continue; + + // for a bar graph, the cursor must be inside the bar + if (series[i].bars.horizontal ? + (mx <= Math.max(b, x) && mx >= Math.min(b, x) && + my >= y + barLeft && my <= y + barRight) : + (mx >= x + barLeft && mx <= x + barRight && + my >= Math.min(b, y) && my <= Math.max(b, y))) + item = [i, j / ps]; + } + } + } + + if (item) { + i = item[0]; + j = item[1]; + ps = series[i].datapoints.pointsize; + + return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps), + dataIndex: j, + series: series[i], + seriesIndex: i }; + } + + return null; + } + + function onMouseMove(e) { + if (options.grid.hoverable) + triggerClickHoverEvent("plothover", e, + function (s) { return s["hoverable"] != false; }); + } + + function onMouseLeave(e) { + if (options.grid.hoverable) + triggerClickHoverEvent("plothover", e, + function (s) { return false; }); + } + + function onClick(e) { + triggerClickHoverEvent("plotclick", e, + function (s) { return s["clickable"] != false; }); + } + + // trigger click or hover event (they send the same parameters + // so we share their code) + function triggerClickHoverEvent(eventname, event, seriesFilter) { + var offset = eventHolder.offset(), + canvasX = event.pageX - offset.left - plotOffset.left, + canvasY = event.pageY - offset.top - plotOffset.top, + pos = canvasToAxisCoords({ left: canvasX, top: canvasY }); + + pos.pageX = event.pageX; + pos.pageY = event.pageY; + + var item = findNearbyItem(canvasX, canvasY, seriesFilter); + + if (item) { + // fill in mouse pos for any listeners out there + item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10); + item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10); + } + + if (options.grid.autoHighlight) { + // clear auto-highlights + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.auto == eventname && + !(item && h.series == item.series && + h.point[0] == item.datapoint[0] && + h.point[1] == item.datapoint[1])) + unhighlight(h.series, h.point); + } + + if (item) + highlight(item.series, item.datapoint, eventname); + } + + placeholder.trigger(eventname, [ pos, item ]); + } + + function triggerRedrawOverlay() { + var t = options.interaction.redrawOverlayInterval; + if (t == -1) { // skip event queue + drawOverlay(); + return; + } + + if (!redrawTimeout) + redrawTimeout = setTimeout(drawOverlay, t); + } + + function drawOverlay() { + redrawTimeout = null; + + // draw highlights + octx.save(); + overlay.clear(); + octx.translate(plotOffset.left, plotOffset.top); + + var i, hi; + for (i = 0; i < highlights.length; ++i) { + hi = highlights[i]; + + if (hi.series.bars.show) + drawBarHighlight(hi.series, hi.point); + else + drawPointHighlight(hi.series, hi.point); + } + octx.restore(); + + executeHooks(hooks.drawOverlay, [octx]); + } + + function highlight(s, point, auto) { + if (typeof s == "number") + s = series[s]; + + if (typeof point == "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i == -1) { + highlights.push({ series: s, point: point, auto: auto }); + + triggerRedrawOverlay(); + } + else if (!auto) + highlights[i].auto = false; + } + + function unhighlight(s, point) { + if (s == null && point == null) { + highlights = []; + triggerRedrawOverlay(); + return; + } + + if (typeof s == "number") + s = series[s]; + + if (typeof point == "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i != -1) { + highlights.splice(i, 1); + + triggerRedrawOverlay(); + } + } + + function indexOfHighlight(s, p) { + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.series == s && h.point[0] == p[0] + && h.point[1] == p[1]) + return i; + } + return -1; + } + + function drawPointHighlight(series, point) { + var x = point[0], y = point[1], + axisx = series.xaxis, axisy = series.yaxis, + highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(); + + if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) + return; + + var pointRadius = series.points.radius + series.points.lineWidth / 2; + octx.lineWidth = pointRadius; + octx.strokeStyle = highlightColor; + var radius = 1.5 * pointRadius; + x = axisx.p2c(x); + y = axisy.p2c(y); + + octx.beginPath(); + if (series.points.symbol == "circle") + octx.arc(x, y, radius, 0, 2 * Math.PI, false); + else + series.points.symbol(octx, x, y, radius, false); + octx.closePath(); + octx.stroke(); + } + + function drawBarHighlight(series, point) { + var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(), + fillStyle = highlightColor, + barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } + + octx.lineWidth = series.bars.lineWidth; + octx.strokeStyle = highlightColor; + + drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth, + function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth); + } + + function getColorOrGradient(spec, bottom, top, defaultColor) { + if (typeof spec == "string") + return spec; + else { + // assume this is a gradient spec; IE currently only + // supports a simple vertical gradient properly, so that's + // what we support too + var gradient = ctx.createLinearGradient(0, top, 0, bottom); + + for (var i = 0, l = spec.colors.length; i < l; ++i) { + var c = spec.colors[i]; + if (typeof c != "string") { + var co = $.color.parse(defaultColor); + if (c.brightness != null) + co = co.scale('rgb', c.brightness); + if (c.opacity != null) + co.a *= c.opacity; + c = co.toString(); + } + gradient.addColorStop(i / (l - 1), c); + } + + return gradient; + } + } + } + + // Add the plot function to the top level of the jQuery object + + $.plot = function(placeholder, data, options) { + //var t0 = new Date(); + var plot = new Plot($(placeholder), data, options, $.plot.plugins); + //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime())); + return plot; + }; + + $.plot.version = "0.8.3"; + + $.plot.plugins = []; + + // Also add the plot function as a chainable property + + $.fn.plot = function(data, options) { + return this.each(function() { + $.plot(this, data, options); + }); + }; + + // round to nearby lower multiple of base + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + +})(jQuery); diff --git a/js/jquery.flot.navigate.js b/js/jquery.flot.navigate.js new file mode 100644 index 0000000..f2b9760 --- /dev/null +++ b/js/jquery.flot.navigate.js @@ -0,0 +1,336 @@ +/* +Flot plugin for adding panning and zooming capabilities to a plot. + +The default behaviour is double click and scrollwheel up/down to zoom +in, drag to pan. The plugin defines plot.zoom({ center }), +plot.zoomOut() and plot.pan(offset) so you easily can add custom +controls. It also fires a "plotpan" and "plotzoom" event when +something happens, useful for synchronizing plots. + +Options: + + zoom: { + interactive: false + trigger: "dblclick" // or "click" for single click + amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out) + } + + pan: { + interactive: false + cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer" + frameRate: 20 + } + + xaxis, yaxis, x2axis, y2axis: { + zoomRange: null // or [number, number] (min range, max range) or false + panRange: null // or [number, number] (min, max) or false + } + +"interactive" enables the built-in drag/click behaviour. If you enable +interactive for pan, then you'll have a basic plot that supports +moving around; the same for zoom. + +"amount" specifies the default amount to zoom in (so 1.5 = 150%) +relative to the current viewport. + +"cursor" is a standard CSS mouse cursor string used for visual +feedback to the user when dragging. + +"frameRate" specifies the maximum number of times per second the plot +will update itself while the user is panning around on it (set to null +to disable intermediate pans, the plot will then not update until the +mouse button is released). + +"zoomRange" is the interval in which zooming can happen, e.g. with +zoomRange: [1, 100] the zoom will never scale the axis so that the +difference between min and max is smaller than 1 or larger than 100. +You can set either end to null to ignore, e.g. [1, null]. If you set +zoomRange to false, zooming on that axis will be disabled. + +"panRange" confines the panning to stay within a range, e.g. with +panRange: [-10, 20] panning stops at -10 in one end and at 20 in the +other. Either can be null, e.g. [-10, null]. If you set +panRange to false, panning on that axis will be disabled. + +Example API usage: + + plot = $.plot(...); + + // zoom default amount in on the pixel (10, 20) + plot.zoom({ center: { left: 10, top: 20 } }); + + // zoom out again + plot.zoomOut({ center: { left: 10, top: 20 } }); + + // zoom 200% in on the pixel (10, 20) + plot.zoom({ amount: 2, center: { left: 10, top: 20 } }); + + // pan 100 pixels to the left and 20 down + plot.pan({ left: -100, top: 20 }) + +Here, "center" specifies where the center of the zooming should +happen. Note that this is defined in pixel space, not the space of the +data points (you can use the p2c helpers on the axes in Flot to help +you convert between these). + +"amount" is the amount to zoom the viewport relative to the current +range, so 1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is +70% (zoom out). You can set the default in the options. + +*/ + + +// First two dependencies, jquery.event.drag.js and +// jquery.mousewheel.js, we put them inline here to save people the +// effort of downloading them. + +/* +jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com) +Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt +*/ +(function(E){E.fn.drag=function(L,K,J){if(K){this.bind("dragstart",L)}if(J){this.bind("dragend",J)}return !L?this.trigger("drag"):this.bind("drag",K?K:L)};var A=E.event,B=A.special,F=B.drag={not:":input",distance:0,which:1,dragging:false,setup:function(J){J=E.extend({distance:F.distance,which:F.which,not:F.not},J||{});J.distance=I(J.distance);A.add(this,"mousedown",H,J);if(this.attachEvent){this.attachEvent("ondragstart",D)}},teardown:function(){A.remove(this,"mousedown",H);if(this===F.dragging){F.dragging=F.proxy=false}G(this,true);if(this.detachEvent){this.detachEvent("ondragstart",D)}}};B.dragstart=B.dragend={setup:function(){},teardown:function(){}};function H(L){var K=this,J,M=L.data||{};if(M.elem){K=L.dragTarget=M.elem;L.dragProxy=F.proxy||K;L.cursorOffsetX=M.pageX-M.left;L.cursorOffsetY=M.pageY-M.top;L.offsetX=L.pageX-L.cursorOffsetX;L.offsetY=L.pageY-L.cursorOffsetY}else{if(F.dragging||(M.which>0&&L.which!=M.which)||E(L.target).is(M.not)){return }}switch(L.type){case"mousedown":E.extend(M,E(K).offset(),{elem:K,target:L.target,pageX:L.pageX,pageY:L.pageY});A.add(document,"mousemove mouseup",H,M);G(K,false);F.dragging=null;return false;case !F.dragging&&"mousemove":if(I(L.pageX-M.pageX)+I(L.pageY-M.pageY)<M.distance){break}L.target=M.target;J=C(L,"dragstart",K);if(J!==false){F.dragging=K;F.proxy=L.dragProxy=E(J||K)[0]}case"mousemove":if(F.dragging){J=C(L,"drag",K);if(B.drop){B.drop.allowed=(J!==false);B.drop.handler(L)}if(J!==false){break}L.type="mouseup"}case"mouseup":A.remove(document,"mousemove mouseup",H);if(F.dragging){if(B.drop){B.drop.handler(L)}C(L,"dragend",K)}G(K,true);F.dragging=F.proxy=M.elem=false;break}return true}function C(M,K,L){M.type=K;var J=E.event.handle.call(L,M);return J===false?false:J||M.result}function I(J){return Math.pow(J,2)}function D(){return(F.dragging===false)}function G(K,J){if(!K){return }K.unselectable=J?"off":"on";K.onselectstart=function(){return J};if(K.style){K.style.MozUserSelect=J?"":"none"}}})(jQuery); + + +/* jquery.mousewheel.min.js + * Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * + * Version: 3.0.2 + * + * Requires: 1.2.2+ + */ +(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery); + + + + +(function ($) { + var options = { + xaxis: { + zoomRange: null, // or [number, number] (min range, max range) + panRange: null // or [number, number] (min, max) + }, + zoom: { + interactive: false, + trigger: "dblclick", // or "click" for single click + amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out) + }, + pan: { + interactive: false, + cursor: "move", + frameRate: 20 + } + }; + + function init(plot) { + function onZoomClick(e, zoomOut) { + var c = plot.offset(); + c.left = e.pageX - c.left; + c.top = e.pageY - c.top; + if (zoomOut) + plot.zoomOut({ center: c }); + else + plot.zoom({ center: c }); + } + + function onMouseWheel(e, delta) { + onZoomClick(e, delta < 0); + return false; + } + + var prevCursor = 'default', prevPageX = 0, prevPageY = 0, + panTimeout = null; + + function onDragStart(e) { + if (e.which != 1) // only accept left-click + return false; + var c = plot.getPlaceholder().css('cursor'); + if (c) + prevCursor = c; + plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor); + prevPageX = e.pageX; + prevPageY = e.pageY; + } + + function onDrag(e) { + var frameRate = plot.getOptions().pan.frameRate; + if (panTimeout || !frameRate) + return; + + panTimeout = setTimeout(function () { + plot.pan({ left: prevPageX - e.pageX, + top: prevPageY - e.pageY }); + prevPageX = e.pageX; + prevPageY = e.pageY; + + panTimeout = null; + }, 1 / frameRate * 1000); + } + + function onDragEnd(e) { + if (panTimeout) { + clearTimeout(panTimeout); + panTimeout = null; + } + + plot.getPlaceholder().css('cursor', prevCursor); + plot.pan({ left: prevPageX - e.pageX, + top: prevPageY - e.pageY }); + } + + function bindEvents(plot, eventHolder) { + var o = plot.getOptions(); + if (o.zoom.interactive) { + eventHolder[o.zoom.trigger](onZoomClick); + eventHolder.mousewheel(onMouseWheel); + } + + if (o.pan.interactive) { + eventHolder.bind("dragstart", { distance: 10 }, onDragStart); + eventHolder.bind("drag", onDrag); + eventHolder.bind("dragend", onDragEnd); + } + } + + plot.zoomOut = function (args) { + if (!args) + args = {}; + + if (!args.amount) + args.amount = plot.getOptions().zoom.amount + + args.amount = 1 / args.amount; + plot.zoom(args); + } + + plot.zoom = function (args) { + if (!args) + args = {}; + + var c = args.center, + amount = args.amount || plot.getOptions().zoom.amount, + w = plot.width(), h = plot.height(); + + if (!c) + c = { left: w / 2, top: h / 2 }; + + var xf = c.left / w, + yf = c.top / h, + minmax = { + x: { + min: c.left - xf * w / amount, + max: c.left + (1 - xf) * w / amount + }, + y: { + min: c.top - yf * h / amount, + max: c.top + (1 - yf) * h / amount + } + }; + + $.each(plot.getAxes(), function(_, axis) { + var opts = axis.options, + min = minmax[axis.direction].min, + max = minmax[axis.direction].max, + zr = opts.zoomRange; + + if (zr === false) // no zooming on this axis + return; + + min = axis.c2p(min); + max = axis.c2p(max); + if (min > max) { + // make sure min < max + var tmp = min; + min = max; + max = tmp; + } + + var range = max - min; + if (zr && + ((zr[0] != null && range < zr[0]) || + (zr[1] != null && range > zr[1]))) + return; + + opts.min = min; + opts.max = max; + }); + + plot.setupGrid(); + plot.draw(); + + if (!args.preventEvent) + plot.getPlaceholder().trigger("plotzoom", [ plot ]); + } + + plot.pan = function (args) { + var delta = { + x: +args.left, + y: +args.top + }; + + if (isNaN(delta.x)) + delta.x = 0; + if (isNaN(delta.y)) + delta.y = 0; + + $.each(plot.getAxes(), function (_, axis) { + var opts = axis.options, + min, max, d = delta[axis.direction]; + + min = axis.c2p(axis.p2c(axis.min) + d), + max = axis.c2p(axis.p2c(axis.max) + d); + + var pr = opts.panRange; + if (pr === false) // no panning on this axis + return; + + if (pr) { + // check whether we hit the wall + if (pr[0] != null && pr[0] > min) { + d = pr[0] - min; + min += d; + max += d; + } + + if (pr[1] != null && pr[1] < max) { + d = pr[1] - max; + min += d; + max += d; + } + } + + opts.min = min; + opts.max = max; + }); + + plot.setupGrid(); + plot.draw(); + + if (!args.preventEvent) + plot.getPlaceholder().trigger("plotpan", [ plot ]); + } + + function shutdown(plot, eventHolder) { + eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick); + eventHolder.unbind("mousewheel", onMouseWheel); + eventHolder.unbind("dragstart", onDragStart); + eventHolder.unbind("drag", onDrag); + eventHolder.unbind("dragend", onDragEnd); + if (panTimeout) + clearTimeout(panTimeout); + } + + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'navigate', + version: '1.3' + }); +})(jQuery); diff --git a/js/jquery.flot.navigate.min.js b/js/jquery.flot.navigate.min.js new file mode 100644 index 0000000..1aa03fe --- /dev/null +++ b/js/jquery.flot.navigate.min.js @@ -0,0 +1 @@ +LyogRmxvdCBwbHVnaW4gZm9yIGFkZGluZyB0aGUgYWJpbGl0eSB0byBwYW4gYW5kIHpvb20gdGhlIHBsb3QuCgpDb3B5cmlnaHQgKGMpIDIwMDctMjAxMyBJT0xBIGFuZCBPbGUgTGF1cnNlbi4KTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLgoKVGhlIGRlZmF1bHQgYmVoYXZpb3VyIGlzIGRvdWJsZSBjbGljayBhbmQgc2Nyb2xsd2hlZWwgdXAvZG93biB0byB6b29tIGluLCBkcmFnCnRvIHBhbi4gVGhlIHBsdWdpbiBkZWZpbmVzIHBsb3Quem9vbSh7IGNlbnRlciB9KSwgcGxvdC56b29tT3V0KCkgYW5kCnBsb3QucGFuKCBvZmZzZXQgKSBzbyB5b3UgZWFzaWx5IGNhbiBhZGQgY3VzdG9tIGNvbnRyb2xzLiBJdCBhbHNvIGZpcmVzCiJwbG90cGFuIiBhbmQgInBsb3R6b29tIiBldmVudHMsIHVzZWZ1bCBmb3Igc3luY2hyb25pemluZyBwbG90cy4KClRoZSBwbHVnaW4gc3VwcG9ydHMgdGhlc2Ugb3B0aW9uczoKCgl6b29tOiB7CgkJaW50ZXJhY3RpdmU6IGZhbHNlCgkJdHJpZ2dlcjogImRibGNsaWNrIiAvLyBvciAiY2xpY2siIGZvciBzaW5nbGUgY2xpY2sKCQlhbW91bnQ6IDEuNSAgICAgICAgIC8vIDIgPSAyMDAlICh6b29tIGluKSwgMC41ID0gNTAlICh6b29tIG91dCkKCX0KCglwYW46IHsKCQlpbnRlcmFjdGl2ZTogZmFsc2UKCQljdXJzb3I6ICJtb3ZlIiAgICAgIC8vIENTUyBtb3VzZSBjdXJzb3IgdmFsdWUgdXNlZCB3aGVuIGRyYWdnaW5nLCBlLmcuICJwb2ludGVyIgoJCWZyYW1lUmF0ZTogMjAKCX0KCgl4YXhpcywgeWF4aXMsIHgyYXhpcywgeTJheGlzOiB7CgkJem9vbVJhbmdlOiBudWxsICAvLyBvciBbIG51bWJlciwgbnVtYmVyIF0gKG1pbiByYW5nZSwgbWF4IHJhbmdlKSBvciBmYWxzZQoJCXBhblJhbmdlOiBudWxsICAgLy8gb3IgWyBudW1iZXIsIG51bWJlciBdIChtaW4sIG1heCkgb3IgZmFsc2UKCX0KCiJpbnRlcmFjdGl2ZSIgZW5hYmxlcyB0aGUgYnVpbHQtaW4gZHJhZy9jbGljayBiZWhhdmlvdXIuIElmIHlvdSBlbmFibGUKaW50ZXJhY3RpdmUgZm9yIHBhbiwgdGhlbiB5b3UnbGwgaGF2ZSBhIGJhc2ljIHBsb3QgdGhhdCBzdXBwb3J0cyBtb3ZpbmcKYXJvdW5kOyB0aGUgc2FtZSBmb3Igem9vbS4KCiJhbW91bnQiIHNwZWNpZmllcyB0aGUgZGVmYXVsdCBhbW91bnQgdG8gem9vbSBpbiAoc28gMS41ID0gMTUwJSkgcmVsYXRpdmUgdG8KdGhlIGN1cnJlbnQgdmlld3BvcnQuCgoiY3Vyc29yIiBpcyBhIHN0YW5kYXJkIENTUyBtb3VzZSBjdXJzb3Igc3RyaW5nIHVzZWQgZm9yIHZpc3VhbCBmZWVkYmFjayB0byB0aGUKdXNlciB3aGVuIGRyYWdnaW5nLgoKImZyYW1lUmF0ZSIgc3BlY2lmaWVzIHRoZSBtYXhpbXVtIG51bWJlciBvZiB0aW1lcyBwZXIgc2Vjb25kIHRoZSBwbG90IHdpbGwKdXBkYXRlIGl0c2VsZiB3aGlsZSB0aGUgdXNlciBpcyBwYW5uaW5nIGFyb3VuZCBvbiBpdCAoc2V0IHRvIG51bGwgdG8gZGlzYWJsZQppbnRlcm1lZGlhdGUgcGFucywgdGhlIHBsb3Qgd2lsbCB0aGVuIG5vdCB1cGRhdGUgdW50aWwgdGhlIG1vdXNlIGJ1dHRvbiBpcwpyZWxlYXNlZCkuCgoiem9vbVJhbmdlIiBpcyB0aGUgaW50ZXJ2YWwgaW4gd2hpY2ggem9vbWluZyBjYW4gaGFwcGVuLCBlLmcuIHdpdGggem9vbVJhbmdlOgpbMSwgMTAwXSB0aGUgem9vbSB3aWxsIG5ldmVyIHNjYWxlIHRoZSBheGlzIHNvIHRoYXQgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBtaW4KYW5kIG1heCBpcyBzbWFsbGVyIHRoYW4gMSBvciBsYXJnZXIgdGhhbiAxMDAuIFlvdSBjYW4gc2V0IGVpdGhlciBlbmQgdG8gbnVsbAp0byBpZ25vcmUsIGUuZy4gWzEsIG51bGxdLiBJZiB5b3Ugc2V0IHpvb21SYW5nZSB0byBmYWxzZSwgem9vbWluZyBvbiB0aGF0IGF4aXMKd2lsbCBiZSBkaXNhYmxlZC4KCiJwYW5SYW5nZSIgY29uZmluZXMgdGhlIHBhbm5pbmcgdG8gc3RheSB3aXRoaW4gYSByYW5nZSwgZS5nLiB3aXRoIHBhblJhbmdlOgpbLTEwLCAyMF0gcGFubmluZyBzdG9wcyBhdCAtMTAgaW4gb25lIGVuZCBhbmQgYXQgMjAgaW4gdGhlIG90aGVyLiBFaXRoZXIgY2FuCmJlIG51bGwsIGUuZy4gWy0xMCwgbnVsbF0uIElmIHlvdSBzZXQgcGFuUmFuZ2UgdG8gZmFsc2UsIHBhbm5pbmcgb24gdGhhdCBheGlzCndpbGwgYmUgZGlzYWJsZWQuCgpFeGFtcGxlIEFQSSB1c2FnZToKCglwbG90ID0gJC5wbG90KC4uLik7CgoJLy8gem9vbSBkZWZhdWx0IGFtb3VudCBpbiBvbiB0aGUgcGl4ZWwgKCAxMCwgMjAgKQoJcGxvdC56b29tKHsgY2VudGVyOiB7IGxlZnQ6IDEwLCB0b3A6IDIwIH0gfSk7CgoJLy8gem9vbSBvdXQgYWdhaW4KCXBsb3Quem9vbU91dCh7IGNlbnRlcjogeyBsZWZ0OiAxMCwgdG9wOiAyMCB9IH0pOwoKCS8vIHpvb20gMjAwJSBpbiBvbiB0aGUgcGl4ZWwgKDEwLCAyMCkKCXBsb3Quem9vbSh7IGFtb3VudDogMiwgY2VudGVyOiB7IGxlZnQ6IDEwLCB0b3A6IDIwIH0gfSk7CgoJLy8gcGFuIDEwMCBwaXhlbHMgdG8gdGhlIGxlZnQgYW5kIDIwIGRvd24KCXBsb3QucGFuKHsgbGVmdDogLTEwMCwgdG9wOiAyMCB9KQoKSGVyZSwgImNlbnRlciIgc3BlY2lmaWVzIHdoZXJlIHRoZSBjZW50ZXIgb2YgdGhlIHpvb21pbmcgc2hvdWxkIGhhcHBlbi4gTm90ZQp0aGF0IHRoaXMgaXMgZGVmaW5lZCBpbiBwaXhlbCBzcGFjZSwgbm90IHRoZSBzcGFjZSBvZiB0aGUgZGF0YSBwb2ludHMgKHlvdSBjYW4KdXNlIHRoZSBwMmMgaGVscGVycyBvbiB0aGUgYXhlcyBpbiBGbG90IHRvIGhlbHAgeW91IGNvbnZlcnQgYmV0d2VlbiB0aGVzZSkuCgoiYW1vdW50IiBpcyB0aGUgYW1vdW50IHRvIHpvb20gdGhlIHZpZXdwb3J0IHJlbGF0aXZlIHRvIHRoZSBjdXJyZW50IHJhbmdlLCBzbwoxIGlzIDEwMCUgKGkuZS4gbm8gY2hhbmdlKSwgMS41IGlzIDE1MCUgKHpvb20gaW4pLCAwLjcgaXMgNzAlICh6b29tIG91dCkuIFlvdQpjYW4gc2V0IHRoZSBkZWZhdWx0IGluIHRoZSBvcHRpb25zLgoKKi8vLyBGaXJzdCB0d28gZGVwZW5kZW5jaWVzLCBqcXVlcnkuZXZlbnQuZHJhZy5qcyBhbmQKLy8ganF1ZXJ5Lm1vdXNld2hlZWwuanMsIHdlIHB1dCB0aGVtIGlubGluZSBoZXJlIHRvIHNhdmUgcGVvcGxlIHRoZQovLyBlZmZvcnQgb2YgZG93bmxvYWRpbmcgdGhlbS4KLyoKanF1ZXJ5LmV2ZW50LmRyYWcuanMgfiB2MS41IH4gQ29weXJpZ2h0IChjKSAyMDA4LCBUaHJlZSBEdWIgTWVkaWEgKGh0dHA6Ly90aHJlZWR1Ym1lZGlhLmNvbSkKTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlIH4gaHR0cDovL3RocmVlZHVibWVkaWEuZ29vZ2xlY29kZS5jb20vZmlsZXMvTUlULUxJQ0VOU0UudHh0CiovKGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoaSl7dmFyIGwsaD10aGlzLHA9aS5kYXRhfHx7fTtpZihwLmVsZW0paD1pLmRyYWdUYXJnZXQ9cC5lbGVtLGkuZHJhZ1Byb3h5PWEucHJveHl8fGgsaS5jdXJzb3JPZmZzZXRYPXAucGFnZVgtcC5sZWZ0LGkuY3Vyc29yT2Zmc2V0WT1wLnBhZ2VZLXAudG9wLGkub2Zmc2V0WD1pLnBhZ2VYLWkuY3Vyc29yT2Zmc2V0WCxpLm9mZnNldFk9aS5wYWdlWS1pLmN1cnNvck9mZnNldFk7ZWxzZSBpZihhLmRyYWdnaW5nfHxwLndoaWNoPjAmJmkud2hpY2ghPXAud2hpY2h8fGUoaS50YXJnZXQpLmlzKHAubm90KSlyZXR1cm47c3dpdGNoKGkudHlwZSl7Y2FzZSJtb3VzZWRvd24iOnJldHVybiBlLmV4dGVuZChwLGUoaCkub2Zmc2V0KCkse2VsZW06aCx0YXJnZXQ6aS50YXJnZXQscGFnZVg6aS5wYWdlWCxwYWdlWTppLnBhZ2VZfSksby5hZGQoZG9jdW1lbnQsIm1vdXNlbW92ZSBtb3VzZXVwIix0LHApLHMoaCwhMSksYS5kcmFnZ2luZz1udWxsLCExO2Nhc2UhYS5kcmFnZ2luZyYmIm1vdXNlbW92ZSI6aWYocihpLnBhZ2VYLXAucGFnZVgpK3IoaS5wYWdlWS1wLnBhZ2VZKTxwLmRpc3RhbmNlKWJyZWFrO2kudGFyZ2V0PXAudGFyZ2V0LGw9bihpLCJkcmFnc3RhcnQiLGgpLGwhPT0hMSYmKGEuZHJhZ2dpbmc9aCxhLnByb3h5PWkuZHJhZ1Byb3h5PWUobHx8aClbMF0pO2Nhc2UibW91c2Vtb3ZlIjppZihhLmRyYWdnaW5nKXtpZihsPW4oaSwiZHJhZyIsaCksdS5kcm9wJiYodS5kcm9wLmFsbG93ZWQ9bCE9PSExLHUuZHJvcC5oYW5kbGVyKGkpKSxsIT09ITEpYnJlYWs7aS50eXBlPSJtb3VzZXVwIn07Y2FzZSJtb3VzZXVwIjpvLnJlbW92ZShkb2N1bWVudCwibW91c2Vtb3ZlIG1vdXNldXAiLHQpLGEuZHJhZ2dpbmcmJih1LmRyb3AmJnUuZHJvcC5oYW5kbGVyKGkpLG4oaSwiZHJhZ2VuZCIsaCkpLHMoaCwhMCksYS5kcmFnZ2luZz1hLnByb3h5PXAuZWxlbT0hMX1yZXR1cm4hMH1mdW5jdGlvbiBuKHQsbixyKXt0LnR5cGU9bjt2YXIgaT1lLmV2ZW50LmRpc3BhdGNoLmNhbGwocix0KTtyZXR1cm4gaT09PSExPyExOml8fHQucmVzdWx0fWZ1bmN0aW9uIHIoZSl7cmV0dXJuIE1hdGgucG93KGUsMil9ZnVuY3Rpb24gaSgpe3JldHVybiBhLmRyYWdnaW5nPT09ITF9ZnVuY3Rpb24gcyhlLHQpe2UmJihlLnVuc2VsZWN0YWJsZT10PyJvZmYiOiJvbiIsZS5vbnNlbGVjdHN0YXJ0PWZ1bmN0aW9uKCl7cmV0dXJuIHR9LGUuc3R5bGUmJihlLnN0eWxlLk1velVzZXJTZWxlY3Q9dD8iIjoibm9uZSIpKX1lLmZuLmRyYWc9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiB0JiZ0aGlzLmJpbmQoImRyYWdzdGFydCIsZSksbiYmdGhpcy5iaW5kKCJkcmFnZW5kIixuKSxlP3RoaXMuYmluZCgiZHJhZyIsdD90OmUpOnRoaXMudHJpZ2dlcigiZHJhZyIpfTt2YXIgbz1lLmV2ZW50LHU9by5zcGVjaWFsLGE9dS5kcmFnPXtub3Q6IjppbnB1dCIsZGlzdGFuY2U6MCx3aGljaDoxLGRyYWdnaW5nOiExLHNldHVwOmZ1bmN0aW9uKG4pe249ZS5leHRlbmQoe2Rpc3RhbmNlOmEuZGlzdGFuY2Usd2hpY2g6YS53aGljaCxub3Q6YS5ub3R9LG58fHt9KSxuLmRpc3RhbmNlPXIobi5kaXN0YW5jZSksby5hZGQodGhpcywibW91c2Vkb3duIix0LG4pLHRoaXMuYXR0YWNoRXZlbnQmJnRoaXMuYXR0YWNoRXZlbnQoIm9uZHJhZ3N0YXJ0IixpKX0sdGVhcmRvd246ZnVuY3Rpb24oKXtvLnJlbW92ZSh0aGlzLCJtb3VzZWRvd24iLHQpLHRoaXM9PT1hLmRyYWdnaW5nJiYoYS5kcmFnZ2luZz1hLnByb3h5PSExKSxzKHRoaXMsITApLHRoaXMuZGV0YWNoRXZlbnQmJnRoaXMuZGV0YWNoRXZlbnQoIm9uZHJhZ3N0YXJ0IixpKX19O3UuZHJhZ3N0YXJ0PXUuZHJhZ2VuZD17c2V0dXA6ZnVuY3Rpb24oKXt9LHRlYXJkb3duOmZ1bmN0aW9uKCl7fX19KShqUXVlcnkpLGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49dHx8d2luZG93LmV2ZW50LHI9W10uc2xpY2UuY2FsbChhcmd1bWVudHMsMSksaT0wLHM9MCxvPTAsdD1lLmV2ZW50LmZpeChuKTtyZXR1cm4gdC50eXBlPSJtb3VzZXdoZWVsIixuLndoZWVsRGVsdGEmJihpPW4ud2hlZWxEZWx0YS8xMjApLG4uZGV0YWlsJiYoaT0tbi5kZXRhaWwvMyksbz1pLHZvaWQgMCE9PW4uYXhpcyYmbi5heGlzPT09bi5IT1JJWk9OVEFMX0FYSVMmJihvPTAscz0tMSppKSx2b2lkIDAhPT1uLndoZWVsRGVsdGFZJiYobz1uLndoZWVsRGVsdGFZLzEyMCksdm9pZCAwIT09bi53aGVlbERlbHRhWCYmKHM9LTEqbi53aGVlbERlbHRhWC8xMjApLHIudW5zaGlmdCh0LGkscyxvKSwoZS5ldmVudC5kaXNwYXRjaHx8ZS5ldmVudC5oYW5kbGUpLmFwcGx5KHRoaXMscil9dmFyIG49WyJET01Nb3VzZVNjcm9sbCIsIm1vdXNld2hlZWwiXTtpZihlLmV2ZW50LmZpeEhvb2tzKWZvcih2YXIgcj1uLmxlbmd0aDtyOyllLmV2ZW50LmZpeEhvb2tzW25bLS1yXV09ZS5ldmVudC5tb3VzZUhvb2tzO2UuZXZlbnQuc3BlY2lhbC5tb3VzZXdoZWVsPXtzZXR1cDpmdW5jdGlvbigpe2lmKHRoaXMuYWRkRXZlbnRMaXN0ZW5lcilmb3IodmFyIGU9bi5sZW5ndGg7ZTspdGhpcy5hZGRFdmVudExpc3RlbmVyKG5bLS1lXSx0LCExKTtlbHNlIHRoaXMub25tb3VzZXdoZWVsPXR9LHRlYXJkb3duOmZ1bmN0aW9uKCl7aWYodGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKWZvcih2YXIgZT1uLmxlbmd0aDtlOyl0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXIoblstLWVdLHQsITEpO2Vsc2UgdGhpcy5vbm1vdXNld2hlZWw9bnVsbH19LGUuZm4uZXh0ZW5kKHttb3VzZXdoZWVsOmZ1bmN0aW9uKGUpe3JldHVybiBlP3RoaXMuYmluZCgibW91c2V3aGVlbCIsZSk6dGhpcy50cmlnZ2VyKCJtb3VzZXdoZWVsIil9LHVubW91c2V3aGVlbDpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy51bmJpbmQoIm1vdXNld2hlZWwiLGUpfX0pfShqUXVlcnkpLGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIG4odCl7ZnVuY3Rpb24gbihlLG4pe3ZhciByPXQub2Zmc2V0KCk7ci5sZWZ0PWUucGFnZVgtci5sZWZ0LHIudG9wPWUucGFnZVktci50b3Asbj90Lnpvb21PdXQoe2NlbnRlcjpyfSk6dC56b29tKHtjZW50ZXI6cn0pfWZ1bmN0aW9uIHIoZSx0KXtyZXR1cm4gZS5wcmV2ZW50RGVmYXVsdCgpLG4oZSx0PDApLCExfWZ1bmN0aW9uIGEoZSl7aWYoZS53aGljaCE9MSlyZXR1cm4hMTt2YXIgbj10LmdldFBsYWNlaG9sZGVyKCkuY3NzKCJjdXJzb3IiKTtuJiYoaT1uKSx0LmdldFBsYWNlaG9sZGVyKCkuY3NzKCJjdXJzb3IiLHQuZ2V0T3B0aW9ucygpLnBhbi5jdXJzb3IpLHM9ZS5wYWdlWCxvPWUucGFnZVl9ZnVuY3Rpb24gZihlKXt2YXIgbj10LmdldE9wdGlvbnMoKS5wYW4uZnJhbWVSYXRlO2lmKHV8fCFuKXJldHVybjt1PXNldFRpbWVvdXQoZnVuY3Rpb24oKXt0LnBhbih7bGVmdDpzLWUucGFnZVgsdG9wOm8tZS5wYWdlWX0pLHM9ZS5wYWdlWCxvPWUucGFnZVksdT1udWxsfSwxL24qMWUzKX1mdW5jdGlvbiBsKGUpe3UmJihjbGVhclRpbWVvdXQodSksdT1udWxsKSx0LmdldFBsYWNlaG9sZGVyKCkuY3NzKCJjdXJzb3IiLGkpLHQucGFuKHtsZWZ0OnMtZS5wYWdlWCx0b3A6by1lLnBhZ2VZfSl9ZnVuY3Rpb24gYyhlLHQpe3ZhciBpPWUuZ2V0T3B0aW9ucygpO2kuem9vbS5pbnRlcmFjdGl2ZSYmKHRbaS56b29tLnRyaWdnZXJdKG4pLHQubW91c2V3aGVlbChyKSksaS5wYW4uaW50ZXJhY3RpdmUmJih0LmJpbmQoImRyYWdzdGFydCIse2Rpc3RhbmNlOjEwfSxhKSx0LmJpbmQoImRyYWciLGYpLHQuYmluZCgiZHJhZ2VuZCIsbCkpfWZ1bmN0aW9uIGgoZSx0KXt0LnVuYmluZChlLmdldE9wdGlvbnMoKS56b29tLnRyaWdnZXIsbiksdC51bmJpbmQoIm1vdXNld2hlZWwiLHIpLHQudW5iaW5kKCJkcmFnc3RhcnQiLGEpLHQudW5iaW5kKCJkcmFnIixmKSx0LnVuYmluZCgiZHJhZ2VuZCIsbCksdSYmY2xlYXJUaW1lb3V0KHUpfXZhciBpPSJkZWZhdWx0IixzPTAsbz0wLHU9bnVsbDt0Lnpvb21PdXQ9ZnVuY3Rpb24oZSl7ZXx8KGU9e30pLGUuYW1vdW50fHwoZS5hbW91bnQ9dC5nZXRPcHRpb25zKCkuem9vbS5hbW91bnQpLGUuYW1vdW50PTEvZS5hbW91bnQsdC56b29tKGUpfSx0Lnpvb209ZnVuY3Rpb24obil7bnx8KG49e30pO3ZhciByPW4uY2VudGVyLGk9bi5hbW91bnR8fHQuZ2V0T3B0aW9ucygpLnpvb20uYW1vdW50LHM9dC53aWR0aCgpLG89dC5oZWlnaHQoKTtyfHwocj17bGVmdDpzLzIsdG9wOm8vMn0pO3ZhciB1PXIubGVmdC9zLGE9ci50b3AvbyxmPXt4OnttaW46ci5sZWZ0LXUqcy9pLG1heDpyLmxlZnQrKDEtdSkqcy9pfSx5OnttaW46ci50b3AtYSpvL2ksbWF4OnIudG9wKygxLWEpKm8vaX19O2UuZWFjaCh0LmdldEF4ZXMoKSxmdW5jdGlvbihlLHQpe3ZhciBuPXQub3B0aW9ucyxyPWZbdC5kaXJlY3Rpb25dLm1pbixpPWZbdC5kaXJlY3Rpb25dLm1heCxzPW4uem9vbVJhbmdlLG89bi5wYW5SYW5nZTtpZihzPT09ITEpcmV0dXJuO3I9dC5jMnAociksaT10LmMycChpKTtpZihyPmkpe3ZhciB1PXI7cj1pLGk9dX1vJiYob1swXSE9bnVsbCYmcjxvWzBdJiYocj1vWzBdKSxvWzFdIT1udWxsJiZpPm9bMV0mJihpPW9bMV0pKTt2YXIgYT1pLXI7aWYocyYmKHNbMF0hPW51bGwmJmE8c1swXXx8c1sxXSE9bnVsbCYmYT5zWzFdKSlyZXR1cm47bi5taW49cixuLm1heD1pfSksdC5zZXR1cEdyaWQoKSx0LmRyYXcoKSxuLnByZXZlbnRFdmVudHx8dC5nZXRQbGFjZWhvbGRlcigpLnRyaWdnZXIoInBsb3R6b29tIixbdCxuXSl9LHQucGFuPWZ1bmN0aW9uKG4pe3ZhciByPXt4OituLmxlZnQseTorbi50b3B9O2lzTmFOKHIueCkmJihyLng9MCksaXNOYU4oci55KSYmKHIueT0wKSxlLmVhY2godC5nZXRBeGVzKCksZnVuY3Rpb24oZSx0KXt2YXIgbj10Lm9wdGlvbnMsaSxzLG89clt0LmRpcmVjdGlvbl07aT10LmMycCh0LnAyYyh0Lm1pbikrbykscz10LmMycCh0LnAyYyh0Lm1heCkrbyk7dmFyIHU9bi5wYW5SYW5nZTtpZih1PT09ITEpcmV0dXJuO3UmJih1WzBdIT1udWxsJiZ1WzBdPmkmJihvPXVbMF0taSxpKz1vLHMrPW8pLHVbMV0hPW51bGwmJnVbMV08cyYmKG89dVsxXS1zLGkrPW8scys9bykpLG4ubWluPWksbi5tYXg9c30pLHQuc2V0dXBHcmlkKCksdC5kcmF3KCksbi5wcmV2ZW50RXZlbnR8fHQuZ2V0UGxhY2Vob2xkZXIoKS50cmlnZ2VyKCJwbG90cGFuIixbdCxuXSl9LHQuaG9va3MuYmluZEV2ZW50cy5wdXNoKGMpLHQuaG9va3Muc2h1dGRvd24ucHVzaChoKX12YXIgdD17eGF4aXM6e3pvb21SYW5nZTpudWxsLHBhblJhbmdlOm51bGx9LHpvb206e2ludGVyYWN0aXZlOiExLHRyaWdnZXI6ImRibGNsaWNrIixhbW91bnQ6MS41fSxwYW46e2ludGVyYWN0aXZlOiExLGN1cnNvcjoibW92ZSIsZnJhbWVSYXRlOjIwfX07ZS5wbG90LnBsdWdpbnMucHVzaCh7aW5pdDpuLG9wdGlvbnM6dCxuYW1lOiJuYXZpZ2F0ZSIsdmVyc2lvbjoiMS4zIn0pfShqUXVlcnkpOw== \ No newline at end of file diff --git a/js/jquery.flot.selection.js b/js/jquery.flot.selection.js new file mode 100644 index 0000000..7f7b326 --- /dev/null +++ b/js/jquery.flot.selection.js @@ -0,0 +1,344 @@ +/* +Flot plugin for selecting regions. + +The plugin defines the following options: + + selection: { + mode: null or "x" or "y" or "xy", + color: color + } + +Selection support is enabled by setting the mode to one of "x", "y" or +"xy". In "x" mode, the user will only be able to specify the x range, +similarly for "y" mode. For "xy", the selection becomes a rectangle +where both ranges can be specified. "color" is color of the selection +(if you need to change the color later on, you can get to it with +plot.getOptions().selection.color). + +When selection support is enabled, a "plotselected" event will be +emitted on the DOM element you passed into the plot function. The +event handler gets a parameter with the ranges selected on the axes, +like this: + + placeholder.bind("plotselected", function(event, ranges) { + alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to) + // similar for yaxis - with multiple axes, the extra ones are in + // x2axis, x3axis, ... + }); + +The "plotselected" event is only fired when the user has finished +making the selection. A "plotselecting" event is fired during the +process with the same parameters as the "plotselected" event, in case +you want to know what's happening while it's happening, + +A "plotunselected" event with no arguments is emitted when the user +clicks the mouse to remove the selection. + +The plugin allso adds the following methods to the plot object: + +- setSelection(ranges, preventEvent) + + Set the selection rectangle. The passed in ranges is on the same + form as returned in the "plotselected" event. If the selection mode + is "x", you should put in either an xaxis range, if the mode is "y" + you need to put in an yaxis range and both xaxis and yaxis if the + selection mode is "xy", like this: + + setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } }); + + setSelection will trigger the "plotselected" event when called. If + you don't want that to happen, e.g. if you're inside a + "plotselected" handler, pass true as the second parameter. If you + are using multiple axes, you can specify the ranges on any of those, + e.g. as x2axis/x3axis/... instead of xaxis, the plugin picks the + first one it sees. + +- clearSelection(preventEvent) + + Clear the selection rectangle. Pass in true to avoid getting a + "plotunselected" event. + +- getSelection() + + Returns the current selection in the same format as the + "plotselected" event. If there's currently no selection, the + function returns null. + +*/ + +(function ($) { + function init(plot) { + var selection = { + first: { x: -1, y: -1}, second: { x: -1, y: -1}, + show: false, + active: false + }; + + // FIXME: The drag handling implemented here should be + // abstracted out, there's some similar code from a library in + // the navigation plugin, this should be massaged a bit to fit + // the Flot cases here better and reused. Doing this would + // make this plugin much slimmer. + var savedhandlers = {}; + + var mouseUpHandler = null; + + function onMouseMove(e) { + if (selection.active) { + updateSelection(e); + + plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]); + } + } + + function onMouseDown(e) { + if (e.which != 1) // only accept left-click + return; + + // cancel out any text selections + document.body.focus(); + + // prevent text selection and drag in old-school browsers + if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) { + savedhandlers.onselectstart = document.onselectstart; + document.onselectstart = function () { return false; }; + } + if (document.ondrag !== undefined && savedhandlers.ondrag == null) { + savedhandlers.ondrag = document.ondrag; + document.ondrag = function () { return false; }; + } + + setSelectionPos(selection.first, e); + + selection.active = true; + + // this is a bit silly, but we have to use a closure to be + // able to whack the same handler again + mouseUpHandler = function (e) { onMouseUp(e); }; + + $(document).one("mouseup", mouseUpHandler); + } + + function onMouseUp(e) { + mouseUpHandler = null; + + // revert drag stuff for old-school browsers + if (document.onselectstart !== undefined) + document.onselectstart = savedhandlers.onselectstart; + if (document.ondrag !== undefined) + document.ondrag = savedhandlers.ondrag; + + // no more dragging + selection.active = false; + updateSelection(e); + + if (selectionIsSane()) + triggerSelectedEvent(); + else { + // this counts as a clear + plot.getPlaceholder().trigger("plotunselected", [ ]); + plot.getPlaceholder().trigger("plotselecting", [ null ]); + } + + return false; + } + + function getSelection() { + if (!selectionIsSane()) + return null; + + var r = {}, c1 = selection.first, c2 = selection.second; + $.each(plot.getAxes(), function (name, axis) { + if (axis.used) { + var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]); + r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) }; + } + }); + return r; + } + + function triggerSelectedEvent() { + var r = getSelection(); + + plot.getPlaceholder().trigger("plotselected", [ r ]); + + // backwards-compat stuff, to be removed in future + if (r.xaxis && r.yaxis) + plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]); + } + + function clamp(min, value, max) { + return value < min ? min: (value > max ? max: value); + } + + function setSelectionPos(pos, e) { + var o = plot.getOptions(); + var offset = plot.getPlaceholder().offset(); + var plotOffset = plot.getPlotOffset(); + pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width()); + pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height()); + + if (o.selection.mode == "y") + pos.x = pos == selection.first ? 0 : plot.width(); + + if (o.selection.mode == "x") + pos.y = pos == selection.first ? 0 : plot.height(); + } + + function updateSelection(pos) { + if (pos.pageX == null) + return; + + setSelectionPos(selection.second, pos); + if (selectionIsSane()) { + selection.show = true; + plot.triggerRedrawOverlay(); + } + else + clearSelection(true); + } + + function clearSelection(preventEvent) { + if (selection.show) { + selection.show = false; + plot.triggerRedrawOverlay(); + if (!preventEvent) + plot.getPlaceholder().trigger("plotunselected", [ ]); + } + } + + // function taken from markings support in Flot + function extractRange(ranges, coord) { + var axis, from, to, key, axes = plot.getAxes(); + + for (var k in axes) { + axis = axes[k]; + if (axis.direction == coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n == 1) + key = coord + "axis"; // support x1axis as xaxis + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function setSelection(ranges, preventEvent) { + var axis, range, o = plot.getOptions(); + + if (o.selection.mode == "y") { + selection.first.x = 0; + selection.second.x = plot.width(); + } + else { + range = extractRange(ranges, "x"); + + selection.first.x = range.axis.p2c(range.from); + selection.second.x = range.axis.p2c(range.to); + } + + if (o.selection.mode == "x") { + selection.first.y = 0; + selection.second.y = plot.height(); + } + else { + range = extractRange(ranges, "y"); + + selection.first.y = range.axis.p2c(range.from); + selection.second.y = range.axis.p2c(range.to); + } + + selection.show = true; + plot.triggerRedrawOverlay(); + if (!preventEvent && selectionIsSane()) + triggerSelectedEvent(); + } + + function selectionIsSane() { + var minSize = 5; + return Math.abs(selection.second.x - selection.first.x) >= minSize && + Math.abs(selection.second.y - selection.first.y) >= minSize; + } + + plot.clearSelection = clearSelection; + plot.setSelection = setSelection; + plot.getSelection = getSelection; + + plot.hooks.bindEvents.push(function(plot, eventHolder) { + var o = plot.getOptions(); + if (o.selection.mode != null) { + eventHolder.mousemove(onMouseMove); + eventHolder.mousedown(onMouseDown); + } + }); + + + plot.hooks.drawOverlay.push(function (plot, ctx) { + // draw selection + if (selection.show && selectionIsSane()) { + var plotOffset = plot.getPlotOffset(); + var o = plot.getOptions(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var c = $.color.parse(o.selection.color); + + ctx.strokeStyle = c.scale('a', 0.8).toString(); + ctx.lineWidth = 1; + ctx.lineJoin = "round"; + ctx.fillStyle = c.scale('a', 0.4).toString(); + + var x = Math.min(selection.first.x, selection.second.x), + y = Math.min(selection.first.y, selection.second.y), + w = Math.abs(selection.second.x - selection.first.x), + h = Math.abs(selection.second.y - selection.first.y); + + ctx.fillRect(x, y, w, h); + ctx.strokeRect(x, y, w, h); + + ctx.restore(); + } + }); + + plot.hooks.shutdown.push(function (plot, eventHolder) { + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mousedown", onMouseDown); + + if (mouseUpHandler) + $(document).unbind("mouseup", mouseUpHandler); + }); + + } + + $.plot.plugins.push({ + init: init, + options: { + selection: { + mode: null, // one of null, "x", "y" or "xy" + color: "#e8cfac" + } + }, + name: 'selection', + version: '1.1' + }); +})(jQuery); -- GitLab