diff --git a/.gitignore b/.gitignore index b8f1fc9..362b66e 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ MANIFEST # Sphinx docs/api docs/_build +docs/_facility_pages # Eclipse editor project files .project diff --git a/.travis.yml b/.travis.yml index 112eb4e..2a216f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,10 +16,6 @@ matrix: - python: 2.7 env: SETUP_CMD='test --coverage' - # Generate docs in Python 2 - - python: 2.7 - env: SETUP_CMD='build_docs' - # Do a coverage test in Python 3. - python: 3.6 env: SETUP_CMD='test --coverage' diff --git a/docs/_templates/facility_page.rst b/docs/_templates/facility_page.rst new file mode 100644 index 0000000..dd2a2e4 --- /dev/null +++ b/docs/_templates/facility_page.rst @@ -0,0 +1,44 @@ +Filters of Observation Facility: {{ facility }} +==================================================== + +{% set facility_data=data[data['Obs. Facility']==facility] %} +{% set inst_list=facility_data['Instrument'].unique().tolist() %} +{% for inst in inst_list %} + +{% if inst!='NA' %} +{% if loop.first %} +Following **Instruments** are present: + +{% endif %} + +{{ inst }} +-------------------------- + +{% endif %} + +{% set inst_data=facility_data[facility_data['Instrument']==inst] %} + +.. list-table:: + :header-rows: 1 + + * - {{ inst_data.index.name }} +{% for col_name in inst_data.columns.values %} + - {{ col_name }} +{% endfor %} + +{% for filter_info in inst_data.itertuples() %} +{% for info in filter_info %} +{% if loop.first %} + * - {{ info }} +{% elif loop.last %} + - {{ info|replace('_ ','\_ ') }} +{% else %} + - {{ info }} +{% endif %} +{% endfor %} +{% endfor %} + + + + +{% endfor %} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index eef4351..e0f6f3e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -178,3 +178,55 @@ edit_on_github_source_root = "" edit_on_github_doc_root = "docs" + + +# Render rst pages as a jinja template to be able +# to generate rst docs from data (i.e. passed to template context) --------- +def rst_jinja(app, docname, source): + if app.builder.format != 'html': # Make sure builder output is HTML + return + src = source[0] + context = app.config.html_context # context dictionary, passed for rendering + context.update(facility_context(docname)) + rendered = app.builder.templates.render_string(src, context) + source[0] = rendered + +def facility_context(docname): + dirs_in_path = docname.split(os.sep) + if '_facility_pages' in dirs_in_path[:-1]: + # doc file (.rst) lies in directory "_facility_pages" + facility_name = dirs_in_path[-1] + context = {'facility': facility_name} + else: + context = {} + return context + +def setup(app): + app.connect("source-read", rst_jinja) + + +import wsynphot +import pandas as pd +import shutil + +# Storing data into variables ------------------ +try: + df = wsynphot.list_filters() +except IOError: # If filter_data.h5 not present + wsynphot.download_filter_data() + df = wsynphot.list_filters() +# Obtain list of Obsv. facilities from df +facility_list = df['Obs. Facility'].unique().tolist() + +# Pass data variables to html_context for rendering templates ------ +html_context = { + 'data': df, + 'facility_list': facility_list +} + +# Automatically create(or overwrite) doc for filters of each obsv. facility +# by using facilty_page.rst as template file to populate all facilty pages +os.makedirs('_facility_pages', exist_ok=True) +for facility in facility_list: + shutil.copyfile('_templates/facility_page.rst', + os.path.join('_facility_pages', '{0}.rst'.format(facility))) diff --git a/docs/filter-curves.ipynb b/docs/filter-curves.ipynb new file mode 100644 index 0000000..a3d35a2 --- /dev/null +++ b/docs/filter-curves.ipynb @@ -0,0 +1,339 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot & Compare Filter Curves by selecting the required Observation Facility and Instrument" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[\u001b[1mpy.warnings \u001b[0m][\u001b[1;33mWARNING\u001b[0m] /home/jpolygon/miniconda3/envs/wsp-doc-new/lib/python2.7/site-packages/tqdm/autonotebook/__init__.py:14: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)\n", + " \" (e.g. in jupyter console)\", TqdmExperimentalWarning)\n", + " (\u001b[1m__init__.py\u001b[0m:14)\n", + "Populating the interactive namespace from numpy and matplotlib\n" + ] + } + ], + "source": [ + "import wsynphot\n", + "%pylab notebook\n", + "plt.style.use('seaborn-colorblind')\n", + "plt.style.use('seaborn-notebook')\n", + "from IPython.display import *\n", + "import ipywidgets as widgets\n", + "from ipywidgets import *\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "9ae5214067b146c1ae9d797345147063", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "aW50ZXJhY3RpdmUoY2hpbGRyZW49KERyb3Bkb3duKGRlc2NyaXB0aW9uPXUnT2JzZXJ2YXRpb24gRmFjaWxpdHk6JywgbGF5b3V0PUxheW91dCh3aWR0aD11JzMwMHB4JyksIG9wdGlvbnM9KHXigKY=\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "try:\n", + " df=wsynphot.list_filters()\n", + "except IOError:#If filter_data.h5 not present\n", + " wsynphot.download_filter_data()\n", + " df=wsynphot.list_filters()\n", + "#Populate dropdown of Obs. facility (widget1) from df\n", + "obsfac=pd.Series(df['Obs. Facility'].unique())\n", + "widget1 = Dropdown(options = obsfac,\n", + " description='Observation Facility:',\n", + " style={'description_width': 'initial'},\n", + " layout=Layout(width='300px'))\n", + "\n", + "widget2 = Dropdown(description='Instrument:',\n", + " layout=Layout(left='40px',width='260px'))\n", + "\n", + "#Update dropdown of Instrument (widget2) on basis of selection in widget1\n", + "def update(*args):\n", + " widget2.options = df[df['Obs. Facility']==widget1.value]['Instrument'].unique().tolist()\n", + " \n", + "widget1.observe(update, names='value')\n", + "\n", + "#Plot the filters on basis of selection from both widgets (the selected obs. facilty & instrument combination)\n", + "def plot_filters(w1,w2):\n", + " if w1 and w2:\n", + " df1=df[df['Obs. Facility']==w1]\n", + " filters=df1[df1['Instrument']==w2].index.tolist()\n", + " plt.figure(figsize=(20,5))\n", + " print 'No of filters:',len(filters)\n", + " for filt in filters:\n", + " filter = wsynphot.FilterCurve.load_filter(filt)\n", + " filter.plot(gca())\n", + " print(filt)\n", + "\n", + "interact(plot_filters,w1=widget1,w2=widget2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.15" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "0407cb0045104ac4893fecdac443d120": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.1.0", + "model_name": "LayoutModel", + "state": {} + }, + "1f3120df079a4f469d0a9ad6f1cb9541": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.4.0", + "model_name": "DescriptionStyleModel", + "state": { + "description_width": "initial" + } + }, + "22434744f0b446a89a6a08444d3ba56b": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.1.0", + "model_name": "LayoutModel", + "state": { + "left": "40px", + "width": "260px" + } + }, + "36560ac929d74ca5a7abdd1a98c2445e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.1.0", + "model_name": "LayoutModel", + "state": {} + }, + "42fc4ed1267c493fa593cb34c0ac574d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.1.0", + "model_name": "LayoutModel", + "state": { + "width": "300px" + } + }, + "793fe4f0940e445ea9680da805b5ed80": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.4.0", + "model_name": "DropdownModel", + "state": { + "_options_labels": [ + "IRAC", + "MIPS" + ], + "description": "Instrument:", + "index": 0, + "layout": "IPY_MODEL_22434744f0b446a89a6a08444d3ba56b", + "style": "IPY_MODEL_92b4ffc2ca2245a0acbcbbdf1eb781f2" + } + }, + "84a56b793c36459aa3095d65a5ab6ed0": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.4.0", + "model_name": "DropdownModel", + "state": { + "_options_labels": [ + "2MASS", + "AAO", + "AKARI", + "Astrosat", + "BOK", + "CAHA", + "CFHT", + "COBE", + "CTIO", + "DENIS", + "Euclid", + "GAIA", + "GALEX", + "GCPD", + "Gemini", + "Generic", + "Geneva", + "GTC", + "Herschel", + "Hipparcos", + "HST", + "IAC80", + "ING", + "INT", + "IRAS", + "ISO", + "IUE", + "JWST", + "Keck", + "Kepler", + "KPNO", + "LasCumbres", + "LaSilla", + "LBT", + "LCO", + "LICK", + "Liverpool", + "LSST", + "McD", + "Misc", + "MKO", + "MMT", + "MSX", + "NIRT", + "NOAO", + "NOT", + "OAF", + "OAJ", + "OSN", + "P200", + "Palomar", + "PAN-STARRS", + "Paranal", + "SAO", + "Scorpio", + "SkyMapper", + "SLOAN", + "SOFIA", + "Special", + "Spitzer", + "STELLA", + "Subaru", + "Swift", + "TCS", + "TD1", + "TESS", + "TJO", + "TNG", + "TNO", + "TYCHO", + "UKIRT", + "VATT", + "WFIRST", + "WHT", + "WISE", + "WIYN" + ], + "description": "Observation Facility:", + "index": 59, + "layout": "IPY_MODEL_42fc4ed1267c493fa593cb34c0ac574d", + "style": "IPY_MODEL_1f3120df079a4f469d0a9ad6f1cb9541" + } + }, + "92b4ffc2ca2245a0acbcbbdf1eb781f2": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.4.0", + "model_name": "DescriptionStyleModel", + "state": { + "description_width": "" + } + }, + "9a5e26ff3a5842d5bd3e376435781908": { + "model_module": "@jupyter-widgets/output", + "model_module_version": "1.0.0", + "model_name": "OutputModel", + "state": { + "layout": "IPY_MODEL_36560ac929d74ca5a7abdd1a98c2445e", + "outputs": [ + { + "data": { + "application/javascript": "/* Put everything inside the global mpl namespace */\nwindow.mpl = {};\n\n\nmpl.get_websocket_type = function() {\n if (typeof(WebSocket) !== 'undefined') {\n return WebSocket;\n } else if (typeof(MozWebSocket) !== 'undefined') {\n return MozWebSocket;\n } else {\n alert('Your browser does not have WebSocket support.' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.');\n };\n}\n\nmpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = (this.ws.binaryType != undefined);\n\n if (!this.supports_binary) {\n var warnings = document.getElementById(\"mpl-warnings\");\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent = (\n \"This browser does not support binary websocket messages. \" +\n \"Performance may be slow.\");\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = $('
');\n this._root_extra_style(this.root)\n this.root.attr('style', 'display: inline-block');\n\n $(parent_element).append(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n fig.send_message(\"send_image_mode\", {});\n if (mpl.ratio != 1) {\n fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n }\n fig.send_message(\"refresh\", {});\n }\n\n this.imageObj.onload = function() {\n if (fig.image_mode == 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function() {\n fig.ws.close();\n }\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n}\n\nmpl.figure.prototype._init_header = function() {\n var titlebar = $(\n '
');\n var titletext = $(\n '
');\n titlebar.append(titletext)\n this.root.append(titlebar);\n this.header = titletext[0];\n}\n\n\n\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.figure.prototype._init_canvas = function() {\n var fig = this;\n\n var canvas_div = $('
');\n\n canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n\n function canvas_keyboard_event(event) {\n return fig.key_event(event, event['data']);\n }\n\n canvas_div.keydown('key_press', canvas_keyboard_event);\n canvas_div.keyup('key_release', canvas_keyboard_event);\n this.canvas_div = canvas_div\n this._canvas_extra_style(canvas_div)\n this.root.append(canvas_div);\n\n var canvas = $('');\n canvas.addClass('mpl-canvas');\n canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n\n this.canvas = canvas[0];\n this.context = canvas[0].getContext(\"2d\");\n\n var backingStore = this.context.backingStorePixelRatio ||\n\tthis.context.webkitBackingStorePixelRatio ||\n\tthis.context.mozBackingStorePixelRatio ||\n\tthis.context.msBackingStorePixelRatio ||\n\tthis.context.oBackingStorePixelRatio ||\n\tthis.context.backingStorePixelRatio || 1;\n\n mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband = $('');\n rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n\n var pass_mouse_events = true;\n\n canvas_div.resizable({\n start: function(event, ui) {\n pass_mouse_events = false;\n },\n resize: function(event, ui) {\n fig.request_resize(ui.size.width, ui.size.height);\n },\n stop: function(event, ui) {\n pass_mouse_events = true;\n fig.request_resize(ui.size.width, ui.size.height);\n },\n });\n\n function mouse_event_fn(event) {\n if (pass_mouse_events)\n return fig.mouse_event(event, event['data']);\n }\n\n rubberband.mousedown('button_press', mouse_event_fn);\n rubberband.mouseup('button_release', mouse_event_fn);\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband.mousemove('motion_notify', mouse_event_fn);\n\n rubberband.mouseenter('figure_enter', mouse_event_fn);\n rubberband.mouseleave('figure_leave', mouse_event_fn);\n\n canvas_div.on(\"wheel\", function (event) {\n event = event.originalEvent;\n event['data'] = 'scroll'\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n mouse_event_fn(event);\n });\n\n canvas_div.append(canvas);\n canvas_div.append(rubberband);\n\n this.rubberband = rubberband;\n this.rubberband_canvas = rubberband[0];\n this.rubberband_context = rubberband[0].getContext(\"2d\");\n this.rubberband_context.strokeStyle = \"#000000\";\n\n this._resize_canvas = function(width, height) {\n // Keep the size of the canvas, canvas container, and rubber band\n // canvas in synch.\n canvas_div.css('width', width)\n canvas_div.css('height', height)\n\n canvas.attr('width', width * mpl.ratio);\n canvas.attr('height', height * mpl.ratio);\n canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n\n rubberband.attr('width', width);\n rubberband.attr('height', height);\n }\n\n // Set the figure to an initial 600x600px, this will subsequently be updated\n // upon first draw.\n this._resize_canvas(600, 600);\n\n // Disable right mouse context menu.\n $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n return false;\n });\n\n function set_focus () {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n}\n\nmpl.figure.prototype._init_toolbar = function() {\n var fig = this;\n\n var nav_element = $('
')\n nav_element.attr('style', 'width: 100%');\n this.root.append(nav_element);\n\n // Define a callback function for later on.\n function toolbar_event(event) {\n return fig.toolbar_button_onclick(event['data']);\n }\n function toolbar_mouse_event(event) {\n return fig.toolbar_button_onmouseover(event['data']);\n }\n\n for(var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n // put a spacer in here.\n continue;\n }\n var button = $('