diff --git a/.ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb b/.ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..b2c4549632725c1ee3c50a465af06e961f44b6c1 --- /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 Binary files /dev/null and b/Nomad_tutorial_head.png differ diff --git a/band_structure_visualization.ipynb b/band_structure_visualization.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..b2c4549632725c1ee3c50a465af06e961f44b6c1 --- /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 0000000000000000000000000000000000000000..644d35e274fd64ddaf6d12af813e820c424176a9 --- /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 0000000000000000000000000000000000000000..a792b71330e21da38fdb543f6f754cd61dd9103b --- /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 0000000000000000000000000000000000000000..cda8038953c76b039e3ab0f1c49607dcbcf6c3ce --- /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 0000000000000000000000000000000000000000..fd33fd20274d8e2b4c5a6134379e0389572f4e09 --- /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 0000000000000000000000000000000000000000..f2b97603c321bcb9dc1ebee45e61a7c19cdd46f3 --- /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 0000000000000000000000000000000000000000..1aa03fe0ece2c4357cfa5061da66b2928eb82ea6 --- /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 0000000000000000000000000000000000000000..7f7b32694bda98c39b5f4af4ef54835c72d41dbb --- /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);