diff --git a/README.md b/README.md
index 845cd08..abb97d7 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@ Figure 3: Sample products from SkySat video collection over Mt. St. Helen's crat
## Dependencies
- See [environment.yml file](/environment.yml) for complete list of Python packages with pinned version numbers.
-- [NASA Ames Stereo Pipeline v 2.7.0](https://stereopipeline.readthedocs.io/en/latest/)
+- [NASA Ames Stereo Pipeline v 3.0.1 alpha (April 22 2022)](https://stereopipeline.readthedocs.io/en/latest/)
## Installation
Please see the [install instructions](/docs/install_instructions.md).
diff --git a/docs/install_instructions.md b/docs/install_instructions.md
index 7666563..27e58a0 100644
--- a/docs/install_instructions.md
+++ b/docs/install_instructions.md
@@ -2,7 +2,7 @@
- We use srtm4 package, which for now needs developer version of libtiff
- So first of all, install libtif on your machine using: `apt-get install libtiff-dev` for Ubuntu or `brew install libtiff` for (macOS)
-- Download Ames Stereo Pipeline (v 2.6.2) executables from [here](https://ti.arc.nasa.gov/tech/asr/groups/intelligent-robotics/ngt/stereo/). Untar the downloaded file, and add the `bin` folder in the untarred folder to your `.bashrc` profile.
+- Download Ames Stereo Pipeline (v 3.0.1 alpha) executables from [here](https://github.com/NeoGeographyToolkit/StereoPipeline/releases/download/2022-04-22-daily-build/StereoPipeline-3.0.1-alpha-2022-04-22-x86_64-Linux.tar.bz2). Untar the downloaded file, and add the `bin` folder in the untarred folder to your `.bashrc` profile.
- Clone the `skysat_stereo` repo to the location of your choice using `https://github.com/uw-cryo/skysat_stereo.git`
- We recommend using conda for managing packages. Powerusers can have a look at the `environment.yml` file in the github repository to make an environment using that.
- Otherwise, one can simply initiate a conda environment to avoid conflicts using the environment.yml file.
@@ -10,5 +10,5 @@
- Each time a new terminal is opened, activate the environment using `conda activate skysat_stereo`.
- Activate the skysat_stereo environment, and install the repository in editable command: `pip install -e skysat_stereo/`
- This will install all library files (the fancy apis), to run the command line calls, these scripts need to added path.
-- To use the command line executables located in the `scripts` directory of `skysat_stereo` directory, add the `skysat_stereo/scripts/` path to your `.bashrc` as well.
+- To use the command line executables located in the `scripts` directory of `skysat_stereo` directory, add the `skysat_stereo/scripts/` path to your `.bashrc` as well. A guide on how to add paths to your .bashrc can be found [here](https://gist.github.com/nex3/c395b2f8fd4b02068be37c961301caa7).
- If any of this sounds confusing, please refer to this [guide](https://github.com/dshean/demcoreg/blob/master/docs/beginners_doc.md) which has tricks for installing packages/enivronment using conda for new users.
diff --git a/environment.yml b/environment.yml
index 2ea9fb8..e11308e 100644
--- a/environment.yml
+++ b/environment.yml
@@ -3,13 +3,13 @@ channels:
- conda-forge
dependencies:
# core data science
- - python=3.7
+ - python
- scipy
- numpy
- pandas
- matplotlib
# geospatial (raster+vector)
- - gdal=2.4
+ - gdal
- rasterio
- geopandas
- shapely
diff --git a/notebooks/gm_triplet_eval.ipynb b/notebooks/gm_triplet_eval.ipynb
new file mode 100644
index 0000000..5c9c174
--- /dev/null
+++ b/notebooks/gm_triplet_eval.ipynb
@@ -0,0 +1,15115 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Bad key \"text.kerning_factor\" on line 4 in\n",
+ "/nobackup/sbhusha1/sw/miniconda3/envs/bhushan_PY3/lib/python3.6/site-packages/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle.\n",
+ "You probably need to get an updated matplotlibrc file from\n",
+ "https://github.com/matplotlib/matplotlib/blob/v3.1.3/matplotlibrc.template\n",
+ "or from the matplotlib source distribution\n"
+ ]
+ }
+ ],
+ "source": [
+ "import numpy as np\n",
+ "import os,sys,glob,shutil\n",
+ "import matplotlib.pyplot as plt\n",
+ "import pandas as pd\n",
+ "import geopandas as gpd\n",
+ "from skysat_stereo import asp_utils as asp\n",
+ "from pygeotools.lib import iolib,warplib,geolib,malib\n",
+ "from imview import pltlib"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%matplotlib notebook"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ba_pointmap = pd.read_csv('/nobackup/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/ba_pinhole/run-final_residuals_no_loss_function_pointmap_point_log_final_reproj_error.csv',skiprows=[1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " -108.118149 \n",
+ " 39.098134 \n",
+ " 2281.748878 \n",
+ " 0.144643 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " -108.118142 \n",
+ " 39.100245 \n",
+ " 2284.510599 \n",
+ " 0.061055 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " -108.118556 \n",
+ " 39.097776 \n",
+ " 2279.759332 \n",
+ " 0.274053 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " -108.118553 \n",
+ " 39.098136 \n",
+ " 2277.914734 \n",
+ " 0.263970 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " -108.118547 \n",
+ " 39.098510 \n",
+ " 2273.751014 \n",
+ " 0.186330 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 365219 \n",
+ " -108.168748 \n",
+ " 38.924607 \n",
+ " 2991.321384 \n",
+ " 0.023239 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 365220 \n",
+ " -108.168749 \n",
+ " 38.925163 \n",
+ " 2977.689364 \n",
+ " 0.094387 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 365221 \n",
+ " -108.168749 \n",
+ " 38.925716 \n",
+ " 2985.847508 \n",
+ " 0.209347 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 365222 \n",
+ " -108.168753 \n",
+ " 38.926825 \n",
+ " 2978.211342 \n",
+ " 0.111194 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 365223 \n",
+ " -108.168758 \n",
+ " 38.927659 \n",
+ " 2963.472100 \n",
+ " 0.115513 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
365224 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "0 -108.118149 39.098134 2281.748878 0.144643 \n",
+ "1 -108.118142 39.100245 2284.510599 0.061055 \n",
+ "2 -108.118556 39.097776 2279.759332 0.274053 \n",
+ "3 -108.118553 39.098136 2277.914734 0.263970 \n",
+ "4 -108.118547 39.098510 2273.751014 0.186330 \n",
+ "... ... ... ... ... \n",
+ "365219 -108.168748 38.924607 2991.321384 0.023239 \n",
+ "365220 -108.168749 38.925163 2977.689364 0.094387 \n",
+ "365221 -108.168749 38.925716 2985.847508 0.209347 \n",
+ "365222 -108.168753 38.926825 2978.211342 0.111194 \n",
+ "365223 -108.168758 38.927659 2963.472100 0.115513 \n",
+ "\n",
+ " num_observations \n",
+ "0 2 \n",
+ "1 2 \n",
+ "2 5 \n",
+ "3 5 \n",
+ "4 5 \n",
+ "... ... \n",
+ "365219 2 \n",
+ "365220 2 \n",
+ "365221 2 \n",
+ "365222 2 \n",
+ "365223 2 \n",
+ "\n",
+ "[365224 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_pointmap"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 20085 \n",
+ " -108.118829 \n",
+ " 39.070752 \n",
+ " 2601.543247 \n",
+ " 0.420886 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ " 20071 \n",
+ " -108.118482 \n",
+ " 39.070748 \n",
+ " 2601.668799 \n",
+ " 0.415747 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ " 14085 \n",
+ " -108.120159 \n",
+ " 39.087575 \n",
+ " 2355.525479 \n",
+ " 0.279019 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 116326 \n",
+ " -108.144538 \n",
+ " 39.109576 \n",
+ " 2064.230687 \n",
+ " 0.159140 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 160172 \n",
+ " -108.145005 \n",
+ " 39.023194 \n",
+ " 3118.588496 \n",
+ " 0.487927 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 117889 \n",
+ " -108.144560 \n",
+ " 39.094883 \n",
+ " 2164.870266 \n",
+ " 0.296114 \n",
+ " 6 \n",
+ " \n",
+ " \n",
+ " 144347 \n",
+ " -108.119827 \n",
+ " 39.067675 \n",
+ " 2704.132638 \n",
+ " 0.291963 \n",
+ " 6 \n",
+ " \n",
+ " \n",
+ " 142779 \n",
+ " -108.144996 \n",
+ " 39.062872 \n",
+ " 2670.656371 \n",
+ " 0.214205 \n",
+ " 6 \n",
+ " \n",
+ " \n",
+ " 142778 \n",
+ " -108.144990 \n",
+ " 39.062521 \n",
+ " 2677.873044 \n",
+ " 0.179413 \n",
+ " 6 \n",
+ " \n",
+ " \n",
+ " 134710 \n",
+ " -108.147745 \n",
+ " 39.068790 \n",
+ " 2505.692425 \n",
+ " 0.283809 \n",
+ " 6 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
1000 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "20085 -108.118829 39.070752 2601.543247 0.420886 \n",
+ "20071 -108.118482 39.070748 2601.668799 0.415747 \n",
+ "14085 -108.120159 39.087575 2355.525479 0.279019 \n",
+ "116326 -108.144538 39.109576 2064.230687 0.159140 \n",
+ "160172 -108.145005 39.023194 3118.588496 0.487927 \n",
+ "... ... ... ... ... \n",
+ "117889 -108.144560 39.094883 2164.870266 0.296114 \n",
+ "144347 -108.119827 39.067675 2704.132638 0.291963 \n",
+ "142779 -108.144996 39.062872 2670.656371 0.214205 \n",
+ "142778 -108.144990 39.062521 2677.873044 0.179413 \n",
+ "134710 -108.147745 39.068790 2505.692425 0.283809 \n",
+ "\n",
+ " num_observations \n",
+ "20085 8 \n",
+ "20071 8 \n",
+ "14085 7 \n",
+ "116326 7 \n",
+ "160172 7 \n",
+ "... ... \n",
+ "117889 6 \n",
+ "144347 6 \n",
+ "142779 6 \n",
+ "142778 6 \n",
+ "134710 6 \n",
+ "\n",
+ "[1000 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_pointmap.sort_values(by=' num_observations',ascending=False).head(1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Index(['# lon', ' lat', ' height_above_datum', ' mean_residual',\n",
+ " ' num_observations'],\n",
+ " dtype='object')"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_pointmap.keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'All points')"
+ ]
+ },
+ "execution_count": 32,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots()\n",
+ "clim = np.percentile(ba_pointmap[' mean_residual'].values,(2,98))\n",
+ "im = ax.scatter(ba_pointmap['# lon'],ba_pointmap[' lat'],\n",
+ " c=ba_pointmap[' mean_residual'].values,vmin=clim[0],vmax=clim[1],cmap='inferno')\n",
+ "plt.colorbar(im,label='Mean Residaul (px)')\n",
+ "plt.title(\"All points\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 204,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'Seen in 6+ images')"
+ ]
+ },
+ "execution_count": 204,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mask_5_multiplicity = ba_pointmap[' num_observations']>=6\n",
+ "ba_pointmap_5above = ba_pointmap[mask_5_multiplicity]\n",
+ "f,ax = plt.subplots()\n",
+ "clim = np.percentile(ba_pointmap_5above[' mean_residual'].values,(2,98))\n",
+ "im = ax.scatter(ba_pointmap_5above['# lon'],ba_pointmap_5above[' lat'],\n",
+ " c=ba_pointmap_5above[' mean_residual'].values,vmin=clim[0],vmax=clim[1],cmap='inferno',s=1)\n",
+ "plt.colorbar(im,label='Mean Residaul (px)')\n",
+ "plt.title('Seen in 6+ images')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 203,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'Seen in 5+ images')"
+ ]
+ },
+ "execution_count": 203,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mask_5_multiplicity = ba_pointmap[' num_observations']>=5\n",
+ "ba_pointmap_5above = ba_pointmap[mask_5_multiplicity]\n",
+ "f,ax = plt.subplots()\n",
+ "clim = np.percentile(ba_pointmap_5above[' mean_residual'].values,(2,98))\n",
+ "im = ax.scatter(ba_pointmap_5above['# lon'],ba_pointmap_5above[' lat'],\n",
+ " c=ba_pointmap_5above[' mean_residual'].values,vmin=clim[0],vmax=clim[1],cmap='inferno',s=1)\n",
+ "plt.colorbar(im,label='Mean Residaul (px)')\n",
+ "plt.title('Seen in 5+ images')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 152,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'Seen in 4+ images')"
+ ]
+ },
+ "execution_count": 152,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mask_5_multiplicity = ba_pointmap[' num_observations']>=4\n",
+ "ba_pointmap_5above = ba_pointmap[mask_5_multiplicity]\n",
+ "f,ax = plt.subplots()\n",
+ "clim = np.percentile(ba_pointmap_5above[' mean_residual'].values,(2,98))\n",
+ "im = ax.scatter(ba_pointmap_5above['# lon'],ba_pointmap_5above[' lat'],\n",
+ " c=ba_pointmap_5above[' mean_residual'].values,vmin=clim[0],vmax=clim[1],cmap='inferno',s=1)\n",
+ "plt.colorbar(im,label='Mean Residaul (px)')\n",
+ "plt.title('Seen in 4+ images')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 151,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " -108.118556 \n",
+ " 39.097776 \n",
+ " 2279.759332 \n",
+ " 0.274053 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " -108.118553 \n",
+ " 39.098136 \n",
+ " 2277.914734 \n",
+ " 0.263970 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " -108.118547 \n",
+ " 39.098510 \n",
+ " 2273.751014 \n",
+ " 0.186330 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 5 \n",
+ " -108.118553 \n",
+ " 39.098834 \n",
+ " 2280.404354 \n",
+ " 0.220636 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 6 \n",
+ " -108.118555 \n",
+ " 39.099167 \n",
+ " 2284.961369 \n",
+ " 0.256914 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 360582 \n",
+ " -108.144335 \n",
+ " 38.959476 \n",
+ " 2823.487414 \n",
+ " 0.448360 \n",
+ " 4 \n",
+ " \n",
+ " \n",
+ " 360590 \n",
+ " -108.144700 \n",
+ " 38.959477 \n",
+ " 2825.607944 \n",
+ " 0.170043 \n",
+ " 4 \n",
+ " \n",
+ " \n",
+ " 360591 \n",
+ " -108.144695 \n",
+ " 38.959753 \n",
+ " 2824.654215 \n",
+ " 0.190384 \n",
+ " 4 \n",
+ " \n",
+ " \n",
+ " 360602 \n",
+ " -108.145054 \n",
+ " 38.959477 \n",
+ " 2825.513682 \n",
+ " 0.160512 \n",
+ " 4 \n",
+ " \n",
+ " \n",
+ " 360610 \n",
+ " -108.145406 \n",
+ " 38.960030 \n",
+ " 2821.089235 \n",
+ " 0.253887 \n",
+ " 4 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
75969 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "2 -108.118556 39.097776 2279.759332 0.274053 \n",
+ "3 -108.118553 39.098136 2277.914734 0.263970 \n",
+ "4 -108.118547 39.098510 2273.751014 0.186330 \n",
+ "5 -108.118553 39.098834 2280.404354 0.220636 \n",
+ "6 -108.118555 39.099167 2284.961369 0.256914 \n",
+ "... ... ... ... ... \n",
+ "360582 -108.144335 38.959476 2823.487414 0.448360 \n",
+ "360590 -108.144700 38.959477 2825.607944 0.170043 \n",
+ "360591 -108.144695 38.959753 2824.654215 0.190384 \n",
+ "360602 -108.145054 38.959477 2825.513682 0.160512 \n",
+ "360610 -108.145406 38.960030 2821.089235 0.253887 \n",
+ "\n",
+ " num_observations \n",
+ "2 5 \n",
+ "3 5 \n",
+ "4 5 \n",
+ "5 5 \n",
+ "6 5 \n",
+ "... ... \n",
+ "360582 4 \n",
+ "360590 4 \n",
+ "360591 4 \n",
+ "360602 4 \n",
+ "360610 4 \n",
+ "\n",
+ "[75969 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 151,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_pointmap_5above"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The point distribution looks decent, although having a better distribution of 5+ images point would have been great. I see that the max number of images in which the point is visible is 8, which is a bit dissapointing, but should be ok."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Coregisteration Analysis"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 39,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "init_diff_map = '/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/refdem/gm_8m_trans-tile-0_gaussfill-tile-0_triplet_median_mos_diff.tif'\n",
+ "fn_diff_map = '/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/refdem/gm_8m_trans-tile-0_gaussfill-tile-0_run-trans_reference-DEM_diff.tif'\n",
+ "f,ax = plt.subplots(1,2)\n",
+ "pltlib.iv_fn(init_diff_map,cmap='RdBu',clim=(-15,15),full=True,ax=ax[0])\n",
+ "pltlib.iv_fn(fn_diff_map,cmap='RdBu',clim=(-15,15),full=True,ax=ax[1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 40,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "init_diff_map = '/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/refdem/gm_8m_trans-tile-0_gaussfill-tile-0_triplet_median_mos_diff.tif'\n",
+ "fn_diff_map = '/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/refdem/gm_8m_trans-tile-0_gaussfill-tile-0_run-trans_reference-DEM_diff.tif'\n",
+ "f,ax = plt.subplots(1,2)\n",
+ "pltlib.iv_fn(init_diff_map,cmap='inferno',full=True,ax=ax[0])\n",
+ "pltlib.iv_fn(fn_diff_map,cmap='inferno',full=True,ax=ax[1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "coreg_points_init = pd.read_csv('/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/georegistered_dem_mos/run-beg_errors.csv',skiprows=[1,2])\n",
+ "coreg_points_fn = pd.read_csv('/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/georegistered_dem_mos/run-end_errors.csv',skiprows=[1,2])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # latitude \n",
+ " longitude \n",
+ " height above datum (meters) \n",
+ " error (meters) \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 39.071082 \n",
+ " -108.173824 \n",
+ " 2527.361658 \n",
+ " 35.648154 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 39.071010 \n",
+ " -108.173827 \n",
+ " 2526.149824 \n",
+ " 35.578709 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 39.101536 \n",
+ " -108.172541 \n",
+ " 2253.121541 \n",
+ " 35.333700 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 39.101464 \n",
+ " -108.172544 \n",
+ " 2253.695594 \n",
+ " 35.465970 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 39.103046 \n",
+ " -108.172389 \n",
+ " 2243.631202 \n",
+ " 35.296623 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 99995 \n",
+ " 38.991916 \n",
+ " -108.091672 \n",
+ " 3156.614654 \n",
+ " 28.079301 \n",
+ " \n",
+ " \n",
+ " 99996 \n",
+ " 38.991412 \n",
+ " -108.091692 \n",
+ " 3160.450896 \n",
+ " 26.680355 \n",
+ " \n",
+ " \n",
+ " 99997 \n",
+ " 38.991340 \n",
+ " -108.091695 \n",
+ " 3161.047654 \n",
+ " 26.794479 \n",
+ " \n",
+ " \n",
+ " 99998 \n",
+ " 38.992994 \n",
+ " -108.091536 \n",
+ " 3155.328412 \n",
+ " 32.252727 \n",
+ " \n",
+ " \n",
+ " 99999 \n",
+ " 38.992850 \n",
+ " -108.091542 \n",
+ " 3155.224321 \n",
+ " 32.727223 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
100000 rows × 4 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # latitude longitude height above datum (meters) error (meters)\n",
+ "0 39.071082 -108.173824 2527.361658 35.648154\n",
+ "1 39.071010 -108.173827 2526.149824 35.578709\n",
+ "2 39.101536 -108.172541 2253.121541 35.333700\n",
+ "3 39.101464 -108.172544 2253.695594 35.465970\n",
+ "4 39.103046 -108.172389 2243.631202 35.296623\n",
+ "... ... ... ... ...\n",
+ "99995 38.991916 -108.091672 3156.614654 28.079301\n",
+ "99996 38.991412 -108.091692 3160.450896 26.680355\n",
+ "99997 38.991340 -108.091695 3161.047654 26.794479\n",
+ "99998 38.992994 -108.091536 3155.328412 32.252727\n",
+ "99999 38.992850 -108.091542 3155.224321 32.727223\n",
+ "\n",
+ "[100000 rows x 4 columns]"
+ ]
+ },
+ "execution_count": 44,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "coreg_points_fn "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Index(['# latitude', 'longitude', 'height above datum (meters)',\n",
+ " 'error (meters)'],\n",
+ " dtype='object')"
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "coreg_points_fn.keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 50,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2)\n",
+ "im1 = ax[0].scatter(coreg_points_init['longitude'],coreg_points_init['# latitude'],\n",
+ " c=coreg_points_init['error (meters)'],cmap='inferno',s=1)\n",
+ "plt.colorbar(im1,label='init error (m)')\n",
+ "\n",
+ "im1 = ax[1].scatter(coreg_points_fn['longitude'],coreg_points_fn['# latitude'],\n",
+ " c=coreg_points_fn['error (meters)'],cmap='inferno',s=1)\n",
+ "plt.colorbar(im1,label='fn error (m)')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "So the max displacement value of 40 m throws out a lot of points. Rerunning with a higher value.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "init_diff = iolib.fn_getma(init_diff_map)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "119.25"
+ ]
+ },
+ "execution_count": 55,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "np.percentile(np.abs(init_diff.compressed()),98)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We will use a max displacement of 150 here then."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "New results"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "coreg_points_init = pd.read_csv('/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/georegistered_dem_mos/max_disp_200_full/run-beg_errors.csv',skiprows=[1,2])\n",
+ "coreg_points_fn = pd.read_csv('/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/georegistered_dem_mos/max_disp_200_full/run-end_errors.csv',skiprows=[1,2])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 62,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2)\n",
+ "im1 = ax[0].scatter(coreg_points_init['longitude'],coreg_points_init['# latitude'],\n",
+ " c=coreg_points_init['error (meters)'],cmap='inferno',s=1)\n",
+ "plt.colorbar(im1,label='init error (m)')\n",
+ "\n",
+ "im1 = ax[1].scatter(coreg_points_fn['longitude'],coreg_points_fn['# latitude'],\n",
+ " c=coreg_points_fn['error (meters)'],cmap='inferno',s=1)\n",
+ "plt.colorbar(im1,label='fn error (m)')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 63,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "coreg_fn = '/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/refdem/gm_8m_trans-tile-0_gaussfill-tile-0_run-trans_reference-DEM_diff.tif'\n",
+ "f,ax = plt.subplots()\n",
+ "pltlib.iv_fn(coreg_fn,ax=ax,cmap='RdBu',full=True,clim=(-15,15))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "TypeError",
+ "evalue": "float() argument must be a string or a number, not 'NoneType'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfloat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mTypeError\u001b[0m: float() argument must be a string or a number, not 'NoneType'"
+ ]
+ }
+ ],
+ "source": [
+ "np.float(None)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 68,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fn = '/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/refdem/gm_8m_trans-tile-0_gaussfill-tile-0_rpc_median_fn_diff.tif'\n",
+ "f,ax = plt.subplots()\n",
+ "pltlib.iv(iolib.fn_getma(fn)-11.81,ax=ax,cmap='RdBu',clim=(-15,15))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Post publication bundle adjustment update."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "cnet = '/nobackup/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/ba_pinhole/run-cnet.csv'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "with open(cnet,'r') as f:\n",
+ " content = f.readlines()\n",
+ "content = [x.strip() for x in content]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2"
+ ]
+ },
+ "execution_count": 75,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "content[0].count('.tif')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "list"
+ ]
+ },
+ "execution_count": 76,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "type(content)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "5976 39.0708724003359364 -108.118417946495512 2718.42901042836593 1 1 1 l1b_img/20191202_175214_ssc4d1_0004_basic_panchromatic_dn.tif 300.054168701171875 1278.578125 1 1 l1b_img/20191202_175247_ssc4d1_0006_basic_panchromatic_dn.tif 516 731 1 1 l1b_img/20191202_175214_ssc4d1_0005_basic_panchromatic_dn.tif 320.898101806640625 158.499832153320312 1 1 l1b_img/20191202_175214_ssc4d2_0008_basic_panchromatic_dn.tif 3171.87109375 1187.5457763671875 1 1 l1b_img/20191202_175214_ssc4d2_0009_basic_panchromatic_dn.tif 3167.041015625 42.8678245544433594 1 1 l1b_img/20191202_175322_ssc4d1_0005_basic_panchromatic_dn.tif 368.530792236328125 452.1015625 1 1 l1b_img/20191202_175322_ssc4d2_0008_basic_panchromatic_dn.tif 3128.061767578125 1287.0479736328125 1 1 l1b_img/20191202_175322_ssc4d2_0009_basic_panchromatic_dn.tif 3092.513671875 123.689239501953125 1 1\n",
+ "5976 39.0708724003359364 -108.118417946495512 2718.42901042836593 1.5 1.5 1.5 l1b_img/20191202_175214_ssc4d1_0004_basic_panchromatic_dn.tif 300.054168701171875 1278.578125 1 1 l1b_img/20191202_175247_ssc4d1_0006_basic_panchromatic_dn.tif 516 731 1 1 l1b_img/20191202_175214_ssc4d1_0005_basic_panchromatic_dn.tif 320.898101806640625 158.499832153320312 1 1 l1b_img/20191202_175214_ssc4d2_0008_basic_panchromatic_dn.tif 3171.87109375 1187.5457763671875 1 1 l1b_img/20191202_175214_ssc4d2_0009_basic_panchromatic_dn.tif 3167.041015625 42.8678245544433594 1 1 l1b_img/20191202_175322_ssc4d1_0005_basic_panchromatic_dn.tif 368.530792236328125 452.1015625 1 1 l1b_img/20191202_175322_ssc4d2_0008_basic_panchromatic_dn.tif 3128.061767578125 1287.0479736328125 1 1 l1b_img/20191202_175322_ssc4d2_0009_basic_panchromatic_dn.tif 3092.513671875 123.689239501953125 1 1\n",
+ "5990 39.0708678008930619 -108.118768397315293 2712.24786647356768 1 1 1 l1b_img/20191202_175214_ssc4d1_0004_basic_panchromatic_dn.tif 262.695892333984375 1275.901611328125 1 1 l1b_img/20191202_175247_ssc4d1_0006_basic_panchromatic_dn.tif 473 731 1 1 l1b_img/20191202_175214_ssc4d1_0005_basic_panchromatic_dn.tif 284.3160400390625 155.902984619140625 1 1 l1b_img/20191202_175214_ssc4d2_0008_basic_panchromatic_dn.tif 3135.376953125 1184.994873046875 1 1 l1b_img/20191202_175214_ssc4d2_0009_basic_panchromatic_dn.tif 3130.23046875 40.3128890991210938 1 1 l1b_img/20191202_175322_ssc4d1_0005_basic_panchromatic_dn.tif 331.244873046875 450.147491455078125 1 1 l1b_img/20191202_175322_ssc4d2_0008_basic_panchromatic_dn.tif 3090.97802734375 1285.0660400390625 1 1 l1b_img/20191202_175322_ssc4d2_0009_basic_panchromatic_dn.tif 3055.51220703125 121.771980285644531 1 1\n",
+ "5990 39.0708678008930619 -108.118768397315293 2712.24786647356768 1.5 1.5 1.5 l1b_img/20191202_175214_ssc4d1_0004_basic_panchromatic_dn.tif 262.695892333984375 1275.901611328125 1 1 l1b_img/20191202_175247_ssc4d1_0006_basic_panchromatic_dn.tif 473 731 1 1 l1b_img/20191202_175214_ssc4d1_0005_basic_panchromatic_dn.tif 284.3160400390625 155.902984619140625 1 1 l1b_img/20191202_175214_ssc4d2_0008_basic_panchromatic_dn.tif 3135.376953125 1184.994873046875 1 1 l1b_img/20191202_175214_ssc4d2_0009_basic_panchromatic_dn.tif 3130.23046875 40.3128890991210938 1 1 l1b_img/20191202_175322_ssc4d1_0005_basic_panchromatic_dn.tif 331.244873046875 450.147491455078125 1 1 l1b_img/20191202_175322_ssc4d2_0008_basic_panchromatic_dn.tif 3090.97802734375 1285.0660400390625 1 1 l1b_img/20191202_175322_ssc4d2_0009_basic_panchromatic_dn.tif 3055.51220703125 121.771980285644531 1 1\n"
+ ]
+ }
+ ],
+ "source": [
+ "final_gcp_list = []\n",
+ "outfn = os.path.splitext(cnet)[0]+'_gcp.gcp'\n",
+ "counter = 1\n",
+ "with open (outfn,'w') as f:\n",
+ " for line in content:\n",
+ " num_img = line.count('.tif')\n",
+ " if num_img<4:\n",
+ " continue\n",
+ " else:\n",
+ " new_str = f\"{counter} {line.split(' ',1)[1]}\"\n",
+ " if num_img == 8:\n",
+ " print(new_str)\n",
+ " if num_img >=6:\n",
+ " new_str = new_str.split(' 1 1 1 ')[0] + ' 1.5 1.5 1.5 '+new_str.split(' 1 1 1 ')[1]\n",
+ " elif num_img ==5:\n",
+ " new_str = new_str.split(' 1 1 1 ')[0] + ' 2.75 2.75 2.75 '+new_str.split(' 1 1 1 ')[1]\n",
+ " elif num_img ==4:\n",
+ " new_str = new_str.split(' 1 1 1 ')[0] + ' 3 3 3 '+new_str.split(' 1 1 1 ')[1]\n",
+ " if num_img == 8:\n",
+ " print(new_str)\n",
+ " final_gcp_list.append(new_str)\n",
+ " counter = counter + 1\n",
+ " f.write(new_str+'\\n')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 240,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "76313"
+ ]
+ },
+ "execution_count": 240,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "counter"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 100,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'1 39.0977741324629164 -108.118557970037728 2279.13343122196284 1.75 1.75 1.75 l1b_img/20191202_175214_ssc4d1_0001_basic_panchromatic_dn.tif 470.95989990234375 1332.419677734375 1 1 l1b_img/20191202_175322_ssc4d2_0006_basic_panchromatic_dn.tif 3124 396 1 1 l1b_img/20191202_175214_ssc4d1_0002_basic_panchromatic_dn.tif 403.45831298828125 192.45086669921875 1 1 l1b_img/20191202_175214_ssc4d2_0005_basic_panchromatic_dn.tif 3167.3525390625 996.81500244140625 1 1 l1b_img/20191202_175247_ssc4d1_0002_basic_panchromatic_dn.tif 497.6298828125 1073.089599609375 1 1'"
+ ]
+ },
+ "execution_count": 100,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "final_gcp_list[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 95,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "76312"
+ ]
+ },
+ "execution_count": 95,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(final_gcp_list)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Output BA"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 241,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackup/sbhusha1/sw/miniconda3/envs/bhushan_PY3/lib/python3.6/site-packages/IPython/core/interactiveshell.py:3063: DtypeWarning: Columns (4) have mixed types.Specify dtype option on import or set low_memory=False.\n",
+ " interactivity=interactivity, compiler=compiler, result=result)\n"
+ ]
+ }
+ ],
+ "source": [
+ "ba_post_gcp = pd.read_csv('/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/ba_pinhole/gcp_ba/run-final_residuals_no_loss_function_pointmap_point_log.csv',skiprows=[1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 242,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ba_post_gcp_init = pd.read_csv('/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/ba_pinhole/gcp_ba/run-initial_residuals_no_loss_function_pointmap_point_log.csv',skiprows=[1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 243,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " -108.118147 \n",
+ " 39.098136 \n",
+ " 2280.730844 \n",
+ " 0.072376 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " -108.118140 \n",
+ " 39.100246 \n",
+ " 2283.845318 \n",
+ " 0.053444 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " -108.118555 \n",
+ " 39.097776 \n",
+ " 2278.906168 \n",
+ " 0.207273 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " -108.118552 \n",
+ " 39.098137 \n",
+ " 2277.141977 \n",
+ " 0.255374 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " -108.118547 \n",
+ " 39.098510 \n",
+ " 2272.928680 \n",
+ " 0.199640 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 443277 \n",
+ " -108.144371 \n",
+ " 38.960914 \n",
+ " 2438.695318 \n",
+ " 34.746116 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443278 \n",
+ " -108.144876 \n",
+ " 38.960387 \n",
+ " 2551.408783 \n",
+ " 22.570890 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443279 \n",
+ " -108.144846 \n",
+ " 38.960754 \n",
+ " 2531.794920 \n",
+ " 24.661153 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443280 \n",
+ " -108.145260 \n",
+ " 38.960279 \n",
+ " 2574.073339 \n",
+ " 20.115521 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443281 \n",
+ " -108.145624 \n",
+ " 38.960786 \n",
+ " 2580.641146 \n",
+ " 19.032209 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
443282 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "0 -108.118147 39.098136 2280.730844 0.072376 \n",
+ "1 -108.118140 39.100246 2283.845318 0.053444 \n",
+ "2 -108.118555 39.097776 2278.906168 0.207273 \n",
+ "3 -108.118552 39.098137 2277.141977 0.255374 \n",
+ "4 -108.118547 39.098510 2272.928680 0.199640 \n",
+ "... ... ... ... ... \n",
+ "443277 -108.144371 38.960914 2438.695318 34.746116 \n",
+ "443278 -108.144876 38.960387 2551.408783 22.570890 \n",
+ "443279 -108.144846 38.960754 2531.794920 24.661153 \n",
+ "443280 -108.145260 38.960279 2574.073339 20.115521 \n",
+ "443281 -108.145624 38.960786 2580.641146 19.032209 \n",
+ "\n",
+ " num_observations \n",
+ "0 2 \n",
+ "1 2 \n",
+ "2 5 \n",
+ "3 5 \n",
+ "4 5 \n",
+ "... ... \n",
+ "443277 4 # GCP \n",
+ "443278 4 # GCP \n",
+ "443279 4 # GCP \n",
+ "443280 4 # GCP \n",
+ "443281 4 # GCP \n",
+ "\n",
+ "[443282 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 243,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 119,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "# lon float64\n",
+ " lat float64\n",
+ " height_above_datum float64\n",
+ " mean_residual float64\n",
+ " num_observations object\n",
+ "dtype: object"
+ ]
+ },
+ "execution_count": 119,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp.dtypes"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 244,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ba_post_gcp[' num_observations'] = ba_post_gcp[' num_observations'].astype(str)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 122,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "# lon float64\n",
+ " lat float64\n",
+ " height_above_datum float64\n",
+ " mean_residual float64\n",
+ " num_observations object\n",
+ "dtype: object"
+ ]
+ },
+ "execution_count": 122,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp.dtypes"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 245,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "mask_gcp = ba_post_gcp[' num_observations'].str.contains(' # GCP')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 246,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ba_post_gcp_gcp_only = ba_post_gcp[mask_gcp] "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 247,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 366970 \n",
+ " -108.118549 \n",
+ " 39.097799 \n",
+ " 2283.798669 \n",
+ " 1.215974 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " 366971 \n",
+ " -108.118545 \n",
+ " 39.098161 \n",
+ " 2282.018344 \n",
+ " 1.331600 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " 366972 \n",
+ " -108.118540 \n",
+ " 39.098534 \n",
+ " 2277.845099 \n",
+ " 1.250983 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " 366973 \n",
+ " -108.118544 \n",
+ " 39.098866 \n",
+ " 2285.859984 \n",
+ " 1.519592 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " 366974 \n",
+ " -108.118542 \n",
+ " 39.099205 \n",
+ " 2291.927724 \n",
+ " 1.894149 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 443277 \n",
+ " -108.144371 \n",
+ " 38.960914 \n",
+ " 2438.695318 \n",
+ " 34.746116 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443278 \n",
+ " -108.144876 \n",
+ " 38.960387 \n",
+ " 2551.408783 \n",
+ " 22.570890 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443279 \n",
+ " -108.144846 \n",
+ " 38.960754 \n",
+ " 2531.794920 \n",
+ " 24.661153 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443280 \n",
+ " -108.145260 \n",
+ " 38.960279 \n",
+ " 2574.073339 \n",
+ " 20.115521 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443281 \n",
+ " -108.145624 \n",
+ " 38.960786 \n",
+ " 2580.641146 \n",
+ " 19.032209 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
76312 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "366970 -108.118549 39.097799 2283.798669 1.215974 \n",
+ "366971 -108.118545 39.098161 2282.018344 1.331600 \n",
+ "366972 -108.118540 39.098534 2277.845099 1.250983 \n",
+ "366973 -108.118544 39.098866 2285.859984 1.519592 \n",
+ "366974 -108.118542 39.099205 2291.927724 1.894149 \n",
+ "... ... ... ... ... \n",
+ "443277 -108.144371 38.960914 2438.695318 34.746116 \n",
+ "443278 -108.144876 38.960387 2551.408783 22.570890 \n",
+ "443279 -108.144846 38.960754 2531.794920 24.661153 \n",
+ "443280 -108.145260 38.960279 2574.073339 20.115521 \n",
+ "443281 -108.145624 38.960786 2580.641146 19.032209 \n",
+ "\n",
+ " num_observations \n",
+ "366970 5 # GCP \n",
+ "366971 5 # GCP \n",
+ "366972 5 # GCP \n",
+ "366973 5 # GCP \n",
+ "366974 5 # GCP \n",
+ "... ... \n",
+ "443277 4 # GCP \n",
+ "443278 4 # GCP \n",
+ "443279 4 # GCP \n",
+ "443280 4 # GCP \n",
+ "443281 4 # GCP \n",
+ "\n",
+ "[76312 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 247,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_gcp_only"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 258,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ba_post_gcp_tie_points_only = ba_post_gcp[~mask_gcp] "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 259,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 20136 \n",
+ " -108.118469 \n",
+ " 39.070746 \n",
+ " 2605.421575 \n",
+ " 0.511189 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ " 20150 \n",
+ " -108.118820 \n",
+ " 39.070750 \n",
+ " 2605.183823 \n",
+ " 0.534066 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ " 172702 \n",
+ " -108.144929 \n",
+ " 39.004476 \n",
+ " 3083.113500 \n",
+ " 0.228984 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 12223 \n",
+ " -108.120505 \n",
+ " 39.087169 \n",
+ " 2357.327895 \n",
+ " 0.266872 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 166625 \n",
+ " -108.145301 \n",
+ " 39.016146 \n",
+ " 3100.664120 \n",
+ " 0.877038 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 318664 \n",
+ " -108.108132 \n",
+ " 38.942354 \n",
+ " 3085.617673 \n",
+ " 0.224653 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 318665 \n",
+ " -108.108124 \n",
+ " 38.942909 \n",
+ " 3086.322984 \n",
+ " 0.117203 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 318666 \n",
+ " -108.108113 \n",
+ " 38.944578 \n",
+ " 3085.047470 \n",
+ " 0.009852 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 318667 \n",
+ " -108.108103 \n",
+ " 38.946247 \n",
+ " 3082.571090 \n",
+ " 0.122820 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366969 \n",
+ " -108.169424 \n",
+ " 38.927623 \n",
+ " 2857.397389 \n",
+ " 0.000308 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
366970 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "20136 -108.118469 39.070746 2605.421575 0.511189 \n",
+ "20150 -108.118820 39.070750 2605.183823 0.534066 \n",
+ "172702 -108.144929 39.004476 3083.113500 0.228984 \n",
+ "12223 -108.120505 39.087169 2357.327895 0.266872 \n",
+ "166625 -108.145301 39.016146 3100.664120 0.877038 \n",
+ "... ... ... ... ... \n",
+ "318664 -108.108132 38.942354 3085.617673 0.224653 \n",
+ "318665 -108.108124 38.942909 3086.322984 0.117203 \n",
+ "318666 -108.108113 38.944578 3085.047470 0.009852 \n",
+ "318667 -108.108103 38.946247 3082.571090 0.122820 \n",
+ "366969 -108.169424 38.927623 2857.397389 0.000308 \n",
+ "\n",
+ " num_observations \n",
+ "20136 8 \n",
+ "20150 8 \n",
+ "172702 7 \n",
+ "12223 7 \n",
+ "166625 7 \n",
+ "... ... \n",
+ "318664 2 \n",
+ "318665 2 \n",
+ "318666 2 \n",
+ "318667 2 \n",
+ "366969 2 \n",
+ "\n",
+ "[366970 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 259,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_tie_points_only.sort_values(by=' num_observations',ascending=False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 141,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 437254 \n",
+ " -108.148533 \n",
+ " 38.979423 \n",
+ " 2556.806360 \n",
+ " 0.019993 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 381592 \n",
+ " -108.118762 \n",
+ " 38.999357 \n",
+ " 3133.411731 \n",
+ " 0.025504 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 390125 \n",
+ " -108.098821 \n",
+ " 38.927623 \n",
+ " 2897.323361 \n",
+ " 0.030982 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 398099 \n",
+ " -108.135530 \n",
+ " 39.086612 \n",
+ " 2278.328935 \n",
+ " 0.032866 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 389391 \n",
+ " -108.106506 \n",
+ " 38.932952 \n",
+ " 3055.098630 \n",
+ " 0.033386 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 373743 \n",
+ " -108.121513 \n",
+ " 39.062918 \n",
+ " 1136.846796 \n",
+ " 338.542573 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " 384458 \n",
+ " -108.107542 \n",
+ " 38.994951 \n",
+ " 1702.668909 \n",
+ " 400.606461 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 432286 \n",
+ " -108.153930 \n",
+ " 39.025062 \n",
+ " 4774.219284 \n",
+ " 466.238738 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 387760 \n",
+ " -108.105440 \n",
+ " 38.969129 \n",
+ " 1173.011542 \n",
+ " 564.982503 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 412849 \n",
+ " -108.143703 \n",
+ " 39.030208 \n",
+ " 1601.017886 \n",
+ " 642.523036 \n",
+ " 6 # GCP \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
76312 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "437254 -108.148533 38.979423 2556.806360 0.019993 \n",
+ "381592 -108.118762 38.999357 3133.411731 0.025504 \n",
+ "390125 -108.098821 38.927623 2897.323361 0.030982 \n",
+ "398099 -108.135530 39.086612 2278.328935 0.032866 \n",
+ "389391 -108.106506 38.932952 3055.098630 0.033386 \n",
+ "... ... ... ... ... \n",
+ "373743 -108.121513 39.062918 1136.846796 338.542573 \n",
+ "384458 -108.107542 38.994951 1702.668909 400.606461 \n",
+ "432286 -108.153930 39.025062 4774.219284 466.238738 \n",
+ "387760 -108.105440 38.969129 1173.011542 564.982503 \n",
+ "412849 -108.143703 39.030208 1601.017886 642.523036 \n",
+ "\n",
+ " num_observations \n",
+ "437254 4 # GCP \n",
+ "381592 4 # GCP \n",
+ "390125 4 # GCP \n",
+ "398099 4 # GCP \n",
+ "389391 4 # GCP \n",
+ "... ... \n",
+ "373743 5 # GCP \n",
+ "384458 4 # GCP \n",
+ "432286 4 # GCP \n",
+ "387760 4 # GCP \n",
+ "412849 6 # GCP \n",
+ "\n",
+ "[76312 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 141,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "plotter = ba_post_gcp_gcp_only.sort_values(by=' mean_residual',ascending=True)\n",
+ "ba_post_gcp_gcp_only.sort_values(by=' mean_residual',ascending=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 142,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'Seen in 4+ images')"
+ ]
+ },
+ "execution_count": 142,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots()\n",
+ "clim = np.percentile(plotter[' mean_residual'].values,(2,98))\n",
+ "im = ax.scatter(plotter['# lon'],plotter[' lat'],\n",
+ " c=plotter[' mean_residual'].values,vmin=clim[0],vmax=clim[1],cmap='inferno')\n",
+ "plt.colorbar(im,label='Mean Residaul (GCP (m))')\n",
+ "plt.title('Seen in 4+ images')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 148,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plotter[' num_observations'] = [np.float(x.split(' #')[0]) for x in plotter[' num_observations'].values]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 154,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'Seen in 4+ images')"
+ ]
+ },
+ "execution_count": 154,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mask_5_multiplicity = plotter[' num_observations']>=5\n",
+ "plotter = plotter[mask_5_multiplicity]\n",
+ "f,ax = plt.subplots()\n",
+ "clim = np.percentile(plotter[' mean_residual'].values,(2,98))\n",
+ "im = ax.scatter(plotter['# lon'],plotter[' lat'],\n",
+ " c=plotter[' mean_residual'].values,vmin=clim[0],vmax=clim[1],cmap='inferno',s=1)\n",
+ "plt.colorbar(im,label='Mean Residaul (GCP (m))')\n",
+ "plt.title('Seen in 4+ images')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 156,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "443282"
+ ]
+ },
+ "execution_count": 156,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(ba_post_gcp)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 157,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "443282"
+ ]
+ },
+ "execution_count": 157,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(ba_post_gcp_init)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 250,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 443277 \n",
+ " -108.144371 \n",
+ " 38.960914 \n",
+ " 2438.695318 \n",
+ " 34.746116 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443278 \n",
+ " -108.144876 \n",
+ " 38.960387 \n",
+ " 2551.408783 \n",
+ " 22.570890 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443279 \n",
+ " -108.144846 \n",
+ " 38.960754 \n",
+ " 2531.794920 \n",
+ " 24.661153 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443280 \n",
+ " -108.145260 \n",
+ " 38.960279 \n",
+ " 2574.073339 \n",
+ " 20.115521 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443281 \n",
+ " -108.145624 \n",
+ " 38.960786 \n",
+ " 2580.641146 \n",
+ " 19.032209 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "443277 -108.144371 38.960914 2438.695318 34.746116 \n",
+ "443278 -108.144876 38.960387 2551.408783 22.570890 \n",
+ "443279 -108.144846 38.960754 2531.794920 24.661153 \n",
+ "443280 -108.145260 38.960279 2574.073339 20.115521 \n",
+ "443281 -108.145624 38.960786 2580.641146 19.032209 \n",
+ "\n",
+ " num_observations \n",
+ "443277 4 # GCP \n",
+ "443278 4 # GCP \n",
+ "443279 4 # GCP \n",
+ "443280 4 # GCP \n",
+ "443281 4 # GCP "
+ ]
+ },
+ "execution_count": 250,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp.tail()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 251,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ba_post_gcp_init[' num_observations'] = ba_post_gcp_init[' num_observations'].astype('str')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 252,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 67119 \n",
+ " -108.120637 \n",
+ " 38.986280 \n",
+ " 2912.322639 \n",
+ " 14.425146 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 67120 \n",
+ " -108.120489 \n",
+ " 38.987176 \n",
+ " 2807.210331 \n",
+ " 45.767511 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 67121 \n",
+ " -108.120732 \n",
+ " 38.986691 \n",
+ " 2958.227250 \n",
+ " 4.008846 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 68206 \n",
+ " -108.120658 \n",
+ " 38.977442 \n",
+ " 3094.220706 \n",
+ " 22.541937 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 131179 \n",
+ " -108.146358 \n",
+ " 39.077695 \n",
+ " 2426.920278 \n",
+ " 16.574568 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 151034 \n",
+ " -108.146640 \n",
+ " 39.042325 \n",
+ " 3018.801929 \n",
+ " 13.269050 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 129432 \n",
+ " -108.145286 \n",
+ " 39.077459 \n",
+ " 2433.146504 \n",
+ " 16.154130 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 149841 \n",
+ " -108.119906 \n",
+ " 39.060249 \n",
+ " 2897.315121 \n",
+ " 21.492003 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 20136 \n",
+ " -108.118418 \n",
+ " 39.070872 \n",
+ " 2718.429010 \n",
+ " 34.589947 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ " 20150 \n",
+ " -108.118768 \n",
+ " 39.070868 \n",
+ " 2712.247866 \n",
+ " 32.760469 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
100 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "67119 -108.120637 38.986280 2912.322639 14.425146 \n",
+ "67120 -108.120489 38.987176 2807.210331 45.767511 \n",
+ "67121 -108.120732 38.986691 2958.227250 4.008846 \n",
+ "68206 -108.120658 38.977442 3094.220706 22.541937 \n",
+ "131179 -108.146358 39.077695 2426.920278 16.574568 \n",
+ "... ... ... ... ... \n",
+ "151034 -108.146640 39.042325 3018.801929 13.269050 \n",
+ "129432 -108.145286 39.077459 2433.146504 16.154130 \n",
+ "149841 -108.119906 39.060249 2897.315121 21.492003 \n",
+ "20136 -108.118418 39.070872 2718.429010 34.589947 \n",
+ "20150 -108.118768 39.070868 2712.247866 32.760469 \n",
+ "\n",
+ " num_observations \n",
+ "67119 7 \n",
+ "67120 7 \n",
+ "67121 7 \n",
+ "68206 7 \n",
+ "131179 7 \n",
+ "... ... \n",
+ "151034 7 \n",
+ "129432 7 \n",
+ "149841 7 \n",
+ "20136 8 \n",
+ "20150 8 \n",
+ "\n",
+ "[100 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 252,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_init.sort_values(by=' num_observations').tail(100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 254,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "mask_gcp_init = ba_post_gcp_init[' num_observations'].str.contains(' # GCP')\n",
+ "ba_post_gcp_init_gcp_only = ba_post_gcp_init[mask_gcp_i"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 255,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 443281 \n",
+ " -108.145624 \n",
+ " 38.960785 \n",
+ " 2580.608477 \n",
+ " 18.860951 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 432800 \n",
+ " -108.156575 \n",
+ " 39.022656 \n",
+ " 3147.677780 \n",
+ " 12.642455 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 432799 \n",
+ " -108.156559 \n",
+ " 39.016192 \n",
+ " 3085.092181 \n",
+ " 0.626022 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 432798 \n",
+ " -108.156559 \n",
+ " 39.015913 \n",
+ " 3084.635628 \n",
+ " 0.633214 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "443281 -108.145624 38.960785 2580.608477 18.860951 \n",
+ "432800 -108.156575 39.022656 3147.677780 12.642455 \n",
+ "432799 -108.156559 39.016192 3085.092181 0.626022 \n",
+ "432798 -108.156559 39.015913 3084.635628 0.633214 \n",
+ "\n",
+ " num_observations \n",
+ "443281 4 # GCP \n",
+ "432800 4 # GCP \n",
+ "432799 4 # GCP \n",
+ "432798 4 # GCP "
+ ]
+ },
+ "execution_count": 255,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_init_gcp_only.sort_values(by=' num_observations').head(4)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 256,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 443281 \n",
+ " -108.145624 \n",
+ " 38.960786 \n",
+ " 2580.641146 \n",
+ " 19.032209 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 432800 \n",
+ " -108.156577 \n",
+ " 39.022652 \n",
+ " 3147.424124 \n",
+ " 12.684333 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 432799 \n",
+ " -108.156558 \n",
+ " 39.016190 \n",
+ " 3085.273418 \n",
+ " 0.347216 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 432798 \n",
+ " -108.156558 \n",
+ " 39.015912 \n",
+ " 3084.886359 \n",
+ " 0.273412 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "443281 -108.145624 38.960786 2580.641146 19.032209 \n",
+ "432800 -108.156577 39.022652 3147.424124 12.684333 \n",
+ "432799 -108.156558 39.016190 3085.273418 0.347216 \n",
+ "432798 -108.156558 39.015912 3084.886359 0.273412 \n",
+ "\n",
+ " num_observations \n",
+ "443281 4 # GCP \n",
+ "432800 4 # GCP \n",
+ "432799 4 # GCP \n",
+ "432798 4 # GCP "
+ ]
+ },
+ "execution_count": 256,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_gcp_only.sort_values(by=' num_observations').head(4)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 257,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 6358 \n",
+ " -108.120580 \n",
+ " 39.095318 \n",
+ " 2330.744052 \n",
+ " 10.679483 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 150530 \n",
+ " -108.145742 \n",
+ " 39.044836 \n",
+ " 2970.397820 \n",
+ " 27.015171 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 20150 \n",
+ " -108.118768 \n",
+ " 39.070868 \n",
+ " 2712.247866 \n",
+ " 32.760469 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ " 20136 \n",
+ " -108.118418 \n",
+ " 39.070872 \n",
+ " 2718.429010 \n",
+ " 34.589947 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "6358 -108.120580 39.095318 2330.744052 10.679483 \n",
+ "150530 -108.145742 39.044836 2970.397820 27.015171 \n",
+ "20150 -108.118768 39.070868 2712.247866 32.760469 \n",
+ "20136 -108.118418 39.070872 2718.429010 34.589947 \n",
+ "\n",
+ " num_observations \n",
+ "6358 7 \n",
+ "150530 7 \n",
+ "20150 8 \n",
+ "20136 8 "
+ ]
+ },
+ "execution_count": 257,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_init.sort_values(by = ' num_observations').tail(4)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 234,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 338988 \n",
+ " -108.135532 \n",
+ " 38.984955 \n",
+ " 2669.721190 \n",
+ " 0.013663 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 335785 \n",
+ " -108.137978 \n",
+ " 39.007565 \n",
+ " 3089.740890 \n",
+ " 0.101869 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 335784 \n",
+ " -108.137978 \n",
+ " 39.007288 \n",
+ " 3085.617797 \n",
+ " 0.178612 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 335783 \n",
+ " -108.137979 \n",
+ " 39.007011 \n",
+ " 3091.728091 \n",
+ " 0.045034 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 335782 \n",
+ " -108.137976 \n",
+ " 39.006733 \n",
+ " 3100.296468 \n",
+ " 0.019523 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 151034 \n",
+ " -108.146590 \n",
+ " 39.042477 \n",
+ " 3053.094561 \n",
+ " 0.352388 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 129432 \n",
+ " -108.145362 \n",
+ " 39.077179 \n",
+ " 2394.059311 \n",
+ " 0.412062 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 149841 \n",
+ " -108.120000 \n",
+ " 39.059932 \n",
+ " 2962.480847 \n",
+ " 0.280069 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 20136 \n",
+ " -108.118474 \n",
+ " 39.070746 \n",
+ " 2605.581818 \n",
+ " 0.510054 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ " 20150 \n",
+ " -108.118825 \n",
+ " 39.070749 \n",
+ " 2605.388363 \n",
+ " 0.532704 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
443282 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "338988 -108.135532 38.984955 2669.721190 0.013663 \n",
+ "335785 -108.137978 39.007565 3089.740890 0.101869 \n",
+ "335784 -108.137978 39.007288 3085.617797 0.178612 \n",
+ "335783 -108.137979 39.007011 3091.728091 0.045034 \n",
+ "335782 -108.137976 39.006733 3100.296468 0.019523 \n",
+ "... ... ... ... ... \n",
+ "151034 -108.146590 39.042477 3053.094561 0.352388 \n",
+ "129432 -108.145362 39.077179 2394.059311 0.412062 \n",
+ "149841 -108.120000 39.059932 2962.480847 0.280069 \n",
+ "20136 -108.118474 39.070746 2605.581818 0.510054 \n",
+ "20150 -108.118825 39.070749 2605.388363 0.532704 \n",
+ "\n",
+ " num_observations \n",
+ "338988 2 \n",
+ "335785 2 \n",
+ "335784 2 \n",
+ "335783 2 \n",
+ "335782 2 \n",
+ "... ... \n",
+ "151034 7 \n",
+ "129432 7 \n",
+ "149841 7 \n",
+ "20136 8 \n",
+ "20150 8 \n",
+ "\n",
+ "[443282 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 234,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp.sort_values(by=' num_observations')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 193,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 6358 \n",
+ " -108.120580 \n",
+ " 39.095318 \n",
+ " 2330.744052 \n",
+ " 10.679483 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 150530 \n",
+ " -108.145742 \n",
+ " 39.044836 \n",
+ " 2970.397820 \n",
+ " 27.015171 \n",
+ " 7 \n",
+ " \n",
+ " \n",
+ " 20150 \n",
+ " -108.118768 \n",
+ " 39.070868 \n",
+ " 2712.247866 \n",
+ " 32.760469 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ " 20136 \n",
+ " -108.118418 \n",
+ " 39.070872 \n",
+ " 2718.429010 \n",
+ " 34.589947 \n",
+ " 8 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "6358 -108.120580 39.095318 2330.744052 10.679483 \n",
+ "150530 -108.145742 39.044836 2970.397820 27.015171 \n",
+ "20150 -108.118768 39.070868 2712.247866 32.760469 \n",
+ "20136 -108.118418 39.070872 2718.429010 34.589947 \n",
+ "\n",
+ " num_observations \n",
+ "6358 7 \n",
+ "150530 7 \n",
+ "20150 8 \n",
+ "20136 8 "
+ ]
+ },
+ "execution_count": 193,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_init = pd.read_csv('/nobackupp2/sbhusha1/conus_stereo2swe/conus_stereo2swe_gm/skysat_triplet_20191202/l1b_gm_20191202_processing/proc_out/ba_pinhole/run-initial_residuals_no_loss_function_pointmap_point_log_initial_reproj_error.csv',skiprows=[1])\n",
+ "ba_init.sort_values(by = ' num_observations').tail(4)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 168,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ "Empty DataFrame\n",
+ "Columns: [# lon, lat, height_above_datum, mean_residual, num_observations]\n",
+ "Index: []"
+ ]
+ },
+ "execution_count": 168,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp[((ba_post_gcp['# lon'].values + 108.145107) == 0.000000)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 166,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-108.11814909, -108.11814215, -108.11855663, ..., -108.14469993,\n",
+ " -108.1451072 , -108.14547914])"
+ ]
+ },
+ "execution_count": 166,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp['# lon'].values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 176,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 141660 \n",
+ " -108.145107 \n",
+ " 39.066302 \n",
+ " 2583.598147 \n",
+ " 0.516720 \n",
+ " 4 \n",
+ " \n",
+ " \n",
+ " 195417 \n",
+ " -108.145107 \n",
+ " 38.968767 \n",
+ " 2680.576193 \n",
+ " 0.135673 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 195421 \n",
+ " -108.145107 \n",
+ " 38.970154 \n",
+ " 2671.949767 \n",
+ " 0.113051 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 195422 \n",
+ " -108.145107 \n",
+ " 38.970429 \n",
+ " 2674.136431 \n",
+ " 0.172455 \n",
+ " 4 \n",
+ " \n",
+ " \n",
+ " 195426 \n",
+ " -108.145107 \n",
+ " 38.971818 \n",
+ " 2652.394952 \n",
+ " 0.208836 \n",
+ " 4 \n",
+ " \n",
+ " \n",
+ " 242744 \n",
+ " -108.145107 \n",
+ " 39.032196 \n",
+ " 3133.376122 \n",
+ " 0.557969 \n",
+ " 3 \n",
+ " \n",
+ " \n",
+ " 333196 \n",
+ " -108.145107 \n",
+ " 39.031904 \n",
+ " 3131.041877 \n",
+ " 0.304995 \n",
+ " 3 \n",
+ " \n",
+ " \n",
+ " 402435 \n",
+ " -108.145107 \n",
+ " 39.070879 \n",
+ " 2502.495960 \n",
+ " 4.797769 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " 402436 \n",
+ " -108.145107 \n",
+ " 39.071251 \n",
+ " 2489.843251 \n",
+ " 1.931918 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " 422959 \n",
+ " -108.145107 \n",
+ " 38.970958 \n",
+ " 2681.939125 \n",
+ " 1.402186 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 423552 \n",
+ " -108.145107 \n",
+ " 38.969571 \n",
+ " 2664.851443 \n",
+ " 1.356346 \n",
+ " 5 # GCP \n",
+ " \n",
+ " \n",
+ " 424975 \n",
+ " -108.145107 \n",
+ " 38.963497 \n",
+ " 2759.624332 \n",
+ " 3.263399 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ " 443280 \n",
+ " -108.145107 \n",
+ " 38.959275 \n",
+ " 2868.453373 \n",
+ " 4.779105 \n",
+ " 4 # GCP \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "141660 -108.145107 39.066302 2583.598147 0.516720 \n",
+ "195417 -108.145107 38.968767 2680.576193 0.135673 \n",
+ "195421 -108.145107 38.970154 2671.949767 0.113051 \n",
+ "195422 -108.145107 38.970429 2674.136431 0.172455 \n",
+ "195426 -108.145107 38.971818 2652.394952 0.208836 \n",
+ "242744 -108.145107 39.032196 3133.376122 0.557969 \n",
+ "333196 -108.145107 39.031904 3131.041877 0.304995 \n",
+ "402435 -108.145107 39.070879 2502.495960 4.797769 \n",
+ "402436 -108.145107 39.071251 2489.843251 1.931918 \n",
+ "422959 -108.145107 38.970958 2681.939125 1.402186 \n",
+ "423552 -108.145107 38.969571 2664.851443 1.356346 \n",
+ "424975 -108.145107 38.963497 2759.624332 3.263399 \n",
+ "443280 -108.145107 38.959275 2868.453373 4.779105 \n",
+ "\n",
+ " num_observations \n",
+ "141660 4 \n",
+ "195417 5 \n",
+ "195421 5 \n",
+ "195422 4 \n",
+ "195426 4 \n",
+ "242744 3 \n",
+ "333196 3 \n",
+ "402435 5 # GCP \n",
+ "402436 5 # GCP \n",
+ "422959 4 # GCP \n",
+ "423552 5 # GCP \n",
+ "424975 4 # GCP \n",
+ "443280 4 # GCP "
+ ]
+ },
+ "execution_count": 176,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp[np.round(ba_post_gcp['# lon'].values,6) == -108.145107]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# How much do the ips change ?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 263,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ba_post_gcp_init_ip_only = ba_post_gcp_init[~mask_gcp_init]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 264,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " -108.118146 \n",
+ " 39.098135 \n",
+ " 2282.616044 \n",
+ " 0.052001 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " -108.118138 \n",
+ " 39.100248 \n",
+ " 2285.537279 \n",
+ " 0.093070 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " -108.118550 \n",
+ " 39.097799 \n",
+ " 2283.913644 \n",
+ " 1.160294 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " -108.118546 \n",
+ " 39.098160 \n",
+ " 2282.115572 \n",
+ " 1.287246 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " -108.118540 \n",
+ " 39.098534 \n",
+ " 2277.929599 \n",
+ " 1.215152 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 366965 \n",
+ " -108.169455 \n",
+ " 38.924560 \n",
+ " 2872.587258 \n",
+ " 0.619915 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366966 \n",
+ " -108.169449 \n",
+ " 38.925120 \n",
+ " 2859.826488 \n",
+ " 0.605476 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366967 \n",
+ " -108.169446 \n",
+ " 38.925675 \n",
+ " 2868.806470 \n",
+ " 0.809941 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366968 \n",
+ " -108.169440 \n",
+ " 38.926791 \n",
+ " 2862.968897 \n",
+ " 0.656242 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366969 \n",
+ " -108.169437 \n",
+ " 38.927630 \n",
+ " 2849.645456 \n",
+ " 0.302239 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
366970 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "0 -108.118146 39.098135 2282.616044 0.052001 \n",
+ "1 -108.118138 39.100248 2285.537279 0.093070 \n",
+ "2 -108.118550 39.097799 2283.913644 1.160294 \n",
+ "3 -108.118546 39.098160 2282.115572 1.287246 \n",
+ "4 -108.118540 39.098534 2277.929599 1.215152 \n",
+ "... ... ... ... ... \n",
+ "366965 -108.169455 38.924560 2872.587258 0.619915 \n",
+ "366966 -108.169449 38.925120 2859.826488 0.605476 \n",
+ "366967 -108.169446 38.925675 2868.806470 0.809941 \n",
+ "366968 -108.169440 38.926791 2862.968897 0.656242 \n",
+ "366969 -108.169437 38.927630 2849.645456 0.302239 \n",
+ "\n",
+ " num_observations \n",
+ "0 2 \n",
+ "1 2 \n",
+ "2 5 \n",
+ "3 5 \n",
+ "4 5 \n",
+ "... ... \n",
+ "366965 2 \n",
+ "366966 2 \n",
+ "366967 2 \n",
+ "366968 2 \n",
+ "366969 2 \n",
+ "\n",
+ "[366970 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 264,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_init_ip_only"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 262,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " -108.118147 \n",
+ " 39.098136 \n",
+ " 2280.730844 \n",
+ " 0.072376 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " -108.118140 \n",
+ " 39.100246 \n",
+ " 2283.845318 \n",
+ " 0.053444 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " -108.118555 \n",
+ " 39.097776 \n",
+ " 2278.906168 \n",
+ " 0.207273 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " -108.118552 \n",
+ " 39.098137 \n",
+ " 2277.141977 \n",
+ " 0.255374 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " -108.118547 \n",
+ " 39.098510 \n",
+ " 2272.928680 \n",
+ " 0.199640 \n",
+ " 5 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 366965 \n",
+ " -108.169435 \n",
+ " 38.924563 \n",
+ " 2880.749572 \n",
+ " 0.038537 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366966 \n",
+ " -108.169431 \n",
+ " 38.925122 \n",
+ " 2867.912943 \n",
+ " 0.154684 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366967 \n",
+ " -108.169429 \n",
+ " 38.925674 \n",
+ " 2876.910136 \n",
+ " 0.291092 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366968 \n",
+ " -108.169425 \n",
+ " 38.926786 \n",
+ " 2870.916319 \n",
+ " 0.219006 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 366969 \n",
+ " -108.169424 \n",
+ " 38.927623 \n",
+ " 2857.397389 \n",
+ " 0.000308 \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
366970 rows × 5 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual \\\n",
+ "0 -108.118147 39.098136 2280.730844 0.072376 \n",
+ "1 -108.118140 39.100246 2283.845318 0.053444 \n",
+ "2 -108.118555 39.097776 2278.906168 0.207273 \n",
+ "3 -108.118552 39.098137 2277.141977 0.255374 \n",
+ "4 -108.118547 39.098510 2272.928680 0.199640 \n",
+ "... ... ... ... ... \n",
+ "366965 -108.169435 38.924563 2880.749572 0.038537 \n",
+ "366966 -108.169431 38.925122 2867.912943 0.154684 \n",
+ "366967 -108.169429 38.925674 2876.910136 0.291092 \n",
+ "366968 -108.169425 38.926786 2870.916319 0.219006 \n",
+ "366969 -108.169424 38.927623 2857.397389 0.000308 \n",
+ "\n",
+ " num_observations \n",
+ "0 2 \n",
+ "1 2 \n",
+ "2 5 \n",
+ "3 5 \n",
+ "4 5 \n",
+ "... ... \n",
+ "366965 2 \n",
+ "366966 2 \n",
+ "366967 2 \n",
+ "366968 2 \n",
+ "366969 2 \n",
+ "\n",
+ "[366970 rows x 5 columns]"
+ ]
+ },
+ "execution_count": 262,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_tie_points_only"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 266,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 366970.000000 \n",
+ " 366970.000000 \n",
+ " 366970.000000 \n",
+ " 3.669700e+05 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " -108.133389 \n",
+ " 39.027481 \n",
+ " 2762.208143 \n",
+ " 5.368301e-01 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 0.021671 \n",
+ " 0.056262 \n",
+ " 364.919764 \n",
+ " 7.749393e+00 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " -108.174143 \n",
+ " 38.919623 \n",
+ " -4581.584816 \n",
+ " 2.531421e-07 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " -108.151412 \n",
+ " 38.980794 \n",
+ " 2478.121990 \n",
+ " 1.281938e-01 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " -108.133529 \n",
+ " 39.027174 \n",
+ " 2872.604925 \n",
+ " 2.089905e-01 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " -108.115611 \n",
+ " 39.075534 \n",
+ " 3085.037291 \n",
+ " 3.491223e-01 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " -108.091977 \n",
+ " 39.142886 \n",
+ " 8872.152087 \n",
+ " 1.271454e+03 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual\n",
+ "count 366970.000000 366970.000000 366970.000000 3.669700e+05\n",
+ "mean -108.133389 39.027481 2762.208143 5.368301e-01\n",
+ "std 0.021671 0.056262 364.919764 7.749393e+00\n",
+ "min -108.174143 38.919623 -4581.584816 2.531421e-07\n",
+ "25% -108.151412 38.980794 2478.121990 1.281938e-01\n",
+ "50% -108.133529 39.027174 2872.604925 2.089905e-01\n",
+ "75% -108.115611 39.075534 3085.037291 3.491223e-01\n",
+ "max -108.091977 39.142886 8872.152087 1.271454e+03"
+ ]
+ },
+ "execution_count": 266,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_tie_points_only.describe()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 267,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " # lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 366970.000000 \n",
+ " 366970.000000 \n",
+ " 366970.000000 \n",
+ " 366970.000000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " -108.133395 \n",
+ " 39.027455 \n",
+ " 2769.851711 \n",
+ " 4.437387 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 0.021671 \n",
+ " 0.056246 \n",
+ " 382.071973 \n",
+ " 28.473622 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " -108.174127 \n",
+ " 38.919597 \n",
+ " -1125.717729 \n",
+ " 0.000009 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " -108.151415 \n",
+ " 38.980813 \n",
+ " 2482.692373 \n",
+ " 0.359159 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " -108.133535 \n",
+ " 39.027173 \n",
+ " 2872.305307 \n",
+ " 0.637086 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " -108.115617 \n",
+ " 39.075517 \n",
+ " 3088.103747 \n",
+ " 1.453265 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " -108.091974 \n",
+ " 39.142893 \n",
+ " 10237.367508 \n",
+ " 1457.501704 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " # lon lat height_above_datum mean_residual\n",
+ "count 366970.000000 366970.000000 366970.000000 366970.000000\n",
+ "mean -108.133395 39.027455 2769.851711 4.437387\n",
+ "std 0.021671 0.056246 382.071973 28.473622\n",
+ "min -108.174127 38.919597 -1125.717729 0.000009\n",
+ "25% -108.151415 38.980813 2482.692373 0.359159\n",
+ "50% -108.133535 39.027173 2872.305307 0.637086\n",
+ "75% -108.115617 39.075517 3088.103747 1.453265\n",
+ "max -108.091974 39.142893 10237.367508 1457.501704"
+ ]
+ },
+ "execution_count": 267,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_init_ip_only.describe()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 268,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Index(['# lon', ' lat', ' height_above_datum', ' mean_residual',\n",
+ " ' num_observations'],\n",
+ " dtype='object')"
+ ]
+ },
+ "execution_count": 268,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ba_post_gcp_init_ip_only.keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 271,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ht_diff = ba_post_gcp_init_ip_only[' height_above_datum'].values - ba_post_gcp_tie_points_only[' height_above_datum'].values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 272,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'count': 366970,\n",
+ " 'min': -4178.349023178371,\n",
+ " 'max': 7286.82730182968,\n",
+ " 'ptp': 11465.176325008051,\n",
+ " 'mean': 7.643568483781767,\n",
+ " 'std': 107.48510554273223,\n",
+ " 'nmad': 2.4581982525031365,\n",
+ " 'med': 0.06023638168881007,\n",
+ " 'median': 0.06023638168881007,\n",
+ " 'p16': -2.707271398727608,\n",
+ " 'p84': 5.025767337780594,\n",
+ " 'spread': 3.866519368254101,\n",
+ " 'mode': -4178.349023178371}"
+ ]
+ },
+ "execution_count": 272,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "malib.get_stats_dict(ht_diff)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 275,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 275,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots()\n",
+ "clim = malib.calcperc_sym(ht_diff,(2,98))\n",
+ "im = ax.scatter(ba_post_gcp_init_ip_only['# lon'],ba_post_gcp_init_ip_only[' lat'],\n",
+ " c=ht_diff,vmin=clim[0],vmax=clim[1],cmap='RdBu',s=1)\n",
+ "plt.colorbar(im,label='Height Difference after optimisation(m)')\n",
+ "#plt.title('Seen in 4+ images')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 276,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from shapely.geometry import Point,Polygon\n",
+ "from pyproj import Proj, transform"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 279,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def point_convert(lon,lat,proj_out='epsg:32612'):\n",
+ " proj_in = 'epsg:4326'\n",
+ " incord = Proj(init=proj_in)\n",
+ " outcord = Proj(init=proj_out)\n",
+ " return transform(incord,outcord,lon,lat)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 282,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "init_x,init_y = point_convert(ba_post_gcp_init_ip_only['# lon'].values,\n",
+ " ba_post_gcp_init_ip_only[' lat'].values)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 283,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fn_x,fn_y = point_convert(ba_post_gcp_tie_points_only['# lon'].values,\n",
+ " ba_post_gcp_tie_points_only[' lat'].values)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 287,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "shiftx = fn_x - init_x\n",
+ "shifty = fn_y - fn_y"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 288,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-0.08959759, -0.13032306, -0.41854331, ..., 1.45154076,\n",
+ " 1.39110341, 1.22009026])"
+ ]
+ },
+ "execution_count": 288,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "shiftx"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 289,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 0., 0., ..., 0., 0., 0.])"
+ ]
+ },
+ "execution_count": 289,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "shifty"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 291,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "366970,366970,366970, 366970, 366970,\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(f'{len(shiftx)},{len(shifty)},{len(init_x)}, {len(init_y)}, {len(np.sqrt(shiftx**2+shifty**2))},')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 293,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.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",
+ "\n",
+ "mpl.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 = $(' ');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $(' ');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $(' ');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $(' ');\n",
+ "\n",
+ " var fmt_picker = $(' ');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " ' ', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option);\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"
\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html(' ');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = ' ';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.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) { continue; };\n",
+ "\n",
+ " var button = $(' ');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $(' ');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('
');\n",
+ " var button = $(' ');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "ename": "ValueError",
+ "evalue": "operands could not be broadcast together with shapes (733940,) (366970,) ",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0max\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubplots\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0max\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mquiver\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0minit_x\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0minit_y\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshiftx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshifty\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m/nobackup/sbhusha1/sw/miniconda3/envs/bhushan_PY3/lib/python3.6/site-packages/matplotlib/__init__.py\u001b[0m in \u001b[0;36minner\u001b[0;34m(ax, data, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1597\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0minner\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0max\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1598\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1599\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0max\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msanitize_sequence\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1600\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1601\u001b[0m \u001b[0mbound\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnew_sig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbind\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0max\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/nobackup/sbhusha1/sw/miniconda3/envs/bhushan_PY3/lib/python3.6/site-packages/matplotlib/axes/_axes.py\u001b[0m in \u001b[0;36mquiver\u001b[0;34m(self, *args, **kw)\u001b[0m\n\u001b[1;32m 5056\u001b[0m \u001b[0margs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_quiver_units\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5057\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 5058\u001b[0;31m \u001b[0mq\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmquiver\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mQuiver\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5059\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5060\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_collection\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mq\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mautolim\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/nobackup/sbhusha1/sw/miniconda3/envs/bhushan_PY3/lib/python3.6/site-packages/matplotlib/quiver.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, ax, scale, headwidth, headlength, headaxislength, minshaft, minlength, units, scale_units, angles, width, color, pivot, *args, **kw)\u001b[0m\n\u001b[1;32m 496\u001b[0m **kw)\n\u001b[1;32m 497\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpolykw\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkw\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 498\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_UVC\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mU\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mV\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mC\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 499\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_initialized\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 500\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/nobackup/sbhusha1/sw/miniconda3/envs/bhushan_PY3/lib/python3.6/site-packages/matplotlib/quiver.py\u001b[0m in \u001b[0;36mset_UVC\u001b[0;34m(self, U, V, C)\u001b[0m\n\u001b[1;32m 586\u001b[0m \u001b[0mU\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmasked_invalid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mU\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 587\u001b[0m \u001b[0mV\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmasked_invalid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mV\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 588\u001b[0;31m \u001b[0mmask\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmask_or\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mU\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmask\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mV\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmask\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshrink\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 589\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mC\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 590\u001b[0m \u001b[0mC\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmasked_invalid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/nobackup/sbhusha1/sw/miniconda3/envs/bhushan_PY3/lib/python3.6/site-packages/numpy/ma/core.py\u001b[0m in \u001b[0;36mmask_or\u001b[0;34m(m1, m2, copy, shrink)\u001b[0m\n\u001b[1;32m 1762\u001b[0m \u001b[0m_recursive_mask_or\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mm2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnewmask\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1763\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mnewmask\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1764\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mmake_mask\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mumath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlogical_or\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mm2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshrink\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mshrink\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1765\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1766\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mValueError\u001b[0m: operands could not be broadcast together with shapes (733940,) (366970,) "
+ ]
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots()\n",
+ "ax.quiver([init_x,init_y], shiftx, shifty,)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "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.10"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/notebooks/skysat_l1a_bundle_adjustment.ipynb b/notebooks/skysat_l1a_bundle_adjustment.ipynb
new file mode 100644
index 0000000..62fd51e
--- /dev/null
+++ b/notebooks/skysat_l1a_bundle_adjustment.ipynb
@@ -0,0 +1,6032 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "745c4c61-6d61-4819-bba1-5f8943404210",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%matplotlib inline\n",
+ "%load_ext autoreload\n",
+ "%autoreload 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a8ee33b2-f91c-4971-9c7b-11fc14a84f5d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os,sys,glob,shutil\n",
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import geopandas as gpd\n",
+ "import cv2\n",
+ "import matplotlib.pyplot as plt\n",
+ "from pygeotools.lib import geolib,warplib,malib,iolib\n",
+ "from imview import pltlib\n",
+ "from skysat_stereo import skysat\n",
+ "from scipy.spatial.transform import Rotation as R\n",
+ "from skysat_stereo import asp_utils as asp\n",
+ "\n",
+ "from shapely import wkt\n",
+ "from shapely.geometry.polygon import orient"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "f3ff47c1-aaff-4980-bacd-34b3ea003766",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/change/s108_20210406T040909Z\n"
+ ]
+ }
+ ],
+ "source": [
+ "%cd /nobackup/sbhusha1/change/s108_20210406T040909Z/"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "859a99a5-f322-4f2b-b45f-4386444324f7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fn = 'frame_index.csv'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "35a23ab7-6d56-421f-9fa2-8bffbd5c06bd",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/pyproj/crs/crs.py:53: FutureWarning: '+init=:' syntax is deprecated. ':' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6\n",
+ " return _prepare_from_string(\" \".join(pjargs))\n"
+ ]
+ }
+ ],
+ "source": [
+ "frame_index = skysat.parse_frame_index(fn,True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "22809f57-6b49-45cf-899a-653bcfe7f248",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " name \n",
+ " datetime \n",
+ " gsd \n",
+ " sat_az \n",
+ " sat_elev \n",
+ " x_sat_eci_km \n",
+ " y_sat_eci_km \n",
+ " z_sat_eci_km \n",
+ " qw_eci \n",
+ " qx_eci \n",
+ " ... \n",
+ " y_sat_ecef_km \n",
+ " z_sat_ecef_km \n",
+ " qw_ecef \n",
+ " qx_ecef \n",
+ " qy_ecef \n",
+ " qz_ecef \n",
+ " bit_dpth \n",
+ " geom \n",
+ " integration_time_ms \n",
+ " filename \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1301717367.65046096_sc00108_c3_PAN \n",
+ " 2021-04-06T04:09:09.650461+00:00 \n",
+ " 1.124777 \n",
+ " 43.757951 \n",
+ " 54.626309 \n",
+ " 5446.94887 \n",
+ " 3118.34934 \n",
+ " -2698.79223 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " 4588.27493 \n",
+ " -2687.66720 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON ((131.075182669813 -25.252703375099,13... \n",
+ " 0.52316 \n",
+ " 1301717367.65046096_sc00108_c3_PAN_i0000000000... \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 1301717367.65046573_sc00108_c2_PAN \n",
+ " 2021-04-06T04:09:09.650466+00:00 \n",
+ " 1.135013 \n",
+ " 43.555569 \n",
+ " 54.168736 \n",
+ " 5446.94886 \n",
+ " 3118.34933 \n",
+ " -2698.79227 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " 4588.27492 \n",
+ " -2687.66724 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON ((131.04976305695 -25.2915903643759,13... \n",
+ " 0.52316 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
2 rows × 23 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " name datetime \\\n",
+ "0 1301717367.65046096_sc00108_c3_PAN 2021-04-06T04:09:09.650461+00:00 \n",
+ "1 1301717367.65046573_sc00108_c2_PAN 2021-04-06T04:09:09.650466+00:00 \n",
+ "\n",
+ " gsd sat_az sat_elev x_sat_eci_km y_sat_eci_km z_sat_eci_km \\\n",
+ "0 1.124777 43.757951 54.626309 5446.94887 3118.34934 -2698.79223 \n",
+ "1 1.135013 43.555569 54.168736 5446.94886 3118.34933 -2698.79227 \n",
+ "\n",
+ " qw_eci qx_eci ... y_sat_ecef_km z_sat_ecef_km qw_ecef qx_ecef \\\n",
+ "0 0.653283 0.373069 ... 4588.27493 -2687.66720 0.215369 -0.712615 \n",
+ "1 0.653283 0.373069 ... 4588.27492 -2687.66724 0.215369 -0.712615 \n",
+ "\n",
+ " qy_ecef qz_ecef bit_dpth \\\n",
+ "0 0.088349 -0.661809 16 \n",
+ "1 0.088349 -0.661809 16 \n",
+ "\n",
+ " geom integration_time_ms \\\n",
+ "0 POLYGON ((131.075182669813 -25.252703375099,13... 0.52316 \n",
+ "1 POLYGON ((131.04976305695 -25.2915903643759,13... 0.52316 \n",
+ "\n",
+ " filename \n",
+ "0 1301717367.65046096_sc00108_c3_PAN_i0000000000... \n",
+ "1 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ "\n",
+ "[2 rows x 23 columns]"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "frame_index.head(2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "c90b273b-d585-4fc7-be84-16e101899b5a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def modernize_frame_index(frame_index_fn,return_frame_index=True,outfn=None):\n",
+ " \"\"\"\n",
+ " Update frame_index to what ASP understands currently, i.e.,\n",
+ " Update name columns and geometry columns\n",
+ " \n",
+ " Parameters\n",
+ " -------------\n",
+ " frame_index_fn: string\n",
+ " path to frame_index\n",
+ " outfn (Optional): string\n",
+ " path to output frame_index filename\n",
+ " \"\"\"\n",
+ " def _correct_geom(row):\n",
+ " return wkt.loads(row['geom'])\n",
+ " frame_index = pd.read_csv(frame_index_fn)\n",
+ " frame_index['geom'] = frame_index.apply(_correct_geom,axis=1)\n",
+ " \n",
+ " # orient the Polygon geometry\n",
+ " \n",
+ " updated_geomlist_asp_convention = [orient(test_geom,-1) for test_geom in frame_index['geom'].values]\n",
+ " # remove the space between POLYGON and ((# \n",
+ " updated_geomlist_asp_convention = [f\"POLYGON(({str(test_geom).split(' ((')[1]}\" for test_geom in updated_geomlist_asp_convention]\n",
+ " \n",
+ " # remove the repeated last coordinate\n",
+ " updated_geomlist_asp_convention = [','.join(test_geom.split(',')[:-1])+'))' for test_geom in updated_geomlist_asp_convention]\n",
+ " \n",
+ " # update geometry column\n",
+ " frame_index['geom'] = updated_geomlist_asp_convention\n",
+ " \n",
+ " # update name\n",
+ " frame_index['name'] = [os.path.splitext(name)[0] for name in frame_index.filename.values]\n",
+ " print(os.path.splitext(frame_index.filename.values[0])[0])\n",
+ " # writeout\n",
+ " if not outfn:\n",
+ " outfn = os.path.splitext(frame_index_fn)[0] + '_with_orient.csv'\n",
+ " frame_index.to_csv(outfn,index=False)\n",
+ " \n",
+ " if return_frame_index:\n",
+ " return frame_index\n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "1fdd7089-a74c-49d8-984d-89dbf9f98bfe",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def correct_geom(row):\n",
+ " return wkt.loads(row['geom'])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "bbd3ba36-ccf1-4666-8a9f-5aed9ff7ae57",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index['geom'] = frame_index.apply(correct_geom,axis=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "014cdec1-6d67-4d91-86b4-2c79c8dedf65",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "POLYGON ((131.075182669813 -25.252703375099, 131.075086503775 -25.2420213590524, 131.046827540786 -25.2474006834797, 131.046927861518 -25.2580848603599, 131.075182669813 -25.252703375099))\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(frame_index['geom'].values[0])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "72fd217b-3267-43f7-adb6-d571e5f6cb58",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "updated_geomlist_asp_convention = frame_index['geom'].values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "e9c468e2-63f0-4411-a8ce-4e4ac719fa35",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "updated_geomlist_asp_convention = [f\"POLYGON(({str(test_geom).split(' ((')[1]}\" for test_geom in updated_geomlist_asp_convention]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "id": "1287d8d6-9d69-49d8-b10b-7e5edf610e32",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "updated_geomlist_asp_convention = [','.join(test_geom.split(',')[:-1])+'))' for test_geom in updated_geomlist_asp_convention]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "id": "fa9feb77-7923-4437-9d76-5e3157ac1b0e",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/pyproj/crs/crs.py:53: FutureWarning: '+init=:' syntax is deprecated. ':' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6\n",
+ " return _prepare_from_string(\" \".join(pjargs))\n"
+ ]
+ }
+ ],
+ "source": [
+ "frame_index_opt1 = skysat.parse_frame_index(fn,True)\n",
+ "frame_index_opt1_fn = os.path.splitext(fn)[0]+'_without_orient.csv'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "id": "ca89c3b8-0c6b-4e0a-8bb5-b7d21b257ab5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index_opt1['geom'] = updated_geomlist_asp_convention"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "00335134-e03f-4bfe-818d-3cc1553e1498",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index_opt1['name'] = frame_index_opt1['filename']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "9682c43b-78b7-4d36-b620-ab1f83f92b98",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index_opt1.to_csv(frame_index_opt1_fn,index=False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "id": "9f1b479d-53ac-4c35-9436-3dd6158bdbd2",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "fontconfig\t frame_index_with_orient.csv\t isce.log out\n",
+ "frame_index.csv frame_index_without_orient.csv l1a_frames test\n"
+ ]
+ }
+ ],
+ "source": [
+ "! ls"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d92ddbd0-292d-42b0-975b-d89f88c4e5ab",
+ "metadata": {},
+ "source": [
+ "### With orient"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "id": "25911ca9-fed8-4326-a552-4ed1564f88ed",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/pyproj/crs/crs.py:53: FutureWarning: '+init=:' syntax is deprecated. ':' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6\n",
+ " return _prepare_from_string(\" \".join(pjargs))\n"
+ ]
+ }
+ ],
+ "source": [
+ "frame_index_opt2 = skysat.parse_frame_index(fn,True)\n",
+ "frame_index_opt2_fn = os.path.splitext(fn)[0]+'_with_orient.csv'\n",
+ "frame_index_opt2['geom'] = frame_index_opt2.apply(correct_geom,axis=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "id": "b137799a-84f0-4c23-bd56-937cf896594e",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "POLYGON ((131.075182669813 -25.252703375099, 131.075086503775 -25.2420213590524, 131.046827540786 -25.2474006834797, 131.046927861518 -25.2580848603599, 131.075182669813 -25.252703375099))\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(frame_index_opt2['geom'].values[0])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "id": "ff84bfe7-55f9-4dc7-a38f-ac444fe5a76d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "updated_geomlist_asp_convention = [orient(test_geom,-1) for test_geom in frame_index_opt2['geom'].values]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "id": "6c6926be-e7c9-4d6b-9dce-f66aeb31a01b",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "POLYGON ((131.075182669813 -25.252703375099, 131.046927861518 -25.2580848603599, 131.046827540786 -25.2474006834797, 131.075086503775 -25.2420213590524, 131.075182669813 -25.252703375099))\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(updated_geomlist_asp_convention[0])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "id": "10433227-c697-40a6-b61e-cd48405dabd4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "updated_geomlist_asp_convention = [f\"POLYGON(({str(test_geom).split(' ((')[1]}\" for test_geom in updated_geomlist_asp_convention]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "id": "79665ffa-6422-47e3-97ba-627c7697eebd",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "POLYGON((131.075182669813 -25.252703375099, 131.046927861518 -25.2580848603599, 131.046827540786 -25.2474006834797, 131.075086503775 -25.2420213590524, 131.075182669813 -25.252703375099))\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(updated_geomlist_asp_convention[0])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "id": "4d6d2a8d-0449-4257-9953-46d5f83ccb8a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "updated_geomlist_asp_convention = [','.join(test_geom.split(',')[:-1])+'))' for test_geom in updated_geomlist_asp_convention]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "id": "33bf62d3-ca62-4a23-9437-206639f07331",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "POLYGON((131.075182669813 -25.252703375099, 131.046927861518 -25.2580848603599, 131.046827540786 -25.2474006834797, 131.075086503775 -25.2420213590524))\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(updated_geomlist_asp_convention[0])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 69,
+ "id": "538283f7-af9b-41f9-9775-ee05c6223ac6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index_opt2['geom'] = updated_geomlist_asp_convention"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 70,
+ "id": "dc77def7-39a7-4007-980e-ecfd951d3289",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " name \n",
+ " datetime \n",
+ " gsd \n",
+ " sat_az \n",
+ " sat_elev \n",
+ " x_sat_eci_km \n",
+ " y_sat_eci_km \n",
+ " z_sat_eci_km \n",
+ " qw_eci \n",
+ " qx_eci \n",
+ " ... \n",
+ " y_sat_ecef_km \n",
+ " z_sat_ecef_km \n",
+ " qw_ecef \n",
+ " qx_ecef \n",
+ " qy_ecef \n",
+ " qz_ecef \n",
+ " bit_dpth \n",
+ " geom \n",
+ " integration_time_ms \n",
+ " filename \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1301717367.65046096_sc00108_c3_PAN \n",
+ " 2021-04-06T04:09:09.650461+00:00 \n",
+ " 1.124777 \n",
+ " 43.757951 \n",
+ " 54.626309 \n",
+ " 5446.94887 \n",
+ " 3118.34934 \n",
+ " -2698.79223 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " 4588.27493 \n",
+ " -2687.66720 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON((131.075182669813 -25.252703375099, 13... \n",
+ " 0.52316 \n",
+ " 1301717367.65046096_sc00108_c3_PAN_i0000000000... \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 1301717367.65046573_sc00108_c2_PAN \n",
+ " 2021-04-06T04:09:09.650466+00:00 \n",
+ " 1.135013 \n",
+ " 43.555569 \n",
+ " 54.168736 \n",
+ " 5446.94886 \n",
+ " 3118.34933 \n",
+ " -2698.79227 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " 4588.27492 \n",
+ " -2687.66724 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON((131.04976305695 -25.2915903643759, 13... \n",
+ " 0.52316 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
2 rows × 23 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " name datetime \\\n",
+ "0 1301717367.65046096_sc00108_c3_PAN 2021-04-06T04:09:09.650461+00:00 \n",
+ "1 1301717367.65046573_sc00108_c2_PAN 2021-04-06T04:09:09.650466+00:00 \n",
+ "\n",
+ " gsd sat_az sat_elev x_sat_eci_km y_sat_eci_km z_sat_eci_km \\\n",
+ "0 1.124777 43.757951 54.626309 5446.94887 3118.34934 -2698.79223 \n",
+ "1 1.135013 43.555569 54.168736 5446.94886 3118.34933 -2698.79227 \n",
+ "\n",
+ " qw_eci qx_eci ... y_sat_ecef_km z_sat_ecef_km qw_ecef qx_ecef \\\n",
+ "0 0.653283 0.373069 ... 4588.27493 -2687.66720 0.215369 -0.712615 \n",
+ "1 0.653283 0.373069 ... 4588.27492 -2687.66724 0.215369 -0.712615 \n",
+ "\n",
+ " qy_ecef qz_ecef bit_dpth \\\n",
+ "0 0.088349 -0.661809 16 \n",
+ "1 0.088349 -0.661809 16 \n",
+ "\n",
+ " geom integration_time_ms \\\n",
+ "0 POLYGON((131.075182669813 -25.252703375099, 13... 0.52316 \n",
+ "1 POLYGON((131.04976305695 -25.2915903643759, 13... 0.52316 \n",
+ "\n",
+ " filename \n",
+ "0 1301717367.65046096_sc00108_c3_PAN_i0000000000... \n",
+ "1 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ "\n",
+ "[2 rows x 23 columns]"
+ ]
+ },
+ "execution_count": 70,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "frame_index_opt2.head(2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "id": "c04f9595-f987-43d7-9c76-59578565bfd2",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'POLYGON((131.075182669813 -25.252703375099, 131.046927861518 -25.2580848603599, 131.046827540786 -25.2474006834797, 131.075086503775 -25.2420213590524))'"
+ ]
+ },
+ "execution_count": 71,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "updated_geomlist_asp_convention[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 72,
+ "id": "176e6cc8-2d1e-4211-bcca-f984d1a940aa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index_opt2['name'] = frame_index_opt2['filename']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "id": "98d3f6ed-5b80-42e7-9ba9-91225c238079",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index_opt2.to_csv(frame_index_opt2_fn,index=False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 74,
+ "id": "105864f9-7834-4ac1-9056-c23292b0a2c0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Get AOI for reference DEMs"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "id": "c5a9817c-a008-43b5-b369-5fe88819cde2",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "fontconfig\t frame_index_with_orient.csv\t isce.log out\n",
+ "frame_index.csv frame_index_without_orient.csv l1a_frames test\n"
+ ]
+ }
+ ],
+ "source": [
+ "! ls"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a3cf1dd1-d9cd-4768-9d4f-41af043f14b3",
+ "metadata": {},
+ "source": [
+ "### Get bounds for fetching DEM on batComputer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "id": "569f48d2-6015-45c9-9283-bba275ca3efa",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/pyproj/crs/crs.py:53: FutureWarning: '+init=:' syntax is deprecated. ':' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6\n",
+ " return _prepare_from_string(\" \".join(pjargs))\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "array([130.99536167, -25.47722607, 131.07518267, -25.24202136])"
+ ]
+ },
+ "execution_count": 76,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "skysat.parse_frame_index(fn).total_bounds"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "efa45f3a-6fe6-4a7d-a58a-957d776f79a5",
+ "metadata": {},
+ "source": [
+ "### Get frame_index for only c2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 77,
+ "id": "1ab3ac23-cb27-476d-9895-864c01d01551",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_list = sorted(glob.glob('l1a_frames/*c2*.tif'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "id": "cfeaf7f6-99ab-477d-96a6-337561e23388",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "frame_base = [os.path.basename(frame) for frame in frame_list]\n",
+ "mask = frame_index_opt2['filename'].isin(frame_base)\n",
+ "frame_index_c2 = frame_index_opt2[mask]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "id": "af183067-9661-46c1-9a70-a6e446416457",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index_opt2_c2_fn = os.path.splitext(fn)[0]+'_with_orient_c2.csv'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 90,
+ "id": "9e2d9936-a8a1-4b39-9b04-152b561ecca2",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'1301717367.65046573_sc00108_c2_PAN_i0000000000'"
+ ]
+ },
+ "execution_count": 90,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "os.path.splitext(frame_index_c2['name'].values[0])[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 91,
+ "id": "4967eae0-5f69-47d0-80d0-5c93c154ff80",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ ":1: SettingWithCopyWarning: \n",
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
+ "\n",
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
+ " frame_index_c2['name'] = [os.path.splitext(name)[0] for name in frame_index_c2.name.values]\n"
+ ]
+ }
+ ],
+ "source": [
+ "frame_index_c2['name'] = [os.path.splitext(name)[0] for name in frame_index_c2.name.values]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 92,
+ "id": "f068481c-dd6a-4fae-b543-81d5dc814af3",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array(['1301717367.65046573_sc00108_c2_PAN_i0000000000',\n",
+ " '1301717367.67254806_sc00108_c2_PAN_i0000000001'], dtype=object)"
+ ]
+ },
+ "execution_count": 92,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "frame_index_c2.head(2).name.values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 93,
+ "id": "ea45b4fa-22ad-40c2-950b-8563e0143036",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "frame_index_c2.to_csv(frame_index_opt2_c2_fn,index=False)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a874ae7e-d1bd-4723-b89e-00254ab882c2",
+ "metadata": {},
+ "source": [
+ "### Generate cameras as \n",
+ "`skysat_preprocess.py -mode video -t pinhole -img processing/c2/ -sampler 306 -outdir processing/camera_camgen/ -frame_index frame_index_with_orient_c2.csv -dem $refdem -product_level l1a`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 95,
+ "id": "1ad01e0e-3911-4e5b-82ed-9159ca68845c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'1301717367.82759547_sc00108_c2_PAN_i0000000008'"
+ ]
+ },
+ "execution_count": 95,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "frame_index_c2.name.values[8]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6c5e1558-697a-4dc4-bf3c-b90e7547ea1a",
+ "metadata": {},
+ "source": [
+ "### Evaluate disparity from original cameras"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 104,
+ "id": "d3aed6b4-0492-492e-b03d-03323ad3c952",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 104,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "disparity = 'processing/c2_first2_rpc/run-D.tif'\n",
+ "dx,dy = [iolib.fn_getma(disparity,i) for i in range(1,3)]\n",
+ "f,ax = plt.subplots(1,2)\n",
+ "pltlib.iv(dx,ax=ax[0],cmap='RdBu',clim=malib.calcperc_sym(dx))\n",
+ "pltlib.iv(dy,ax=ax[1],cmap='RdBu',clim=malib.calcperc_sym(dy))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 101,
+ "id": "3ec08cfc-c5cd-41b5-a079-ecef1086e699",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'count': 2592287,\n",
+ " 'min': -15.0,\n",
+ " 'max': 23.0,\n",
+ " 'ptp': 38.0,\n",
+ " 'mean': -0.05425363781093683,\n",
+ " 'std': 1.0992474135577537,\n",
+ " 'nmad': 0.0,\n",
+ " 'med': 0.0,\n",
+ " 'median': 0.0,\n",
+ " 'p16': 0.0,\n",
+ " 'p84': 0.0,\n",
+ " 'spread': 0.0,\n",
+ " 'mode': 0.0}"
+ ]
+ },
+ "execution_count": 101,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "malib.get_stats_dict(dx)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 102,
+ "id": "258aaf0e-065e-4b6e-9bd5-088c20ff050a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'count': 2581377,\n",
+ " 'min': -4.0,\n",
+ " 'max': 4.0,\n",
+ " 'ptp': 8.0,\n",
+ " 'mean': 0.0037049993085085985,\n",
+ " 'std': 0.12830423093875531,\n",
+ " 'nmad': 0.0,\n",
+ " 'med': 0.0,\n",
+ " 'median': 0.0,\n",
+ " 'p16': 0.0,\n",
+ " 'p84': 0.0,\n",
+ " 'spread': 0.0,\n",
+ " 'mode': 0.0}"
+ ]
+ },
+ "execution_count": 102,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "malib.get_stats_dict(dy)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23094e17-cf77-46f4-bcca-fed6e643c05d",
+ "metadata": {},
+ "source": [
+ "#### After affine-epipolar alignment, there is not any disparity in the x and y direction."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 107,
+ "id": "ba06c56e-8619-4c44-99eb-536633c800b3",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 107,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "disparity = 'processing/c2_first2_pinholeasp/run-D.tif'\n",
+ "dx,dy = [iolib.fn_getma(disparity,i) for i in range(1,3)]\n",
+ "f,ax = plt.subplots(1,2)\n",
+ "pltlib.iv(dx,ax=ax[0],cmap='RdBu',clim=malib.calcperc_sym(dx))\n",
+ "pltlib.iv(dy,ax=ax[1],cmap='RdBu',clim=malib.calcperc_sym(dy))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 111,
+ "id": "e99c1a91-ce11-482d-b39f-91193cde82b2",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " name \n",
+ " datetime \n",
+ " gsd \n",
+ " sat_az \n",
+ " sat_elev \n",
+ " x_sat_eci_km \n",
+ " y_sat_eci_km \n",
+ " z_sat_eci_km \n",
+ " qw_eci \n",
+ " qx_eci \n",
+ " ... \n",
+ " y_sat_ecef_km \n",
+ " z_sat_ecef_km \n",
+ " qw_ecef \n",
+ " qx_ecef \n",
+ " qy_ecef \n",
+ " qz_ecef \n",
+ " bit_dpth \n",
+ " geom \n",
+ " integration_time_ms \n",
+ " filename \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000 \n",
+ " 2021-04-06T04:09:09.650466+00:00 \n",
+ " 1.135013 \n",
+ " 43.555569 \n",
+ " 54.168736 \n",
+ " 5446.94886 \n",
+ " 3118.34933 \n",
+ " -2698.79227 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " 4588.27492 \n",
+ " -2687.66724 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON((131.04976305695 -25.2915903643759, 13... \n",
+ " 0.52316 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 1301717367.67254806_sc00108_c2_PAN_i0000000001 \n",
+ " 2021-04-06T04:09:09.672548+00:00 \n",
+ " 1.134851 \n",
+ " 43.562772 \n",
+ " 54.176972 \n",
+ " 5446.90313 \n",
+ " 3118.29668 \n",
+ " -2698.94581 \n",
+ " 0.653341 \n",
+ " 0.373022 \n",
+ " ... \n",
+ " 4588.24975 \n",
+ " -2687.82088 \n",
+ " 0.215390 \n",
+ " -0.712554 \n",
+ " 0.088362 \n",
+ " -0.661865 \n",
+ " 16 \n",
+ " POLYGON((131.049760248284 -25.2921811831888, 1... \n",
+ " 0.46002 \n",
+ " 1301717367.67254806_sc00108_c2_PAN_i0000000001... \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
2 rows × 23 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " name \\\n",
+ "1 1301717367.65046573_sc00108_c2_PAN_i0000000000 \n",
+ "4 1301717367.67254806_sc00108_c2_PAN_i0000000001 \n",
+ "\n",
+ " datetime gsd sat_az sat_elev \\\n",
+ "1 2021-04-06T04:09:09.650466+00:00 1.135013 43.555569 54.168736 \n",
+ "4 2021-04-06T04:09:09.672548+00:00 1.134851 43.562772 54.176972 \n",
+ "\n",
+ " x_sat_eci_km y_sat_eci_km z_sat_eci_km qw_eci qx_eci ... \\\n",
+ "1 5446.94886 3118.34933 -2698.79227 0.653283 0.373069 ... \n",
+ "4 5446.90313 3118.29668 -2698.94581 0.653341 0.373022 ... \n",
+ "\n",
+ " y_sat_ecef_km z_sat_ecef_km qw_ecef qx_ecef qy_ecef qz_ecef \\\n",
+ "1 4588.27492 -2687.66724 0.215369 -0.712615 0.088349 -0.661809 \n",
+ "4 4588.24975 -2687.82088 0.215390 -0.712554 0.088362 -0.661865 \n",
+ "\n",
+ " bit_dpth geom \\\n",
+ "1 16 POLYGON((131.04976305695 -25.2915903643759, 13... \n",
+ "4 16 POLYGON((131.049760248284 -25.2921811831888, 1... \n",
+ "\n",
+ " integration_time_ms filename \n",
+ "1 0.52316 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ "4 0.46002 1301717367.67254806_sc00108_c2_PAN_i0000000001... \n",
+ "\n",
+ "[2 rows x 23 columns]"
+ ]
+ },
+ "execution_count": 111,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "frame_index_c2.head(2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 113,
+ "id": "9df57032-fc77-4c95-9047-0439d70c70de",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " x_sat_ecef_km \n",
+ " y_sat_ecef_km \n",
+ " z_sat_ecef_km \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " -4289.64010 \n",
+ " 4588.27492 \n",
+ " -2687.66724 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " -4289.57102 \n",
+ " 4588.24975 \n",
+ " -2687.82088 \n",
+ " \n",
+ " \n",
+ " 6 \n",
+ " -4289.50184 \n",
+ " 4588.22453 \n",
+ " -2687.97475 \n",
+ " \n",
+ " \n",
+ " 9 \n",
+ " -4289.43264 \n",
+ " 4588.19931 \n",
+ " -2688.12863 \n",
+ " \n",
+ " \n",
+ " 12 \n",
+ " -4289.36345 \n",
+ " 4588.17409 \n",
+ " -2688.28250 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 904 \n",
+ " -4268.70025 \n",
+ " 4580.54902 \n",
+ " -2733.91167 \n",
+ " \n",
+ " \n",
+ " 906 \n",
+ " -4268.63031 \n",
+ " 4580.52290 \n",
+ " -2734.06504 \n",
+ " \n",
+ " \n",
+ " 911 \n",
+ " -4268.56033 \n",
+ " 4580.49677 \n",
+ " -2734.21848 \n",
+ " \n",
+ " \n",
+ " 914 \n",
+ " -4268.49038 \n",
+ " 4580.47064 \n",
+ " -2734.37185 \n",
+ " \n",
+ " \n",
+ " 917 \n",
+ " -4268.41729 \n",
+ " 4580.44334 \n",
+ " -2734.53210 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
306 rows × 3 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " x_sat_ecef_km y_sat_ecef_km z_sat_ecef_km\n",
+ "1 -4289.64010 4588.27492 -2687.66724\n",
+ "4 -4289.57102 4588.24975 -2687.82088\n",
+ "6 -4289.50184 4588.22453 -2687.97475\n",
+ "9 -4289.43264 4588.19931 -2688.12863\n",
+ "12 -4289.36345 4588.17409 -2688.28250\n",
+ ".. ... ... ...\n",
+ "904 -4268.70025 4580.54902 -2733.91167\n",
+ "906 -4268.63031 4580.52290 -2734.06504\n",
+ "911 -4268.56033 4580.49677 -2734.21848\n",
+ "914 -4268.49038 4580.47064 -2734.37185\n",
+ "917 -4268.41729 4580.44334 -2734.53210\n",
+ "\n",
+ "[306 rows x 3 columns]"
+ ]
+ },
+ "execution_count": 113,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "frame_index_c2[['x_sat_ecef_km','y_sat_ecef_km','z_sat_ecef_km']]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 117,
+ "id": "e05a7d2b-6d48-4e65-ad4f-51a4a6599adb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def total_offset(row):\n",
+ " return np.sqrt((row['x_sat_ecef_km']**2+row['y_sat_ecef_km']**2+row['z_sat_ecef_km']**2))*1000"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 119,
+ "id": "d438e8e1-460c-4f41-a4e7-2834a4ce957e",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ ":1: SettingWithCopyWarning: \n",
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
+ "\n",
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
+ " frame_index_c2['total_cam_offset'] = frame_index_c2[['x_sat_ecef_km','y_sat_ecef_km','z_sat_ecef_km']].diff().apply(total_offset,axis=1)\n"
+ ]
+ }
+ ],
+ "source": [
+ "frame_index_c2['total_cam_offset'] = frame_index_c2[['x_sat_ecef_km','y_sat_ecef_km','z_sat_ecef_km']].diff().apply(total_offset,axis=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 120,
+ "id": "ea44c73e-1f5e-402e-ac62-785306cb156a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " name \n",
+ " datetime \n",
+ " gsd \n",
+ " sat_az \n",
+ " sat_elev \n",
+ " x_sat_eci_km \n",
+ " y_sat_eci_km \n",
+ " z_sat_eci_km \n",
+ " qw_eci \n",
+ " qx_eci \n",
+ " ... \n",
+ " z_sat_ecef_km \n",
+ " qw_ecef \n",
+ " qx_ecef \n",
+ " qy_ecef \n",
+ " qz_ecef \n",
+ " bit_dpth \n",
+ " geom \n",
+ " integration_time_ms \n",
+ " filename \n",
+ " total_cam_offset \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000 \n",
+ " 2021-04-06T04:09:09.650466+00:00 \n",
+ " 1.135013 \n",
+ " 43.555569 \n",
+ " 54.168736 \n",
+ " 5446.94886 \n",
+ " 3118.34933 \n",
+ " -2698.79227 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " -2687.66724 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON((131.04976305695 -25.2915903643759, 13... \n",
+ " 0.52316 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ " NaN \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 1301717367.67254806_sc00108_c2_PAN_i0000000001 \n",
+ " 2021-04-06T04:09:09.672548+00:00 \n",
+ " 1.134851 \n",
+ " 43.562772 \n",
+ " 54.176972 \n",
+ " 5446.90313 \n",
+ " 3118.29668 \n",
+ " -2698.94581 \n",
+ " 0.653341 \n",
+ " 0.373022 \n",
+ " ... \n",
+ " -2687.82088 \n",
+ " 0.215390 \n",
+ " -0.712554 \n",
+ " 0.088362 \n",
+ " -0.661865 \n",
+ " 16 \n",
+ " POLYGON((131.049760248284 -25.2921811831888, 1... \n",
+ " 0.46002 \n",
+ " 1301717367.67254806_sc00108_c2_PAN_i0000000001... \n",
+ " 170.325644 \n",
+ " \n",
+ " \n",
+ " 6 \n",
+ " 1301717367.69466472_sc00108_c2_PAN_i0000000002 \n",
+ " 2021-04-06T04:09:09.694665+00:00 \n",
+ " 1.134703 \n",
+ " 43.569988 \n",
+ " 54.185219 \n",
+ " 5446.85732 \n",
+ " 3118.24395 \n",
+ " -2699.09959 \n",
+ " 0.653398 \n",
+ " 0.372975 \n",
+ " ... \n",
+ " -2687.97475 \n",
+ " 0.215412 \n",
+ " -0.712494 \n",
+ " 0.088375 \n",
+ " -0.661921 \n",
+ " 16 \n",
+ " POLYGON((131.049764812089 -25.2927659348767, 1... \n",
+ " 0.46002 \n",
+ " 1301717367.69466472_sc00108_c2_PAN_i0000000002... \n",
+ " 170.581059 \n",
+ " \n",
+ " \n",
+ " 9 \n",
+ " 1301717367.71678233_sc00108_c2_PAN_i0000000003 \n",
+ " 2021-04-06T04:09:09.716782+00:00 \n",
+ " 1.134540 \n",
+ " 43.577207 \n",
+ " 54.193467 \n",
+ " 5446.81151 \n",
+ " 3118.19121 \n",
+ " -2699.25338 \n",
+ " 0.653455 \n",
+ " 0.372928 \n",
+ " ... \n",
+ " -2688.12863 \n",
+ " 0.215434 \n",
+ " -0.712434 \n",
+ " 0.088388 \n",
+ " -0.661978 \n",
+ " 16 \n",
+ " POLYGON((131.049773684881 -25.2933467270526, 1... \n",
+ " 0.46002 \n",
+ " 1301717367.71678233_sc00108_c2_PAN_i0000000003... \n",
+ " 170.598191 \n",
+ " \n",
+ " \n",
+ " 12 \n",
+ " 1301717367.73889995_sc00108_c2_PAN_i0000000004 \n",
+ " 2021-04-06T04:09:09.738900+00:00 \n",
+ " 1.134323 \n",
+ " 43.584427 \n",
+ " 54.201714 \n",
+ " 5446.76570 \n",
+ " 3118.13847 \n",
+ " -2699.40715 \n",
+ " 0.653513 \n",
+ " 0.372881 \n",
+ " ... \n",
+ " -2688.28250 \n",
+ " 0.215455 \n",
+ " -0.712373 \n",
+ " 0.088400 \n",
+ " -0.662034 \n",
+ " 16 \n",
+ " POLYGON((131.04977682712 -25.2939331452357, 13... \n",
+ " 0.46002 \n",
+ " 1301717367.73889995_sc00108_c2_PAN_i0000000004... \n",
+ " 170.585115 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
5 rows × 24 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " name \\\n",
+ "1 1301717367.65046573_sc00108_c2_PAN_i0000000000 \n",
+ "4 1301717367.67254806_sc00108_c2_PAN_i0000000001 \n",
+ "6 1301717367.69466472_sc00108_c2_PAN_i0000000002 \n",
+ "9 1301717367.71678233_sc00108_c2_PAN_i0000000003 \n",
+ "12 1301717367.73889995_sc00108_c2_PAN_i0000000004 \n",
+ "\n",
+ " datetime gsd sat_az sat_elev \\\n",
+ "1 2021-04-06T04:09:09.650466+00:00 1.135013 43.555569 54.168736 \n",
+ "4 2021-04-06T04:09:09.672548+00:00 1.134851 43.562772 54.176972 \n",
+ "6 2021-04-06T04:09:09.694665+00:00 1.134703 43.569988 54.185219 \n",
+ "9 2021-04-06T04:09:09.716782+00:00 1.134540 43.577207 54.193467 \n",
+ "12 2021-04-06T04:09:09.738900+00:00 1.134323 43.584427 54.201714 \n",
+ "\n",
+ " x_sat_eci_km y_sat_eci_km z_sat_eci_km qw_eci qx_eci ... \\\n",
+ "1 5446.94886 3118.34933 -2698.79227 0.653283 0.373069 ... \n",
+ "4 5446.90313 3118.29668 -2698.94581 0.653341 0.373022 ... \n",
+ "6 5446.85732 3118.24395 -2699.09959 0.653398 0.372975 ... \n",
+ "9 5446.81151 3118.19121 -2699.25338 0.653455 0.372928 ... \n",
+ "12 5446.76570 3118.13847 -2699.40715 0.653513 0.372881 ... \n",
+ "\n",
+ " z_sat_ecef_km qw_ecef qx_ecef qy_ecef qz_ecef bit_dpth \\\n",
+ "1 -2687.66724 0.215369 -0.712615 0.088349 -0.661809 16 \n",
+ "4 -2687.82088 0.215390 -0.712554 0.088362 -0.661865 16 \n",
+ "6 -2687.97475 0.215412 -0.712494 0.088375 -0.661921 16 \n",
+ "9 -2688.12863 0.215434 -0.712434 0.088388 -0.661978 16 \n",
+ "12 -2688.28250 0.215455 -0.712373 0.088400 -0.662034 16 \n",
+ "\n",
+ " geom integration_time_ms \\\n",
+ "1 POLYGON((131.04976305695 -25.2915903643759, 13... 0.52316 \n",
+ "4 POLYGON((131.049760248284 -25.2921811831888, 1... 0.46002 \n",
+ "6 POLYGON((131.049764812089 -25.2927659348767, 1... 0.46002 \n",
+ "9 POLYGON((131.049773684881 -25.2933467270526, 1... 0.46002 \n",
+ "12 POLYGON((131.04977682712 -25.2939331452357, 13... 0.46002 \n",
+ "\n",
+ " filename total_cam_offset \n",
+ "1 1301717367.65046573_sc00108_c2_PAN_i0000000000... NaN \n",
+ "4 1301717367.67254806_sc00108_c2_PAN_i0000000001... 170.325644 \n",
+ "6 1301717367.69466472_sc00108_c2_PAN_i0000000002... 170.581059 \n",
+ "9 1301717367.71678233_sc00108_c2_PAN_i0000000003... 170.598191 \n",
+ "12 1301717367.73889995_sc00108_c2_PAN_i0000000004... 170.585115 \n",
+ "\n",
+ "[5 rows x 24 columns]"
+ ]
+ },
+ "execution_count": 120,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "frame_index_c2.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 126,
+ "id": "d8b0657c-20e8-4906-af78-1d31b5c5e9b7",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "fontconfig\t\t frame_index_with_orient_c2.csv l1a_frames\n",
+ "frame_index.csv\t\t frame_index_without_orient.csv processing\n",
+ "frame_index_with_orient.csv isce.log\t\t\t refdem\n"
+ ]
+ }
+ ],
+ "source": [
+ "! ls"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "200c68fa-cb76-446a-86cc-4777db40b319",
+ "metadata": {},
+ "source": [
+ "### Initialise camera using RPC model and camgen"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 121,
+ "id": "ebf5f564-89dd-4aff-ab9d-13dfab8cab8a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from p_tqdm import p_map"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 124,
+ "id": "0644f569-8bb1-4746-8ee3-f423fc3f322c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "product_level = 'l1a'\n",
+ "outdir = 'processing/camera_camgen_rpc/'\n",
+ "if not os.path.exists(outdir):\n",
+ " os.makedirs(outdir)\n",
+ "dem = 'refdem/change_uluru_srtm.tif'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "85f6a36d-8156-406d-ab20-12204d4bf811",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 127,
+ "id": "b8745644-4231-4e8f-87aa-a85540d3cef2",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "9ae1259add45437ca9fe0fcb9b711a24",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/306 [00:00, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "writing gcp with basename removed\n",
+ "Total expected GCP 2448\n",
+ "Total number of GCPs found 2447\n"
+ ]
+ }
+ ],
+ "source": [
+ "img_list = sorted(glob.glob('processing/c2/*.tiff'))\n",
+ "img_list = [os.path.splitext(os.path.basename(img))[0] for img in img_list]\n",
+ "cam_list = [glob.glob(os.path.join('processing/c2/','{}*.tiff'.format(img)))[0] for img in img_list]\n",
+ "n = len(img_list)\n",
+ "if product_level == 'l1b':\n",
+ " pitch = [0.8]*n\n",
+ "else:\n",
+ " pitch = [1.0]*n\n",
+ "out_fn = [os.path.join(outdir,'{}_rpc.tsai'.format(frame)) for frame in img_list]\n",
+ "out_gcp = [os.path.join(outdir,'{}_rpc.gcp'.format(frame)) for frame in img_list]\n",
+ "camera = cam_list\n",
+ "frame_index = [None]*n\n",
+ "img_list = cam_list\n",
+ "gcp_factor = 8\n",
+ "fl = [553846.153846]*n\n",
+ "cx = [1280]*n\n",
+ "cy = [540]*n\n",
+ "dem = dem\n",
+ "ht_datum = [malib.get_stats_dict(iolib.fn_getma(dem))['median']]*n # use this value for height where DEM has no-data\n",
+ "gcp_std = [1]*n\n",
+ "datum = ['WGS84']*n\n",
+ "refdem = [dem]*n\n",
+ "n_proc = 20\n",
+ "#n_proc = cpu_count()\n",
+ "cam_gen_log = p_map(asp.cam_gen,img_list,fl,cx,cy,pitch,ht_datum,gcp_std,out_fn,out_gcp,datum,refdem,camera,frame_index,num_cpus = n_proc)\n",
+ "print(\"writing gcp with basename removed\")\n",
+ "# count expexted gcp \n",
+ "print(f\"Total expected GCP {gcp_factor*n}\") \n",
+ "asp.clean_gcp(out_gcp,outdir)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 129,
+ "id": "cd6a1d62-10e9-40c8-b838-eacf76742b44",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "camera_folder,gcp_folder = outdir,outdir"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 130,
+ "id": "455dd9a6-f724-45d7-92e9-3a293ca9d6b8",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "IndexError",
+ "evalue": "list index out of range",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0mglob\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mglob\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcamera_folder\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'*{}*.tsai'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbasename\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mframe\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mframe\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mframe_index_c2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'name'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0mglob\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mglob\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcamera_folder\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'*{}*.tsai'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbasename\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mframe\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mframe\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mframe_index_c2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'name'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mIndexError\u001b[0m: list index out of range"
+ ]
+ }
+ ],
+ "source": [
+ "[glob.glob(os.path.join(camera_folder,'*{}*.tsai'.format(os.path.basename(frame))))[0] for frame in frame_index_c2['name'].values]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 132,
+ "id": "bad4d07a-a041-4725-b9dd-658e7937e898",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'1301717367.65046573_sc00108_c2_PAN_i0000000000'"
+ ]
+ },
+ "execution_count": 132,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "frame_index_c2['name'].values[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 137,
+ "id": "65bdb0f6-00ef-4fcd-ba84-f85c10ed9714",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test = (os.path.join(camera_folder,'*{}*.tsai'.format(os.path.basename(frame_index_c2['name'].values[0]))))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 138,
+ "id": "57b89f33-6930-44c9-8c7d-3b5247ab9644",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "processing/camera_camgen_rpc/1301717367.65046573_sc00108_c2_PAN_i0000000000_rpc.tsai\n"
+ ]
+ }
+ ],
+ "source": [
+ "! ls $test"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 140,
+ "id": "1b46ae4d-0cdd-4f9f-bc82-e70ca8e07563",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "292"
+ ]
+ },
+ "execution_count": 140,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(sorted(glob.glob('processing/camera_camgen_rpc/*.tsai')))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d309062c-efd6-4251-86a4-55d8eef48229",
+ "metadata": {},
+ "source": [
+ "### Check with scipy camera"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 141,
+ "id": "38a152ae-d439-4a61-9ff0-268e532003d6",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/sw/imview/imview/lib/pltlib.py:149: MatplotlibDeprecationWarning: You are modifying the state of a globally registered colormap. In future versions, you will not be able to modify a registered colormap in-place. To remove this warning, you can make a copy of the colormap first. cmap = copy.copy(mpl.cm.get_cmap(\"RdBu\"))\n",
+ " cmap.set_bad('k', alpha=1)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 141,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "disparity = 'processing/c2_first2_pinholeasp_scipy/run-D.tif'\n",
+ "dx,dy = [iolib.fn_getma(disparity,i) for i in range(1,3)]\n",
+ "f,ax = plt.subplots(1,2)\n",
+ "pltlib.iv(dx,ax=ax[0],cmap='RdBu',clim=malib.calcperc_sym(dx))\n",
+ "pltlib.iv(dy,ax=ax[1],cmap='RdBu',clim=malib.calcperc_sym(dy))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "8274507c-4350-438c-9090-741c9b62ccad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "### Correct frame_index's"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "77ed442b-0f3b-4eea-a5ce-7b1b4efe1910",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_frame_fn = 'frame_index.csv'\n",
+ "nadir_frame_fn = '../s108_20210406T040941Z/frame_index.csv'\n",
+ "aft_frame_fn = '../s108_20210406T041015Z/frame_index.csv'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "id": "e4dfccaa-af72-42b7-8ef3-578ddd8dba83",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1301717367.65046096_sc00108_c3_PAN_i0000000000\n"
+ ]
+ }
+ ],
+ "source": [
+ "for_frame = modernize_frame_index(for_frame_fn)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "51d8b463-3c92-49c5-b7b4-d26a1b119b4c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " name \n",
+ " datetime \n",
+ " gsd \n",
+ " sat_az \n",
+ " sat_elev \n",
+ " x_sat_eci_km \n",
+ " y_sat_eci_km \n",
+ " z_sat_eci_km \n",
+ " qw_eci \n",
+ " qx_eci \n",
+ " ... \n",
+ " y_sat_ecef_km \n",
+ " z_sat_ecef_km \n",
+ " qw_ecef \n",
+ " qx_ecef \n",
+ " qy_ecef \n",
+ " qz_ecef \n",
+ " bit_dpth \n",
+ " geom \n",
+ " integration_time_ms \n",
+ " filename \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1301717367.65046096_sc00108_c3_PAN_i0000000000 \n",
+ " 2021-04-06T04:09:09.650461+00:00 \n",
+ " 1.124777 \n",
+ " 43.757951 \n",
+ " 54.626309 \n",
+ " 5446.94887 \n",
+ " 3118.34934 \n",
+ " -2698.79223 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " 4588.27493 \n",
+ " -2687.66720 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON((131.075182669813 -25.252703375099, 13... \n",
+ " 0.52316 \n",
+ " 1301717367.65046096_sc00108_c3_PAN_i0000000000... \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000 \n",
+ " 2021-04-06T04:09:09.650466+00:00 \n",
+ " 1.135013 \n",
+ " 43.555569 \n",
+ " 54.168736 \n",
+ " 5446.94886 \n",
+ " 3118.34933 \n",
+ " -2698.79227 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " 4588.27492 \n",
+ " -2687.66724 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON((131.04976305695 -25.2915903643759, 13... \n",
+ " 0.52316 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
2 rows × 23 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " name \\\n",
+ "0 1301717367.65046096_sc00108_c3_PAN_i0000000000 \n",
+ "1 1301717367.65046573_sc00108_c2_PAN_i0000000000 \n",
+ "\n",
+ " datetime gsd sat_az sat_elev \\\n",
+ "0 2021-04-06T04:09:09.650461+00:00 1.124777 43.757951 54.626309 \n",
+ "1 2021-04-06T04:09:09.650466+00:00 1.135013 43.555569 54.168736 \n",
+ "\n",
+ " x_sat_eci_km y_sat_eci_km z_sat_eci_km qw_eci qx_eci ... \\\n",
+ "0 5446.94887 3118.34934 -2698.79223 0.653283 0.373069 ... \n",
+ "1 5446.94886 3118.34933 -2698.79227 0.653283 0.373069 ... \n",
+ "\n",
+ " y_sat_ecef_km z_sat_ecef_km qw_ecef qx_ecef qy_ecef qz_ecef \\\n",
+ "0 4588.27493 -2687.66720 0.215369 -0.712615 0.088349 -0.661809 \n",
+ "1 4588.27492 -2687.66724 0.215369 -0.712615 0.088349 -0.661809 \n",
+ "\n",
+ " bit_dpth geom \\\n",
+ "0 16 POLYGON((131.075182669813 -25.252703375099, 13... \n",
+ "1 16 POLYGON((131.04976305695 -25.2915903643759, 13... \n",
+ "\n",
+ " integration_time_ms filename \n",
+ "0 0.52316 1301717367.65046096_sc00108_c3_PAN_i0000000000... \n",
+ "1 0.52316 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ "\n",
+ "[2 rows x 23 columns]"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "for_frame.head(2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "2ac0aba0-dc8a-404a-a05a-d8e98879c2dc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "nadir_frame = modernize_frame_index(nadir_frame_fn)\n",
+ "aft_frame = modernize_frame_index(aft_frame_fn)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "id": "8d53c25d-bcf4-4785-ba85-5efea74d447e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_c2_img_list = sorted(glob.glob('l1a_frames/*c2*.tif'))\n",
+ "nadir_c2_img_list = sorted(glob.glob('../s108_20210406T040941Z/l1a_frames/*c2*.tif'))\n",
+ "aft_c2_img_list = sorted(glob.glob('../s108_20210406T041015Z/l1a_frames/*c2*.tif'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "id": "fcf026f9-5fa5-41a7-bb5d-15822beadc72",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_base = [os.path.splitext(os.path.basename(frame))[0] for frame in for_c2_img_list]\n",
+ "nadir_base = [os.path.splitext(os.path.basename(frame))[0] for frame in nadir_c2_img_list]\n",
+ "aft_base = [os.path.splitext(os.path.basename(frame))[0] for frame in aft_c2_img_list]\n",
+ "\n",
+ "\n",
+ "mask = for_frame['name'].isin(for_base)\n",
+ "for_frame_c2 = for_frame[mask]\n",
+ "\n",
+ "mask = nadir_frame['name'].isin(nadir_base)\n",
+ "nadir_frame_c2 = nadir_frame[mask]\n",
+ "\n",
+ "mask = aft_frame['name'].isin(aft_base)\n",
+ "aft_frame_c2 = aft_frame[mask]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "0247f0d6-3e05-4736-9aeb-98eb5d369545",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_c2_out = '../processing/frame_index_format_for_c2.csv'\n",
+ "nadir_c2_out = '../processing/frame_index_format_nadir_c2.csv'\n",
+ "aft_c2_out = '../processing/frame_index_format_aft_c2.csv'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "id": "1de65d26-7130-4c0c-80fa-5983b29c229d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_frame_c2.to_csv(for_c2_out,index=False)\n",
+ "nadir_frame_c2.to_csv(nadir_c2_out,index=False)\n",
+ "aft_frame_c2.to_csv(aft_c2_out,index=False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "id": "a65d1332-fc52-4d21-9f28-91ec788004b5",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "282"
+ ]
+ },
+ "execution_count": 42,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(aft_base)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7d1e423-fbf2-4b1d-a114-2019ffd9a163",
+ "metadata": {},
+ "source": [
+ "### Find intersections between frames"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "d3dff489-9cdf-4ffd-af20-c69530efdbf3",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/pyproj/crs/crs.py:53: FutureWarning: '+init=:' syntax is deprecated. ':' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6\n",
+ " return _prepare_from_string(\" \".join(pjargs))\n"
+ ]
+ }
+ ],
+ "source": [
+ "for_c2 = skysat.parse_frame_index(for_c2_out).to_crs('EPSG:32752')\n",
+ "nadir_c2 = skysat.parse_frame_index(nadir_c2_out).to_crs('EPSG:32752')\n",
+ "aft_c2 = skysat.parse_frame_index(aft_c2_out).to_crs('EPSG:32752')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "03faafdd-0349-46e7-83ba-bad9372221d1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "opt1_intersect = gpd.overlay(for_c2,nadir_c2,how='intersection')\n",
+ "opt2_intersect = gpd.overlay(for_c2,aft_c2,how='intersection')\n",
+ "opt3_intersect = gpd.overlay(nadir_c2,aft_c2,how='intersection')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "b6745bb7-fab4-45df-a36a-fdc0ce37e2b0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "overlap_c2_fn = '../processing/c2_overlap.txt'\n",
+ "with open(overlap_c2_fn,'w') as f:\n",
+ " for df in [opt1_intersect,opt2_intersect,opt3_intersect]:\n",
+ " for idx,img1 in enumerate(df['name_1'].values):\n",
+ " img2 = df['name_2'].values[idx]\n",
+ " img1 = 'c2/'+img1+'.tiff'\n",
+ " img2 = 'c2/'+img2+'.tiff'\n",
+ " f.write(f\"{img1} {img2} \\n\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "id": "0ca7ecce-3ef7-4956-9482-70fb08d25d03",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "img1_list = list(opt1_intersect['name_1'].values) + list(opt2_intersect['name_1'].values) + list(opt3_intersect['name_1'].values)\n",
+ "img2_list = list(opt1_intersect['name_2'].values) + list(opt2_intersect['name_2'].values) + list(opt3_intersect['name_2'].values)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "id": "6c4177fc-b814-4823-a879-3bf0355ccd76",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "40216"
+ ]
+ },
+ "execution_count": 66,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(img1_list)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "id": "5e67a158-c1ec-4832-9653-07555f2ef981",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "40216"
+ ]
+ },
+ "execution_count": 67,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(img2_list)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "id": "15ba1992-b73a-4983-a4b1-b8bc13f3f573",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def chunks(lst, n):\n",
+ " \"\"\"Yield successive n-sized chunks from lst.\"\"\"\n",
+ " # https://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks\n",
+ " for i in range(0, len(lst), n):\n",
+ " yield lst[i:i + n]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "id": "8ec55c49-810c-4bbc-996b-cab339585108",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "img1_meg_list = list(chunks(img1_list,100))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 74,
+ "id": "da6ec804-fb3b-4dd9-944f-54a73404a5b4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "img2_meg_list = list(chunks(img2_list,100))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "id": "af557911-6f0c-4074-b28a-778bd8896f7d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "403"
+ ]
+ },
+ "execution_count": 76,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(img2_meg_list)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "id": "824813e4-650c-40d1-9ee0-9c1b5e1fdabe",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'1301717367.65046573_sc00108_c2_PAN_i0000000000'"
+ ]
+ },
+ "execution_count": 78,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "img1_meg_list[0][0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "id": "976ceea0-eff9-4d36-bec4-290f615d341e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "find_matches = '../processing/c2_find_matches.txt'\n",
+ "fn_num = 0\n",
+ "i = 0\n",
+ "with open(find_matches,'w') as f:\n",
+ " \n",
+ " for idx,lists in enumerate(img1_meg_list):\n",
+ " for cdx,img1, in enumerate(lists):\n",
+ " img2 = img2_meg_list[idx][cdx]\n",
+ " cam1 = glob.glob(f'../processing/scipy_camera/{img1}*.tsai')[0]\n",
+ " cam2 = glob.glob(f'../processing/scipy_camera/{img2}*.tsai')[0]\n",
+ "\n",
+ " img1 = 'c2/'+img1+'.tiff'\n",
+ " img2 = 'c2/'+img2+'.tiff'\n",
+ " #print(f'../processing/scipy_camera/{img1}*.tsai')\n",
+ "\n",
+ " f.write(f\"bundle_adjust --threads 1 --stop-after-matching -t nadirpinhole --datum WGS84 --disable-tri-ip-filter --ip-per-tile 1000 --ip-inlier-factor 0.2 --ip-num-ransac-iterations 1000 --skip-rough-homography --min-triangulation-angle 0.0001 --min-matches 4 -o c2_strip_full_sfm/proc{fn_num}/run {img1} {img2} {cam1} {cam2} \\n\")\n",
+ " i = i+1\n",
+ " if i == 100:\n",
+ " fn_num = fn_num+1\n",
+ " i = 0"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "4f84a74b-249f-4368-913f-2e5868426f18",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[Errno 2] No such file or directory: '../../processing/'\n",
+ "/nobackupp11/sbhusha1/change/s108_20210406T040909Z\n"
+ ]
+ }
+ ],
+ "source": [
+ "%cd ../../processing/"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 87,
+ "id": "2ef8067a-4f3b-450a-96a1-c9f91728ba52",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\u001b[0m\u001b[01;34mc2\u001b[0m/ \u001b[01;34mfontconfig\u001b[0m/ \u001b[01;34mtest\u001b[0m/\n",
+ "\u001b[01;34mc2_delete\u001b[0m/ frame_index_format_aft_c2.csv \u001b[01;34mtest2\u001b[0m/\n",
+ "c2_find_matches.txt frame_index_format_for_c2.csv \u001b[01;34mtestrpc\u001b[0m/\n",
+ "c2_overlap.txt frame_index_format_nadir_c2.csv\n",
+ "\u001b[01;34mcamgen_out\u001b[0m/ \u001b[01;34mscipy_camera\u001b[0m/\n"
+ ]
+ }
+ ],
+ "source": [
+ "ls"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 99,
+ "id": "386304c6-f15d-4598-82c4-55a7cac2bc09",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "find_matches = '../processing/c2_find_matches.txt'\n",
+ "fn_num = 0\n",
+ "i = 0\n",
+ "with open(find_matches,'w') as f:\n",
+ " \n",
+ " for idx,img1_list in enumerate(img1_meg_list):\n",
+ " img2_list = img2_meg_list[idx]\n",
+ " uniq_img_list = np.unique(img1_list+img2_list)\n",
+ " uniq_cam_list = [f'scipy_camera/{img1}_scipy.tsai' for img1 in uniq_img_list]\n",
+ " overlap_fn = f'c2_overlap_{idx}.txt'\n",
+ " with open(overlap_fn,'w') as foo:\n",
+ " for mdx,img1 in enumerate(img1_list):\n",
+ " foo.write(f\"c2/{img1}.tiff c2/{img2_list[mdx]}.tiff \\n\")\n",
+ " uniq_img_list = [f\"c2/{img}.tiff\" for img in uniq_img_list] \n",
+ " img_str = ' '.join(uniq_img_list)\n",
+ " cam_str = ' '.join(uniq_cam_list)\n",
+ " ba_str = f\"bundle_adjust --threads 1 --stop-after-matching -t nadirpinhole --datum WGS84 --disable-tri-ip-filter --ip-per-tile 1000 --ip-inlier-factor 0.2 --ip-num-ransac-iterations 1000 --skip-rough-homography --min-triangulation-angle 0.0001 --min-matches 4 --overlap-list {overlap_fn} -o c2_strip_full_sfm/proc_{idx}/run\"\n",
+ " out_str = ba_str + \" \" + img_str + \" \" + cam_str + \"\\n\"\n",
+ " f.write(out_str)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 100,
+ "id": "263f8acb-ae75-4a87-8e58-35122e21642d",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "13\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(len(uniq_cam_list))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 101,
+ "id": "b4924cf9-f1ba-45c1-ab33-5290d2e98c03",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "13\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(len(uniq_img_list))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "49ebc2aa-ed49-403d-8c09-d2d6926b6c54",
+ "metadata": {},
+ "source": [
+ "### Get first 100 images from nadir and perform stereo with those only"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "452c8fb5-0fbb-495b-830c-c66c9eab04e7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(100, 23)"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "nadir_c2.iloc[:100].shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "id": "96c08cd1-700c-43fa-abc1-ee0a851f9377",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def find_intersection(gdf1,gdf2):\n",
+ " from itertools import combinations\n",
+ " valid_combinations = list(combinations((list(gdf1.name.values)+list(gdf2.name.values)),2))\n",
+ " valid_combinations = [f'{x[0]}__{x[1]}' for x in valid_combinations]\n",
+ " def make_sep(row):\n",
+ " return f\"{row['name_1']}__{row['name_2']}\"\n",
+ " gdf = gpd.overlay(gdf1,gdf2,how='intersection')\n",
+ " print (gdf.shape)\n",
+ " #gdf['int_area'] = gdf.area*1e-6\n",
+ " #area_mask = gdf['int_area'] >= 1\n",
+ " #valid_gdf = gdf[mask]\n",
+ " valid_gdf = gdf.copy()\n",
+ " print(valid_combinations[0])\n",
+ " valid_gdf['sep1'] = valid_gdf.apply(make_sep,axis=1)\n",
+ " return valid_gdf[valid_gdf['sep1'].isin(valid_combinations)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "a660ff5e-864b-4abb-b610-50e6ed480e58",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(3333, 45)\n",
+ "1301717367.65046573_sc00108_c2_PAN_i0000000000__1301717367.67254806_sc00108_c2_PAN_i0000000001\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "(3333, 46)"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "find_intersection(for_c2,nadir_c2_100).shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "fc030d24-841c-4251-85f1-94c70ea895d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "nadir_c2_100 = nadir_c2.iloc[:100]\n",
+ "opt1_intersect = gpd.overlay(for_c2,nadir_c2_100,how='intersection')\n",
+ "opt3_intersect = gpd.overlay(nadir_c2_100,aft_c2,how='intersection')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "58eb356c-995b-4a9e-9388-f41da0988bd8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "! ls"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "9c088b2d-2772-4231-afe7-f7fe9dac12d4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_c2_matching = np.unique(opt1_intersect['name_1'].values)\n",
+ "aft_c2_matching = np.unique(opt3_intersect['name_2'].values)\n",
+ "for_100mask = for_c2['name'].isin(for_c2_matching)\n",
+ "for_c2_100 = for_c2[for_100mask]\n",
+ "\n",
+ "aft_100mask = aft_c2['name'].isin(aft_c2_matching)\n",
+ "aft_c2_100 = aft_c2[aft_100mask]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "id": "b0b1bae2-e0e8-4149-b1ad-a6c5bb04ff32",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(84, 23)"
+ ]
+ },
+ "execution_count": 30,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aft_c2_100.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "id": "252ca210-14ac-4eb4-8a03-df655ec3fb1b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(87, 23)"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "for_c2_100.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "0f069d75-4f5e-477c-8a51-d197eaf7a1b5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "opt2_intersect = gpd.overlay(for_c2_100,aft_c2_100,how='intersection')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "id": "bef19aef-c2c9-4503-abdf-eaf12fe21781",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "overlap_c2_100fn = '../processing/c2_overlap_nadir100.txt'\n",
+ "with open(overlap_c2_100fn,'w') as f:\n",
+ " for df in [opt1_intersect,opt2_intersect,opt3_intersect]:\n",
+ " for idx,img1 in enumerate(df['name_1'].values):\n",
+ " img2 = df['name_2'].values[idx]\n",
+ " img1 = 'c2/'+img1+'.tiff'\n",
+ " img2 = 'c2/'+img2+'.tiff'\n",
+ " f.write(f\"{img1} {img2} \\n\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "id": "d097d6b1-810f-415b-bec8-6709058e768d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "87"
+ ]
+ },
+ "execution_count": 75,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(for_c2_matching)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "6ebed3f2-e865-4d85-9a50-d196ecd4036c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "img_list = for_c2_matching.tolist()+nadir_c2_100.name.values.tolist()+aft_c2_matching.tolist()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "c059f8b7-1b01-4ea8-9c09-86b4c2d07130",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "cam_list = [f'scipy_camera/{img}_scipy.tsai' for img in img_list]\n",
+ "img_list = [f'c2/{img}.tiff' for img in img_list]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "4c913e27-6496-49d4-ad5e-06b74b475bf8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "cam_list_fn = '../processing/nadir100_cam_list.txt'\n",
+ "img_list_fn = '../processing/nadir100_img_list.txt'\n",
+ "with open(cam_list_fn,'w') as f:\n",
+ " out_str = ' '.join(cam_list)\n",
+ " f.write(out_str)\n",
+ " \n",
+ "with open(img_list_fn,'w') as f:\n",
+ " out_str = ' '.join(img_list)\n",
+ " f.write(out_str)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "32269982-5cee-4604-9021-201298a869b9",
+ "metadata": {},
+ "source": [
+ "time bundle_adjust --force-reuse-match-files --skip-rough-homography --min-triangulation-angle 0.0001 --save-cnet-as-csv --individually-normalize --translation-weight 0.6 --rotation-weight 0 --remove-outliers-params '75 3 5 6' -t nadirpinhole --inline-adjustments --num-iterations 250 --num-passes 2 --overlap-list c2_overlap_nadir100.txt -o c2_strip_full_sfm/run $(cat nadir100_img_list.txt) $(cat nadir100_cam_list.txt) | tee nadir_100_img.log"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "id": "5911967b-cce5-4738-bae5-54c19213be6e",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.0051"
+ ]
+ },
+ "execution_count": 49,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "15*170/500000"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "id": "d2451e5a-7fae-4361-b926-f20e88ec7779",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Index(['name', 'datetime', 'gsd', 'sat_az', 'sat_elev', 'x_sat_eci_km',\n",
+ " 'y_sat_eci_km', 'z_sat_eci_km', 'qw_eci', 'qx_eci', 'qy_eci', 'qz_eci',\n",
+ " 'x_sat_ecef_km', 'y_sat_ecef_km', 'z_sat_ecef_km', 'qw_ecef', 'qx_ecef',\n",
+ " 'qy_ecef', 'qz_ecef', 'bit_dpth', 'geom', 'integration_time_ms',\n",
+ " 'filename'],\n",
+ " dtype='object')"
+ ]
+ },
+ "execution_count": 50,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "nadir_c2_100.keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "id": "42d66f7c-96c6-4a7d-860b-4704c8242439",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "az1,el1 = for_c2_100[['sat_az','sat_elev']].iloc[0]\n",
+ "az2,el2 = for_c2_100[['sat_az','sat_elev']].iloc[14]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "id": "998656c8-ce97-48cc-9f2d-edfd313a3d86",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.10147046988797825"
+ ]
+ },
+ "execution_count": 57,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "az2-az1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "id": "0904c02f-2a64-4beb-98e3-0b00f339376a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.12964550096556873"
+ ]
+ },
+ "execution_count": 58,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "asp.convergence_angle(az1,el1,az2,el2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "id": "de8a12eb-4b6a-4f1a-8887-ad68e9432606",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.0051"
+ ]
+ },
+ "execution_count": 59,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "15*170/500000"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd02655c-0a82-4a78-aa73-fe8c0564575f",
+ "metadata": {},
+ "source": [
+ "### Analyse solved angles"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "7ee4d561-c44c-4d08-9f1d-f61648c2567b",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/change/processing\n"
+ ]
+ }
+ ],
+ "source": [
+ "%cd ../processing/"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "077d98f2-5220-41cc-a8b9-7d139c044a80",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([65.27032536, 11.41033933, 92.17545667])"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "R.from_matrix(np.reshape(asp.read_tsai_dict(cam_list[0])['rotation_matrix'],(3,3))).as_euler('ZYX',degrees=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "id": "466bee0e-fa32-4601-95ab-2f692f6f5356",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "optimised_cam_list = sorted(glob.glob('c2_strip_full_sfm/100_nadircameras/run-*.tsai'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "d2102686-dde8-48f4-a824-88293be6ff14",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([65.25080124, 11.37568374, 92.1711617 ])"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "R.from_matrix(np.reshape(asp.read_tsai_dict(optimised_cam_list[0])['rotation_matrix'],(3,3))).as_euler('ZYX',degrees=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "7f4a26b6-a06e-41f4-991c-aedb21e8152f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_camera_initial = [f'scipy_camera/{img}_scipy.tsai' for img in for_c2_matching]\n",
+ "for_camera_opt = [f'c2_strip_full_sfm/100_nadircameras/run-{img}_scipy.tsai' for img in for_c2_matching]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "ade92131-5ee2-441a-bee9-c439727b8d24",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_initial_rotation_angles = [R.from_matrix(np.reshape(asp.read_tsai_dict(cam)['rotation_matrix'],(3,3))).as_euler('ZYX',degrees=True) for cam in for_camera_initial]\n",
+ "for_initial_yaw = [r[0] for r in for_initial_rotation_angles]\n",
+ "for_initial_pitch = [r[1] for r in for_initial_rotation_angles]\n",
+ "for_initial_roll = [r[2] for r in for_initial_rotation_angles]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "99d0b582-0468-419a-b695-677b99e65436",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_optimised_rotation_angles = [R.from_matrix(np.reshape(asp.read_tsai_dict(cam)['rotation_matrix'],(3,3))).as_euler('ZYX',degrees=True) for cam in for_camera_opt]\n",
+ "for_optimised_yaw = [r[0] for r in for_optimised_rotation_angles]\n",
+ "for_optimised_pitch = [r[1] for r in for_optimised_rotation_angles]\n",
+ "for_optimised_roll = [r[2] for r in for_optimised_rotation_angles]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "abe34826-c8ab-481a-b26d-18c023302060",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%matplotlib inline"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "id": "0a410e67-b394-4b2d-8b0c-8e4bbc8ab3ba",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ "ax[0].scatter(np.arange(len(for_optimised_pitch)),for_initial_yaw,label='yaw',s=1)\n",
+ "ax[0].scatter(np.arange(len(for_optimised_pitch)),for_initial_pitch,label='pitch',s=1)\n",
+ "ax[0].scatter(np.arange(len(for_optimised_pitch)),for_initial_roll,label='roll',s=1)\n",
+ "\n",
+ "ax[1].scatter(np.arange(len(for_optimised_pitch)),for_optimised_yaw,label='yaw',s=1)\n",
+ "ax[1].scatter(np.arange(len(for_optimised_pitch)),for_optimised_pitch,label='pitch',s=1)\n",
+ "ax[1].scatter(np.arange(len(for_optimised_pitch)),for_optimised_roll,label='roll',s=1)\n",
+ "\n",
+ "ax[0].set_title('For cameras initial')\n",
+ "ax[1].set_title('For cameras optimised')\n",
+ "ax[0].set_ylabel('Degrees')\n",
+ "ax[0].set_xlabel('Frame number')\n",
+ "ax[1].set_xlabel('Frame number')\n",
+ "ax[0].legend()\n",
+ "ax[1].legend()\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "e95542af-ae8e-4842-ac3b-bdfb6c5ccdab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def poly_resid(df, col, deg=2):\n",
+ " \"\"\"\n",
+ " Written by David originally\n",
+ " \"\"\"\n",
+ " poly_fit = np.poly1d(np.polyfit(df.index, df[col], deg))\n",
+ " resid = poly_fit(df.index) - df[col]\n",
+ " return resid"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "id": "79ab6637-773a-4036-8373-943a6331ae19",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/geopandas/geodataframe.py:1322: SettingWithCopyWarning: \n",
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
+ "\n",
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
+ " super(GeoDataFrame, self).__setitem__(key, value)\n"
+ ]
+ }
+ ],
+ "source": [
+ "for_c2_100['init_yaw'] = for_initial_yaw\n",
+ "for_c2_100['init_pitch'] = for_initial_pitch\n",
+ "for_c2_100['init_roll'] = for_initial_roll"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "id": "e2e32741-f1bb-442a-8283-becfa8ae5e8b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_c2_100['opt_yaw'] = for_optimised_yaw\n",
+ "for_c2_100['opt_pitch'] = for_optimised_pitch\n",
+ "for_c2_100['opt_roll'] = for_optimised_roll"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "98d772d2-ea9f-4224-baf3-d3f85ceea9a4",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots()\n",
+ "poly_resid(for_c2_100,'opt_yaw',deg=3).plot(ax=ax)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "f6780d1a-89f0-4d18-89fd-f72b8954628d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots()\n",
+ "poly_resid(for_c2_100,'init_yaw',deg=3).plot(ax=ax)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "1397d4aa-a484-48a3-ae3a-b6b4ef0329aa",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ "deg=2\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'init_yaw',deg=deg),label='yaw')\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'init_pitch',deg=deg),label='pitch')\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'init_roll',deg=deg),label='roll')\n",
+ "\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_yaw',deg=deg),label='yaw')\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_pitch',deg=deg),label='pitch')\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_roll',deg=deg),label='roll')\n",
+ "\n",
+ "ax[0].set_title('For cameras initial')\n",
+ "ax[1].set_title('For cameras optimised')\n",
+ "\n",
+ "ax[0].legend()\n",
+ "ax[1].legend()\n",
+ "ax[0].set_ylabel('Degrees')\n",
+ "ax[0].set_xlabel('Frame number')\n",
+ "ax[1].set_xlabel('Frame number')\n",
+ "plt.suptitle('Degree 2 fit')\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "id": "a0027a66-7154-4c9b-a892-7f14dbb5d7ad",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ "deg=3\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'init_yaw',deg=deg),label='yaw')\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'init_pitch',deg=deg),label='pitch')\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'init_roll',deg=deg),label='roll')\n",
+ "\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_yaw',deg=deg),label='yaw')\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_pitch',deg=deg),label='pitch')\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_roll',deg=deg),label='roll')\n",
+ "\n",
+ "ax[0].set_title('For cameras initial')\n",
+ "ax[1].set_title('For cameras optimised')\n",
+ "\n",
+ "ax[0].legend()\n",
+ "ax[1].legend()\n",
+ "\n",
+ "ax[0].set_ylabel('Degrees')\n",
+ "ax[0].set_xlabel('Frame number')\n",
+ "ax[1].set_xlabel('Frame number')\n",
+ "plt.suptitle('Degree 3 fit')\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3e2c9b36-8c87-4bdc-8fd0-4583f10f6b17",
+ "metadata": {},
+ "source": [
+ "#### Verify with ephemris estimate"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "id": "769aeebb-e875-4a7c-9c30-f33c68690543",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "r = R.from_quat(for_c2_100[['qx_ecef','qy_ecef','qz_ecef','qw_ecef']].values).as_euler('ZYX', degrees=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "id": "11340a5c-565c-434d-b486-c912695635f4",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/geopandas/geodataframe.py:1322: SettingWithCopyWarning: \n",
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
+ "\n",
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
+ " super(GeoDataFrame, self).__setitem__(key, value)\n"
+ ]
+ }
+ ],
+ "source": [
+ "for_c2_100['ephem_yaw'] = r[:,0]\n",
+ "for_c2_100['ephem_pitch'] = r[:,1]\n",
+ "for_c2_100['ephem_roll'] = r[:,2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "id": "2fc30e94-7dd1-4c45-a98e-5f6b63b7f81d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ "ax[0].scatter(np.arange(len(for_optimised_pitch)),for_c2_100['ephem_yaw'],label='yaw')\n",
+ "ax[0].scatter(np.arange(len(for_optimised_pitch)),for_c2_100['ephem_pitch'],label='pitch')\n",
+ "ax[0].scatter(np.arange(len(for_optimised_pitch)),for_c2_100['ephem_roll'],label='roll')\n",
+ "\n",
+ "ax[1].scatter(np.arange(len(for_optimised_pitch)),for_optimised_yaw,label='yaw')\n",
+ "ax[1].scatter(np.arange(len(for_optimised_pitch)),for_optimised_pitch,label='pitch')\n",
+ "ax[1].scatter(np.arange(len(for_optimised_pitch)),for_optimised_roll,label='roll')\n",
+ "\n",
+ "ax[0].set_title('For cameras Ephemris')\n",
+ "ax[1].set_title('For cameras optimised')\n",
+ "\n",
+ "ax[0].legend()\n",
+ "ax[1].legend()\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "id": "c7ccd11a-455d-4f2e-8d97-4eecd2871559",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ "deg=3\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'ephem_yaw',deg=deg),label='yaw')\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'ephem_pitch',deg=deg),label='pitch')\n",
+ "ax[0].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'ephem_roll',deg=deg),label='roll')\n",
+ "\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_yaw',deg=deg),label='yaw')\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_pitch',deg=deg),label='pitch')\n",
+ "ax[1].plot(np.arange(len(for_optimised_pitch)),poly_resid(for_c2_100,'opt_roll',deg=deg),label='roll')\n",
+ "\n",
+ "ax[0].set_title('For cameras Ephemeris')\n",
+ "ax[1].set_title('For cameras optimised')\n",
+ "\n",
+ "ax[0].legend()\n",
+ "ax[1].legend()\n",
+ "plt.suptitle('Degree 3 fit')\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "82f13181-3205-41c4-8ee8-1cb2d26600d2",
+ "metadata": {},
+ "source": [
+ "### Results for nadir cameras"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "84d6e44d-5a0d-4845-a847-ec956f9718b6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "nadir_camera_initial = [f'scipy_camera/{img}_scipy.tsai' for img in nadir_c2_100.name.values]\n",
+ "nadir_camera_opt = [f'c2_strip_full_sfm/100_nadircameras/run-{img}_scipy.tsai' for img in nadir_c2_100.name.values]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "id": "ec3e31cb-45c7-412a-af1f-7329b6bc199c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "nadir_initial_rotation_angles = np.array([R.from_matrix(np.reshape(asp.read_tsai_dict(cam)['rotation_matrix'],(3,3))).as_euler('ZYX',degrees=True) for cam in nadir_camera_initial])\n",
+ "#nadir_initial_yaw = [r[0] for r in for_initial_rotation_angles]\n",
+ "#nadir_initial_pitch = [r[1] for r in for_initial_rotation_angles]\n",
+ "#nadir_initial_roll = [r[2] for r in for_initial_rotation_angles]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "id": "5f9bb775-ee4f-4cc2-99eb-5cf94a163236",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "nadir_opt_rotation_angles = np.array([R.from_matrix(np.reshape(asp.read_tsai_dict(cam)['rotation_matrix'],(3,3))).as_euler('ZYX',degrees=True) for cam in nadir_camera_opt])\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "id": "bcc3aead-c8d8-4b1e-b0ab-3f4d50c72eb7",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/geopandas/geodataframe.py:1322: SettingWithCopyWarning: \n",
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
+ "\n",
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
+ " super(GeoDataFrame, self).__setitem__(key, value)\n"
+ ]
+ }
+ ],
+ "source": [
+ "nadir_c2_100['init_yaw'] = nadir_initial_rotation_angles[:,0]\n",
+ "nadir_c2_100['init_pitch'] = nadir_initial_rotation_angles[:,1]\n",
+ "nadir_c2_100['init_roll'] = nadir_initial_rotation_angles[:,2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "id": "2dfb5a29-b76e-41e4-80d7-92608a2fce67",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "nadir_c2_100['opt_yaw'] = nadir_opt_rotation_angles[:,0]\n",
+ "nadir_c2_100['opt_pitch'] = nadir_opt_rotation_angles[:,1]\n",
+ "nadir_c2_100['opt_roll'] = nadir_opt_rotation_angles[:,2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "id": "f0b57116-a5f1-4a7e-a6b1-5914dc4413aa",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ "ax[0].scatter(np.arange(len(nadir_c2_100)),nadir_c2_100['init_yaw'],label='yaw',s=1)\n",
+ "ax[0].scatter(np.arange(len(nadir_c2_100)),nadir_c2_100['init_pitch'],label='pitch',s=1)\n",
+ "ax[0].scatter(np.arange(len(nadir_c2_100)),nadir_c2_100['init_roll'],label='roll',s=1)\n",
+ "\n",
+ "ax[1].scatter(np.arange(len(nadir_c2_100)),nadir_c2_100['opt_yaw'],label='yaw',s=1)\n",
+ "ax[1].scatter(np.arange(len(nadir_c2_100)),nadir_c2_100['opt_pitch'],label='pitch',s=1)\n",
+ "ax[1].scatter(np.arange(len(nadir_c2_100)),nadir_c2_100['opt_roll'],label='roll',s=1)\n",
+ "\n",
+ "ax[0].set_title('Nadir cameras initial')\n",
+ "ax[1].set_title('Nadir cameras optimised')\n",
+ "ax[0].set_ylabel('Degrees')\n",
+ "ax[0].set_xlabel('Frame number')\n",
+ "ax[1].set_xlabel('Frame number')\n",
+ "ax[0].legend()\n",
+ "ax[1].legend()\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "id": "6321667b-fc2d-49df-b8ff-7d3d35ff38f7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ "deg=3\n",
+ "ax[0].plot(np.arange(len(nadir_c2_100)),poly_resid(nadir_c2_100,'init_yaw',deg=deg),label='yaw')\n",
+ "ax[0].plot(np.arange(len(nadir_c2_100)),poly_resid(nadir_c2_100,'init_pitch',deg=deg),label='pitch')\n",
+ "ax[0].plot(np.arange(len(nadir_c2_100)),poly_resid(nadir_c2_100,'init_roll',deg=deg),label='roll')\n",
+ "\n",
+ "ax[1].plot(np.arange(len(nadir_c2_100)),poly_resid(nadir_c2_100,'opt_yaw',deg=deg),label='yaw')\n",
+ "ax[1].plot(np.arange(len(nadir_c2_100)),poly_resid(nadir_c2_100,'opt_pitch',deg=deg),label='pitch')\n",
+ "ax[1].plot(np.arange(len(nadir_c2_100)),poly_resid(nadir_c2_100,'opt_roll',deg=deg),label='roll')\n",
+ "\n",
+ "ax[0].set_title('Nadir cameras initial')\n",
+ "ax[1].set_title('Nadir cameras optimised')\n",
+ "\n",
+ "ax[0].legend()\n",
+ "ax[1].legend()\n",
+ "\n",
+ "ax[0].set_ylabel('Degrees')\n",
+ "ax[0].set_xlabel('Frame number')\n",
+ "ax[1].set_xlabel('Frame number')\n",
+ "plt.suptitle('Degree 3 fit')\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "id": "aefc0791-03eb-46a1-8ad0-1654f9edeaf4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "r = R.from_quat(nadir_c2_100[['qx_ecef','qy_ecef','qz_ecef','qw_ecef']].values).as_euler('ZYX', degrees=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "id": "2d1389cf-fb1e-4bbf-be7f-4ae1ba41afde",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/miniconda3/envs/bhushan_PY3/lib/python3.8/site-packages/geopandas/geodataframe.py:1322: SettingWithCopyWarning: \n",
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
+ "\n",
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
+ " super(GeoDataFrame, self).__setitem__(key, value)\n"
+ ]
+ }
+ ],
+ "source": [
+ "nadir_c2_100['ephem_yaw'] = r[:,0]\n",
+ "nadir_c2_100['ephem_pitch'] = r[:,1]\n",
+ "nadir_c2_100['ephem_roll'] = r[:,2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "id": "846a4011-cb5f-49bb-b41d-7ffd6cca3e87",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ "nx = np.arange(len(nadir_c2_100))\n",
+ "ax[0].scatter(nx,nadir_c2_100['ephem_yaw'],label='yaw',s=1)\n",
+ "ax[0].scatter(nx,nadir_c2_100['ephem_pitch'],label='pitch',s=1)\n",
+ "ax[0].scatter(nx,nadir_c2_100['ephem_roll'],label='roll',s=1)\n",
+ "\n",
+ "ax[1].scatter(nx,nadir_c2_100['opt_yaw'],label='yaw',s=1)\n",
+ "ax[1].scatter(nx,nadir_c2_100['opt_pitch'],label='pitch',s=1)\n",
+ "ax[1].scatter(nx,nadir_c2_100['opt_roll'],label='roll',s=1)\n",
+ "\n",
+ "ax[0].set_title('Nadir cameras Ephemris')\n",
+ "ax[1].set_title('Nadir cameras optimised')\n",
+ "\n",
+ "ax[0].legend()\n",
+ "ax[1].legend()\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "id": "79227ff2-90bc-47cb-bc7b-6a6f2bae2c66",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 46,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(subplot_kw={'projection': 'polar'})\n",
+ "az_for = np.deg2rad(for_c2_100['sat_az'])\n",
+ "el = 90 - for_c2_100['sat_elev']\n",
+ "ax.scatter(az_for, el, label='For', s=3)\n",
+ "\n",
+ "az_for = np.deg2rad(nadir_c2_100['sat_az'])\n",
+ "el = 90 - nadir_c2_100['sat_elev']\n",
+ "ax.scatter(az_for, el, label='Nadir', s=3)\n",
+ "\n",
+ "az_for = np.deg2rad(aft_c2_100['sat_az'])\n",
+ "el = 90 - aft_c2_100['sat_elev']\n",
+ "ax.scatter(az_for, el, label='Aft', s=3)\n",
+ "\n",
+ "\n",
+ "ax.set_rmin(0)\n",
+ "ax.set_rmax(70)\n",
+ "\n",
+ "ax.legend()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "id": "f8e22368-20b0-4bab-9664-9b5395005fd2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from pyproj import Transformer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "id": "7f827836-88b3-43c3-b7c0-2e7de4ea8566",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def plot_skysat_ground_space(gdf,ax,color,label):\n",
+ " \"\"\"\n",
+ " Plot skysat footprint and space track\n",
+ " \"\"\"\n",
+ " gdf_unary = gpd.GeoDataFrame({'idx':[0],'geometry':gdf.unary_union},crs=gdf.crs)\n",
+ " ecef2utm = Transformer.from_crs('EPSG:4978',gdf.crs)\n",
+ " sat_pos = ecef2utm.transform(gdf['x_sat_ecef_km']*1000,gdf['y_sat_ecef_km']*1000,gdf['z_sat_ecef_km']*1000)\n",
+ " gdf_unary.plot(ax=ax,facecolor=color)\n",
+ " ax.scatter(sat_pos[0],sat_pos[1],c=color,s=3,label=label)\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "id": "18b35046-7a2b-40b2-8304-967356000f5a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 49,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots(figsize=(5,8))\n",
+ "plot_skysat_ground_space(for_c2_100,ax,'blue',label='Forward')\n",
+ "plot_skysat_ground_space(nadir_c2_100,ax,'green',label='Nadir')\n",
+ "plot_skysat_ground_space(aft_c2_100,ax,'red',label='Aft')\n",
+ "ax.legend()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "id": "d358b661-53af-4636-9dd4-13d873c43038",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def df2gdf(df):\n",
+ " df = df.rename(columns={'# lon':'lon',' lat':'lat',' height_above_datum':'height_above_datum',' mean_residual':'mean_residual'})\n",
+ " df['geometry'] = df.apply(point_convert, axis=1)\n",
+ " gdf = gpd.GeoDataFrame(df,geometry='geometry',crs='epsg:4326')\n",
+ " gdf = gdf.to_crs('epsg:3857')\n",
+ " gdf = gdf.sort_values('mean_residual',ascending=True)\n",
+ " return gdf\n",
+ "def point_convert(row):\n",
+ " from shapely.geometry import Point\n",
+ " geom = Point(row['lon'],row['lat'])\n",
+ " return geom"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "id": "81b872bd-f59d-49a5-be1e-a72e150da91a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "reproj_error = df2gdf(pd.read_csv('c2_strip_full_sfm/run-final_residuals_no_loss_function_pointmap_point_log.csv',skiprows=[1]))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "id": "c5dc7b01-a232-4478-90b0-d403de156b41",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " lon \n",
+ " lat \n",
+ " height_above_datum \n",
+ " mean_residual \n",
+ " num_observations \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 60361.000000 \n",
+ " 60361.000000 \n",
+ " 60361.000000 \n",
+ " 6.036100e+04 \n",
+ " 60361.000000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 131.037905 \n",
+ " -25.372628 \n",
+ " 512.342602 \n",
+ " 3.557947e-01 \n",
+ " 13.971621 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 0.007098 \n",
+ " 0.052496 \n",
+ " 275.009452 \n",
+ " 9.518729e-01 \n",
+ " 14.497970 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 131.017656 \n",
+ " -25.471764 \n",
+ " -2968.950932 \n",
+ " 3.625870e-07 \n",
+ " 2.000000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 131.031757 \n",
+ " -25.417596 \n",
+ " 495.531595 \n",
+ " 7.502979e-02 \n",
+ " 2.000000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 131.037528 \n",
+ " -25.367498 \n",
+ " 502.832402 \n",
+ " 1.200681e-01 \n",
+ " 7.000000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 131.043957 \n",
+ " -25.327641 \n",
+ " 510.039080 \n",
+ " 1.564852e-01 \n",
+ " 23.000000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 131.057608 \n",
+ " -25.275769 \n",
+ " 3983.472909 \n",
+ " 1.092883e+01 \n",
+ " 54.000000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " lon lat height_above_datum mean_residual \\\n",
+ "count 60361.000000 60361.000000 60361.000000 6.036100e+04 \n",
+ "mean 131.037905 -25.372628 512.342602 3.557947e-01 \n",
+ "std 0.007098 0.052496 275.009452 9.518729e-01 \n",
+ "min 131.017656 -25.471764 -2968.950932 3.625870e-07 \n",
+ "25% 131.031757 -25.417596 495.531595 7.502979e-02 \n",
+ "50% 131.037528 -25.367498 502.832402 1.200681e-01 \n",
+ "75% 131.043957 -25.327641 510.039080 1.564852e-01 \n",
+ "max 131.057608 -25.275769 3983.472909 1.092883e+01 \n",
+ "\n",
+ " num_observations \n",
+ "count 60361.000000 \n",
+ "mean 13.971621 \n",
+ "std 14.497970 \n",
+ "min 2.000000 \n",
+ "25% 2.000000 \n",
+ "50% 7.000000 \n",
+ "75% 23.000000 \n",
+ "max 54.000000 "
+ ]
+ },
+ "execution_count": 52,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "reproj_error.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eb5aa45a-3fa6-45bd-b6d3-36ac7e8bebbb",
+ "metadata": {},
+ "source": [
+ "### FFT signal analysis\n",
+ "#### With residual of degree 2 (roll angle, Foreward scan)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "id": "cd9ef5b4-fd5d-4543-ba5e-282ebfb72799",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "roll_angle_residual = poly_resid(for_c2_100,'opt_roll',deg=2).values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "id": "7ced6ca3-1c0f-4c9d-81dc-b3704d48f988",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fft_roll_fore = np.fft.fft(roll_angle_residual)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "id": "d1ad42f2-68f0-49c4-9602-1b5c566fd15a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-2.27373675e-13+0.00000000e+00j, 4.42427981e-04-2.96686157e-03j,\n",
+ " -5.28713977e-05+1.71745820e-03j, -1.51895388e-04+2.30732983e-03j,\n",
+ " 5.76824313e-05+1.26603794e-03j, 2.05368610e-03+1.06066111e-03j,\n",
+ " -1.21156506e-02+2.48276704e-03j, -3.02685048e-03+1.01324621e-03j,\n",
+ " -2.12647486e-03+1.24915155e-03j, -2.07220701e-03+1.16987278e-03j,\n",
+ " -2.71974343e-03+1.15216283e-03j, -5.49532390e-03+2.75076618e-03j,\n",
+ " 5.65646528e-03-3.43392868e-03j, 9.28239436e-04-6.99249024e-04j,\n",
+ " 2.01168723e-04-2.72176037e-04j, -2.26762275e-04-2.40369074e-06j,\n",
+ " -5.20237823e-04+2.62781374e-04j, -1.84899641e-03+1.67692099e-03j,\n",
+ " 5.85929010e-04-1.62917163e-03j, -1.10992006e-04-8.47104529e-04j,\n",
+ " -4.72975335e-04-7.25552171e-04j, -4.12896537e-04-1.37911550e-03j,\n",
+ " -1.24748051e-03-1.64512226e-03j, -7.59658958e-03-7.91204708e-03j,\n",
+ " 1.75406437e-03+1.58204284e-03j, 5.52422726e-04+5.78336281e-04j,\n",
+ " 2.74555323e-04+2.70038504e-04j, 1.02346573e-04+8.90610202e-05j,\n",
+ " -6.68434265e-05+6.24611089e-05j, 4.80845286e-03-6.16526923e-03j,\n",
+ " -2.03611695e-04-1.07240733e-04j, -2.95159617e-04-1.52146786e-04j,\n",
+ " -4.40255902e-04-1.77777767e-04j, -8.56141231e-04-3.43289701e-04j,\n",
+ " -1.93040592e-03-4.52432030e-04j, 8.59663827e-03+6.69399983e-06j,\n",
+ " 1.46322837e-03-4.17971483e-04j, 8.14511952e-04-6.66413790e-04j,\n",
+ " 6.83933117e-04-8.56203521e-04j, 4.01222203e-04-1.30933450e-03j,\n",
+ " 3.62028913e-04-3.23477749e-03j, 1.21846234e-04+4.29164134e-03j,\n",
+ " 2.62536224e-04+9.93285129e-04j, 2.87797963e-04+2.74396364e-04j,\n",
+ " 2.87797963e-04-2.74396364e-04j, 2.62536224e-04-9.93285129e-04j,\n",
+ " 1.21846234e-04-4.29164134e-03j, 3.62028913e-04+3.23477749e-03j,\n",
+ " 4.01222203e-04+1.30933450e-03j, 6.83933117e-04+8.56203521e-04j,\n",
+ " 8.14511952e-04+6.66413790e-04j, 1.46322837e-03+4.17971483e-04j,\n",
+ " 8.59663827e-03-6.69399983e-06j, -1.93040592e-03+4.52432030e-04j,\n",
+ " -8.56141231e-04+3.43289701e-04j, -4.40255902e-04+1.77777767e-04j,\n",
+ " -2.95159617e-04+1.52146786e-04j, -2.03611695e-04+1.07240733e-04j,\n",
+ " 4.80845286e-03+6.16526923e-03j, -6.68434265e-05-6.24611089e-05j,\n",
+ " 1.02346573e-04-8.90610202e-05j, 2.74555323e-04-2.70038504e-04j,\n",
+ " 5.52422726e-04-5.78336281e-04j, 1.75406437e-03-1.58204284e-03j,\n",
+ " -7.59658958e-03+7.91204708e-03j, -1.24748051e-03+1.64512226e-03j,\n",
+ " -4.12896537e-04+1.37911550e-03j, -4.72975335e-04+7.25552171e-04j,\n",
+ " -1.10992006e-04+8.47104529e-04j, 5.85929010e-04+1.62917163e-03j,\n",
+ " -1.84899641e-03-1.67692099e-03j, -5.20237823e-04-2.62781374e-04j,\n",
+ " -2.26762275e-04+2.40369074e-06j, 2.01168723e-04+2.72176037e-04j,\n",
+ " 9.28239436e-04+6.99249024e-04j, 5.65646528e-03+3.43392868e-03j,\n",
+ " -5.49532390e-03-2.75076618e-03j, -2.71974343e-03-1.15216283e-03j,\n",
+ " -2.07220701e-03-1.16987278e-03j, -2.12647486e-03-1.24915155e-03j,\n",
+ " -3.02685048e-03-1.01324621e-03j, -1.21156506e-02-2.48276704e-03j,\n",
+ " 2.05368610e-03-1.06066111e-03j, 5.76824313e-05-1.26603794e-03j,\n",
+ " -1.51895388e-04-2.30732983e-03j, -5.28713977e-05-1.71745820e-03j,\n",
+ " 4.42427981e-04+2.96686157e-03j])"
+ ]
+ },
+ "execution_count": 55,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fft_roll_fore"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "id": "4c609396-7d77-4dd8-8bcf-e41b6c859c02",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Value at index 0:\t(0.0004424279810439861-0.0029668615694374385j) \n",
+ "Value at index 86:\t(0.00044242798104398597+0.0029668615694374385j)\n",
+ "Value at index 1:\t(-5.287139774843121e-05+0.0017174581972074915j) \n",
+ "Value at index 85:\t(-5.2871397748431104e-05-0.0017174581972074924j)\n"
+ ]
+ }
+ ],
+ "source": [
+ "for i in range(2):\n",
+ " print(\"Value at index {}:\\t{}\".format(i, fft_roll_fore[i + 1]), \"\\nValue at index {}:\\t{}\".format(fft_roll_fore.size -1 - i, fft_roll_fore[-1 - i]))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ee1d13a6-ceb4-45c4-a713-504664862c14",
+ "metadata": {},
+ "source": [
+ "Here instead of time, lets assume frame to frame variation."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "id": "e6ed72a9-2474-4937-8b3a-135390b33c3b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "87"
+ ]
+ },
+ "execution_count": 57,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "N = roll_angle_residual.shape[0]\n",
+ "N"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "id": "838cdc2c-b272-4680-8e52-ec008e61fb23",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from scipy.fft import fft, fftfreq"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "id": "53de7272-b7a2-44f8-948b-f19a946ebdc4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "x_axis = fftfreq(N,1/45) # frequencies ?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 60,
+ "id": "442b1594-56f8-4113-bcc0-eec7b080946b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "y_axis = fft(roll_angle_residual)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "id": "ab1669bf-9622-4b39-8def-e20e1c1352f2",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[]"
+ ]
+ },
+ "execution_count": 61,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "f,ax = plt.subplots()\n",
+ "ax.plot(x_axis, np.abs(y_axis))\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "08471c71-9491-4d13-839f-6969cdbf5e47",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def compute_fft(data, sampling_rate=45):\n",
+ " \n",
+ " '''\n",
+ " Provided kindly by Michelle \n",
+ " Perform discrete fast fourier transform on input data. Handling for 1d and 2d FFT. \n",
+ " Returns: fourier transform, power spectrum, frequencies, sorted indices and inverse transform\n",
+ " '''\n",
+ " n=len(data)\n",
+ " sampling_rate = sampling_rate\n",
+ " time_step=1/sampling_rate\n",
+ " \n",
+ " dim=len(data.shape)\n",
+ " \n",
+ " if dim == 2:\n",
+ " fft_vals = np.fft.fft2(data)\n",
+ " fft_recon = np.fft.ifft2(fft_vals) #inverse Fourier transform\n",
+ " return fft_vals, fft_recon\n",
+ " else:\n",
+ " fft_vals=np.fft.fft(data) # compute fourier transform on the data\n",
+ " fft_recon = np.fft.ifft(fft_vals) #inverse Fourier transform\n",
+ " \n",
+ " power_spectrum=np.abs(fft_vals)**2 # extract the power spectrum \n",
+ " freqs=np.fft.fftfreq(n, time_step) # create necessary frequencies based on sampling rate\n",
+ " idx=np.argsort(freqs)\n",
+ " \n",
+ " return fft_vals, power_spectrum, freqs, idx, fft_recon\n",
+ "\n",
+ "def truncate(n, decimals=2):\n",
+ " '''Return value truncated to specified decimal places. Default hundredths'''\n",
+ " return int(n * 10**decimals) / 10**decimals\n",
+ " \n",
+ "def extract_arr(arr):\n",
+ " '''Extract and return x and y disparity maps and calculate magnitude'''\n",
+ " x=arr[0,:,:]\n",
+ " y=arr[1,:,:]\n",
+ " m=np.sqrt(x**2+y**2)\n",
+ " return(x, y, m)\n",
+ "\n",
+ "def top_freqs(freqs, power_spectrum, thresh=45):\n",
+ " '''Compute and return frequencies at which power spectrum values surpass threshold.'''\n",
+ " location=np.where(power_spectrum>thresh)\n",
+ " max_freqs=freqs[location]\n",
+ " max_power=power_spectrum[location]\n",
+ " \n",
+ " max_power=list(max_power[max_freqs>0])\n",
+ " max_freqs=list(max_freqs[max_freqs>0])\n",
+ " \n",
+ " max_freqs = [truncate(f) for f in max_freqs]\n",
+ " max_power = [truncate(f) for f in max_power]\n",
+ " \n",
+ " return max_freqs, max_power\n",
+ " \n",
+ "def plot_power(freqs, idx, power_spectrum, title=\"Power spectrum values\", color='midnightblue', fig=3, vlim=None, ylims=None):\n",
+ " '''Plot power spectrum values in frequency domain'''\n",
+ " plt.figure(fig)\n",
+ " plt.title(title)\n",
+ " plt.plot(freqs[idx], power_spectrum[idx],color=color)\n",
+ " if ylims is not None:\n",
+ " plt.ylim(ylims[0], ylims[1])\n",
+ " if vlim is not None:\n",
+ " plt.xlim(vlim[0], vlim[1])\n",
+ " else:\n",
+ " plt.xlim(0,20);\n",
+ " plt.xlabel(\"Hertz\");"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "id": "065d57ae-33e6-4839-bff0-2356f709a6cd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(roll_angle_residual)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "id": "6b0bf7cf-c0cd-4739-81e4-644bf3f86444",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(roll_angle_residual)\n",
+ "plot_power(freqs, idx, power_spectrum)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "58ac8949-378d-4cd4-8d85-4f2a94a88af6",
+ "metadata": {},
+ "source": [
+ "#### With original time series (roll angle, Foreward scan)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "id": "e096700d-8e37-47f7-8714-a09694639db9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(for_c2_100.opt_roll.values)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "id": "485c2686-3a55-4a3a-9f28-82a0a5a3bcad",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_power(freqs, idx, power_spectrum)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a3b75e9e-e90c-4516-9945-b60ffb0f7c36",
+ "metadata": {},
+ "source": [
+ "### Full time series"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "id": "8c9a4b2a-b2c6-4055-8ecc-5245c9d8a885",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " name \n",
+ " datetime \n",
+ " gsd \n",
+ " sat_az \n",
+ " sat_elev \n",
+ " x_sat_eci_km \n",
+ " y_sat_eci_km \n",
+ " z_sat_eci_km \n",
+ " qw_eci \n",
+ " qx_eci \n",
+ " ... \n",
+ " y_sat_ecef_km \n",
+ " z_sat_ecef_km \n",
+ " qw_ecef \n",
+ " qx_ecef \n",
+ " qy_ecef \n",
+ " qz_ecef \n",
+ " bit_dpth \n",
+ " geom \n",
+ " integration_time_ms \n",
+ " filename \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000 \n",
+ " 2021-04-06T04:09:09.650466+00:00 \n",
+ " 1.135013 \n",
+ " 43.555569 \n",
+ " 54.168736 \n",
+ " 5446.94886 \n",
+ " 3118.34933 \n",
+ " -2698.79227 \n",
+ " 0.653283 \n",
+ " 0.373069 \n",
+ " ... \n",
+ " 4588.27492 \n",
+ " -2687.66724 \n",
+ " 0.215369 \n",
+ " -0.712615 \n",
+ " 0.088349 \n",
+ " -0.661809 \n",
+ " 16 \n",
+ " POLYGON ((706378.314 7201186.637, 703496.725 7... \n",
+ " 0.52316 \n",
+ " 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 1301717367.67254806_sc00108_c2_PAN_i0000000001 \n",
+ " 2021-04-06T04:09:09.672548+00:00 \n",
+ " 1.134851 \n",
+ " 43.562772 \n",
+ " 54.176972 \n",
+ " 5446.90313 \n",
+ " 3118.29668 \n",
+ " -2698.94581 \n",
+ " 0.653341 \n",
+ " 0.373022 \n",
+ " ... \n",
+ " 4588.24975 \n",
+ " -2687.82088 \n",
+ " 0.215390 \n",
+ " -0.712554 \n",
+ " 0.088362 \n",
+ " -0.661865 \n",
+ " 16 \n",
+ " POLYGON ((706377.030 7201121.192, 703495.434 7... \n",
+ " 0.46002 \n",
+ " 1301717367.67254806_sc00108_c2_PAN_i0000000001... \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
2 rows × 23 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " name \\\n",
+ "0 1301717367.65046573_sc00108_c2_PAN_i0000000000 \n",
+ "1 1301717367.67254806_sc00108_c2_PAN_i0000000001 \n",
+ "\n",
+ " datetime gsd sat_az sat_elev \\\n",
+ "0 2021-04-06T04:09:09.650466+00:00 1.135013 43.555569 54.168736 \n",
+ "1 2021-04-06T04:09:09.672548+00:00 1.134851 43.562772 54.176972 \n",
+ "\n",
+ " x_sat_eci_km y_sat_eci_km z_sat_eci_km qw_eci qx_eci ... \\\n",
+ "0 5446.94886 3118.34933 -2698.79227 0.653283 0.373069 ... \n",
+ "1 5446.90313 3118.29668 -2698.94581 0.653341 0.373022 ... \n",
+ "\n",
+ " y_sat_ecef_km z_sat_ecef_km qw_ecef qx_ecef qy_ecef qz_ecef \\\n",
+ "0 4588.27492 -2687.66724 0.215369 -0.712615 0.088349 -0.661809 \n",
+ "1 4588.24975 -2687.82088 0.215390 -0.712554 0.088362 -0.661865 \n",
+ "\n",
+ " bit_dpth geom \\\n",
+ "0 16 POLYGON ((706378.314 7201186.637, 703496.725 7... \n",
+ "1 16 POLYGON ((706377.030 7201121.192, 703495.434 7... \n",
+ "\n",
+ " integration_time_ms filename \n",
+ "0 0.52316 1301717367.65046573_sc00108_c2_PAN_i0000000000... \n",
+ "1 0.46002 1301717367.67254806_sc00108_c2_PAN_i0000000001... \n",
+ "\n",
+ "[2 rows x 23 columns]"
+ ]
+ },
+ "execution_count": 67,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "for_c2.head(2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "id": "8aa8438b-8bf2-47a6-9d98-cdd676fa23ba",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_optimised_camera = np.array([R.from_matrix(np.reshape(asp.read_tsai_dict(f'c2_strip_full_sfm/run-{name}_scipy.tsai')['rotation_matrix'],(3,3))).as_euler('ZYX',degrees=True) for name in for_c2.name.values])\n",
+ "for_original_camera = np.array([R.from_matrix(np.reshape(asp.read_tsai_dict(f'scipy_camera/{name}_scipy.tsai')['rotation_matrix'],(3,3))).as_euler('ZYX',degrees=True) for name in for_c2.name.values])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 69,
+ "id": "bc5cf568-3c50-4388-a8c1-52c94914bb11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_c2['opt_yaw'] = for_optimised_camera[:,0]\n",
+ "for_c2['opt_pitch'] = for_optimised_camera[:,1]\n",
+ "for_c2['opt_roll'] = for_optimised_camera[:,2]\n",
+ "\n",
+ "for_c2['init_yaw'] = for_original_camera[:,0]\n",
+ "for_c2['init_pitch'] = for_original_camera[:,1]\n",
+ "for_c2['init_roll'] = for_original_camera[:,2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "19e06c87-7a09-4911-8900-2fdab5b62dbd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def plot_camera_angles(df,camera,zoom=None):\n",
+ " \"\"\"\n",
+ " Plot camera angles before and after bundle adjustment\n",
+ " \"\"\"\n",
+ " f,ax = plt.subplots(1,2,sharex=True,sharey=True)\n",
+ " ax[0].scatter(np.arange(len(df)),df['init_yaw'],label='yaw',s=1)\n",
+ " ax[0].scatter(np.arange(len(df)),df['init_pitch'],label='pitch',s=1)\n",
+ " ax[0].scatter(np.arange(len(df)),df['init_roll'],label='roll',s=1)\n",
+ "\n",
+ " ax[1].scatter(np.arange(len(df)),df['opt_yaw'],label='yaw',s=1)\n",
+ " ax[1].scatter(np.arange(len(df)),df['opt_pitch'],label='pitch',s=1)\n",
+ " ax[1].scatter(np.arange(len(df)),df['opt_roll'],label='roll',s=1)\n",
+ "\n",
+ " ax[0].set_title(f'{camera} cameras initial')\n",
+ " ax[1].set_title(f'{camera} cameras optimised')\n",
+ " ax[0].set_ylabel('Degrees')\n",
+ " ax[0].set_xlabel('Frame number')\n",
+ " ax[1].set_xlabel('Frame number')\n",
+ " ax[0].legend()\n",
+ " ax[1].legend()\n",
+ "\n",
+ " plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "id": "bb9d526a-b94f-4776-8a30-059a8f89dbf6",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_camera_angles(for_c2,'Foreword')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "38e43e35-3b51-4ea8-9e5b-79a38d512ce9",
+ "metadata": {},
+ "source": [
+ "#### With original time series (roll angle, Foreward scan)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 72,
+ "id": "15782917-8c6d-4626-9f89-eac91c3dab94",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(for_c2.opt_yaw.values)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "id": "4419b652-a173-4d2f-a384-fc0cdeb8e286",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_power(freqs, idx, power_spectrum)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "51d1edbc-c442-45c9-a08f-b2a6e3142446",
+ "metadata": {},
+ "source": [
+ "#### With residual of degree 2 (roll angle, Foreward scan)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "id": "5c0e3d9a-a9fd-416d-a6f3-530a049ca079",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def plot_residuals(df,camera,polydegree=2,zoom=None):\n",
+ " \"\"\"\n",
+ " Plot residuals using a polynomial fit of a given degree\n",
+ " \"\"\"\n",
+ " lw = 0.9\n",
+ " alpha = 1\n",
+ " f,ax = plt.subplots(1,2,sharex=True,sharey=True,figsize=(10,3.5))\n",
+ " ax[0].axhline(y=0,linestyle='--',c='k',linewidth=lw-0.3)\n",
+ " ax[1].axhline(y=0,linestyle='--',c='k',linewidth=lw-0.3)\n",
+ " ax[0].plot(np.arange(len(df)),poly_resid(df,'init_yaw',polydegree),label='yaw',linewidth=lw,alpha=alpha)\n",
+ " ax[0].plot(np.arange(len(df)),poly_resid(df,'init_pitch',polydegree),label='pitch',linewidth=lw,alpha=alpha)\n",
+ " ax[0].plot(np.arange(len(df)),poly_resid(df,'init_roll',polydegree),label='roll',linewidth=lw,alpha=alpha)\n",
+ " \n",
+ " ax[1].plot(np.arange(len(df)),poly_resid(df,'opt_yaw',polydegree),label='yaw',linewidth=lw,alpha=alpha)\n",
+ " ax[1].plot(np.arange(len(df)),poly_resid(df,'opt_pitch',polydegree),label='pitch',linewidth=lw,alpha=alpha)\n",
+ " ax[1].plot(np.arange(len(df)),poly_resid(df,'opt_roll',polydegree),label='roll',linewidth=lw,alpha=alpha)\n",
+ "\n",
+ " ax[0].set_title(f'{camera} cameras initial')\n",
+ " ax[1].set_title(f'{camera} cameras optimised')\n",
+ " ax[0].set_ylabel('Degrees')\n",
+ " ax[0].set_xlabel('Frame number')\n",
+ " ax[1].set_xlabel('Frame number')\n",
+ " ax[0].legend()\n",
+ " ax[1].legend()\n",
+ " if zoom:\n",
+ " ax[0].set_ylim(zoom)\n",
+ " n = len(df)\n",
+ " ax[0].set_xlim((0,n))\n",
+ " #ax[0].grid('--')\n",
+ " plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "id": "2a5de55c-7dfc-4cab-8325-66031c963f60",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_residuals(for_c2,'Foreward')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "id": "bfb6871d-2dfa-47fd-893b-6a274544e3f5",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_residuals(for_c2,'Foreward',2,(-0.001,0.001))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 77,
+ "id": "54d1c1ac-a76a-4ee8-aace-8bd1d872ff04",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(for_c2,'opt_roll',2).values)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "id": "267d8c03-1843-4c6d-a51c-b5aa3b17b3c6",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_power(freqs, idx, power_spectrum,title='Power spectrum Foreward camera roll residuals')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "id": "41125786-c78b-4837-8ae2-60b97f94c682",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(for_c2,'opt_yaw',2).values)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "id": "022b053e-e7e2-4b06-b8d6-ad05a8c9d9a6",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_power(freqs, idx, power_spectrum,title='Power spectrum Foreward camera yaw residuals')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 81,
+ "id": "1fa7ffb6-123e-4521-8b36-9d16c7cf1647",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(for_c2,'opt_pitch',2).values)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "id": "b6ad17d6-66c8-4c99-8622-f5c59d12dc48",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_power(freqs, idx, power_spectrum,title='Power spectrum Foreward camera pitch residuals')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "d6df41b1-9d61-498f-92df-54ca6a94e57c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def produce_m(lon,lat,m_meridian_offset=0):\n",
+ " \"\"\"\n",
+ " Produce M matrix which facilitates conversion from Lon-lat to ECEF coordinates\n",
+ " https://github.com/visionworkbench/visionworkbench/blob/master/src/vw/Cartography/Datum.cc#L249\n",
+ " This is known as direction cosie matrix\n",
+ " lon: numeric\n",
+ " longitude of spacecraft\n",
+ " lat: numeric\n",
+ " latitude of spacecraft\n",
+ " \"\"\"\n",
+ " if lat < -90:\n",
+ " lat = -90\n",
+ " if lat > 90:\n",
+ " lat = 90\n",
+ " \n",
+ " rlon = (lon + m_meridian_offset) * (np.pi/180)\n",
+ " rlat = lat * (np.pi/180)\n",
+ " slat = np.sin(rlat)\n",
+ " clat = np.cos(rlat)\n",
+ " slon = np.sin(rlon)\n",
+ " clon = np.cos(rlon)\n",
+ " \n",
+ " R = np.ones((3,3),dtype=float)\n",
+ " R[0,0] = -slat*clon\n",
+ " R[1,0] = -slat*slon\n",
+ " R[2,0] = clat\n",
+ " R[0,1] = -slon\n",
+ " R[1,1] = clon\n",
+ " R[2,1] = 0.0\n",
+ " R[0,2] = -clon*clat\n",
+ " R[1,2] = -slon*clat\n",
+ " R[2,2] = -slat\n",
+ " return R"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 101,
+ "id": "8332a8a6-699c-41a4-9d8d-079b6ce1b601",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-1])"
+ ]
+ },
+ "execution_count": 101,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "-np.array([1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "efe1886e-08ef-4157-b851-d3401cee0f90",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def convert_ecef2NED(asp_rotation,lon,lat):\n",
+ " \"\"\"\n",
+ " convert rotation matrices from ECEF to North-East-Down convention\n",
+ " \"\"\"\n",
+ " m = produce_m(lon,lat)\n",
+ " r_ned = np.matmul(np.linalg.inv(m),asp_rotation)\n",
+ " #r_ned = np.matmul(np.transpose(m),asp_rotation)\n",
+ " #r_ned = np.matmul(m,asp_rotation)\n",
+ " return r_ned"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 188,
+ "id": "46d04239-02d2-4a51-a588-33b2862cc80e",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1.5707963267948966"
+ ]
+ },
+ "execution_count": 188,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "np.deg2rad(90)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "74f8f50a-253f-42f4-b810-1893a63deca5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ned_rotation_from_tsai(tsai_fn):\n",
+ " #coordinate conversion step\n",
+ " from pyproj import Transformer\n",
+ " ecef_proj = 'EPSG:4978'\n",
+ " geo_proj = 'EPSG:4326'\n",
+ " ecef2wgs = Transformer.from_crs(ecef_proj,geo_proj)\n",
+ " \n",
+ " # read tsai files\n",
+ " asp_dict = asp.read_tsai_dict(tsai_fn)\n",
+ " \n",
+ " # get camera position\n",
+ " cam_cen = asp_dict['cam_cen_ecef']\n",
+ " lat,lon,h = ecef2wgs.transform(*cam_cen)\n",
+ " #print(lat,lon)\n",
+ " # get camera rotation angle\n",
+ " rot_mat = np.reshape(asp_dict['rotation_matrix'],(3,3))\n",
+ " \n",
+ " #rotate about z axis by 90 degrees\n",
+ " #https://math.stackexchange.com/questions/651413/given-the-degrees-to-rotate-around-axis-how-do-you-come-up-with-rotation-matrix\n",
+ " rot_z = np.zeros((3,3),float)\n",
+ " angle = np.pi/2\n",
+ " rot_z[0,0] = np.cos(angle) \n",
+ " rot_z[0,1] = -1 * np.sin(angle)\n",
+ " rot_z[1,0] = np.sin(angle)\n",
+ " rot_z[1,1] = np.cos(angle)\n",
+ " rot_z[2,2] = 1\n",
+ " \n",
+ " \n",
+ " \n",
+ " #return np.matmul(rot_z,convert_ecef2NED(rot_mat,lon,lat))\n",
+ " return R.from_matrix(np.matmul(rot_z,np.linalg.inv(convert_ecef2NED(rot_mat,lon,lat)))).as_euler('ZYX',degrees=True)\n",
+ " \n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81da9eb9-4c3f-4b4c-aaa5-ee54d42226f0",
+ "metadata": {},
+ "source": [
+ "### With correct order of angles (y-p-r)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "9633133d-c285-4a1d-a25d-18e2fad181f5",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/change/s108_20210406T040909Z\n"
+ ]
+ }
+ ],
+ "source": [
+ "! pwd"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "28699e91-5dd9-405a-a496-4e38923f89ae",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/nobackupp11/sbhusha1/change/processing\n"
+ ]
+ }
+ ],
+ "source": [
+ "%cd ../processing/"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "id": "faacbe40-3378-4661-a94f-9833334ce0a1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_optimised_camera = np.array([ned_rotation_from_tsai(f'c2_strip_full_sfm/run-{name}_scipy.tsai') for name in for_c2.name.values])\n",
+ "for_original_camera = np.array([ned_rotation_from_tsai(f'scipy_camera/{name}_scipy.tsai') for name in for_c2.name.values])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "90dee0ac-fbcb-4ab4-bed5-56a22e282bbd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for_c2['opt_yaw'] = for_optimised_camera[:,0]\n",
+ "for_c2['opt_pitch'] = for_optimised_camera[:,1]\n",
+ "for_c2['opt_roll'] = for_optimised_camera[:,2]\n",
+ "for_c2['init_yaw'] = for_original_camera[:,0]\n",
+ "for_c2['init_pitch'] = for_original_camera[:,1]\n",
+ "for_c2['init_roll'] = for_original_camera[:,2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "id": "632b7631-73f6-4142-9050-540166ca6d1c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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bXWRMjOzwnKRMjOzwmp3kZLUR9Im5QjGzMwsq6QiJek6SZtIGkRydd0CSWeUNzSz7vftb3+biy+++L33Z599NpdccglTpkxh9913Z5ddduH2228H4MILL+SSSy4B4LTTTmP//fcH4C9/+QvHHHNM9wdv1k6VkO+l7kmNi4g3gMOAPwKjgBavwjPrLstWvcNl9y9k2ap3umR+J554IldffTUA69ev5/rrr+dzn/sct956K48++ij33nsvp59+OhHBpEmTeOCBBwCoq6tj5cqVrF27llmzZjFx4sQuiccsqzfme6mXoFdJqiIpUj+PiLWSmr0lkVl3uqnuJb5/1zMAnDx5TKfnV1NTw7Bhw5g7dy5Llixht912Y+jQoZx22mnMnDmTPn368PLLL7NkyRL22GMP5syZw5tvvsmAAQPYfffdqaur44EHHnhvi9OsK/XGfC+1SF1G8sPax4GZkrYF3ihXUGalOrJ25AZ/u8JJJ53EVVddxT//+U9OOOEErr32WhoaGpgzZw5VVVXU1NSwevXq97qvvPJKPv7xjzN+/HjuvfdeFi5cyI477thl8Zg16o35XtLhvoi4JCK2iYjPROJF4BNli8qsREMH9efkyWMYOqh/l83z8MMP509/+hOzZ8/mwAMPZMWKFWy++eZUVVVx77338uKLL7437qRJk/jxj3/MpEmTmDhxIpdeeikTJkzoVb9/se7TG/O91AsntpD0a0l3pe/HAceVLSqzHPXv359PfOITfPazn6Vv375MmzaNuro6amtrufbaa/nIRz7y3rgTJ05k8eLF7L333myxxRYMHDjQ56OsohQ930s93HcVcCVwdvr+78ANwK/LEJNZrtavX8/DDz/MTTfdBMDw4cN56KGHmh13ypQprF279r33f//737slRrOuUvR8L/XqvuERcSOwHiAi3gV8c1frcZ5++mm23357pkyZwtixY/MOx6ysKiHfS92TWiVpGOlDBiXtBawoW1RmORk3bhzPP/983mGYdYtKyPdSi9TXSZ7nNEbSg0A1MLVsUZmZmVFikYqIRyVNBj5M8hj3BRGxto3JzMzMOqWkIiXpQyR7U9tGxP+RNFbShyPijrambS9JN5AUQ4AhwPKImCCpBpgPLEiHPRwRp3T18s3MrDhKPdx3JTAH2Dt9Xw/cBHR5kYqIzzV2S/pPNjz3tTAiJnT1Ms3M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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_camera_angles(for_c2,'Foreward')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "35d7cd42-d736-4c92-aa0a-51a07a9c92d0",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_residuals(for_c2,'Foreward',1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "b869bd5b-c6ac-4a32-a487-165d870e0405",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_residuals(for_c2,'Foreward',1,(-0.05,0.05))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "8eb24500-58f7-40d6-9ba4-ec6bc20ef805",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "nadir_optimised_camera = np.array([ned_rotation_from_tsai(f'c2_strip_full_sfm/run-{name}_scipy.tsai') for name in nadir_c2.name.values])\n",
+ "nadir_original_camera = np.array([ned_rotation_from_tsai(f'scipy_camera/{name}_scipy.tsai') for name in nadir_c2.name.values])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "id": "a7d8882d-ca4f-41d3-bb80-b30960c597ab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "nadir_c2['opt_yaw'] = nadir_optimised_camera[:,0]\n",
+ "nadir_c2['opt_pitch'] = nadir_optimised_camera[:,1]\n",
+ "nadir_c2['opt_roll'] = nadir_optimised_camera[:,2]\n",
+ "nadir_c2['init_yaw'] = nadir_original_camera[:,0]\n",
+ "nadir_c2['init_pitch'] = nadir_original_camera[:,1]\n",
+ "nadir_c2['init_roll'] = nadir_original_camera[:,2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "id": "e865fb05-966d-41bf-8961-25b29fbb519f",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_camera_angles(nadir_c2,'Nadir')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "id": "e1f93c98-364c-4e84-87ec-d86f35708d64",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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ylNEZAPBMsLvUtWXlj/E8uD5il9By6Yk0h69o4lFfc/OphixiJv3+fe973287W1v40Mf+hC+7/PVr36VX/ziF7znPe+hubmZvr4+Lr/8ct785jdz9dVX81d/9Vd88IMfZOfOnSQSCVKpFA8++CBXXXXVosZtqoeV+1MVLUGpalpEfhv4PuACX1TV50Tk/eHzdwB/ArQDnwtHf6RVdUexYi5VniqeX+woylt3dzft7e088cQTHD9+nIsuuoi2tjY+8pGP8MADD+A4DocPH+b48eNccsklPPbYY4yOjhKLxbj44ovZuXMnP/vZz6bOMI0pB6Ve7ot6oa6q3gfcN+OxO7Ju3wrcutxxlZu0pxXVxBeLuHStqF/2/d56663cddddHDt2jPe+9718+ctfpre3l8cee4xoNEp3dzfxeHzq9pe+9CVe+cpXsm3bNn784x+zZ88ezj333GWP21QGK/ensrn4KoCvldXEVyxvfetb+d73vsejjz7K61//eoaHh1m5ciXRaJQf//jHHDhwckWAq6++mk9/+tNcffXVXHXVVdxxxx1ceOGFVXVNi6kMpVzubaqjCuD5lVWDKpaamhpe85rX0Nraiuu63HzzzbzpTW9ix44dXHjhhZxzzjlT21511VV8/OMf54orrqChoYHa2lrrfzJlqZTLvSWoCuD5imc1qNPm+z4PP/ww3/jGNwDo6OjgoYceyrnttddeSyp1cmj/Sy/ZGB5Tnkq53FsTXwVI+4pvNajT8vzzz3PmmWdy7bXXsmXLlmKHY8yyKPVybzWoCuD5imN9H6dl69at7N27t9hhGLOsSr3cWw2qAni+4jqWoIwxlcUSVAXw1BKUMabyWIKqANbEZ4ypRJagKoDvK1aBMsZUGktQxszh1ltv5fnnnwfgE5/4xJzbv+c97+Gb3/zmUodlzJIqhXJvCaoC2OwFS+vzn/88W7cGiz0X8o9qTCUohXJvCcqY0P79+znnnHN497vfzbZt27jpppuYmJjgmmuuYefOndx+++1MTk5y4YUXcvPNNwPwT//0T2zbto3t27fzrne9a+q9HnjgAV75yleyefNmq02ZklbK5d6ugzKlJ52AseOL+56NqyASm3OzXbt28YUvfIErr7yS9773vXzuc5+beu6Tn/wkn/3sZ3nyyScBeO655/j4xz/Oz3/+czo6OhgYGJja9ujRozz4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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_residuals(nadir_c2,'Nadir',1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "id": "64c18098-5e04-4d63-a4da-505a2bd39c43",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_residuals(nadir_c2,'Nadir',1,zoom=(-0.05,0.05))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "ec365c27-cd6e-426d-a6be-528a125cf97d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "aft_optimised_camera = np.array([ned_rotation_from_tsai(f'c2_strip_full_sfm/run-{name}_scipy.tsai') for name in aft_c2.name.values])\n",
+ "aft_original_camera = np.array([ned_rotation_from_tsai(f'scipy_camera/{name}_scipy.tsai') for name in aft_c2.name.values])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "id": "26e0a0ff-eff6-4baf-9f8c-fe863d10180c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "aft_c2['opt_yaw'] = aft_optimised_camera[:,0]\n",
+ "aft_c2['opt_pitch'] = aft_optimised_camera[:,1]\n",
+ "aft_c2['opt_roll'] = aft_optimised_camera[:,2]\n",
+ "aft_c2['init_yaw'] = aft_original_camera[:,0]\n",
+ "aft_c2['init_pitch'] = aft_original_camera[:,1]\n",
+ "aft_c2['init_roll'] = aft_original_camera[:,2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "id": "9413cd9f-52d9-4d6b-a95d-d89e522e9e5e",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_camera_angles(aft_c2,'Aft')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "id": "ff7ffc85-1830-45c4-bbea-d526fe188de7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plot_residuals(aft_c2,'Aft',2,zoom=(-0.01,0.01))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 87,
+ "id": "324da498-7f58-43a0-aa44-51f391a61f70",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.14, 0.29, 0.44, 0.58, 0.73], [0.0, 0.0, 0.0, 0.0, 0.0])"
+ ]
+ },
+ "execution_count": 87,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYwAAAEWCAYAAAB1xKBvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAApHUlEQVR4nO3de7xcZX3v8c93752du4RLkEsCQQgcsArFiLFKi3gjkRJLWwutAl4asaBi8Rzx8vJQq0fUl0WtmpS2KNQL2HqLNghaBCsXTbCIRAgEBLIhhEC4J9nZl9/5Yz2TrMyemb02ZNbsRb7v12tesy7PM/PMmrXmN89lraWIwMzMbDRdnS6AmZlVgwOGmZkV4oBhZmaFOGCYmVkhDhhmZlaIA4aZmRXigFFRkq6R9I5Ol2NnkPRVSR9P08dJ6utAGTryvnVlOEDSU5K6m6w/X9LXdtJ7haRDdsZr2a5jlwkYku6RtDkdkLXHfp0ul1lNRNwXEdMiYqjTZWlE0hmShtKx84SkmyWd2OlydUraHj/vdDnKtMsEjOSP0wFZezwwlsySetpVsBbvKUmV/p6a/WN+rnqOf94bImIaMAP4V+BbkvYouxCdOBafiefavlDpH6KdQdJESZ+T9EB6fE7SxLTuOEl9kj4g6UHgK5K6JJ0n6S5Jj0jadsBIukTSuWl6/1Tt/5s0f4ikjSkA7C7ph5I2SHo0Tc/KlekaSZ+QdB2wCXiBpNdKul3S45K+CKjFZzpG0sr0L3C9pH/IrXulpOslPSZpraQz0vI3SPqflGetpPNzeeakz3K6pPskPSzpwy3e/6uSlkhaLulp4FWSDk+f6zFJqySd9Ay+LiR9PpXvCUk3STo2t+789H1cKunJ9D7zcuuPTp/xSUn/LulypaawBu+zn6Rvp+/od5LeM8bP2zR/s+8nt5170vxBkq5N5f0xsFfuNUY0oSmrRb8m9x43pO29TtIXJfU2Kf9CSb9N73O/pPe3/hYgIoaBi4HJZPvnbmm7b5B0r6SPKP3RSfMvSdNvTp/xiDT/DknfS9Otjq3atnm7pPuAqxt8jr2UHUuPKTvW/jtXhnskfTB9zkclfUXSpFzeE5XVmB5Tdny8OLdutqTvpM/2SNqWhwNLgZcrq3E91mJf2KH5WHU1k/S5/kbSnek7+HtJB6fv74m0HRp+d6WLiF3iAdwDvKbB8o8BNwJ7AzOB64G/T+uOAwaBTwETyQ6Oc1L6WWnZPwHfTOnfBvwgTf8lcBdweW7d99P0nsCfAlOA6cC/A9/Lleka4D7ghUBPKtcTwJ8BE4D3pXK9o8lnvQF4S5qeBsxP0wcATwKnptfZEzgq91lfRPYn4sXAeuCNad0cIIB/TtvgSKAfOLzJ+38VeBx4RXq96cAa4ENAL3B8KsdhufQfz5Wjr8X3+OZU7h7gXOBBYFJadz6wBVgIdAOfBG5M63qBe4H3ps9+MrC10fumMt8EfDTlewFwN/D6gp93Sqv8Lb6f2nbuyaX7B7L97A/TNvtas+1Ebh8HXgLMT9tpDnAbcE4ubQCHpOl1wLFpenfg6Caf8wzg52m6J23LJ4HdgEuB76fveg5wB/D2lPZS4Nw0fRHZcfGu3Lr3pelzaH5s1bbNpcBUYHKD8n2S7Ed8QnocCyi3bW4FZgN7ANflvvujgYeAl5HtN6en9BPT/K+BC9P7TgJeWb89WuwLk8iO53c02o6572IZ8DyyY74f+C+y/WY34LfA6Z3+DY2IXS5gPAU8lh7fS8vvAhbm0r0euCe2H5RbST9IadltwKtz8/sCA+kAOji9dlfacd/J9h+hS4C/bVK2o4BHc/PXAB/LzZ9G+uFL8wL6aB4wfgb8HbBX3fIPAt8tuL0+B1yYpueknXpWbv0vgVOa5P0qcGlu/liyH/au3LJvAufn0hcKGA3e61HgyDR9PvCT3LojgM1p+g+B+0k/IGnZzxu9L9kPx30Ntt1XCn7elvlbfD+17dxDFtwHgam59d+gYMBoUMZz8t89OwaM+9K++rxRtvUZqUyPAQ+T/bi/huxHtR84Ipf2ncA1afrtwLLc8fMO4LI0fy8pQNH62Kptmxe0KN/HyILWIQ3W3QOcmZtfCNyVppeQ/iTm1q8G/gh4ObCBFMQbbI9GAePSumXXMHrAeEVu/ibgA7n5zwKfK3pMtPOxqzVJvTEiZqTHG9Oy/ch22pp707KaDRGxJTd/IPDdVHV9jGwnHwKeHxF3kQWlo8h+JH8IPCDpMLKd71oASVMk/VOqqj9B9gMyQzu2d67NTe+Xn49sL8qvr/d24FDgdkkrtL1jcjZZgBxB0ssk/TRVux8HziTXBJI8mJveRPbvuJkR5Y+sGaPmXmD/FvkbknSupNuUNc09RvYPLF/O+jJOSk08+wH3p23XqIx5BwL71b7j9D4fAp7fomj51xotf7PvJ28/sj8RT+eW3dsgXUOSDk3NMw+mfez/MfL7rPlTsh/Qe1MT2MtbvPSN6fjZKyLmR8RP0uvWanD5sta+32uBYyXtQxZcLgdeIWkO2fd3c0rX9NjKvW6r/f4zZDXZqyTdLem8uvX5vPnj/EDg3Lrva3ZaPxu4NyIGW7xvvVZlbGZ9bnpzg/lWx1ppdrWA0cgDZDtMzQFpWU3smJy1wIJc4JkREZMi4v60/lqypqPetOxashrC7mw/MM4FDgNeFhHPI/v3Czv2S+Tfdx3ZjpslkpSfrxcRd0bEqWTNbJ8C/kPS1FT2g5tk+wZZtXh2ROxGVkNq2k9SQL78DwCztWPn/QFk//gLU9Zf8QHgTcDuETGDrPpfpJzrgP3Ttqtptg3XAr+r+46nR8TCFq9fH4ia5m/x/dSXd/e65Qfkpp8ma/oCtnWuzsytXwLcDsxN+9iHaLKdImJFRCxK5fke8K0Wn7ORh8lqAvXH0f3p9deQBe/3AD+LiCfJAvtisn/atT8Sox1bMPJ4zH+OJyPi3Ih4AfDHwN9KenUuSf77zh/na4FP1L3vlIj4Zlp3gBp3sjcrS/3yHb4rYJ9mn2G8c8DImkY+ImmmpL3I2p1bjXVfCnxC0oEAKd+i3PprgbPJag2QVUffTXZg1IZLTif71/BY6tT7v6OU8T+BF0o6Oe2476HFTpc6FmemA/GxtHgI+DrwGklvktQjaU9JR+XKtDEitkg6hqwPZmf5BdlB838kTZB0HNkBfdkYX2c6WZPIBqBH0kfJ2n2LuIFsG5ydPvsi4JgmaX8JPKFssMNkSd2Sfk/SSwu+V8v8Lb6fbSLiXmAl8HeSeiW9kmyb1dxBVnt6g6QJwEfI2txrppP1ez0l6X8B72pU0PTafyVpt4gYSHnGNKw37dffIjsupqdj42/Z8TiqHRfXpvlr6uZh9GOrJWUd14ekPwW1z5H/LGdJmpWOuQ+R1XQg65s7M9WyJWlq2q7Tyb7LdcAFafkkSa9I+dYDswp0SN8MnJxaFg4hq2FWkgMGfJzswLwF+A3wq7Ssmc+T/RO/StKTZO24L8utv5bsYK0FjJ+T/bv4WS7N58g6j2vtwD9qVcCIeBj4c+AC4BFgLlmnXTMnAKskPZXKe0pEbImI+8iaHs4FNpLtyEemPH8DfCx9po8y9n+Zrcq/FTgJWED2mb8MnBYRt4/xpa4EriD7sbyXrIO7UPU/leFksoP1MbLO8x+Stb3Xpx0i+3E+CvhdKvO/kDWfFHmv0fI3/H4avNRfku1bG8n+VFyae4/Hyb6zfyH7J/80Wb9WzftT/ifJfhAvp7m3APekpqszybbNWL07leFusn3+G2SjqGrqj4v6eRj92BrNXOAnZM3CNwBfjohrcuu/AVyVyng36TiPiJXAXwNfJOsTW0PWz5D/Lg8h6+vpA/4ivd7VwCrgQUkPtyjXhWR9oevJ+jK/PobPNK7URhCY7XIk/QJYGhFf6XRZrL0k3UPW8fyTTpelylzDsF2GpD+StE9qkjqdbPhwy9qdmW1XibMlzXaSw8ia2qaRjRb7s4hY19kimVWHm6TMzKwQN0mZmVkhlWqS2muvvWLOnDmdLoaZWaXcdNNND0fEzNFTtlapgDFnzhxWrlzZ6WKYmVWKpMJXCWjFTVJmZlaIA4aZmRXigGFmZoU4YJiZWSEOGGZmVkihgCHpBEmrJa1pcI352n2nv5DW3yLp6CJ5Jb07rVsl6dPP/uOYmVm7jDqsNl1n/0vAa8mu1LhC0rKI+G0u2QKyK0XOJbu65BLgZa3ySnoVsAh4cUT0S9p7Z34wMzPbuYrUMI4B1kTE3ekS0ZeR/dDnLSK7LWFExI1kd4/bd5S87wIuiIh+gIh4aKyFv+66O1mzZszZzMzsGSgSMPZnx3sO9DHy1prN0rTKeyjZbRt/oey2kA1vTiNpsaSVklZu2LBhh3Xve983+fKXry7wEczM7NkqEjAa3dax/oqFzdK0yttDdtvS+cD/Br5Vd/vMLHHERRExLyLmzZy545ntTz+9la1bx3KrXTMze6aKXBqkjx3vhTuLHe953SpNb4u8fcB3Irtc7i8lDZPdTH7HakQL/f0DDA0Nj57QzMyetSI1jBXAXEkHpXvXnkJ2G8W8ZcBpabTUfODxdJ+BVnm/BxwPIOlQsuDS6jaHO4gItmxxwDAzK8uoNYyIGJR0Ntn9lLuBiyNilaQz0/qlwHKye0WvATYBb22VN730xcDFkm4lu9/t6TGGm3MMDAwxPBwOGGZmJSl0tdqIWE4WFPLLluamAziraN60fCvP7GbzAPT3Z30XQ0O+AZSZWRkqe6b3li0DAAwNDXW4JGZmu4bKBoz+/lrAcA3DzKwMlQ0YmzfXAob7MMzMylDZgLG9D8MBw8ysDJUNGNv7MBwwzMzK4IBhZmaFVDZgbO/0dsAwMytDZQOGaxhmZuWqbMDwiXtmZuWqbMDwsFozs3JVNmBs2bIVcMAwMytLZQOGz8MwMytXZQOGO73NzMpV2YDhGoaZWbkqGzDch2FmVq7KBgzXMMzMylXZgLG9D8PnYZiZlaGyAcPnYZiZlauyAcNNUmZm5apswHCnt5lZuSobMFzDMDMrV2UDhk/cMzMr13MgYHiUlJlZGSobMGpNUhHB8LBrGWZm7VYoYEg6QdJqSWsknddgvSR9Ia2/RdLRo+WVdL6k+yXdnB4Lx1LwWg0DXMswMyvDqAFDUjfwJWABcARwqqQj6pItAOamx2JgScG8F0bEUemxfCwFr92iFdyPYWZWhiI1jGOANRFxd0RsBS4DFtWlWQRcGpkbgRmS9i2Y9xmpnbgHDhhmZmUoEjD2B9bm5vvSsiJpRst7dmrCuljS7o3eXNJiSSslrdywYQOQ9Vv09w8yZUov4IBhZlaGIgFDDZbVdxo0S9Mq7xLgYOAoYB3w2UZvHhEXRcS8iJg3c+ZMALZuHSIimDp1IuCAYWZWhiIBow+YnZufBTxQME3TvBGxPiKGImIY+Gey5qtCah3eDhhmZuUpEjBWAHMlHSSpFzgFWFaXZhlwWhotNR94PCLWtcqb+jhq/gS4tWihax3ebpIyMytPz2gJImJQ0tnAlUA3cHFErJJ0Zlq/FFgOLATWAJuAt7bKm17605KOImuiugd4Z9FCj6xheFitmVm7jRowANKQ1+V1y5bmpgM4q2jetPwtYyppTu2kPdcwzMzKU8kzvTdvzq5U6z4MM7PyVDJg1Jqkpk1zwDAzK0slA0atSWryZDdJmZmVpZIBw8NqzczKV8mAURtW61FSZmblqWTA2F7DqDVJDXWyOGZmu4RKBoxaH4ZrGGZm5alkwKhdqXbKFPdhmJmVpZIBY2STlAOGmVm7VTJgbL+WlGsYZmZlqWTA2LJlgN7ebiZMyIrvgGFm1n6VDBj9/YNMmjSBri4HDDOzslQyYGzZMsDEiRPo6XHAMDMrS2UDxqRJE+jurgUMD6s1M2u3SgaM/v4BJk7syQUM1zDMzNqtkgFj8+b6GoYDhplZu1UyYNQ6vR0wzMzKU8mAMbIPwwHDzKzdKhkw+vtrAUOAA4aZWRkqGTCyYbU9HiVlZlaiygaMHZukfHlzM7N2q2TA6O8fZOJEn4dhZlamSgYMd3qbmZWvkgHDw2rNzMpXKGBIOkHSaklrJJ3XYL0kfSGtv0XS0WPI+35JIWmvImWJiAad3g4YZmbtNmrAkNQNfAlYABwBnCrpiLpkC4C56bEYWFIkr6TZwGuB+4oWuHbzJA+rNTMrV5EaxjHAmoi4OyK2ApcBi+rSLAIujcyNwAxJ+xbIeyHwf4DCvda1+3lnAaMbcMAwMytDkYCxP7A2N9+XlhVJ0zSvpJOA+yPi163eXNJiSSslrdywYUOTGoZHSZmZtVuRgKEGy+p/oZulabhc0hTgw8BHR3vziLgoIuZFxLyZM2duuz2r+zDMzMpVJGD0AbNz87OABwqmabb8YOAg4NeS7knLfyVpn9EKk69hSKKrSw4YZmYlKBIwVgBzJR0kqRc4BVhWl2YZcFoaLTUfeDwi1jXLGxG/iYi9I2JORMwhCyxHR8SDoxUm34cB0N3d5YBhZlaCntESRMSgpLOBK4Fu4OKIWCXpzLR+KbAcWAisATYBb22V99kUePPmWpOUA4aZWZlGDRgAEbGcLCjkly3NTQdwVtG8DdLMKVIO2LFJChwwzMzKUrkzvWud3pMmZbGuu9t9GGZmZahcwKjVMPJNUoODDhhmZu1WuYAxMJBdyry3t1bD6GJ42AHDzKzdKhswJkzIzvLO+jB84p6ZWbtVLmAMDmYBo6cnK3pXl5ukzMzKULmAMTCQBYdaDaOnx01SZmZlqFzA2F7DyDdJOWCYmbVb5QJGoz4MN0mZmbVf5QLGyBqG3CRlZlaCygWM7TWMrOgeJWVmVo7KBYzBwWG6ukRX1/aAUat1mJlZ+1QuYAwMDG3rv4DaiXuuYZiZtVsFA8bgtv4L8CgpM7OyVDBgDNPb64BhZla2ygWMwcEh1zDMzDqgcgFjYKA+YPjy5mZmZahcwBgcHNo2pBZcwzAzK0vlAsbAwHCDJimPkjIza7fKBYyshuE+DDOzslUuYIzsw3DAMDMrQ+UChmsYZmadUbmAkdUw8p3eHiVlZlaGygWMwcHhuhpGtwOGmVkJKhcwfB6GmVlnFAoYkk6QtFrSGknnNVgvSV9I62+RdPRoeSX9fUp7s6SrJO1XpCyN+zA8rNbMrN1GDRiSuoEvAQuAI4BTJR1Rl2wBMDc9FgNLCuT9TES8OCKOAn4IfLRIgT1KysysM4rUMI4B1kTE3RGxFbgMWFSXZhFwaWRuBGZI2rdV3oh4Ipd/KlComjAwMOSLD5qZdUCRgLE/sDY335eWFUnTMq+kT0haC/wVTWoYkhZLWilp5YYNG3zxQTOzDikSMNRgWX1toFmalnkj4sMRMRv4OnB2ozePiIsiYl5EzJs5c2a6gZKvJWVmVrYiAaMPmJ2bnwU8UDBNkbwA3wD+tEBZGBysv5aUR0mZmZWhSMBYAcyVdJCkXuAUYFldmmXAaWm01Hzg8YhY1yqvpLm5/CcBtxcp8MhbtHZ7lJSZWQl6RksQEYOSzgauBLqBiyNilaQz0/qlwHJgIbAG2AS8tVXe9NIXSDoMGAbuBc4sUuCRfRhiaGioSFYzM3sWRg0YABGxnCwo5JctzU0HcFbRvGl5oSaoeiNrGD4Pw8ysDJU70zurYYzs9M5ilpmZtUvlAsbAQP21pLKPMDzsgGFm1k6VCxgRMeI8DMAjpczM2qxSAaPW7NSohuGAYWbWXhULGNmzaxhmZuWrWMCo1TB2vIES4JFSZmZtVrGAkT27hmFmVr6KBYxaDWP76SMOGGZm5ahowNjxPAxwwDAza7eKBYzs2U1SZmblq1jA8LBaM7NOqWTAqL/4IDhgmJm1W8UCRva8Yx9GFjw8rNbMrL0qFjBa1TB8iXMzs3aqWMDInhv3YbiGYWbWThULGI1qGO70NjMrQ6UCRo1HSZmZla9SAWN7DcMn7pmZla2SAcM1DDOz8lUsYGTP7sMwMytfxQJGFjF6exsNq/UoKTOzdqpYwMieG9UwBgd9HoaZWTtVLGA078MYHnYNw8ysnSoWMLLnfA2jNmLKfRhmZu1VKGBIOkHSaklrJJ3XYL0kfSGtv0XS0aPllfQZSben9N+VNGO0cjSqYXR11ZqkHDDMzNpp1IAhqRv4ErAAOAI4VdIRdckWAHPTYzGwpEDeHwO/FxEvBu4APjhaWVqdhzE87IBhZtZORWoYxwBrIuLuiNgKXAYsqkuzCLg0MjcCMyTt2ypvRFwVEYMp/43ArNEK0uhaUm6SMjMrR5GAsT+wNjffl5YVSVMkL8DbgCsavbmkxZJWSlr59NNPA9trFeAmKTOzshQJGGqwrH5IUrM0o+aV9GFgEPh6ozePiIsiYl5EzJs8eQoTJnQjbX/Z2nkYbpIyM2uvngJp+oDZuflZwAMF0/S2yivpdOBE4NVR66BoISJ2GCEF20dM+cQ9M7P2KlLDWAHMlXSQpF7gFGBZXZplwGlptNR84PGIWNcqr6QTgA8AJ0XEpqIFzt9tD6CrK6thuEnKzKy9Rq1hRMSgpLOBK4Fu4OKIWCXpzLR+KbAcWAisATYBb22VN730F4GJwI9TE9ONEXHmKGUZUcPwKCkzs3IUaZIiIpaTBYX8sqW56QDOKpo3LT9kTCUlGyWVHyEFHiVlZlaWip3pPbKG4VFSZmblqFzAyF+pFtwkZWZWlooFDBqMkqo1SXmUlJlZO1UsYMSIPozto6R8eXMzs3aqXMDIX0cKfHlzM7OyVCxgeJSUmVmnVCxgeJSUmVmnVCxgjKxhQNYs5VFSZmbtVbGAMbKGAVmzlJukzMzaq2IBgxGd3pA1S7lJysysvSoVMGDksFrILnHuJikzs/aqVMBodOIeZMt84p6ZWXtVLGA0rmF0dcl9GGZmbVa5gNGohtHd7U5vM7N2q1jAYMTFB8GjpMzMylCxgNG4htHV5YBhZtZuFQsYI2/RCq5hmJmVoWIBo1UfhkdJmZm1U8UCRuNLg2SjpHx5czOzdqpUwIBmlwbxeRhmZu1WsYDRqobhPgwzs3aqXMBodC0pn4dhZtZ+lQsYjWoYHiVlZtZ+lQsYPg/DzKwzCgUMSSdIWi1pjaTzGqyXpC+k9bdIOnq0vJL+XNIqScOS5hUtcLOr1TpgmJm116gBQ1I38CVgAXAEcKqkI+qSLQDmpsdiYEmBvLcCJwM/G0uBPUrKzKwzitQwjgHWRMTdEbEVuAxYVJdmEXBpZG4EZkjat1XeiLgtIlaPtcCNzvT2KCkzs/YrEjD2B9bm5vvSsiJpiuRtSdJiSSslrYTGNQyPkjIza78iAUMNltW3/zRLUyRvSxFxUUTMi4h5AL29PSPSeJSUmVn7jfz1HakPmJ2bnwU8UDBNb4G8Y9Lsnt4OGGZm7VWkhrECmCvpIEm9wCnAsro0y4DT0mip+cDjEbGuYN4xaTxKygHDzKzdRq1hRMSgpLOBK4Fu4OKIWCXpzLR+KbAcWAisATYBb22VF0DSnwD/CMwE/lPSzRHx+lEL3HCUlAOGmVm7FWmSIiKWkwWF/LKluekAziqaNy3/LvDdsRQWml1Lypc3NzNrt+fEmd4+cc/MrP0qFzB8xz0zs86oXMDwtaTMzDqjcgHDo6TMzDqjcgHDo6TMzDqjcgHDo6TMzDqjcgGj8R33xNDQUAdKY2a266hcwGh8xz1f3tzMrN0qGDBGnmvoy5ubmbVfBQNGo/Mwuh0wzMzarHIBw2d6m5l1RuUCRrNRUsPDQUQwPOzAYWbWDhULGEIaeU+m2sipp5/u5/jjP81nP/ujsgtmZvacV6mA0SBWANmZ3gCXXHIdd9yxns9//sfceef6EktmZvbcV7GA0ThidHVly5cs+SlHHjmbqVMn8pGPfIfsqutmZrYzVCxgNF5e6wjfuPFpPvjBN/D+95/Af//3HVxxxW9KLJ2Z2XNbxQJG44jR3Z0tf8lLDuTYYw/l9NNfweGH78v553/Po6fMzHaSigWMxst7e7OT+c4553VIoqenm/e+97X09T3KihW/K7GEZmbPXYVu0TpeNKthnHjiUUybNonjjz9827Ljjz+ciRN7uOKKW5g//+Cyimhm9pxVqRpGM3vsMZWTT37JDgFl2rRJHHvsofzoR7e689vMbCeoVMBoVsNo5oQTXsTatRtZteqBNpXIzGzX8ZwOGK9//e/R1SWuuOKWNpXIzGzXUbGAMbb0e+45jZe+9CCuvPLW9hRojCKCrVsHO10MM7Nn5DnR6d3KggUv4vzzv8+SJT/l2mtvZ/36J3jVqw7nda97ITNmTKG/f4C9934e++47Y+cXOGfLlgHe+c5LuPXWPn7wg3PYb7/2vp+Z2c6mIh3Ckk4APg90A/8SERfUrVdavxDYBJwREb9qlVfSHsDlwBzgHuBNEfFoq3LsvvsB8eij943h48F99z3C/PkfB2DOnL2YPXsPbrzxLgYGtt+hr6tLLFjwIt72tmOZNWsPJNh996lMnTpxTO/VzKZN/Zxxxr9y3XVrmDixhxe+cD/+4z/OZuLESsXrEdau3ciUKb3suee0ThfFzFqQdFNEzHvWrzNawJDUDdwBvBboA1YAp0bEb3NpFgLvJgsYLwM+HxEva5VX0qeBjRFxgaTzgN0j4gOtyrLHHgfGxo33jvlDXn31bey551Re/OLZSOKJJzZz/fVrGBgYore3h5tuuoevfe0GHnts0w755szZi0MP3YcJE7J7hk+ePIE995zGjBlT6OnpQlJ6ZFfM7eqqTQsQ/f0D9PU9yi9/eTerVz/IhReeypQpvfz1X3+V0077Ay644M/H/FnGg76+jXzqU8v59rdvYvLkXt75zj/iXe86nunTJ3W6aLucRx55ijvueJD77tvIpk1b2bJlgAMO2IP58w+uZCB/5JGnWLHidwwODjFv3kHss89unS7SmA0NDXP//Y/y0ENPMmVKL1On9jJt2iSmTOll0qQJz6il5NkqM2C8HDg/Il6f5j8IEBGfzKX5J+CaiPhmml8NHEdWe2iYt5YmItZJ2jflP6xVWfbc88B45JGxB4wiNm3q5+qrb2PTpq0MDQXr1z/Ob3/7AGvWPERE0NUlNm3ayiOPPMVTT/UXft3ddpvMrFl7cM45r+UNbzgSgI9//Ad8+ctXs9tuk5k0aQJdXWLLlgE2bx7YIW8tGI02nU+fPe/wKiOWNUoXwbbhx9lTUNs1IiI9attqKxMmdPO2tx1LX9+jLFv2P/T2djNx4oRtwVPK3icLotufs/cs/4ApogPHcSHDw8HQ0DBDQ8NE1Kaz5y1bBprmmzVr9xG3AyjyY1Wfpqzt0t8/yNq1G3dYtu++M5g8ecJOf6+xDLUfy6j84eFh1q9/gv7+xn2V3d1dTJ3ay9SpE7ddNDWvyLYfmWZkovpF11//kZ0SMIq0iewPrM3N95HVIkZLs/8oeZ8fEesAUtDYu9GbS1oMLAZ4/vNnFSjuMzNlykROPPGoQmkHB4cYHo5t9+DI7sOR/aBuvy9H0NvbzbRpI/91n3feQvbeezpr125k8+YBhoaGmTKld9sPLuz4A57Nx7bn/A/59vXFltW/Xm26Vluqqf2454NLbXratEm8+c0v39YP8653Hcf3v38zg4NDO2yLHbfN9uXj0Xg9Vyciu/RNd3cX3d1ZrbY239XVxd57T+eww/bhoINmMn36JHp7e1i9+kFuuGENq1c/2HB/2D7faL8YPU27dHd38Za3/AEvfelB9PZ2s2LF7/jNb/oYHCx+eZ+x/HsfSyAcy+vOnDmdQw7Zm3322Y0tWwZ46ql+nn56x8dTT/WP2LYj50e+9jNNc/31hYvfUpGA0WhL1RezWZoieVuKiIuAiwDmzZs3Lo7qRnf9G2v+xYuP2zmFGQeOPPIAjjzygE4Xw5J58+Ywb96cThfjWfv93z+w00V4zliy5LSd8jpFhtX2AbNz87OA+jPhmqVplXd9aooiPT9UvNhmZla2IgFjBTBX0kGSeoFTgGV1aZYBpykzH3g8NTe1yrsMOD1Nnw58/1l+FjMza6NRm6QiYlDS2cCVZENjL46IVZLOTOuXAsvJRkitIRtW+9ZWedNLXwB8S9LbgfuAag4ZMjPbRRQ6D2O8mDdvXqxcubLTxTAzq5SdNay2UpcGMTOzznHAMDOzQhwwzMysEAcMMzMrpFKd3pKeBFZ3uhwF7AU83OlCFOBy7jxVKCO4nDtbVcp5WERMf7YvUrXLpa7eGT397SZppcu581ShnFUoI7icO1uVyrkzXsdNUmZmVogDhpmZFVK1gHFRpwtQkMu5c1WhnFUoI7icO9suVc5KdXqbmVnnVK2GYWZmHeKAYWZmhYzLgCHpBEmrJa1J9/uuXy9JX0jrb5F0dAfKOFvSTyXdJmmVpPc2SHOcpMcl3ZweH+1AOe+R9Jv0/iOG1o2TbXlYbhvdLOkJSefUpenItpR0saSHJN2aW7aHpB9LujM9794kb8v9uIRyfkbS7el7/a6kGU3yttxHSijn+ZLuz323C5vk7fT2vDxXxnsk3dwkbynbs9lvUFv3z+33ax4fD7LLoN8FvADoBX4NHFGXZiFwBdkd/eYDv+hAOfcFjk7T04E7GpTzOOCHHd6e9wB7tVjf8W3Z4Pt/EDhwPGxL4A+Bo4Fbc8s+DZyXps8DPtXkc7Tcj0so5+uAnjT9qUblLLKPlFDO84H3F9gvOro969Z/FvhoJ7dns9+gdu6f47GGcQywJiLujoitwGXAoro0i4BLI3MjMEPp7n1liYh1EfGrNP0kcBvZPcyrpuPbss6rgbsi4t4OlmGbiPgZsLFu8SLgkjR9CfDGBlmL7MdtLWdEXBURg2n2RrI7XnZUk+1ZRMe3Z40kAW8Cvtmu9y+ixW9Q2/bP8Rgw9gfW5ub7GPlDXCRNaSTNAX4f+EWD1S+X9GtJV0h6YbklA7J7qF8l6SZJixusH1fbkuyujM0OxE5vy5rnR3ZHSdLz3g3SjLft+jaymmQjo+0jZTg7NZ1d3KQJZTxtz2OB9RFxZ5P1pW/Put+gtu2f4zFgqMGy+rG/RdKUQtI04NvAORHxRN3qX5E1rRwJ/CPwvZKLB/CKiDgaWACcJekP69aPp23ZC5wE/HuD1eNhW47FeNquHwYGga83STLaPtJuS4CDgaOAdWTNPfXGzfYETqV17aLU7TnKb1DTbA2Wjbo9x2PA6ANm5+ZnAQ88gzRtJ2kC2Rf19Yj4Tv36iHgiIp5K08uBCZL2KrOMEfFAen4I+C5ZVTRvXGzLZAHwq4hYX79iPGzLnPW1Zrv0/FCDNONiu0o6HTgR+KtIjdf1CuwjbRUR6yNiKCKGgX9u8v7jZXv2ACcDlzdLU+b2bPIb1Lb9czwGjBXAXEkHpX+cpwDL6tIsA05LI3zmA4/XqmBlSe2Y/wrcFhH/0CTNPikdko4h296PlFjGqZKm16bJOkFvrUvW8W2Z0/SfW6e3ZZ1lwOlp+nTg+w3SFNmP20rSCcAHgJMiYlOTNEX2kbaq6zP7kybv3/HtmbwGuD0i+hqtLHN7tvgNat/+2e6e/GfY+7+QrMf/LuDDadmZwJlpWsCX0vrfAPM6UMZXklXhbgFuTo+FdeU8G1hFNgLhRuAPSi7jC9J7/zqVY1xuy1SOKWQBYLfcso5vS7IAtg4YIPtX9nZgT+C/gDvT8x4p7X7A8lb7ccnlXEPWTl3bP5fWl7PZPlJyOf8t7Xu3kP1o7Tset2da/tXaPplL25Ht2eI3qG37py8NYmZmhYzHJikzMxuHHDDMzKwQBwwzMyvEAcPMzApxwDAzs0IcMMwakPRU3fwZkr44xtc4qtmVV82qyAHDrA3SGcFHkY11N3tO6Ol0AcyqRtJMYClwQFp0TkRcJ+l8spOj5gAPk51YNVnSK4FPkp11u1/KcxDwnoi4BLOKcMAwa2xy3Q1y9mD7pRM+D1wYET+XdABwJXB4WvcS4JURsVnSGWRnzp+d1l0OIOklwFcY/xdQNNuBA4ZZY5sj4qjaTO3HP82+BjgiXdoK4Hm16wcByyJic7MXTRdM/DfgTRHx+M4utFk7OWCYjV0X8PL6wJACyNPNMknqJrtRzcciotQL/JntDO70Nhu7q8guhghko6GapHuS7NaZNRcAt0TEZe0rmln7OGCYjd17gHnpDnG/JbuqbiM/JWu6ulnSXwDvB16X5m+WdFJZBTbbGXy1WjMzK8Q1DDMzK8QBw8zMCnHAMDOzQhwwzMysEAcMMzMrxAHDzMwKccAwM7NC/j80zHAawFgnoQAAAABJRU5ErkJggg==\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(for_c2,'opt_roll',2))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Foreward scan roll angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0001)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 89,
+ "id": "a82a25f9-e5a9-412a-8b73-4fd2ffe3f299",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.14, 0.29, 2.94, 6.02, 12.05, 15.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0])"
+ ]
+ },
+ "execution_count": 89,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(for_c2,'opt_pitch',2))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Foreward scan Pitch angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0005)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 90,
+ "id": "42c40c1c-1576-4c60-9a77-7fafda275446",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.14,\n",
+ " 0.29,\n",
+ " 0.44,\n",
+ " 0.58,\n",
+ " 0.73,\n",
+ " 0.88,\n",
+ " 1.02,\n",
+ " 1.17,\n",
+ " 1.32,\n",
+ " 1.47,\n",
+ " 1.61,\n",
+ " 1.76,\n",
+ " 1.91,\n",
+ " 2.05,\n",
+ " 2.2,\n",
+ " 2.35,\n",
+ " 2.5,\n",
+ " 2.64,\n",
+ " 2.94,\n",
+ " 3.08,\n",
+ " 3.23,\n",
+ " 3.38,\n",
+ " 3.67,\n",
+ " 3.82,\n",
+ " 3.97,\n",
+ " 4.11,\n",
+ " 4.26,\n",
+ " 4.41,\n",
+ " 4.55,\n",
+ " 4.7,\n",
+ " 5.0,\n",
+ " 5.29,\n",
+ " 5.58,\n",
+ " 5.73,\n",
+ " 5.88,\n",
+ " 6.02,\n",
+ " 6.17,\n",
+ " 6.32,\n",
+ " 6.61,\n",
+ " 6.91,\n",
+ " 7.5,\n",
+ " 7.94,\n",
+ " 8.08,\n",
+ " 8.23,\n",
+ " 8.38,\n",
+ " 8.67,\n",
+ " 8.82,\n",
+ " 8.97,\n",
+ " 9.26,\n",
+ " 9.7,\n",
+ " 9.85,\n",
+ " 10.0,\n",
+ " 10.29,\n",
+ " 10.44,\n",
+ " 10.58,\n",
+ " 11.17,\n",
+ " 11.32,\n",
+ " 11.61,\n",
+ " 11.76,\n",
+ " 12.05,\n",
+ " 12.5,\n",
+ " 12.79,\n",
+ " 12.94,\n",
+ " 13.08,\n",
+ " 13.38,\n",
+ " 13.52,\n",
+ " 13.67,\n",
+ " 13.97,\n",
+ " 14.11,\n",
+ " 14.41,\n",
+ " 15.0,\n",
+ " 15.29,\n",
+ " 15.44,\n",
+ " 15.58,\n",
+ " 16.76,\n",
+ " 17.05,\n",
+ " 17.5,\n",
+ " 18.23,\n",
+ " 18.52,\n",
+ " 18.67,\n",
+ " 18.97,\n",
+ " 19.41,\n",
+ " 20.0,\n",
+ " 20.14,\n",
+ " 20.44,\n",
+ " 20.58,\n",
+ " 20.73,\n",
+ " 21.02,\n",
+ " 21.32,\n",
+ " 21.47,\n",
+ " 21.61,\n",
+ " 22.05],\n",
+ " [0.0,\n",
+ " 0.11,\n",
+ " 0.03,\n",
+ " 0.03,\n",
+ " 0.04,\n",
+ " 0.01,\n",
+ " 0.08,\n",
+ " 0.06,\n",
+ " 0.02,\n",
+ " 0.04,\n",
+ " 0.01,\n",
+ " 0.01,\n",
+ " 0.01,\n",
+ " 0.0,\n",
+ " 0.01,\n",
+ " 0.01,\n",
+ " 0.01,\n",
+ " 0.01,\n",
+ " 0.0,\n",
+ " 0.01,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0])"
+ ]
+ },
+ "execution_count": 90,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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Wj799BvuvPMc0tKSWbhw74ephkIhtm4t3uv1lVIqHt8GhfbqaAabKYQ116cANlMoKCjjq6+2UFtb1ygojBkzhKQk4cQTD+a6605i1KgBzQaFPXuq2b27otHjBQWlXHLJDMaM+SMLFuj5D0358stN3HHHf/SiSEolwLdBIRhMbO6jljRgQI/IbS+ZwpAhtrP57beXAzQKCj16dOHll29k+vQrEBHGjBnCihV5cYepBoN1TJr0CBMmPEh1df0lQj/77FtOO+2vLFiwni5d0nj88fcTfm/fJffc8ybPPPNZ5HNRSjXPt0GhPZuPwucqgPdMAeDtt1cQCCQxdOgBjcqMHTuUrKwMAI491g5TXbp0c8zne+65eaxatY1Nm3byzDOfApCXV8zVVz9FdnZn3n77F0yZchJz567a7yfcq64O8tprSyMnB3r19ddbmTcvFxHhscfe1+tftJIPPljNypVbGzy2dWsxVVW17VQjta98GRRCIcPXX2+lZ0/vM562pMzMdLp370zXrumRay00JRxENm4sYujQHNLSkpssf/TRgxCRmGc679xZzl//+jYnnHAwP/jBIUyb9l927drDLbe8iDHw/PNTGD68D1deOY709BSmT/8o7usUF+/hs8++bbb+YaFQiPnz1+31F3rPnsaZT01NMEZJ7x59dC4//eks7r57dkLrPfnkJ3TqlModd5zF8uV5fPrpN82v1E6MMZGLSvlFbm4BX3+9tckyy5dv4YornuTKK5+K7DPbt5dw8sn3ce21z7RFNVUr8GVQKCoqZ8eOUm666dR2q8PAgT08ZQlgL/DTr182UH/SWlO6devEoYf2ifQJzJo1jylTnmXmzM+5887X2LOnmj/96TzuuONsSkuruOCCx/n002/4/e/P4cADuwO2SerCC8fwyiuL2b69pNFrVFXVcsklM5g8+Qlmz248YV+03bsruPrqZzjvvMc4++xpkdFUXt133xxGjvxt5HwMgLvvns3hh/+O5cu3JPRcYZs2FfH44++Tnd2ZmTM/5733vF0GtbCwjNdeW8LkycdwzTUn0qtXVx5//IO9qgNAeXnVXq/bnIqKai69dAbjxv2ZLVt2tdrrhG3evJMPPljdZOb0xhvLOOOMBzj77If54ovcmGVqaoL84hf/JCMjla1bi5k1ax4A9947hz17qvngg9W8//6qJutx2ml/5aWXFjZZ348+WsOkSY+waJGO1msrnoKCiIwXkbUikisit8VYLiLyiLN8uYgc5XXdWAoLSzn11EM59tih3t9JC5sy5WRuuOEHnssPHmw7pw89tPmgALYJacmSTTz88Hv8+tf/5rPPvuX221/mlVeWcPXVJzBsWC9GjOjL5MnHsGZNPieeeDCXXnpcg+e4/vqTCQZDXHDB41x99dP88Y+zycuzo5J++9tXWLZsMwMH9uDWW19iw4ZCKipquP32l/nhDx9i7dr8yPMsWbKR8eP/lw8/XM2UKSexbVsxZ575v9x//9vMmjWPN99cxueff8uqVdvIz9/dKJN4662vmDbtv4RChhtumMmOHSW88soSpk//kKqqWi677O+Ra1REq6sL8fzz87j//rcbZRp33vk6yckB3n77F4wY0ZdbbnmJbdt2s3t3BTt2lLBr1x4qKqobHeCee+5zamrquOaaE0lLS+a6607i00+/aRCwmhMM1vHGG8uYNOkRDj74di688G+eDkzV1UG+/norRUVlzZYtL6/ikktm8PHHa9m1aw+TJz/Btm27qakJ8vbby/nXvxZSWNj880QrKals9BmFQiGeeuoTfvCD+7n00hlcc80zjeq4e3cF998/h+uvn8nIkf0YMKAHV1zxZMyg/sgjc1m9Op/HHruUE044mGnT/ssXX+Ty738v4tprT2TIkBzuuuv1yCg+t4qKGq655hlWrdrG//t/L0UCz1tvfcXIkb/lmmue5vPPv+Whh97jkktmsHjxRi67bAYrVuQlvC2as23bbu699y1uv/3lRhNbAmzZsotHH53LkiUbPTVBGmNYtGgDubkFDR4PhULs3FnOmjX5MV/HT6S5NyoiAeAb4HQgD1gEXGyMWeUqMxH4GTAROBaYZow51su6saSm9jJffrmUww7rt9dvrK3dfvvLzJz5OU89dTUTJnyv2fKvv/4lP/nJcwCce+5RTJv2YzZt2smyZZuZOPHwSLNVQUEpDz74LlOnnk7fvlmNnmfWrHnMmbOcHTtKWbeuABE48cThzJ27iqlTT+PSS4/njDMeoG/fLOrqQqxdu51u3TpRU1PHnXeew+LFG3n55cX06ZPFjBlXcPTRg9i6tZipU1/giy/iH0SzsjIYP/57jBs3jF//+t8cckhv7rnnfM499zGGDs0hN7eAUaMGcM8953H++Y/TvXtn7r9/Mgce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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(for_c2,'opt_yaw',2))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Foreward scan Yaw angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0005)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "id": "986d59cd-9788-41b2-9f0b-7f6a8bdcee4b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.12, 0.24, 0.36, 0.48, 0.6, 0.72, 0.84, 0.96, 1.08, 1.2, 1.32, 3.01],\n",
+ " [0.23, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])"
+ ]
+ },
+ "execution_count": 48,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(nadir_c2,'opt_roll',1))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Nadir scan roll angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0001)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "id": "d8f2f5f0-7d49-4f8f-9410-3a77bb5455c1",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.12,\n",
+ " 0.24,\n",
+ " 0.36,\n",
+ " 0.48,\n",
+ " 0.6,\n",
+ " 0.72,\n",
+ " 0.84,\n",
+ " 0.96,\n",
+ " 1.08,\n",
+ " 1.2,\n",
+ " 1.32,\n",
+ " 1.44,\n",
+ " 1.56,\n",
+ " 1.68,\n",
+ " 1.93,\n",
+ " 2.05,\n",
+ " 2.17,\n",
+ " 2.29,\n",
+ " 2.41,\n",
+ " 2.53,\n",
+ " 2.65,\n",
+ " 2.77,\n",
+ " 2.89,\n",
+ " 3.01,\n",
+ " 3.25,\n",
+ " 3.37,\n",
+ " 3.49,\n",
+ " 3.61,\n",
+ " 3.73,\n",
+ " 3.98,\n",
+ " 4.1,\n",
+ " 4.22,\n",
+ " 4.34,\n",
+ " 4.58,\n",
+ " 4.7,\n",
+ " 4.82,\n",
+ " 5.42,\n",
+ " 5.79,\n",
+ " 6.15,\n",
+ " 6.63,\n",
+ " 7.23,\n",
+ " 8.08,\n",
+ " 8.32,\n",
+ " 8.56,\n",
+ " 8.68,\n",
+ " 8.8,\n",
+ " 8.92,\n",
+ " 9.16,\n",
+ " 9.65,\n",
+ " 10.01,\n",
+ " 10.25,\n",
+ " 10.49,\n",
+ " 10.61,\n",
+ " 10.73,\n",
+ " 11.09,\n",
+ " 11.34,\n",
+ " 12.3,\n",
+ " 12.42,\n",
+ " 12.66,\n",
+ " 12.9,\n",
+ " 13.63,\n",
+ " 13.75,\n",
+ " 13.99,\n",
+ " 14.11,\n",
+ " 14.35,\n",
+ " 15.2,\n",
+ " 15.44,\n",
+ " 15.56,\n",
+ " 15.68,\n",
+ " 15.92,\n",
+ " 16.28,\n",
+ " 16.4,\n",
+ " 17.13,\n",
+ " 17.37,\n",
+ " 17.61,\n",
+ " 17.97,\n",
+ " 18.45,\n",
+ " 18.57,\n",
+ " 18.82,\n",
+ " 19.18,\n",
+ " 19.42,\n",
+ " 19.54,\n",
+ " 19.66,\n",
+ " 20.02,\n",
+ " 20.26,\n",
+ " 20.75,\n",
+ " 21.11,\n",
+ " 21.23,\n",
+ " 21.35,\n",
+ " 21.47,\n",
+ " 21.71,\n",
+ " 21.83,\n",
+ " 21.95,\n",
+ " 22.43],\n",
+ " [0.18,\n",
+ " 0.21,\n",
+ " 0.14,\n",
+ " 0.09,\n",
+ " 0.06,\n",
+ " 0.06,\n",
+ " 0.01,\n",
+ " 0.1,\n",
+ " 0.02,\n",
+ " 0.03,\n",
+ " 0.05,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0])"
+ ]
+ },
+ "execution_count": 49,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(nadir_c2,'opt_yaw',1))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Nadir scan Yaw angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0005)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "id": "ab6d1bac-a3a2-4ddb-8baf-2c31b3c907fe",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.12,\n",
+ " 0.24,\n",
+ " 0.36,\n",
+ " 0.48,\n",
+ " 0.72,\n",
+ " 0.84,\n",
+ " 0.96,\n",
+ " 1.08,\n",
+ " 3.01,\n",
+ " 6.03,\n",
+ " 8.92,\n",
+ " 9.04,\n",
+ " 11.94,\n",
+ " 12.06,\n",
+ " 20.99],\n",
+ " [0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])"
+ ]
+ },
+ "execution_count": 50,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(nadir_c2,'opt_pitch',1))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Nadir scan Pitch angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0001)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 97,
+ "id": "747df95f-a75d-4b05-adf4-205f10858646",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.15, 3.03, 5.9, 6.06, 11.96, 15.0, 18.03, 21.06],\n",
+ " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])"
+ ]
+ },
+ "execution_count": 97,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(aft_c2,'opt_pitch',2))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Aft scan Pitch angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0001)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 98,
+ "id": "8e9c3d8d-0407-42b0-9128-8587e8cc35a7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.15,\n",
+ " 0.31,\n",
+ " 0.47,\n",
+ " 0.63,\n",
+ " 0.79,\n",
+ " 0.95,\n",
+ " 1.11,\n",
+ " 1.27,\n",
+ " 1.43,\n",
+ " 1.59,\n",
+ " 1.75,\n",
+ " 1.91,\n",
+ " 2.07,\n",
+ " 2.23,\n",
+ " 2.39,\n",
+ " 2.71,\n",
+ " 3.03,\n",
+ " 3.19,\n",
+ " 3.35,\n",
+ " 3.51,\n",
+ " 3.67,\n",
+ " 4.14,\n",
+ " 4.3,\n",
+ " 4.46,\n",
+ " 4.62,\n",
+ " 4.94,\n",
+ " 5.42,\n",
+ " 5.74,\n",
+ " 5.9,\n",
+ " 6.22,\n",
+ " 6.38,\n",
+ " 6.54,\n",
+ " 7.18,\n",
+ " 7.34,\n",
+ " 7.65,\n",
+ " 8.13,\n",
+ " 8.29,\n",
+ " 8.45,\n",
+ " 8.61,\n",
+ " 8.93,\n",
+ " 9.09,\n",
+ " 9.25,\n",
+ " 9.57,\n",
+ " 10.05,\n",
+ " 10.53,\n",
+ " 10.85,\n",
+ " 11.96,\n",
+ " 12.12,\n",
+ " 12.44,\n",
+ " 13.08,\n",
+ " 13.72,\n",
+ " 14.2,\n",
+ " 15.63,\n",
+ " 15.79,\n",
+ " 15.95,\n",
+ " 16.11,\n",
+ " 16.27,\n",
+ " 16.91,\n",
+ " 19.46,\n",
+ " 19.62,\n",
+ " 19.94,\n",
+ " 20.42,\n",
+ " 20.58,\n",
+ " 21.54],\n",
+ " [0.02,\n",
+ " 0.17,\n",
+ " 0.2,\n",
+ " 0.05,\n",
+ " 0.11,\n",
+ " 0.03,\n",
+ " 0.01,\n",
+ " 0.02,\n",
+ " 0.02,\n",
+ " 0.0,\n",
+ " 0.02,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0])"
+ ]
+ },
+ "execution_count": 98,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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MCX198RicQ4caOPFFxt59tk9HD7czoUXLuKSS85k+vQanHN0dfWxffsBNm/ex5EjHaxceQrnnXdKahm5dHf3s29fK/v3HyWRSBAOhygrizBzZg0zZkymvDySmralpYunntrJli376Orqo7u7j5KSMDNnTqa+fhIAvb1Renuj9PXF6O2NUltbycqVCzjnnDlEImE6O/vo6uqjpqaCyspSenr62batiW3b9jN1ajWLF89i7typx9xNeTCJRIKWli4OHerAOUdZWYTy8hLKyiKUlZUQjcZpbu6kubmTqVOrmD+/7pi/KV08nqC/P0Y0Gk/9mEFVVRmRSAm/+c1WfvKTp3jooZcAryl7zpwpXHXVcq699nW0tHTywANbeO6511iz5uNj03xkZm8A7nDOvd1//xcAzrm/S5vmO8DDzrmf+O+3A28BFgw1bzYLF57ldu7cNrK/qIj27WvlHe/4Jo2NralhVVVlfOADF1BTU8GaNc+mvkFPnlzB3LlTUx/ExYtn86lPXZa6JxPAoUPt3HXXo9x992O0tfUMum4zY8qUSurrJ3HVVcv42Mcupqamgqamo6xe/RD/9V8baW3toqyshL4+79bjlZWldHf3p5YRDoeora2ktbWLRCL7/33atGpqasrp6uqjtbWbaHTgW/M117yOr33tvfT09PO1r93PPfc8TTw+9DeYigrvg/jBD76Br3zl3cd8+B5++CU+9amfcPBgO6efPoO3v/0ctm8/wIMPbs257EgkzNSpVUyeXAFALJYgkXDE4wlisThHjnQeE3e66uoyenujxGIDy042B4ZCxjvesYKDB9t55JHtx807ZUoll166mG3bmti8eR/V1WXU1HgxtLX10NXVl3WdtbWVzJo1mW3bmgBv3ygpCROJhCkpCRGJhIlG4xw82J6Ku7w8wowZNYTDIZxzNDW10dsb5eKLz0jd5n379gOpbRQKGYmEo6QkhJll/fsrKkqpri6jvb0ntY9kqq+fhBkcPtyZqkgikTCTJpXT0tKV2obd3f1Z96FIJMyMGTXE445EIkE8niAed8Tjcf934pjKMJvq6jIqK0uJRErYt2/gs5b88tHfH6O9PftTEs0sFXdpaRjnOGZblJdHiEbjx+1bpaXe5zQWSxAKec9zLy+PEAoZ8bi3fznnSCS8ZJi+/wzFzJg+3Utg/f1xotGBJJDrc5huxowa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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(aft_c2,'opt_yaw',2))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Aft scan Yaw angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0005)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 99,
+ "id": "419a1ae2-63d1-4d43-bf9e-db0d42e465e4",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([0.15, 0.31, 0.47], [0.0, 0.0, 0.0])"
+ ]
+ },
+ "execution_count": 99,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fft_vals, power_spectrum, freqs, idx, fft_recon = compute_fft(poly_resid(aft_c2,'opt_roll',2))\n",
+ "plot_power(freqs, idx, power_spectrum, 'Aft scan Roll angle residuals Power spectrum')\n",
+ "top_freqs(freqs,power_spectrum,0.0005)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cea605cc-9993-4a51-a082-9ffaba8b7a17",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "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.8.8"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/scripts/legacy/skysat_orthorectify.py b/scripts/legacy/skysat_orthorectify.py
new file mode 100755
index 0000000..90de931
--- /dev/null
+++ b/scripts/legacy/skysat_orthorectify.py
@@ -0,0 +1,224 @@
+#! /usr/bin/env python
+
+import numpy as np
+import os,sys,glob,shutil
+import argparse
+from skysat_stereo import asp_utils as asp
+from skysat_stereo import skysat
+from p_tqdm import p_map
+from imview import pltlib
+import itertools
+import ast
+import matplotlib.pyplot as plt
+from multiprocessing import cpu_count
+
+def get_parser():
+ parser = argparse.ArgumentParser(description='create browse image from input Skysat directory')
+ parser.add_argument('-img_folder', help='Folder containing subdirectories of imagefiles', required=True)
+ session_choice = ['rpc','pinhole']
+ parser.add_argument('-session',choices = session_choice, default = 'rpc', help = 'Session for mapproject (defualt: %(default)s)')
+ parser.add_argument('-out_folder',help='Folder where output orthoimages will be stored', required=True)
+ parser.add_argument('-tr',help='Output image resolution',default=None)
+ parser.add_argument('-tsrs',help='Output crs as EPSG code, example EPSG:32610')
+ parser.add_argument('-DEM',help='Optional DEM for mapprojecting',default='WGS84')
+ parser.add_argument('-delete_temporary_files',help='Delete temporary individual mapprojected files written to disc',default=True)
+ map_choices = ['science','browse']
+ parser.add_argument('-mode',choices=map_choices,default='browse',help='select mode for mapprojection default: %(default)s')
+ parser.add_argument('-ba_prefix',default=None,help='bundle adjust prefix for rpc, or joiner for bundle adjusted pinhole cameras',required=False)
+ parser.add_argument('-cam',default=None,help='camera folder containing list of tsai files for pinhole files',required=False)
+ parser.add_argument('-frame_index',default=None,help="frame index to read frame's actual Ground sampling distance",required=False)
+ orthomosaic_choice = [1,0]
+ parser.add_argument('-orthomosaic',default=0,type=int,choices=orthomosaic_choice, help="if mode is science, enabling this (1) will also produce a final orthomosaic (default: %(default)s)")
+ parser.add_argument('-copy_rpc',default=0,type=int,choices=orthomosaic_choice,help='if mode is science, enabling this (1) will copy rpc metadata in the orthoimage (default: %(default)s)')
+ data_choices = ['video','triplet']
+ parser.add_argument('-data',default='triplet',choices=data_choices,help="select if mosaicing video or triplet product in science mode (default: %(default)s)")
+ parser.add_argument('-overlap_list', default=None,
+ help='list containing pairs for which feature matching was restricted due during cross track bundle adjustment (not required during basic triplet processing)')
+ return parser
+
+def main():
+ parser = get_parser()
+ args = parser.parse_args()
+ tr = str(args.tr)
+ tsrs = args.tsrs
+ dir = os.path.abspath(args.img_folder)
+ outdir = os.path.abspath(args.out_folder)
+ images = sorted(glob.glob(os.path.join(dir,'*.tif*')))
+ if os.path.islink(images[0]):
+ images = [os.readlink(x) for x in images]
+ del_opt = args.delete_temporary_files
+ dem=args.DEM
+ cam_folder = args.cam
+ ba_prefix = args.ba_prefix
+ mode = args.mode
+ if mode == 'browse':
+ """
+ this block creates low-res orthomosaics from RPC info for browsing purpose only
+ """
+ for_img_list,nadir_img_list,aft_img_list,for_time,nadir_time,aft_time = skysat.sort_img_list(images)
+ for_out_dir = os.path.join(outdir,'for_map_browse')
+ nadir_out_dir = os.path.join(outdir,'nadir_map_browse')
+ aft_out_dir = os.path.join(outdir,'aft_map_browse')
+ for_out_list = [os.path.join(for_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in for_img_list]
+ nadir_out_list = [os.path.join(nadir_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in nadir_img_list]
+ aft_out_list = [os.path.join(aft_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in aft_img_list]
+ for_count,nadir_count,aft_count = [len(for_img_list), len(nadir_img_list), len(aft_img_list)]
+ print("Performing orthorectification for forward images {}".format(for_time))
+ for_map_log = p_map(asp.mapproject,for_img_list,for_out_list,[args.session]*for_count,['WGS84']*for_count,[None]*for_count,
+ ['EPSG:4326']*for_count,[None]*for_count,[None]*for_count,[None]*for_count)
+ print("Performing orthorectification for nadir images {}".format(nadir_time))
+ nadir_map_log = p_map(asp.mapproject,nadir_img_list,nadir_out_list,[args.session]*nadir_count,['WGS84']*nadir_count,[None]*nadir_count,
+ ['EPSG:4326']*nadir_count,[None]*nadir_count,[None]*nadir_count,[None]*nadir_count)
+ print("Performing orthorectification for aft images {}".format(aft_time))
+ aft_map_log = p_map(asp.mapproject,aft_img_list,aft_out_list,[args.session]*aft_count,['WGS84']*aft_count,[None]*aft_count,
+ ['EPSG:4326']*aft_count,[None]*aft_count,[None]*aft_count,[None]*aft_count)
+ ortho_log = os.path.join(outdir,'low_res_ortho.log')
+ print("Orthorectification log saved at {}".format(ortho_log))
+ with open(ortho_log,'w') as f:
+ total_ortho_log = for_map_log+nadir_map_log+aft_map_log
+ for log in itertools.chain.from_iterable(total_ortho_log):
+ f.write(log)
+
+ # after orthorectification, now do mosaic
+ for_out_mos = os.path.join(outdir,'for_map_mos_{}m.tif'.format(tr))
+ for_map_list = sorted(glob.glob(os.path.join(for_out_dir,'*.tif')))
+ nadir_out_mos = os.path.join(outdir,'nadir_map_mos_{}m.tif'.format(tr))
+ nadir_map_list = sorted(glob.glob(os.path.join(nadir_out_dir,'*.tif')))
+ aft_out_mos = os.path.join(outdir,'aft_map_mos_{}m.tif'.format(tr))
+ aft_map_list = sorted(glob.glob(os.path.join(aft_out_dir,'*.tif')))
+ print("Preparing forward browse orthomosaic")
+ for_mos_log = asp.dem_mosaic(for_map_list,for_out_mos,tr,tsrs,stats='first',tile_size=None)
+ print("Preparing nadir browse orthomosaic")
+ nadir_mos_log = asp.dem_mosaic(nadir_map_list, nadir_out_mos, tr, tsrs,stats='first',tile_size=None)
+ print("Preparing aft browse orthomosaic")
+ aft_mos_log = asp.dem_mosaic(aft_map_list, aft_out_mos, tr, tsrs,stats='first',tile_size=None)
+ ## delete temporary files
+ if del_opt:
+ [shutil.rmtree(x) for x in [for_out_dir,nadir_out_dir,aft_out_dir]]
+ #Save figure to jpeg ?
+ fig_title = os.path.basename(images[0]).split('_',15)[0]+'_'+for_time+'_'+nadir_time+'_'+aft_time
+ fig,ax = plt.subplots(1,3,figsize=(10,10))
+ pltlib.iv_fn(for_out_mos,full=True,ax=ax[0],cmap='gray',scalebar=True,title='Forward')
+ pltlib.iv_fn(nadir_out_mos,full=True,ax=ax[1],cmap='gray',scalebar=True,title='NADIR')
+ pltlib.iv_fn(aft_out_mos,full=True,ax=ax[2],cmap='gray',scalebar=True,title='Aft')
+ plt.tight_layout(rect=[0, 0.03, 1, 0.95])
+ fig.suptitle(fig_title)
+ browse_img_fn = os.path.join(outdir,'browse_img_{}_{}m.jpg'.format(fig_title,tr))
+ fig.savefig(browse_img_fn,dpi=300,bbox_inches='tight',pad_inches=0.1)
+ print("Browse figure saved at {}".format(browse_img_fn))
+
+ if mode == 'science':
+ img_list = images
+ if args.overlap_list is not None:
+ # need to remove images and cameras which are not optimised during bundle adjustment
+ # read pairs from input overlap list
+ initial_count = len(img_list)
+ with open(args.overlap_list) as f:
+ content = f.readlines()
+ content = [x.strip() for x in content]
+ l_img = [x.split(' ')[0] for x in content]
+ r_img = [x.split(' ')[1] for x in content]
+ total_img = l_img + r_img
+ uniq_idx = np.unique(total_img, return_index=True)[1]
+ img_list = [total_img[idx] for idx in sorted(uniq_idx)]
+
+ print(f"Out of the initial {initial_count} images, {len(img_list)} will be orthorectified using adjusted cameras")
+
+ if args.frame_index is not None:
+ frame_index = skysat.parse_frame_index(args.frame_index)
+ img_list = [glob.glob(os.path.join(dir,'{}*.tiff'.format(frame)))[0] for frame in frame_index.name.values]
+ print("no of images is {}".format(len(img_list)))
+ img_prefix = [os.path.splitext(os.path.basename(img))[0] for img in img_list]
+ out_list = [os.path.join(outdir,img+'_map.tif') for img in img_prefix]
+ session_list = [args.session]*len(img_list)
+ dem_list = [dem]*len(img_list)
+ tr_list = [args.tr]*len(img_list)
+ if args.frame_index is not None:
+ # this hack is for video
+ df = skysat.parse_frame_index(args.frame_index)
+ trunc_df = df[df['name'].isin(img_prefix)]
+ tr_list = [str(gsd) for gsd in trunc_df.gsd.values]
+ srs_list = [tsrs]*len(img_list)
+ if args.session == 'pinhole':
+ if ba_prefix:
+ cam_list = [glob.glob(os.path.abspath(ba_prefix)+'-'+os.path.splitext(os.path.basename(x))[0]+'*.tsai')[0] for x in img_list]
+ print("No of cameras is {}".format(len(cam_list)))
+ else:
+ print(os.path.join(os.path.abspath(args.cam),os.path.splitext(os.path.basename(img_list[0]))[0]+'*.tsai'))
+ cam_list = [glob.glob(os.path.join(os.path.abspath(args.cam),os.path.splitext(os.path.basename(x))[0]+'*.tsai'))[0] for x in img_list]
+ else:
+ cam_list = [None]*len(img_list)
+ if ba_prefix:
+ # not yet implemented
+ ba_prefix_list = [ba_prefix]*len(img_list)
+
+ print("Mapping given images")
+ ortho_logs = p_map(asp.mapproject,img_list,out_list,session_list,dem_list,tr_list,srs_list,cam_list,
+ [None]*len(img_list),[None]*len(img_list),num_cpus=int(cpu_count()/4))
+ ortho_log = os.path.join(outdir,'ortho.log')
+ print("Saving Orthorectification log at {}".format(ortho_log))
+ with open(ortho_log,'w') as f:
+ for log in ortho_logs:
+ f.write(log)
+ if args.copy_rpc == 1:
+ print("Copying RPC from native image to orthoimage in parallel")
+ copy_rpc_out = p_map(skysat.copy_rpc,img_list,out_list,num_cpus=cpu_count())
+ if args.orthomosaic == 1:
+ print("Will also produce median, weighted average and highest resolution orthomosaic")
+ if args.data == 'triplet':
+ # sort images based on timestamps and resolutions
+ img_list, time_list = skysat.sort_img_list(out_list)
+ res_sorted_list = skysat.res_sort(out_list)
+
+ # define mosaic prefix containing timestamps of inputs
+ mos_prefix = '_'.join(np.unique([t.split('_')[0] for t in time_list]))+'__'+'_'.join(np.unique([t.split('_')[1] for t in time_list]))
+
+ # define output filenames
+ res_sorted_mosaic = os.path.join(outdir,'{}_finest_orthomosaic.tif'.format(mos_prefix))
+ median_mosaic = os.path.join(outdir,'{}_median_orthomosaic.tif'.format(mos_prefix))
+ wt_avg_mosaic = os.path.join(outdir,'{}_wt_avg_orthomosaic.tif'.format(mos_prefix))
+ indi_mos_list = [os.path.join(outdir,f'{time}_first_orthomosaic.tif') for time in time_list]
+
+
+ print("producing finest resolution on top mosaic, per-pixel median and wt_avg mosaic")
+ all_3_view_mos_logs = p_map(asp.dem_mosaic, [res_sorted_list]*3, [res_sorted_mosaic,median_mosaic,wt_avg_mosaic],
+ ['None']*3, [None]*3, ['first','median',None],[None]*3,num_cpus=4)
+
+ print("producing idependent mosaic for different views in parallel")
+ indi_mos_count = len(time_list)
+ if indi_mos_count>3:
+ tile_size = 400
+ else:
+ tile_size = None
+
+ indi_mos_log = p_map(asp.dem_mosaic,img_list, indi_mos_list, ['None']*indi_mos_count, [None]*indi_mos_count,
+ ['first']*indi_mos_count,[tile_size]*indi_mos_count)
+
+ # write out log files
+ out_log = os.path.join(outdir,'science_mode_ortho_mos.log')
+ total_mos_log = all_3_view_mos_logs+indi_mos_log
+ print("Saving orthomosaic log at {}".format(out_log))
+ with open(out_log,'w') as f:
+ for log in itertools.chain.from_iterable(total_mos_log):
+ f.write(log)
+
+ if args.data == 'video':
+ res_sorted_list = skysat.res_sort(out_list)
+ print("producing orthomasaic with finest on top")
+ res_sorted_mosaic = os.path.join(outdir,'video_finest_orthomosaic.tif')
+ print("producing orthomasaic with per-pixel median stats")
+ median_mosaic = os.path.join(outdir,'video_median_orthomosaic.tif')
+ print("producing orthomosaic with weighted average statistics")
+ wt_avg_mosaic = os.path.join(outdir,'video_wt_avg_orthomosaic.tif')
+ print("Mosaicing will be done in parallel")
+ all_3_view_mos_logs = p_map(asp.dem_mosaic, [res_sorted_list]*3, [res_sorted_mosaic,median_mosaic,wt_avg_mosaic], ['None']*3, [None]*3, ['first','median',None],[None]*3)
+ out_log = os.path.join(outdir,'science_mode_ortho_mos.log')
+ print("Saving orthomosaic log at {}".format(out_log))
+ with open(out_log,'w') as f:
+ for log in all_3_view_mos_logs:
+ f.write(log)
+ print("Script is complete!")
+
+if __name__=='__main__':
+ main()
+
diff --git a/scripts/legacy/skysat_overlap.py b/scripts/legacy/skysat_overlap.py
new file mode 100755
index 0000000..8057692
--- /dev/null
+++ b/scripts/legacy/skysat_overlap.py
@@ -0,0 +1,105 @@
+#! /usr/bin/env python
+
+import argparse
+import glob
+from skysat_stereo import asp_utils as asp
+from skysat_stereo import skysat
+from skysat_stereo import misc_geospatial as geo
+import time
+import os,sys,glob
+from p_tqdm import p_umap, p_map
+from multiprocessing import cpu_count
+from shapely.geometry import Polygon
+from itertools import combinations,compress
+import numpy as np
+import geopandas as gpd
+import pandas as pd
+def getparser():
+ parser = argparse.ArgumentParser(description='Script to make overlapping pairs based on user defined minimum overlap percentage')
+ parser.add_argument('-img_folder', help='Folder containing images with RPC information', required=True)
+ parser.add_argument('-percentage', '--percentage', help='percentage_overlap between 0 to 1', required=True)
+ parser.add_argument('-outfn','--out_fn',help='Text file containing the overlapping pairs')
+ parser.add_argument('-cross_track',action='store_true',help='Also make cross-track pairs')
+ parser.add_argument('-aoi_bbox',help='Return interesecting footprint within this aoi only',default=None)
+ return parser
+
+# Global var
+geo_crs = 'EPSG:4326'
+
+def main():
+ #The following block of code is useful for getting a shapefile encompassing the entire subset (Use for clipping DEMs etc)
+ #Also, I define the local ortho coordinates using the center of the big bounding box
+ init_time = time.time()
+ parser = getparser()
+ args = parser.parse_args()
+ img_folder = args.img_folder
+ try:
+ img_list = sorted(glob.glob(os.path.join(img_folder,'*.tif')))
+ print("Number of images {}".format(len(img_list)))
+ except:
+ print ("No images found in the directory. Make sure they end with a .tif extension")
+ sys.exit()
+ out_fn = args.out_fn
+ perc_overlap = np.float(args.percentage)
+ out_shp = os.path.splitext(out_fn)[0]+'_bound.gpkg'
+ n_proc = cpu_count()
+ shp_list = p_umap(skysat.skysat_footprint,img_list,num_cpus=2*n_proc)
+ merged_shape = geo.shp_merger(shp_list)
+ bbox = merged_shape.total_bounds
+ print (f'Bounding box lon_lat is:{bbox}')
+ bound_poly = Polygon([[bbox[0],bbox[3]],[bbox[2],bbox[3]],[bbox[2],bbox[1]],[bbox[0],bbox[1]]])
+ bound_shp = gpd.GeoDataFrame(index=[0],geometry=[bound_poly],crs=geo_crs)
+ bound_centroid = bound_shp.centroid
+ cx = bound_centroid.x.values[0]
+ cy = bound_centroid.y.values[0]
+ pad = np.ptp([bbox[3],bbox[1]])/6.0
+ lat_1 = bbox[1]+pad
+ lat_2 = bbox[3]-pad
+ #local_ortho = '+proj=ortho +lat_0={} +lon_0={}'.format(cy,cx)
+ local_aea = "+proj=aea +lat_1={} +lat_2={} +lat_0={} +lon_0={} +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs".format(lat_1,lat_2,cy,cx)
+ print ('Local Equal Area coordinate system is : {} \n'.format(local_aea))
+ print('Saving bound shapefile at {} \n'.format(out_shp))
+ bound_shp.to_file(out_shp,driver='GPKG')
+
+
+ # condition to check bbox aoi
+ if args.aoi_bbox:
+ bbox = gpd.read_file(args.aoi_bbox)
+ mask = merged_shape.to_crs(bbox.crs).intersects(bbox)
+ img_list = merged_shape[mask].img.values
+
+ img_combinations = list(combinations(img_list,2))
+ n_comb = len(img_combinations)
+ perc_overlap = np.ones(n_comb,dtype=float)*perc_overlap
+ proj = local_aea
+ tv = p_map(skysat.frame_intsec, img_combinations, [proj]*n_comb, perc_overlap,num_cpus=4*n_proc)
+ # result to this contains truth value (0 or 1, overlap percentage)
+ truth_value = [tvs[0] for tvs in tv]
+ overlap = [tvs[1] for tvs in tv]
+ valid_list = list(compress(img_combinations,truth_value))
+ overlap_perc_list = list(compress(overlap,truth_value))
+ print('Number of valid combinations are {}, out of total {} input images making total combinations {}\n'.format(len(valid_list),len(img_list),n_comb))
+ with open(out_fn, 'w') as f:
+ img1_list = [x[0] for x in valid_list]
+ img2_list = [x[1] for x in valid_list]
+ for idx,i in enumerate(valid_list):
+ #f.write("%s %s\n" % i)
+ f.write(f"{os.path.abspath(img1_list[idx])} {os.path.abspath(img2_list[idx])}\n")
+ out_fn_overlap = os.path.splitext(out_fn)[0]+'_with_overlap_perc.pkl'
+ img1_list = [x[0] for x in valid_list]
+ img2_list = [x[1] for x in valid_list]
+ out_df = pd.DataFrame({'img1':img1_list,'img2':img2_list,'overlap_perc':overlap_perc_list})
+ out_df.to_pickle(out_fn_overlap)
+ if args.cross_track:
+ cross_track = True
+ else:
+ cross_track = False
+ out_fn_stereo = os.path.splitext(out_fn_overlap)[0]+'_stereo_only.pkl'
+ stereo_only_df = skysat.prep_trip_df(out_fn_overlap,cross_track=cross_track)
+ stereo_only_df.to_pickle(out_fn_stereo)
+ out_fn_stereo_ba = os.path.splitext(out_fn_overlap)[0]+'_stereo_only.txt'
+ stereo_only_df[['img1','img2']].to_csv(out_fn_stereo_ba,sep=' ',header=False,index=False)
+ print('Script completed in time {} s!'.format(time.time()-init_time))
+
+if __name__=="__main__":
+ main()
diff --git a/scripts/legacy/skysat_preprocess.py b/scripts/legacy/skysat_preprocess.py
new file mode 100755
index 0000000..5020d0a
--- /dev/null
+++ b/scripts/legacy/skysat_preprocess.py
@@ -0,0 +1,114 @@
+#! /usr/bin/env python
+
+import os,sys,glob,re
+import argparse
+from pygeotools.lib import iolib,malib
+from skysat_stereo import asp_utils as asp
+from skysat_stereo import skysat
+from p_tqdm import p_map
+import numpy as np
+from multiprocessing import cpu_count
+import pandas as pd
+
+def getparser():
+ parser = argparse.ArgumentParser(description = 'Script for initialing frame cameras for Skysat triplet stereo and video, performing user defined video subsampling')
+ modes = ['video','triplet']
+ parser.add_argument('-mode',default='video',choices=modes, help='choose Skysat product to work with')
+ session_choices = ['rpc','pinhole']
+ parser.add_argument('-t',default='pinhole',choices=session_choices,help='choose between pinhole and rpc mode (default: %(default)s)')
+ parser.add_argument('-img',default=None,help='folder containing images',required=True)
+ sampling_mode_choices = ['sampling_interval', 'num_images']
+ parser.add_argument('-video_sampling_mode', default = 'num_images', choices = sampling_mode_choices, required = False, help = 'Chose desired sampling procedure, either fixed sampling interval or by equally distributed user defined number of samples (default: %(default)s)')
+ parser.add_argument('-sampler',default = 5 ,type = int, help = 'if video_sampling_mode: sampling_interval, this is the sampling interval, else this is the number of samples to be selected (default: %(default)s)')
+ parser.add_argument('-outdir', default = None, required = True, help = 'Output folder to save cameras and GCPs')
+ parser.add_argument('-frame_index',default=None,help='Frame index csv file provided with L1A video products, will be used for determining stereo combinations')
+ parser.add_argument('-overlap_pkl',default=None,help='pkl dataframe containing entries of overlapping pairs for triplet run, obtained from skysat_overlap_parallel.py')
+ parser.add_argument('-dem',default=None,help='Reference DEM to be used for frame camera initialisation')
+ product_levels = ['l1a','l1b']
+ parser.add_argument('-product_level', choices = product_levels,default='l1b',required = False, help = 'Product level being processed, (default: %(default)s)')
+ return parser
+
+def main():
+ parser = getparser()
+ args = parser.parse_args()
+ mode = args.mode
+ session = args.t
+ img_folder = os.path.abspath(args.img)
+ outdir = os.path.abspath(args.outdir)
+ if not os.path.exists(outdir):
+ try:
+ os.makedir(outdir)
+ except:
+ os.makedirs(outdir)
+ if mode == 'video':
+ sampling = args.video_sampling_mode
+ frame_index = skysat.parse_frame_index(args.frame_index,True)
+ product_level = 'l1a'
+ num_samples = len(frame_index)
+ frames = frame_index.name.values
+ sampler = args.sampler
+ outdf = os.path.join(outdir,os.path.basename(args.frame_index))
+ if sampling == 'sampling_interval':
+ print("Hardcoded sampling interval results in frame exclusion at the end of the video sequence based on step size, better to chose the num_images mode and the program will equally distribute accordingly")
+ idx = np.arange(0,num_samples,sampler)
+ outdf = '{}_sampling_inteval_{}.csv'.format(os.path.splitext(outdf)[0],sampler)
+ else:
+ print("Sampling {} from {} of the input video sequence".format(sampler,num_samples))
+ idx = np.linspace(0,num_samples-1,sampler,dtype=int)
+ outdf = '{}_sampling_inteval_aprox{}.csv'.format(os.path.splitext(outdf)[0],idx[1]-idx[0])
+ sub_sampled_frames = frames[idx]
+ sub_df = frame_index[frame_index['name'].isin(list(sub_sampled_frames))]
+ sub_df.to_csv(outdf,sep=',',index=False)
+ #this is camera/gcp initialisation
+ n = len(sub_sampled_frames)
+ img_list = [glob.glob(os.path.join(img_folder,'{}*.tiff'.format(frame)))[0] for frame in sub_sampled_frames]
+ pitch = [1]*n
+ out_fn = [os.path.join(outdir,'{}_frame_idx.tsai'.format(frame)) for frame in sub_sampled_frames]
+ out_gcp = [os.path.join(outdir,'{}_frame_idx.gcp'.format(frame)) for frame in sub_sampled_frames]
+ frame_index = [args.frame_index]*n
+ camera = [None]*n
+ gcp_factor = 4
+
+ elif mode == 'triplet':
+ df = pd.read_pickle(args.overlap_pkl)
+ img_list = list(np.unique(np.array(list(df.img1.values)+list(df.img2.values))))
+ img_list = [os.path.splitext(os.path.basename(img))[0] for img in img_list]
+ cam_list = [glob.glob(os.path.join(img_folder,'{}*.tif'.format(img)))[0] for img in img_list]
+ n = len(img_list)
+ if args.product_level == 'l1b':
+ pitch = [0.8]*n
+ else:
+ pitch = [1.0]*n
+ out_fn = [os.path.join(outdir,'{}_rpc.tsai'.format(frame)) for frame in img_list]
+ out_gcp = [os.path.join(outdir,'{}_rpc.gcp'.format(frame)) for frame in img_list]
+ camera = cam_list
+ frame_index = [None]*n
+ img_list = cam_list
+ gcp_factor = 8
+ fl = [553846.153846]*n
+ cx = [1280]*n
+ cy = [540]*n
+ dem = args.dem
+ ht_datum = [malib.get_stats_dict(iolib.fn_getma(dem))['median']]*n # use this value for height where DEM has no-data
+ gcp_std = [1]*n
+ datum = ['WGS84']*n
+ refdem = [dem]*n
+ n_proc = 30
+ #n_proc = cpu_count()
+ cam_gen_log = p_map(asp.cam_gen,img_list,fl,cx,cy,pitch,ht_datum,gcp_std,out_fn,out_gcp,datum,refdem,camera,frame_index,num_cpus = n_proc)
+ print("writing gcp with basename removed")
+ # count expexted gcp
+ print(f"Total expected GCP {gcp_factor*n}")
+ asp.clean_gcp(out_gcp,outdir)
+ # saving subprocess consolidated log file
+ from datetime import datetime
+ now = datetime.now()
+ log_fn = os.path.join(outdir,'camgen_{}.log'.format(now))
+ print("saving subprocess camgen log at {}".format(log_fn))
+ with open(log_fn,'w') as f:
+ for log in cam_gen_log:
+ f.write(log)
+ print("Script is complete !")
+
+if __name__=="__main__":
+ main()
diff --git a/scripts/legacy/skysat_stereo_cli.py b/scripts/legacy/skysat_stereo_cli.py
new file mode 100755
index 0000000..cfe2d17
--- /dev/null
+++ b/scripts/legacy/skysat_stereo_cli.py
@@ -0,0 +1,125 @@
+#! /usr/bin/env python
+
+from skysat_stereo import asp_utils as asp
+from skysat_stereo import skysat
+import numpy as np
+import argparse
+import os,sys,glob
+from multiprocessing import cpu_count
+from p_tqdm import p_map
+from tqdm import tqdm
+
+def getparser():
+ parser = argparse.ArgumentParser(description='Script for performing stereo jobs, generalised for skysat video and triplet stereo products')
+ modes = ['video', 'triplet']
+ parser.add_argument('-mode',default='video',choices=modes,help='choose Skysat product to work with')
+ session_choices = ['rpc', 'nadirpinhole', 'rpcmaprpc', 'pinholemappinhole']
+ # mapprojecting inputs are faster to process, and generally more complete
+ # (less holes) + accurate (less blunders in stereo matching)
+ parser.add_argument('-threads',default=cpu_count(),type=int,
+ help='number of threads to use for each stereo process, (default: %(default)s)')
+ entry_choice = ['pprc','corr','rfne','fltr','tri']
+ parser.add_argument('-entry_point',type=str,default='pprc',help='start stereo from a particular stage (default: %(default)s)')
+ parser.add_argument('-t',default='nadirpinhole',choices=session_choices,help='choose between pinhole and rpc mode (default: %(default)s)')
+ parser.add_argument('-img',default=None,help='folder containing images',required=True)
+ parser.add_argument('-cam',default=None,help='folder containing cameras, if using nadirpinhole/pinholemappinhole workflow',required=False)
+ # note that the camera should contain similar names as images. We do a
+ # simple string search to read appropriate camera.
+ parser.add_argument('-ba_prefix',default=None, help='bundle adjust prefix for reading transforms from .adjust files, mainly for rpc runs, or for reading the correct cameras from a bundle adjustment directory containing multiple generations of pinhole cameras', required=False)
+ parser.add_argument('-overlap_pkl',default=None,help='pkl dataframe containing entries of overlapping pairs for triplet run, obtained from skysat_overlap_parallel.py')
+ parser.add_argument('-frame_index',default=None,help='Frame index csv file provided with L1A video products, will be used for determining stereo combinations')
+ parser.add_argument('-sampling_interval',default=5,required=False,type=int,help='Sampling interval between stereo DEM input pairs, or the interval at which master images are picked for multiview stereo triangulation (default: %(default)s)')
+ parser.add_argument('-dem',default=None,help='Reference DEM to be used in triangulation, if input images are mapprojected')
+ texture_choices = ['low', 'normal']
+ parser.add_argument('-texture',default='normal',choices=texture_choices,help='keyword to adapt processing for low texture surfaces, for example in case of fresh snow (default: %(default)s)',required=False)
+ crop_ops = [1,0]
+ parser.add_argument('-crop_map',default=1,type=int,choices=crop_ops,help='To crop mapprojected images to same resolution and extent or not before stereo')
+ parser.add_argument('-outfol', default=None, help='output folder where stereo outputs will be saved', required=True)
+ mvs_choices = [1, 0]
+ parser.add_argument('-mvs', default=0, type=int, choices=mvs_choices, help='1: Use multiview stereo triangulation for video data, do matching with next 20 slave for each master image/camera (defualt: %(default)s')
+ parser.add_argument('-block', default=0, type=int, choices=mvs_choices, help='1: use block matching instead of default MGM (default: %(default)s')
+ parser.add_argument('-full_extent',type=int,choices = mvs_choices,default=1,
+ help='Selecting larger intervals can result in lower footprint output DEM, if 1: then DEMs with smaller interval image pairs will be padded at the begining and end of the video sequence (default: %(default)s)')
+ parser.add_argument('-writeout_only', action='store_true', help='writeout_jobs to a text file, not run')
+ parser.add_argument('-job_fn',type=str,help='text file to write stereo jobs to')
+ parser.add_argument('-cross_track',action='store_true', help='attempt stereo for cross_track pairs as well')
+ return parser
+
+def main():
+ parser = getparser()
+ args = parser.parse_args()
+ img = os.path.abspath(args.img)
+ try:
+ img_list = sorted(glob.glob(os.path.join(img, '*.tif')))
+ temp = img_list[1]
+ except BaseException:
+ img_list = sorted(glob.glob(os.path.join(img, '*.tiff')))
+ if len(img_list) == 0:
+ print("No images in the specified folder, exiting")
+ sys.exit()
+ mode = args.mode
+ session = args.t
+ ba_prefix = args.ba_prefix
+ overlap_list_fn = args.overlap_pkl
+ frame_index = args.frame_index
+ dem = args.dem
+ texture = args.texture
+ sampling_interval = args.sampling_interval
+ if args.cam:
+ cam_folder = args.cam
+ if args.ba_prefix:
+ ba_prefix = args.ba_prefix
+ outfol = args.outfol
+ if mode == 'video':
+ # assume for now that we are still operating on a fixed image interval method
+ # can accomodate different convergence angle function method here.
+ frame_gdf = skysat.parse_frame_index(frame_index)
+ # for now hardcording sgm,mgm,kernel params, should accept as inputs.
+ # Maybe discuss with David with these issues/decisions when the overall
+ # system is in place
+ if args.mvs == 1:
+ job_list = skysat.video_mvs(img,t=session,cam_fol=args.cam,ba_prefix=args.ba_prefix,dem=args.dem,sampling_interval=sampling_interval,texture=texture,outfol=outfol, block=args.block,frame_index=frame_gdf)
+ else:
+ if args.full_extent == 1:
+ full_extent = True
+ else:
+ full_extent=False
+ job_list = skysat.prep_video_stereo_jobs(img,t=session,cam_fol=args.cam,ba_prefix=args.ba_prefix,dem=args.dem,sampling_interval=sampling_interval,texture=texture,outfol=outfol,block=args.block,frame_index=frame_gdf,full_extent=full_extent,entry_point=args.entry_point)
+ elif mode == 'triplet':
+ if args.crop_map == 1:
+ crop_map = True
+ else:
+ crop_map = False
+ job_list = skysat.triplet_stereo_job_list(cross_track=args.cross_track,t=args.t,
+ threads = args.threads,overlap_list=args.overlap_pkl, img_list=img_list, ba_prefix=args.ba_prefix, cam_fol=args.cam, dem=args.dem, crop_map=crop_map,texture=texture, outfol=outfol, block=args.block,entry_point=args.entry_point)
+ if not args.writeout_only:
+ # decide on number of processes
+ # if block matching, Plieades is able to handle 30-40 4 threaded jobs on bro node
+ # if MGM/SGM, 25 . This stepup is arbitrariry, research on it more.
+ # next build should accept no of jobs and stereo threads as inputs
+
+ print(job_list[0])
+ n_cpu = cpu_count()
+ # no of parallel jobs with user specified threads per job
+ jobs = int(n_cpu/args.threads)
+ stereo_log = p_map(asp.run_cmd,['stereo']*len(job_list), job_list, num_cpus=jobs)
+ stereo_log_fn = os.path.join(outfol,'stereo_log.log')
+ print("Consolidated stereo log saved at {}".format(stereo_log_fn))
+ #with open(stereo_log_fn,'w') as f:
+ # for logs in stereo_log:
+ # f.write(logs)
+ else:
+ print(f"Writng jobs at {args.job_fn}")
+ print(f"hey typr of job is {type(job_list)}")
+
+ with open(args.job_fn,'w') as f:
+ for idx,job in enumerate(tqdm(job_list)):
+ try:
+ job_str = 'stereo ' + ' '.join(job) + '\n'
+ f.write(job_str)
+ except:
+ continue
+ print("Script is complete")
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/optimise_raw_camera.py b/scripts/optimise_raw_camera.py
index d8e2bb9..9701993 100755
--- a/scripts/optimise_raw_camera.py
+++ b/scripts/optimise_raw_camera.py
@@ -10,6 +10,7 @@
import argparse
from pygeotools.lib import iolib,geolib
import logging
+from pyproj import Transformer
def cam_solve(q1,q2,q3,q4,CX,CY,CZ,cu,cv,fu,fv,pitch,X,Y,Z):
"""
@@ -128,7 +129,15 @@ def main():
frame_index = pd.read_pickle(f_index)
logging.info("sample fn {}".format(glob.glob(os.path.join(args.camera_folder,
'*{}*.tsai'.format(frame_index['name'].values[0])))))
- cam_list = [glob.glob(os.path.join(args.camera_folder,'*{}*.tsai'.format(os.path.basename(frame))))[0] for frame in frame_index['name'].values]
+
+ # cam_list = [glob.glob(os.path.join(args.camera_folder,'*{}*.tsai'.format(os.path.basename(frame))))[0] for frame in frame_index['name'].values]
+ cam_list = []
+ for frame in frame_index['name'].values:
+ try:
+ cam_list.append(glob.glob(os.path.join(args.camera_folder,'*{}*.tsai'.format(os.path.basename(frame))))[0])
+ except:
+ continue
+
if not args.gcp_folder:
gcp_folder = args.camera_folder
else:
@@ -150,7 +159,10 @@ def main():
gcp = pd.read_csv(glob.glob(os.path.join(gcp_folder,'*{}*.gcp'.format(identifier)))[0],header=None,sep=' ')
im_x,im_y = [gcp[8].values,gcp[9].values]
lon,lat,ht = [gcp[2].values,gcp[1].values,gcp[3].values]
- X,Y,Z = geolib.ll2ecef(lon,lat,ht)
+ ecef_proj = 'EPSG:4978'
+ geo_proj = 'EPSG:4326'
+ wgs2ecef = Transformer.from_crs(geo_proj,ecef_proj)
+ X,Y,Z = wgs2ecef.transform(lat,lon,ht)
CX_idx,CY_idx,CZ_idx = [CX[idx],CY[idx],CZ[idx]]
q1_idx,q2_idx,q3_idx,q4_idx = [q1[idx],q2[idx],q3[idx],q4[idx]]
#tpl_int = (q1_idx,q2_idx,q3_idx,q4_idx)
diff --git a/scripts/prep_dense_ba_run.py b/scripts/prep_dense_ba_run.py
index 508cf9f..37eb9fa 100755
--- a/scripts/prep_dense_ba_run.py
+++ b/scripts/prep_dense_ba_run.py
@@ -4,6 +4,7 @@
import argparse
import numpy
from skysat_stereo import skysat
+from skysat_stereo import skysat_stereo_workflow as workflow
from tqdm import tqdm
import pandas as pd
import shutil
@@ -25,43 +26,19 @@ def main():
parser = getparser()
args = parser.parse_args()
stereo_master_dir = os.path.abspath(args.stereo_dir)
- triplet_stereo_matches = sorted(glob.glob(os.path.join(stereo_master_dir,'20*/*/run*-*disp*.match')))
- print('Found {} dense matches'.format(len(triplet_stereo_matches)))
ba_dir = os.path.abspath(args.ba_dir)
- if not os.path.isdir(ba_dir):
- os.makedirs(ba_dir)
- out_dense_match_list = [os.path.join(ba_dir,'run-'+os.path.basename(match).split('run-disp-',15)[1]) for match in triplet_stereo_matches]
- for idx,match in tqdm(enumerate(triplet_stereo_matches)):
- shutil.copy2(match, out_dense_match_list[idx])
- print("Copied all files successfully")
if args.modify_overlap == 1:
img_fol = os.path.abspath(args.img)
- orig_df = pd.read_pickle(os.path.abspath(args.orig_pickle))
- dense_df = pd.read_pickle(os.path.abspath(args.dense_match_pickle))
- dense_img1 = list(dense_df.img1.values)
- dense_img2 = list(dense_df.img2.values)
- prioirty_list = list(zip(dense_img1,dense_img2))
- regular_img1 = [os.path.basename(x) for x in orig_df.img1.values]
- regular_img2 = [os.path.basename(x) for x in orig_df.img2.values]
- secondary_list = list(zip(regular_img1,regular_img2))
- # adapted from https://www.geeksforgeeks.org/python-extract-unique-tuples-from-list-order-irrespective/
- # note that I am using the more inefficient answer on purpose, because I want to use image pair order from the dense match overlap list
- total_list = priority_list + secondary_list
- final_overlap_set = set()
- temp = [final_overlap_set.add((a, b)) for (a, b) in total_list
- if (a, b) and (b, a) not in final_overlap_set]
- new_img1 = [os.path.join(img_fol,pair[0]) for pair in list(final_overlap_set)]
- new_img2 = [os.path.join(img_fol,pair[1]) for pair in list(final_overlap_set)]
- if not args.out_overlap_fn:
- out_overlap = os.path.join(ba_dir,'overlap_list_adapted_from_dense_matches.txt')
- else:
- out_overlap = os.path.join(ba_dir,args.out_overlap_fn)
- print("Saving adjusted overlap list at {}".format(out_overlap))
- with open(out_overlap,'w') as foo:
- for idx,img1 in enumerate(new_img1):
- out_str = '{} {}\n'.format(img1,new_img2[idx])
- f.write(out_str)
+ orig_pickle = os.path.abspath(args.orig_pickle)
+ dense_match_pickle = os.path.abspath(args.dense_match_pickle)
+ else:
+ img_fol = None
+ orig_pickle=None
+ dense_match_pickle = None
+ workflow.dense_match_wrapper(stereo_master_dir,ba_dir,modify_overlap=args.modify_overlap,
+ img_fol=img_fol,orig_pickle=orig_pickle,dense_match_pickle=dense_match_pickle,
+ out_overlap_fn=args.out_overlap_fn)
print("Script is complete !")
if __name__=="__main__":
- main()
+ main()
\ No newline at end of file
diff --git a/scripts/skysat_ctrack.pbs b/scripts/skysat_ctrack.pbs
new file mode 100644
index 0000000..b87f269
--- /dev/null
+++ b/scripts/skysat_ctrack.pbs
@@ -0,0 +1,80 @@
+#PBS -S /bin/csh
+
+#Can be run interactively
+#qsub -N 169823_177845 -v pair=WV01_20110927_1020010016982300_1020010017784500 ~/bin/singlepair.pbs
+
+#Export environmental variables to batch job
+#PBS -V
+
+#Join stdout and stderr
+#PBS -j oe
+
+#Queue name
+#PBS -q long
+
+#Resources
+#PBS -l select=1:model=bro_ele,walltime=6:00:00
+
+#Mail options
+#PBS -m abe
+
+#Group ID
+# #This was NESSF
+# #PBS -W group_list=s1271
+# #Arendt
+# #PBS -W group_list=s1768
+# #FINESST
+## PBS -W group_list=s3224
+# #HMA2
+# PBS -W group_list=s2407
+#Rerunnable (y/n)
+#PBS -r n
+
+#Check to make sure we're given an input pair
+
+unalias cd
+
+if ($?PBS_O_WORKDIR) then
+ cd $PBS_O_WORKDIR
+else
+ setenv PBS_O_WORKDIR `pwd`
+endif
+
+
+set ts = `date +%Y%m%d_%H%M`
+set logdir = $PBS_O_WORKDIR/log
+if (! -d $logdir) mkdir $logdir
+set jobid = `echo $PBS_JOBID | awk -F'.' '{print $1}'`
+set pair = "skysat_ba"
+set logfile = $logdir/${pair}_${ts}_${jobid}.log
+
+echo $logfile
+
+#Wrapper script to run ASP
+#set script = ./skysat_hardcode.sh
+#set script = ./bundle_adjust_skysat.sh
+#set script = /nobackupp11/sbhusha1/sw/wv_stereo_processing/scripts/new_dg_stereo_SGM.sh
+
+#Create a local copy of script in output directory, for reference
+#set script_cp = $pair/${script:t:r}_${jobid}.${script:e}
+#cp -pv $script $script_cp
+
+echo "Current directory is:"
+pwd
+echo
+
+#set rpcdem = ../stack_all/*gaussfill-tile-0.tif
+#set rpcdem = /nobackup/deshean/snowex/stereo/gm/orig_products/demcoreg_ref_ASO_dsm/gm_8m_trans-tile-0_gaussfill-tile-0.tif
+#set rpcdem = /nobackup/deshean/salardeuni/20190727_sdi_x/rename/P1BS/sdu_x_3697m_dem.tif
+
+#This was for rerunning with updated rpcdem
+if (! $?rpcdem) then
+ set rpcdem = ""
+endif
+
+#bash $script >& $logfile
+#$script_cp $pair $rpcdem $resol >& $logfile
+
+#$script_cp $pair >& $logfile
+
+parallel --progress -j 40 < $job_fn >& $logfile
diff --git a/scripts/skysat_dem_mos.py b/scripts/skysat_dem_mos.py
index dcb3bc6..b878a99 100755
--- a/scripts/skysat_dem_mos.py
+++ b/scripts/skysat_dem_mos.py
@@ -5,17 +5,20 @@
import argparse
from skysat_stereo import asp_utils as asp
from skysat_stereo import skysat
+from skysat_stereo import skysat_stereo_workflow as workflow
+from tqdm import tqdm
from p_tqdm import p_map
-import itertools
+
from pygeotools.lib import iolib,warplib
def getparser():
parser = argparse.ArgumentParser(description='Script to compute DEM mosaics from triplet output directory')
parser.add_argument('-DEM_folder', help='Folder containing subdirectories of DEM', required=True)
- parser.add_argument('-out_folder', help='Where composite DEMs are to be saved, if none, creates a composite DEM directory in the input main directory', required=False)
- parser.add_argument('-identifier',help='if we want to mosaic individually aligned DEM which have been produced by skysat_coreg.py, place the identifiers here',required=False,default=None)
+ parser.add_argument('-out_folder', help='Where composite DEMs are to be saved, if none, creates a composite DEM directory in the input main directory', required=False,default=None)
+ parser.add_argument('-identifier',help='if we want to mosaic individually aligned DEM which have been produced by skysat_pc_cam.py, place the identifiers here',required=False,default=None)
mode_ch = ['video','triplet']
parser.add_argument('-mode',default='triplet',choices=mode_ch,help="select if mosaicing video or triplet stereo output DEMs (default: %(default)s)")
+ parser.add_argument('-tile_size',default=None,help='Tile size for tiled processing, helpful on nodes with less memory or if num_dems are large')
binary_ch = [1,0]
parser.add_argument('-filter_dem',choices=binary_ch,default=1,type=int,
help="filter video DEM composites using max NMAD and min count combination (default: %(default)s)")
@@ -23,102 +26,16 @@ def getparser():
help='minimum DEM count to use in filtering (default: %(default)s)')
parser.add_argument('-max_video_nmad',type=float,default=5,
help='maximum DEM NMAD variability to filter, if DEM count is also <= min_count (default: %(default)s)')
- return parser
+ return parser
def main():
parser = getparser()
args = parser.parse_args()
dir = os.path.abspath(args.DEM_folder)
- if args.out_folder:
- out_folder = os.path.abspath(args.out_folder)
- else:
- out_folder = os.path.join(dir,'composite_dems')
- if not os.path.exists(out_folder):
- os.makedirs(out_folder)
- if args.identifier:
- # for indi align DEMs
- identifier = args.identifier
- else:
- identifier = ''
- if args.mode == 'triplet':
- dir_list = sorted(glob.glob(os.path.join(dir,'20*/')))
- valid_for_nadir_dir = []
- valid_for_aft_dir = []
- valid_nadir_aft_dir = []
- for for_nadir_dir in sorted(glob.glob(os.path.join(dir_list[0],'*/'))):
- try:
- D_sub = iolib.fn_getma(os.path.join(for_nadir_dir,'run-D_sub.tif'),3)
- stats = [np.percentile(D_sub.compressed(),(2,98)),np.mean(D_sub.compressed())]
- DEM = glob.glob(os.path.join(for_nadir_dir,'run*{}*-DEM.tif'.format(identifier)))[0]
- valid_for_nadir_dir.append(for_nadir_dir)
- except:
- continue
- for for_aft_dir in sorted(glob.glob(os.path.join(dir_list[1],'*/'))):
- try:
- # see ASP issue for this dirty hack: https://github.com/NeoGeographyToolkit/StereoPipeline/issues/308
- D_sub = iolib.fn_getma(os.path.join(for_aft_dir,'run-D_sub.tif'),3)
- stats = [np.percentile(D_sub.compressed(),(2,98)),np.mean(D_sub.compressed())]
- DEM = glob.glob(os.path.join(for_aft_dir,'run*{}*-DEM.tif'.format(identifier)))[0]
- valid_for_aft_dir.append(for_aft_dir)
- except:
- continue
- for nadir_aft_dir in sorted(glob.glob(os.path.join(dir_list[2],'*/'))):
- try:
- D_sub = iolib.fn_getma(os.path.join(nadir_aft_dir,'run-D_sub.tif'),3)
- stats = [np.percentile(D_sub.compressed(),(2,98)),np.mean(D_sub.compressed())]
- DEM = glob.glob(os.path.join(nadir_aft_dir,'run*{}*-DEM.tif'.format(identifier)))[0]
- valid_nadir_aft_dir.append(nadir_aft_dir)
- except:
- continue
- for_nadir_list = [glob.glob(os.path.join(dir,'run*{}*-DEM.tif'.format(identifier)))[0] for dir in valid_for_nadir_dir]
- nadir_aft_list = [glob.glob(os.path.join(dir,'run*{}*-DEM.tif'.format(identifier)))[0] for dir in valid_nadir_aft_dir]
- for_aft_list = [glob.glob(os.path.join(dir,'run*{}*-DEM.tif'.format(identifier)))[0] for dir in valid_for_aft_dir]
- total_dem_list = for_nadir_list+for_aft_list+nadir_aft_list
- stats_list = ['nmad','count','median']
- print('total dems are {}'.format(len(total_dem_list)))
- out_fn_list = [os.path.join(out_folder,'triplet_{}_mos.tif'.format(stat)) for stat in stats_list]
- print("Mosaicing output total per-pixel nmad, count, nmad and 3 DEMs from 3 stereo combinations in parallel")
- dem_mos_log = p_map(asp.dem_mosaic,[total_dem_list]*3+[for_aft_list,nadir_aft_list,for_nadir_list],out_fn_list+[os.path.join(out_folder,x) for x in ['for_aft_dem_median_mos.tif', 'nadir_aft_dem_median_mos.tif', 'for_nadir_dem_median_mos.tif']],['None']*6,[None]*6,stats_list+['median']*3,[None]*6,num_cpus=4)
- out_log_fn = os.path.join(out_folder,'skysat_triplet_dem_mos.log')
- print("Saving triplet DEM mosaic log at {}".format(out_log_fn))
- with open(out_log_fn,'w') as f:
- for log in dem_mos_log:
- f.write(log)
- elif args.mode=='video':
- dir_list = sorted(glob.glob(os.path.join(dir,'1*/')))
- valid_video_dir = []
- for video_dir in dir_list:
- try:
- D_sub = iolib.fn_getma(os.path.join(video_dir,'run-D_sub.tif'),3)
- stats = [np.percentile(D_sub.compressed(),(2,98)),np.mean(D_sub.compressed())]
- DEM = glob.glob(os.path.join(video_dir,'run*{}*-DEM.tif'.format(identifier)))[0]
- valid_video_dir.append(video_dir)
- except:
- continue
- video_dem_list = [glob.glob(os.path.join(dir,f'run*{identifier}*-DEM.tif'))[0] for dir in valid_video_dir]
- stats_list = ['median','count','nmad']
- print('total dems are {}'.format(len(video_dem_list)))
- out_fn_list = [os.path.join(out_folder,'video_{}_mos.tif'.format(stat)) for stat in stats_list]
- dem_mos_log = p_map(asp.dem_mosaic,[video_dem_list]*3,out_fn_list,['None']*3,[None]*3,stats_list,[None]*3)
- out_log_fn = os.path.join(out_folder,'skysat_video_dem_mos.log')
- with open(out_log_fn,'w') as f:
- for log in dem_mos_log:
- f.write(log)
- if args.filter_dem == 1:
- print("Filtering DEM using NMAD and count metrics")
- min_count = args.min_video_count
- max_nmad = args.max_video_nmad
- print(f"Filter will use min count of {min_count} and max NMAD of {max_nmad}")
- mos_ds_list = warplib.memwarp_multi_fn(out_fn_list)
- # Filtered array list contains dem_filtered,nmad_filtered, count_filtered in order
- filtered_array_list = skysat.filter_video_dem_by_nmad(mos_ds_list,min_count,max_nmad)
- trailing_str = f'_filt_max_nmad{max_nmad}_min_count{min_count}.tif'
- out_filter_fn_list = [os.path.splitext(fn)[0]+trailing_str for fn in out_fn_list]
- for idx,fn in enumerate(out_filter_fn_list):
- iolib.writeGTiff(filtered_array_list[idx],fn,mos_ds_list[idx])
+ workflow.dem_mosaic_wrapper(dir,mode=args.mode,out_folder=args.out_folder,identifier=args.identifier,
+ tile_size=args.tile_size,filter_dem=args.filter_dem,
+ min_video_count=args.min_video_count,max_video_nmad=args.max_video_nmad)
print("Script complete")
-
+
if __name__=="__main__":
- main()
-
-
+ main()
\ No newline at end of file
diff --git a/scripts/skysat_orthorectify.py b/scripts/skysat_orthorectify.py
index 49a9270..41c1586 100755
--- a/scripts/skysat_orthorectify.py
+++ b/scripts/skysat_orthorectify.py
@@ -5,6 +5,7 @@
import argparse
from skysat_stereo import asp_utils as asp
from skysat_stereo import skysat
+from skysat_stereo import skysat_stereo_workflow as workflow
from p_tqdm import p_map
from imview import pltlib
import itertools
@@ -12,6 +13,7 @@
import matplotlib.pyplot as plt
from multiprocessing import cpu_count
+
def get_parser():
parser = argparse.ArgumentParser(description='create browse image from input Skysat directory')
parser.add_argument('-img_folder', help='Folder containing subdirectories of imagefiles', required=True)
@@ -26,18 +28,24 @@ def get_parser():
parser.add_argument('-mode',choices=map_choices,default='browse',help='select mode for mapprojection default: %(default)s')
parser.add_argument('-ba_prefix',default=None,help='bundle adjust prefix for rpc, or joiner for bundle adjusted pinhole cameras',required=False)
parser.add_argument('-cam',default=None,help='camera folder containing list of tsai files for pinhole files',required=False)
- parser.add_argument('-frame_index',default='None',help="frame index to read frame's actual Ground sampling distance",required=False)
+ parser.add_argument('-frame_index',default=None,help="frame index to read frame's actual Ground sampling distance",required=False)
orthomosaic_choice = [1,0]
parser.add_argument('-orthomosaic',default=0,type=int,choices=orthomosaic_choice, help="if mode is science, enabling this (1) will also produce a final orthomosaic (default: %(default)s)")
parser.add_argument('-copy_rpc',default=0,type=int,choices=orthomosaic_choice,help='if mode is science, enabling this (1) will copy rpc metadata in the orthoimage (default: %(default)s)')
data_choices = ['video','triplet']
parser.add_argument('-data',default='triplet',choices=data_choices,help="select if mosaicing video or triplet product in science mode (default: %(default)s)")
+ parser.add_argument('-overlap_list', default=None,
+ help='list containing pairs for which feature matching was restricted due during cross track bundle adjustment (not required during basic triplet processing)')
return parser
+
def main():
parser = get_parser()
args = parser.parse_args()
- tr = str(args.tr)
+ if args.tr is not None:
+ tr = str(args.tr)
+ else:
+ tr = None
tsrs = args.tsrs
dir = os.path.abspath(args.img_folder)
outdir = os.path.abspath(args.out_folder)
@@ -49,138 +57,13 @@ def main():
cam_folder = args.cam
ba_prefix = args.ba_prefix
mode = args.mode
- if mode == 'browse':
- """
- this block creates low-res orthomosaics from RPC info for browsing purpose only
- """
- for_img_list,nadir_img_list,aft_img_list,for_time,nadir_time,aft_time = skysat.sort_img_list(images)
- for_out_dir = os.path.join(outdir,'for_map_browse')
- nadir_out_dir = os.path.join(outdir,'nadir_map_browse')
- aft_out_dir = os.path.join(outdir,'aft_map_browse')
- for_out_list = [os.path.join(for_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in for_img_list]
- nadir_out_list = [os.path.join(nadir_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in nadir_img_list]
- aft_out_list = [os.path.join(aft_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in aft_img_list]
- for_count,nadir_count,aft_count = [len(for_img_list), len(nadir_img_list), len(aft_img_list)]
- print("Performing orthorectification for forward images {}".format(for_time))
- for_map_log = p_map(asp.mapproject,for_img_list,for_out_list,[args.session]*for_count,['WGS84']*for_count,[None]*for_count,['EPSG:4326']*for_count,[None]*for_count,[None]*for_count)
- print("Performing orthorectification for nadir images {}".format(nadir_time))
- nadir_map_log = p_map(asp.mapproject,nadir_img_list,nadir_out_list,[args.session]*nadir_count,['WGS84']*nadir_count,[None]*nadir_count,['EPSG:4326']*nadir_count,[None]*nadir_count,[None]*nadir_count)
- print("Performing orthorectification for aft images {}".format(aft_time))
- aft_map_log = p_map(asp.mapproject,aft_img_list,aft_out_list,[args.session]*aft_count,['WGS84']*aft_count,[None]*aft_count,['EPSG:4326']*aft_count,[None]*aft_count,[None]*aft_count)
- ortho_log = os.path.join(outdir,'low_res_ortho.log')
- print("Orthorectification log saved at {}".format(ortho_log))
- with open(ortho_log,'w') as f:
- total_ortho_log = for_map_log+nadir_map_log+aft_map_log
- for log in itertools.chain.from_iterable(total_ortho_log):
- f.write(log)
-
- # after orthorectification, now do mosaic
- for_out_mos = os.path.join(outdir,'for_map_mos_{}m.tif'.format(tr))
- for_map_list = sorted(glob.glob(os.path.join(for_out_dir,'*.tif')))
- nadir_out_mos = os.path.join(outdir,'nadir_map_mos_{}m.tif'.format(tr))
- nadir_map_list = sorted(glob.glob(os.path.join(nadir_out_dir,'*.tif')))
- aft_out_mos = os.path.join(outdir,'aft_map_mos_{}m.tif'.format(tr))
- aft_map_list = sorted(glob.glob(os.path.join(aft_out_dir,'*.tif')))
- print("Preparing forward browse orthomosaic")
- for_mos_log = asp.dem_mosaic(for_map_list,for_out_mos,tr,tsrs,'first',None)
- print("Preparing nadir browse orthomosaic")
- nadir_mos_log = asp.dem_mosaic(nadir_map_list, nadir_out_mos, tr, tsrs, 'first',None)
- print("Preparing aft browse orthomosaic")
- aft_mos_log = asp.dem_mosaic(aft_map_list, aft_out_mos, tr, tsrs, 'first',None)
- ## delete temporary files
- if del_opt:
- [shutil.rmtree(x) for x in [for_out_dir,nadir_out_dir,aft_out_dir]]
- #Save figure to jpeg ?
- fig_title = os.path.basename(images[0]).split('_',15)[0]+'_'+for_time+'_'+nadir_time+'_'+aft_time
- fig,ax = plt.subplots(1,3,figsize=(10,10))
- pltlib.iv_fn(for_out_mos,full=True,ax=ax[0],cmap='gray',scalebar=True,title='Forward')
- pltlib.iv_fn(nadir_out_mos,full=True,ax=ax[1],cmap='gray',scalebar=True,title='NADIR')
- pltlib.iv_fn(aft_out_mos,full=True,ax=ax[2],cmap='gray',scalebar=True,title='Aft')
- plt.tight_layout(rect=[0, 0.03, 1, 0.95])
- fig.suptitle(fig_title)
- browse_img_fn = os.path.join(outdir,'browse_img_{}_{}m.jpg'.format(fig_title,tr))
- fig.savefig(browse_img_fn,dpi=300,bbox_inches='tight',pad_inches=0.1)
- print("Browse figure saved at {}".format(browse_img_fn))
-
- if mode == 'science':
- img_list = images
- if args.frame_index is not 'None':
- frame_index = skysat.parse_frame_index(args.frame_index)
- img_list = [glob.glob(os.path.join(dir,'{}*.tiff'.format(frame)))[0] for frame in frame_index.name.values]
- print("no of images is {}".format(len(img_list)))
- img_prefix = [os.path.splitext(os.path.basename(img))[0] for img in img_list]
- out_list = [os.path.join(outdir,img+'_map.tif') for img in img_prefix]
- session_list = [args.session]*len(img_list)
- dem_list = [dem]*len(img_list)
- tr_list = [args.tr]*len(img_list)
- if args.frame_index is not 'None':
- # this hack is for video
- df = skysat.parse_frame_index(args.frame_index)
- trunc_df = df[df['name'].isin(img_prefix)]
- tr_list = [str(gsd) for gsd in trunc_df.gsd.values]
- srs_list = [tsrs]*len(img_list)
- if args.session == 'pinhole':
- if ba_prefix:
- cam_list = [glob.glob(os.path.abspath(ba_prefix)+'-'+os.path.splitext(os.path.basename(x))[0]+'*.tsai')[0] for x in img_list]
- print("No of cameras is {}".format(len(cam_list)))
- else:
- print(os.path.join(os.path.abspath(args.cam),os.path.splitext(os.path.basename(img_list[0]))[0]+'*.tsai'))
- cam_list = [glob.glob(os.path.join(os.path.abspath(args.cam),os.path.splitext(os.path.basename(x))[0]+'*.tsai'))[0] for x in img_list]
- else:
- cam_list = [None]*len(img_list)
- if ba_prefix:
- # not yet implemented
- ba_prefix_list = [ba_prefix]*len(img_list)
- print("Mapping given images")
- ortho_logs = p_map(asp.mapproject,img_list,out_list,session_list,dem_list,tr_list,srs_list,cam_list,num_cpus=int(cpu_count()/4))
- ortho_log = os.path.join(outdir,'ortho.log')
- print("Saving Orthorectification log at {}".format(ortho_log))
- with open(ortho_log,'w') as f:
- for log in ortho_logs:
- f.write(log)
- if args.copy_rpc == 1:
- print("Copying RPC from native image to orthoimage in parallel")
- copy_rpc_out = p_map(skysat.copy_rpc,img_list,out_list,num_cpus=cpu_count())
- if args.orthomosaic == 1:
- print("Will also produce median, weighted average and highest resolution orthomosaic")
- if args.data == 'triplet':
- for_img_list,nadir_img_list,aft_img_list,for_time,nadir_time,aft_time = skysat.sort_img_list(out_list)
- res_sorted_list = skysat.res_sort(out_list)
- res_sorted_mosaic = os.path.join(outdir,'{}_{}_{}_finest_orthomosaic.tif'.format(for_time,nadir_time,aft_time))
- median_mosaic = os.path.join(outdir,'{}_{}_{}_median_orthomosaic.tif'.format(for_time,nadir_time,aft_time))
- wt_avg_mosaic = os.path.join(outdir,'{}_{}_{}_wt_avg_orthomosaic.tif'.format(for_time,nadir_time,aft_time))
- print("producing finest resolution on top mosaic, per-pixel median and wt_avg mosaic")
- all_3_view_mos_logs = p_map(asp.dem_mosaic, [res_sorted_list]*3, [res_sorted_mosaic,median_mosaic,wt_avg_mosaic], ['None']*3, [None]*3, ['first','median',None],[None]*3,num_cpus=4)
- res_sorted_log = asp.dem_mosaic(res_sorted_list,res_sorted_mosaic,tr='None',stats='first')
- print("producing idependent mosaic for different views in parallel")
- for_mosaic = os.path.join(outdir,'{}_for_first_mosaic.tif'.format(for_time))
- nadir_mosaic = os.path.join(outdir,'{}_nadir_first_mosaic.tif'.format(nadir_time))
- aft_mosaic = os.path.join(outdir,'{}_aft_first_mosaic.tif'.format(aft_time))
- # prepare mosaics in parallel
- indi_mos_log = p_map(asp.dem_mosaic,[for_img_list,nadir_img_list,aft_img_list], [for_mosaic,nadir_mosaic,aft_mosaic], ['None']*3, [None]*3, ['first']*3,[None]*3,num_cpus=4)
- out_log = os.path.join(outdir,'science_mode_ortho_mos.log')
- total_mos_log = all_3_view_mos_logs+indi_mos_log
- print("Saving orthomosaic log at {}".format(out_log))
- with open(out_log,'w') as f:
- for log in itertools.chain.from_iterable(total_mos_log):
- f.write(log)
- if args.data == 'video':
- res_sorted_list = skysat.res_sort(out_list)
- print("producing orthomasaic with finest on top")
- res_sorted_mosaic = os.path.join(outdir,'video_finest_orthomosaic.tif')
- print("producing orthomasaic with per-pixel median stats")
- median_mosaic = os.path.join(outdir,'video_median_orthomosaic.tif')
- print("producing orthomosaic with weighted average statistics")
- wt_avg_mosaic = os.path.join(outdir,'video_wt_avg_orthomosaic.tif')
- print("Mosaicing will be done in parallel")
- all_3_view_mos_logs = p_map(asp.dem_mosaic, [res_sorted_list]*3, [res_sorted_mosaic,median_mosaic,wt_avg_mosaic], ['None']*3, [None]*3, ['first','median',None],[None]*3)
- out_log = os.path.join(outdir,'science_mode_ortho_mos.log')
- print("Saving orthomosaic log at {}".format(out_log))
- with open(out_log,'w') as f:
- for log in all_3_view_mos_logs:
- f.write(log)
- print("Script is complete!")
+ workflow.execute_skysat_orhtorectification(images,outdir,data=args.data,dem=dem,
+ tr=tr,tsrs=tsrs,del_opt=args.delete_temporary_files,
+ cam_folder=cam_folder,ba_prefix=ba_prefix,mode=mode,
+ session=args.session,overlap_list=args.overlap_list,
+ frame_index_fn=args.frame_index,copy_rpc=args.copy_rpc,
+ orthomosaic=args.orthomosaic)
+ print("Script is complete!")
if __name__=='__main__':
main()
-
diff --git a/scripts/skysat_overlap.py b/scripts/skysat_overlap.py
index 35cd850..7a048b7 100755
--- a/scripts/skysat_overlap.py
+++ b/scripts/skysat_overlap.py
@@ -4,6 +4,7 @@
import glob
from skysat_stereo import asp_utils as asp
from skysat_stereo import skysat
+from skysat_stereo import skysat_stereo_workflow as workflow
from skysat_stereo import misc_geospatial as geo
import time
import os,sys,glob
@@ -17,12 +18,14 @@
def getparser():
parser = argparse.ArgumentParser(description='Script to make overlapping pairs based on user defined minimum overlap percentage')
parser.add_argument('-img_folder', help='Folder containing images with RPC information', required=True)
- parser.add_argument('-percentage', '--percentage', help='percentage_overlap between 0 to 1', required=True)
+ parser.add_argument('-percentage', '--percentage', help='percentage_overlap between 0 to 1',type=float, required=True)
parser.add_argument('-outfn','--out_fn',help='Text file containing the overlapping pairs')
+ parser.add_argument('-cross_track',action='store_true',help='Also make cross-track pairs')
+ parser.add_argument('-aoi_bbox',help='Return interesecting footprint within this aoi only',default=None)
return parser
# Global var
-geo_crs = {'init':'EPSG:4326'}
+geo_crs = 'EPSG:4326'
def main():
#The following block of code is useful for getting a shapefile encompassing the entire subset (Use for clipping DEMs etc)
@@ -31,61 +34,8 @@ def main():
parser = getparser()
args = parser.parse_args()
img_folder = args.img_folder
- try:
- img_list = sorted(glob.glob(os.path.join(img_folder,'*.tif')))
- print("Number of images {}".format(len(img_list)))
- except:
- print ("No images found in the directory. Make sure they end with a .tif extension")
- sys.exit()
- out_fn = args.out_fn
- perc_overlap = np.float(args.percentage)
- out_shp = os.path.splitext(out_fn)[0]+'_bound.gpkg'
- n_proc = cpu_count()
- shp_list = p_umap(skysat.skysat_footprint,img_list,num_cpus=2*n_proc)
- merged_shape = geo.shp_merger(shp_list)
- bbox = merged_shape.total_bounds
- print (f'Bounding box lon_lat is:{bbox}')
- bound_poly = Polygon([[bbox[0],bbox[3]],[bbox[2],bbox[3]],[bbox[2],bbox[1]],[bbox[0],bbox[1]]])
- bound_shp = gpd.GeoDataFrame(index=[0],geometry=[bound_poly],crs=geo_crs)
- bound_centroid = bound_shp.centroid
- cx = bound_centroid.x.values[0]
- cy = bound_centroid.y.values[0]
- pad = np.ptp([bbox[3],bbox[1]])/6.0
- lat_1 = bbox[1]+pad
- lat_2 = bbox[3]-pad
- #local_ortho = '+proj=ortho +lat_0={} +lon_0={}'.format(cy,cx)
- local_aea = "+proj=aea +lat_1={} +lat_2={} +lat_0={} +lon_0={} +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs".format(lat_1,lat_2,cy,cx)
- print ('Local Equal Area coordinate system is : {} \n'.format(local_aea))
- print('Saving bound shapefile at {} \n'.format(out_shp))
- bound_shp.to_file(out_shp,driver='GPKG')
- img_combinations = list(combinations(img_list,2))
- n_comb = len(img_combinations)
- perc_overlap = np.ones(n_comb,dtype=float)*perc_overlap
- proj = local_aea
- tv = p_map(skysat.frame_intsec, img_combinations, [proj]*n_comb, perc_overlap,num_cpus=4*n_proc)
- # result to this contains truth value (0 or 1, overlap percentage)
- truth_value = [tvs[0] for tvs in tv]
- overlap = [tvs[1] for tvs in tv]
- valid_list = list(compress(img_combinations,truth_value))
- overlap_perc_list = list(compress(overlap,truth_value))
- print('Number of valid combinations are {}, out of total {} input images making total combinations {}\n'.format(len(valid_list),len(img_list),n_comb))
- with open(out_fn, 'w') as f:
- img1_list = [x[0] for x in valid_list]
- img2_list = [x[1] for x in valid_list]
- for idx,i in enumerate(valid_list):
- #f.write("%s %s\n" % i)
- f.write(f"{os.path.abspath(img1_list[idx])} {os.path.abspath(img2_list[idx])}\n")
- out_fn_overlap = os.path.splitext(out_fn)[0]+'_with_overlap_perc.pkl'
- img1_list = [x[0] for x in valid_list]
- img2_list = [x[1] for x in valid_list]
- out_df = pd.DataFrame({'img1':img1_list,'img2':img2_list,'overlap_perc':overlap_perc_list})
- out_df.to_pickle(out_fn_overlap)
- out_fn_stereo = os.path.splitext(out_fn_overlap)[0]+'_stereo_only.pkl'
- stereo_only_df = skysat.prep_trip_df(out_fn_overlap)
- stereo_only_df.to_pickle(out_fn_stereo)
- out_fn_stereo_ba = os.path.splitext(out_fn_overlap)[0]+'_stereo_only.txt'
- stereo_only_df[['img1','img2']].to_csv(out_fn_stereo_ba,sep=' ',header=False,index=False)
- print('Script completed in time {} s!'.format(time.time()-init_time))
+ workflow.prepare_stereopair_list(img_folder,args.percentage,args.out_fn,args.aoi_bbox,cross_track=args.cross_track)
+ print(f'Script completed in time {time.time()-init_time}')
if __name__=="__main__":
main()
diff --git a/scripts/skysat_pc_cam.py b/scripts/skysat_pc_cam.py
index 21915e4..e6c39ac 100755
--- a/scripts/skysat_pc_cam.py
+++ b/scripts/skysat_pc_cam.py
@@ -4,15 +4,14 @@
import numpy as np
from skysat_stereo import asp_utils as asp
from skysat_stereo import skysat
+from skysat_stereo import skysat_stereo_workflow as workflow
from p_tqdm import p_map,p_umap
import psutil
import argparse
from rpcm import geo
from pygeotools.lib import iolib,geolib
-import osr
-# TODO:
-# Determine best parameters for RPC generation
+
def get_parser():
parser = argparse.ArgumentParser(description="utility to grid and register DEMs, pinhole cameras to a referece DEM, using ASP's ICP algorithm")
@@ -25,6 +24,7 @@ def get_parser():
# classic dem align options, also carried forward to multi_align
align_choice = ['point-to-point', 'point-to-plane']
parser.add_argument('-align', choices=align_choice, default='point-to-plane', help='ICP Alignment algorithm (defualt: %(default)s)')
+ parser.add_argument('-initial_align',default=None,type=str,help='Alignment transform from initial PC align run')
parser.add_argument('-max_displacement', default=100.0, type=float, help='Maximum allowable displacement between two DEMs (defualt: %(default)s)')
trans_choice = [0, 1]
parser.add_argument('-trans_only', default=0, type = int, choices=trans_choice, help='1: compute translation only, (default: %(default)s)')
@@ -40,92 +40,22 @@ def get_parser():
parser.add_argument('-dem', default='None', help='DEM used for generating RPC')
parser.add_argument('-img_list', nargs='*', help='list of images for which RPC will be generated')
return parser
+
def main():
parser = get_parser()
args = parser.parse_args()
- # comput number of physical and threaded cores
- n_cpu = psutil.cpu_count(logical=False)
- n_cpu_thread = psutil.cpu_count(logical=True)
mode = args.mode
- pc_list = args.point_cloud_list
if mode == 'gridding_only':
- tr = args.tr
- if args.tsrs is not None:
- tsrs = args.tsrs
- else:
- print("Projected Target CRS not provided, reading from the first point cloud")
- pc_ds = iolib.fn_getds(pc_list[0])
- wgs_srs = osr.SpatialReference()
- wgs_srs.ImportFromEPSG(4326)
- clon,clat = geolib.get_center(pc_ds,t_srs=wgs_srs)
- # if the cloud is from non ortho stereo inputs, this does not work
- if (np.abs(clon)<0.01) & (np.abs(clat)<0.01):
- #fetch the PC-center.txt file instead
- # should probably make this default after more tests and confirmation with Oleg
- pc_center = os.path.splitext(pc_list[0])[0]+'-center.txt'
- with open(pc_center,'r') as f:
- content = f.readlines()
- X,Y,Z = [np.float(x) for x in content[0].split(' ')[:-1]]
- clon,clat,_ = geolib.ecef2ll(X,Y,Z)
- epsg_code = f'EPSG:{geo.compute_epsg(clon,clat)}'
- print(f"Detected EPSG code from point cloud {epsg_code}")
- tsrs = epsg_code
-
- point2dem_opts = asp.get_point2dem_opts(tr=tr, tsrs=tsrs,threads=1)
- job_list = [point2dem_opts + [pc] for pc in pc_list]
- p2dem_log = p_map(asp.run_cmd,['point2dem'] * len(job_list), job_list, num_cpus = n_cpu)
- print(p2dem_log)
- if mode == 'classic_dem_align':
- ref_dem=args.refdem
- source_dem=args.source_dem
- max_displacement=args.max_displacement
- outprefix=args.outprefix
- align=args.align
- if args.trans_only == 0:
- trans_only=False
- else:
- trans_only=True
- asp.dem_align(ref_dem, source_dem, max_displacement, outprefix, align, trans_only,threads=n_cpu)
- if mode == 'multi_align':
- """ Align multiple DEMs to a single source DEM """
- ref_dem=args.refdem
- source_dem_list=args.source_dem_list
- max_displacement=args.max_displacement
- outprefix_list=['{}_aligned_to{}'.format(os.path.splitext(source_dem)[0],os.path.splitext(os.path.basename(ref_dem))[0]) for source_dem in source_dem_list]
- align=args.align
- if args.trans_only == 0:
- trans_only=False
- else:
- trans_only=True
- n_source=len(source_dem_list)
- ref_dem_list=[ref_dem] * n_source
- max_disp_list=[max_displacement] * n_source
- align_list=[align] * n_source
- trans_list=[trans_only] * n_source
- p_umap(asp.dem_align,ref_dem_list,source_dem_list,max_disp_list,outprefix_list,align_list,trans_list,[1]*n_source,num_cpus = n_cpu_thread)
- if mode == 'align_cameras':
- transform_txt = args.transform
- input_camera_list = args.cam_list
- n_cam=len(input_camera_list)
- if (args.rpc == 1) & (args.dem != 'None'):
- print("will also write rpc files")
- dem=args.dem
- img_list=arg.img_list
- rpc=True
- else:
- dem=None
- img_list=[None] * n_cam
- rpc=False
- transform_list=[transform_txt] * n_cam
- outfolder = args.outfol
- if not os.path.exists(outfolder):
- os.makedirs(outfolder)
- outfolder=[outfolder] * n_cam
- write=[True] * n_cam
- rpc=[rpc] * n_cam
- dem=[dem] * n_cam
- p_umap(asp.align_cameras,input_camera_list,transform_list,outfolder,write,rpc,dem,img_list,num_cpus = n_cpu_thread)
-
+ workflow.gridding_wrapper(args.point_cloud_list,args.tr,args.tsrs)
+ elif mode == 'classic_dem_align':
+ workflow.alignment_wrapper_single(args.refdem,args.source_dem,args.max_displacement,args.outprefix,
+ args.align,args.trans_only,initial_align=args.initial_align)
+ elif mode == 'multi_align':
+ workflow.alignment_wrapper_multi(args.refdem,args.source_dem_list,args.max_displacement,args.align,
+ trans_only=args.trans_only,initial_align=args.initial_align)
+ elif mode == 'align_cameras':
+ workflow.align_cameras_wrapper(args.cam_list,args.transform,args.outfol,rpc=args.rpc,
+ dem=args.dem,img_list=args.img_list)
if __name__=="__main__":
main()
diff --git a/scripts/skysat_preprocess.py b/scripts/skysat_preprocess.py
index 5020d0a..1cd1b75 100755
--- a/scripts/skysat_preprocess.py
+++ b/scripts/skysat_preprocess.py
@@ -5,6 +5,7 @@
from pygeotools.lib import iolib,malib
from skysat_stereo import asp_utils as asp
from skysat_stereo import skysat
+from skysat_stereo import skysat_stereo_workflow as workflow
from p_tqdm import p_map
import numpy as np
from multiprocessing import cpu_count
@@ -35,72 +36,10 @@ def main():
session = args.t
img_folder = os.path.abspath(args.img)
outdir = os.path.abspath(args.outdir)
- if not os.path.exists(outdir):
- try:
- os.makedir(outdir)
- except:
- os.makedirs(outdir)
- if mode == 'video':
- sampling = args.video_sampling_mode
- frame_index = skysat.parse_frame_index(args.frame_index,True)
- product_level = 'l1a'
- num_samples = len(frame_index)
- frames = frame_index.name.values
- sampler = args.sampler
- outdf = os.path.join(outdir,os.path.basename(args.frame_index))
- if sampling == 'sampling_interval':
- print("Hardcoded sampling interval results in frame exclusion at the end of the video sequence based on step size, better to chose the num_images mode and the program will equally distribute accordingly")
- idx = np.arange(0,num_samples,sampler)
- outdf = '{}_sampling_inteval_{}.csv'.format(os.path.splitext(outdf)[0],sampler)
- else:
- print("Sampling {} from {} of the input video sequence".format(sampler,num_samples))
- idx = np.linspace(0,num_samples-1,sampler,dtype=int)
- outdf = '{}_sampling_inteval_aprox{}.csv'.format(os.path.splitext(outdf)[0],idx[1]-idx[0])
- sub_sampled_frames = frames[idx]
- sub_df = frame_index[frame_index['name'].isin(list(sub_sampled_frames))]
- sub_df.to_csv(outdf,sep=',',index=False)
- #this is camera/gcp initialisation
- n = len(sub_sampled_frames)
- img_list = [glob.glob(os.path.join(img_folder,'{}*.tiff'.format(frame)))[0] for frame in sub_sampled_frames]
- pitch = [1]*n
- out_fn = [os.path.join(outdir,'{}_frame_idx.tsai'.format(frame)) for frame in sub_sampled_frames]
- out_gcp = [os.path.join(outdir,'{}_frame_idx.gcp'.format(frame)) for frame in sub_sampled_frames]
- frame_index = [args.frame_index]*n
- camera = [None]*n
- gcp_factor = 4
-
- elif mode == 'triplet':
- df = pd.read_pickle(args.overlap_pkl)
- img_list = list(np.unique(np.array(list(df.img1.values)+list(df.img2.values))))
- img_list = [os.path.splitext(os.path.basename(img))[0] for img in img_list]
- cam_list = [glob.glob(os.path.join(img_folder,'{}*.tif'.format(img)))[0] for img in img_list]
- n = len(img_list)
- if args.product_level == 'l1b':
- pitch = [0.8]*n
- else:
- pitch = [1.0]*n
- out_fn = [os.path.join(outdir,'{}_rpc.tsai'.format(frame)) for frame in img_list]
- out_gcp = [os.path.join(outdir,'{}_rpc.gcp'.format(frame)) for frame in img_list]
- camera = cam_list
- frame_index = [None]*n
- img_list = cam_list
- gcp_factor = 8
- fl = [553846.153846]*n
- cx = [1280]*n
- cy = [540]*n
- dem = args.dem
- ht_datum = [malib.get_stats_dict(iolib.fn_getma(dem))['median']]*n # use this value for height where DEM has no-data
- gcp_std = [1]*n
- datum = ['WGS84']*n
- refdem = [dem]*n
- n_proc = 30
- #n_proc = cpu_count()
- cam_gen_log = p_map(asp.cam_gen,img_list,fl,cx,cy,pitch,ht_datum,gcp_std,out_fn,out_gcp,datum,refdem,camera,frame_index,num_cpus = n_proc)
- print("writing gcp with basename removed")
- # count expexted gcp
- print(f"Total expected GCP {gcp_factor*n}")
- asp.clean_gcp(out_gcp,outdir)
- # saving subprocess consolidated log file
+ cam_gen_log = workflow.skysat_preprocess(img_folder,mode,sampling=args.video_sampling_mode,frame_index=args.frame_index,
+ product_level=args.product_level,sampler=args.sampler,overlap_pkl=args.overlap_pkl,dem=args.dem,
+ outdir=args.outdir)
+
from datetime import datetime
now = datetime.now()
log_fn = os.path.join(outdir,'camgen_{}.log'.format(now))
diff --git a/scripts/skysat_stereo_cli.py b/scripts/skysat_stereo_cli.py
index 9edad91..4d724e3 100755
--- a/scripts/skysat_stereo_cli.py
+++ b/scripts/skysat_stereo_cli.py
@@ -7,6 +7,8 @@
import os,sys,glob
from multiprocessing import cpu_count
from p_tqdm import p_map
+from skysat_stereo import skysat_stereo_workflow as workflow
+from tqdm import tqdm
def getparser():
parser = argparse.ArgumentParser(description='Script for performing stereo jobs, generalised for skysat video and triplet stereo products')
@@ -39,70 +41,26 @@ def getparser():
parser.add_argument('-block', default=0, type=int, choices=mvs_choices, help='1: use block matching instead of default MGM (default: %(default)s')
parser.add_argument('-full_extent',type=int,choices = mvs_choices,default=1,
help='Selecting larger intervals can result in lower footprint output DEM, if 1: then DEMs with smaller interval image pairs will be padded at the begining and end of the video sequence (default: %(default)s)')
+ parser.add_argument('-writeout_only', action='store_true', help='writeout_jobs to a text file, not run')
+ parser.add_argument('-job_fn',type=str,help='text file to write stereo jobs to',default=None)
+ parser.add_argument('-cross_track',action='store_true', help='attempt stereo for cross_track pairs as well')
return parser
+
def main():
parser = getparser()
args = parser.parse_args()
img = os.path.abspath(args.img)
- try:
- img_list = sorted(glob.glob(os.path.join(img, '*.tif')))
- temp = img_list[1]
- except BaseException:
- img_list = sorted(glob.glob(os.path.join(img, '*.tiff')))
- if len(img_list) == 0:
- print("No images in the specified folder, exiting")
- sys.exit()
- mode = args.mode
- session = args.t
- ba_prefix = args.ba_prefix
- overlap_list_fn = args.overlap_pkl
- frame_index = args.frame_index
- dem = args.dem
- texture = args.texture
- sampling_interval = args.sampling_interval
- if args.cam:
- cam_folder = args.cam
- if args.ba_prefix:
- ba_prefix = args.ba_prefix
- outfol = args.outfol
- if mode == 'video':
- # assume for now that we are still operating on a fixed image interval method
- # can accomodate different convergence angle function method here.
- frame_gdf = skysat.parse_frame_index(frame_index)
- # for now hardcording sgm,mgm,kernel params, should accept as inputs.
- # Maybe discuss with David with these issues/decisions when the overall
- # system is in place
- if args.mvs == 1:
- job_list = skysat.video_mvs(img,t=session,cam_fol=args.cam,ba_prefix=args.ba_prefix,dem=args.dem,sampling_interval=sampling_interval,texture=texture,outfol=outfol, block=args.block,frame_index=frame_gdf)
- else:
- if args.full_extent == 1:
- full_extent = True
- else:
- full_extent=False
- job_list = skysat.prep_video_stereo_jobs(img,t=session,cam_fol=args.cam,ba_prefix=args.ba_prefix,dem=args.dem,sampling_interval=sampling_interval,texture=texture,outfol=outfol,block=args.block,frame_index=frame_gdf,full_extent=full_extent,entry_point=args.entry_point)
- elif mode == 'triplet':
- if args.crop_map == 1:
- crop_map = True
- else:
- crop_map = False
- job_list = skysat.triplet_stereo_job_list(t=args.t,
- threads = args.threads,overlap_list=args.overlap_pkl, img_list=img_list, ba_prefix=args.ba_prefix, cam_fol=args.cam, dem=args.dem, crop_map=crop_map,texture=texture, outfol=outfol, block=args.block,entry_point=args.entry_point)
- # decide on number of processes
- # if block matching, Plieades is able to handle 30-40 4 threaded jobs on bro node
- # if MGM/SGM, 25 . This stepup is arbitrariry, research on it more.
- # next build should accept no of jobs and stereo threads as inputs
- print(job_list[0])
- n_cpu = cpu_count()
- # no of parallel jobs with user specified threads per job
- jobs = int(n_cpu/args.threads)
- stereo_log = p_map(asp.run_cmd,['stereo']*len(job_list), job_list, num_cpus=jobs)
- stereo_log_fn = os.path.join(outfol,'stereo_log.log')
- print("Consolidated stereo log saved at {}".format(stereo_log_fn))
- #with open(stereo_log_fn,'w') as f:
- # for logs in stereo_log:
- # f.write(logs)
+
+ workflow.execute_skysat_stereo(img,args.outfol,args.mode,session=args.t,
+ dem=args.dem,texture=args.texture,sampling_interval=args.sampling_interval,
+ cam_folder=args.cam,ba_prefix=args.ba_prefix,writeout_only=args.writeout_only,
+ mvs=args.mvs,block=args.block,crop_map=args.crop_map,full_extent=args.full_extent,
+ entry_point=args.entry_point,threads=args.threads,overlap_pkl=args.overlap_pkl,
+ frame_index=args.frame_index,job_fn=args.job_fn,cross_track=args.cross_track)
+
print("Script is complete")
if __name__ == "__main__":
main()
+
diff --git a/scripts/skysat_triplet_pipeline.py b/scripts/skysat_triplet_pipeline.py
index 596439b..fc395a0 100755
--- a/scripts/skysat_triplet_pipeline.py
+++ b/scripts/skysat_triplet_pipeline.py
@@ -1,6 +1,7 @@
#! /usr/bin/env python
import subprocess
import argparse
+from datetime import datetime
import os,sys,glob,shutil
from rpcm import geo
import numpy as np
@@ -8,7 +9,8 @@
from distutils.spawn import find_executable
from skysat_stereo import misc_geospatial as misc
from skysat_stereo import asp_utils as asp
-
+from skysat_stereo import bundle_adjustment_lib as ba
+from skysat_stereo import skysat_stereo_workflow as workflow
"""
Script for running the full pipeline based on workflow described in ISPRS 2020 submission
@@ -20,9 +22,13 @@
def getparser():
parser = argparse.ArgumentParser(description='Wrapper script to run full triplet stereo workflow')
parser.add_argument('-in_img',default=None,type=str,help='path to Folder containing L1B imagery')
+ parser.add_argument('-aoi_bbox',default=None,type=str,help='path to bounding box shapefile if limiting processing to a smaller aoi')
parser.add_argument('-orthodem',default=None,type=str,help='path to Reference DEM to use in orthorectification and camera resection, if not provided, will use coregdem')
parser.add_argument('-coregdem',default=None,type=str,help='path to reference DEM to use in coregisteration')
parser.add_argument('-mask_dem',default=1,type=int,choices=[1,0],help='mask reference DEM for static surfaces before coreg (default: %(default)s)')
+ mask_opt = ['glaciers','glaciers+nlcd']
+ parser.add_argument('-mask_dem_opt',default='glaciers',choices=mask_opt,help='surfaces to mask if -mask_dem=1, default is glaciers which uses RGI polygons.\
+ If processing in CONUS, the option of glaciers+nlcd also additionaly masks out forest surfaces')
parser.add_argument('-ortho_workflow',default=1,type=int,choices=[1,0],help='option to orthorectify before stereo or not')
parser.add_argument('-block_matching',default=0,type=int,choices=[1,0],help='whether to use block matching in final stereo matching, default is 0 (not)')
parser.add_argument('-job_name',default=None,type=str,help='identifier for output folder and final composite products')
@@ -101,10 +107,10 @@ def main():
# step 7. dem_alignment
alignment_dir = os.path.join(out_fol,'georegistered_dem_mos')
-
+
# step 8, camera alignment
aligned_cam_dir = os.path.join(out_fol,'georegistered_cameras')
-
+
# step 9, final orthorectification
final_ortho_dir = os.path.join(out_fol,'georegistered_orthomosaics')
@@ -118,7 +124,7 @@ def main():
else:
steps2run = np.array(args.partial_workflow_steps).astype(int)
- #workflow_steps
+ #workflow_steps
# create output directory
if not os.path.exists(out_fol):
os.makedirs(out_fol)
@@ -129,8 +135,11 @@ def main():
if not os.path.exists(refdem_dir):
os.makedirs(refdem_dir)
shutil.copy2(coreg_dem,os.path.join(refdem_dir,os.path.basename(coreg_dem)))
- if not coreg_dem == ortho_dem:
+ if coreg_dem != ortho_dem:
+ diff_dem = True
shutil.copy2(ortho_dem,os.path.join(refdem_dir,os.path.basename(ortho_dem)))
+ else:
+ diff_dem = False
# replace old variable names
coreg_dem = os.path.join(refdem_dir,os.path.basename(coreg_dem))
ortho_dem = os.path.join(refdem_dir,os.path.basename(ortho_dem))
@@ -141,8 +150,10 @@ def main():
# Step 1 Compute overlapping pairs
# Inputs: Image directory, minimum overlap percentage
overlap_perc = 0.01 # 1 percent essentially
- cmd = ['-img_folder',img_folder,'-percentage',str(overlap_perc),'-outfn',overlap_full_txt]
- asp.run_cmd('skysat_overlap.py',cmd)
+
+ workflow.prepare_stereopair_list(img_folder,overlap_perc,overlap_full_txt,
+ aoi_bbox=args.aoi_bbox)
+
print("Computing Target UTM zones for orthorectification")
gdf = gpd.read_file(bound_fn)
@@ -156,13 +167,13 @@ def main():
gdf_proj.to_file(bound_buffer_fn,driver='GPKG')
print("Cropping reference DEMs to extent of SkySat footprint + 1 km buffer")
- asp.run_cmd('clip_raster_by_shp.py',[coreg_dem,bound_buffer_fn])
- asp.run_cmd('trim_ndv.py',[os.path.splitext(coreg_dem)[0]+'_shpclip.tif'])
+ misc.clip_raster_by_shp_disk(coreg_dem,bound_buffer_fn)
+ misc.ndvtrim_function(os.path.splitext(coreg_dem)[0]+'_shpclip.tif')
coreg_dem = os.path.splitext(coreg_dem)[0]+'_shpclip_trim.tif'
- if ortho_dem != coreg_dem:
- clip_log = asp.run_cmd('clip_raster_by_shp.py',[ortho_dem,bound_buffer_fn])
- print(clip_log)
- asp.run_cmd('trim_ndv.py',[os.path.splitext(ortho_dem)[0]+'_shpclip.tif'])
+
+ if diff_dem:
+ misc.clip_raster_by_shp_disk(ortho_dem,bound_buffer_fn)
+ misc.ndvtrim_function(os.path.splitext(ortho_dem)[0]+'_shpclip.tif')
ortho_dem = os.path.splitext(ortho_dem)[0]+'_shpclip_trim.tif'
else:
ortho_dem = coreg_dem
@@ -170,9 +181,16 @@ def main():
if 2 in steps2run:
print("Generating Frame Cameras")
- frame_cam_cmd = ['-mode','triplet','-t','rpc','-img',img_folder,'-outdir',cam_gcp_directory,
- '-overlap_pkl',overlap_stereo_pkl,'-dem',ortho_dem]
- asp.run_cmd('skysat_preprocess.py',frame_cam_cmd)
+ cam_gen_log = workflow.skysat_preprocess(img_folder,mode='triplet',
+ product_level='l1b',overlap_pkl=overlap_stereo_pkl,dem=ortho_dem,
+ outdir=cam_gcp_directory)
+
+ now = datetime.now()
+ log_fn = os.path.join(cam_gcp_directory,'camgen_{}.log'.format(now))
+ print("saving subprocess camgen log at {}".format(log_fn))
+ with open(log_fn,'w') as f:
+ for log in cam_gen_log:
+ f.write(log)
if 3 in steps2run:
# specify whether to run using maprojected sessions or not
@@ -180,67 +198,75 @@ def main():
if map:
# orthorectify all the images first
print("Orthorectifying images using RPC camera")
- ortho_cmd = ['-img_folder',img_folder,'-session',init_ortho_session,'-out_folder',init_ortho_dir,
- '-tsrs',epsg_code,'-DEM',ortho_dem,'-mode','science','-orthomosaic','0','-copy_rpc','1','-data','triplet']
- #Note above, copy_rpc = 1, because we want the orthoimages to have RPC info embedded in gdal header for stereo later
- asp.run_cmd('skysat_orthorectify.py',ortho_cmd)
+ workflow.execute_skysat_orhtorectification(images=img_list,data='triplet',session=init_ortho_session,
+ outdir=init_ortho_dir,tsrs=epsg_code,dem=ortho_dem,mode='science',
+ overlap_list=overlap_stereo_txt,copy_rpc=1,orthomosaic=0)
init_stereo_input_img_folder = init_ortho_dir
else:
init_stereo_input_img_folder = img_folder
print("Running stereo using RPC cameras")
- stereo_cmd = ['-mode','triplet','-threads','2','-t',init_stereo_session,'-img',init_stereo_input_img_folder,
- '-overlap_pkl',overlap_stereo_pkl,'-dem',ortho_dem,'-block','1','-crop_map','0','-outfol',init_stereo_dir]
# Note crop_map = 0 option, this does not do warping to common extent and resolution for orthoimages before stereo, because we want to
# presrve this crucail information for correctly unwarped dense match points
- asp.run_cmd('skysat_stereo_cli.py',stereo_cmd)
+ workflow.execute_skysat_stereo(init_stereo_input_img_folder,init_stereo_dir,
+ mode='triplet',session=init_stereo_session,
+ dem=ortho_dem,texture='normal',writeout_only=False,
+ block=1,crop_map=0,threads=2,overlap_pkl=overlap_stereo_pkl,
+ cross_track=False)
+
# copy dense match file to ba directory
- dense_match_cmd = ['-img', img_folder, '-orig_pickle', overlap_stereo_pkl, '-stereo_dir', init_stereo_dir,
- '-ba_dir', init_ba, '-modify_overlap','0']
- asp.run_cmd('prep_dense_ba_run.py',dense_match_cmd)
+ workflow.dense_match_wrapper(stereo_master_dir=os.path.abspath(init_stereo_dir),
+ ba_dir=os.path.abspath(init_ba),modify_overlap=0)
if 4 in steps2run:
# this is bundle adjustment step
# we use dense files copied from previous step
+
ba_prefix = os.path.join(init_ba,'run')
- ba_cmd = ['-mode', 'full_triplet', '-t', 'nadirpinhole', '-img', img_folder,
- '-cam', cam_gcp_directory, '-overlap_list', overlap_stereo_txt, '-num_iter', '700', '-num_pass', '2','-ba_prefix',ba_prefix]
print("running bundle adjustment")
- asp.run_cmd('ba_skysat.py',ba_cmd)
+ ba.bundle_adjust_stable(img=img_folder,ba_prefix=ba_prefix,cam=os.path.abspath(cam_gcp_directory),
+ session='nadirpinhole',overlap_list=overlap_stereo_txt,
+ num_iter=700,num_pass=2,mode='full_triplet')
+
if 5 in steps2run:
# this is where final stereo will take place
# first we orthorectify again, if map = True
if map:
+ workflow.execute_skysat_orhtorectification(images=img_list,data='triplet',session=final_ortho_session,
+ outdir=intermediate_ortho_dir,tsrs=epsg_code,dem=ortho_dem,
+ ba_prefix=ba_prefix+'-run',mode='science',overlap_list=overlap_stereo_txt,
+ copy_rpc=1,orthomosaic=0)
print("Running intermediate orthorectification with bundle adjusted pinhole cameras")
- ortho_cmd = ['-img_folder',img_folder,'-session',final_ortho_session,'-out_folder',intermediate_ortho_dir,
- '-tsrs',epsg_code,'-DEM',ortho_dem,'-mode','science','-orthomosaic','0','-data','triplet','-ba_prefix',ba_prefix+'-run']
- asp.run_cmd('skysat_orthorectify.py',ortho_cmd)
+
final_stereo_input_img_folder = intermediate_ortho_dir
else:
final_stereo_input_img_folder = img_folder
# now run stereo
- stereo_cmd = ['-mode','triplet','-threads','2','-t',final_stereo_session,'-img',final_stereo_input_img_folder,
- '-overlap_pkl',overlap_stereo_pkl,'-dem',ortho_dem, '-crop_map','1', '-outfol', final_stereo_dir,
- '-ba_prefix',ba_prefix+'-run','-block',str(args.block_matching)]
print("Running final stereo reconstruction")
- asp.run_cmd('skysat_stereo_cli.py',stereo_cmd)
+ workflow.execute_skysat_stereo(final_stereo_input_img_folder,
+ final_stereo_dir,ba_prefix=ba_prefix+'-run',
+ mode='triplet',session=final_stereo_session,
+ dem=ortho_dem,texture='normal',writeout_only=False,
+ block=args.block_matching,crop_map=1,threads=2,overlap_pkl=overlap_stereo_pkl,
+ cross_track=False)
+
if 6 in steps2run:
pc_list = sorted(glob.glob(os.path.join(final_stereo_dir,'20*/2*/run-PC.tif')))
print(f"Identified {len(pc_list)} clouds")
+
# this is dem gridding followed by mosaicing
- dem_grid_cmd = ['-mode','gridding_only', '-tr', '2', '-point_cloud_list'] + pc_list
+ workflow.gridding_wrapper(pc_list,tr=2)
- asp.run_cmd('skysat_pc_cam.py',dem_grid_cmd)
print("Mosaicing DEMs")
- dem_mos_cmd = ['-mode','triplet','-DEM_folder',final_stereo_dir,'-out_folder',mos_dem_dir]
- asp.run_cmd('skysat_dem_mos.py',dem_mos_cmd)
-
+
+ workflow.dem_mosaic_wrapper(dir=os.path.abspath(final_stereo_dir),mode='triplet',
+ out_folder=os.path.abspath(mos_dem_dir))
if 7 in steps2run:
# this is DEM alignment step
@@ -250,36 +276,40 @@ def main():
# actually use dem_mask.py with options of nlcd, nlcd_filter (not_forest) and of course RGI glacier polygons
if args.mask_dem == 1:
# this might change for non-US sites, best to use bareground files
- mask_dem_cmd = ['--nlcd','--glaciers']
+ if args.mask_dem_opt == 'glaciers':
+ mask_list = ['glaciers']
+ elif args.msak_dem_opt == 'glaciers+nlcd':
+ mask_list = ['nlcd','glaciers']
print("Masking reference DEM to static surfaces")
- asp.run_cmd('dem_mask.py',mask_dem_cmd+[os.path.abspath(coreg_dem)])
+ misc.dem_mask_disk(mask_list,os.path.abspath(coreg_dem))
coreg_dem = os.path.splitext(coreg_dem)[0]+'_ref.tif'
#now perform alignment
- median_mos_dem = glob.glob(os.path.join(mos_dem_dir,'triplet_median_mos.tif'))[0]
- dem_align_cmd = ['-mode','classic_dem_align','-max_displacement','40','-refdem',coreg_dem,
- '-source_dem',median_mos_dem,'-outprefix',os.path.join(alignment_dir,'run')]
+ median_mos_dem = glob.glob(os.path.join(mos_dem_dir,'multiview_*_median_mos.tif'))[0]
print("Aligning DEMs")
- asp.run_cmd('skysat_pc_cam.py',dem_align_cmd)
-
+ workflow.alignment_wrapper_single(coreg_dem,source_dem=median_mos_dem,max_displacement=40,
+ outprefix=os.path.join(alignment_dir,'run'))
+
if 8 in steps2run:
# this steps aligns the frame camera models
camera_list = sorted(glob.glob(os.path.join(init_ba,'run-run-*.tsai')))
print(f"Detected {len(camera_list)} cameras to be registered to DEM")
alignment_vector = glob.glob(os.path.join(alignment_dir,'alignment_vector.txt'))[0]
- camera_align_cmd = ['-mode','align_cameras','-transform',alignment_vector,
- '-outfol',aligned_cam_dir,'-cam_list']+camera_list
+ if not os.path.exists(aligned_cam_dir):
+ os.makedirs(aligned_cam_dir)
print("Aligning cameras")
- asp.run_cmd('skysat_pc_cam.py',camera_align_cmd)
+ workflow.align_cameras_wrapper(input_camera_list=camera_list,transform_txt=alignment_vector,
+ outfolder=aligned_cam_dir)
if 9 in steps2run:
# this produces final georegistered orthomosaics
georegistered_median_dem = glob.glob(os.path.join(alignment_dir,'run-trans_*DEM.tif'))[0]
- ortho_cmd = ['-img_folder',img_folder,'-session',final_ortho_session,'-out_folder',final_ortho_dir,
- '-tsrs',epsg_code,'-DEM',georegistered_median_dem,'-mode','science','-orthomosaic','1','-data','triplet',
- '-ba_prefix',os.path.join(aligned_cam_dir,'run-run')]
print("Running final orthomsaic creation")
- asp.run_cmd('skysat_orthorectify.py',ortho_cmd)
+ workflow.execute_skysat_orhtorectification(images=img_list,data='triplet',session=final_ortho_session,
+ outdir=final_ortho_dir,tsrs=epsg_code,dem=georegistered_median_dem,
+ ba_prefix=os.path.join(aligned_cam_dir,'run-run'),mode='science',
+ overlap_list=overlap_stereo_txt,copy_rpc=0,orthomosaic=1)
+
if 10 in steps2run:
# this produces a final plot of orthoimage,DEM, NMAD and countmaps
ortho = glob.glob(os.path.join(final_ortho_dir,'*finest_orthomosaic.tif'))[0]
diff --git a/skysat_stereo/__init__.py b/skysat_stereo/__init__.py
index bf4847c..8c18fa6 100644
--- a/skysat_stereo/__init__.py
+++ b/skysat_stereo/__init__.py
@@ -1,3 +1,3 @@
#! /usr/bin/env python
-__all__=['asp_utils','skysat','misc_geospatial']
+__all__=['asp_utils','skysat','misc_geospatial','skysat_stereo_workflow','bundle_adjustment_lib']
diff --git a/skysat_stereo/asp_utils.py b/skysat_stereo/asp_utils.py
index 9d8f6cc..19a0987 100644
--- a/skysat_stereo/asp_utils.py
+++ b/skysat_stereo/asp_utils.py
@@ -4,7 +4,7 @@
import os,sys,glob,shutil,psutil
import pandas as pd
import geopandas as gpd
-from pyproj import Proj, transform
+from pyproj import Proj, transform, Transformer
from rpcm import rpc_from_geotiff
from distutils.spawn import find_executable
import subprocess
@@ -40,15 +40,19 @@ def run_cmd(bin, args, **kw):
#binpath = os.path.join('/opt/StereoPipeline/bin/',bin)
call = [binpath,]
#print(call)
- call.extend(args)
+
#print(call)
#print(' '.join(call))
+ if args is not None:
+ call.extend(args)
+ #print(call)
try:
- out = subprocess.check_output(call,encoding='UTF-8')
+ out = subprocess.run(call,check=True,capture_output=True,encoding='UTF-8').stdout
except:
out = "the command {} failed to run, see corresponding asp log".format(call)
return out
+
def read_tsai_dict(tsai):
"""
read tsai frame model from asp and return a python dictionary containing the parameters
@@ -76,7 +80,12 @@ def read_tsai_dict(tsai):
rot = content[10].split(' = ',10)[1].split(' ')
rot_mat = [np.float(x) for x in rot] # rotation matrix for camera to world coordinates transformation
pitch = np.float(content[11].split(' = ',10)[1]) # pixel pitch
- cam_cen_lat_lon = geolib.ecef2ll(cam_cen[0],cam_cen[1],cam_cen[2]) # camera center coordinates in geographic coordinates
+
+ ecef_proj = 'EPSG:4978'
+ geo_proj = 'EPSG:4326'
+ ecef2wgs = Transformer.from_crs(ecef_proj,geo_proj)
+ cam_cen_lat_lon = ecef2wgs.transform(cam_cen[0],cam_cen[1],cam_cen[2]) # this returns lat, lon and height
+ # cam_cen_lat_lon = geolib.ecef2ll(cam_cen[0],cam_cen[1],cam_cen[2]) # camera center coordinates in geographic coordinates
tsai_dict = {'camera':camera,'focal_length':(fu,fv),'optical_center':(cu,cv),'cam_cen_ecef':cam_cen,'cam_cen_wgs':cam_cen_lat_lon,'rotation_matrix':rot_mat,'pitch':pitch}
return tsai_dict
@@ -164,7 +173,7 @@ def cam_gen(img,fl=553846.153846,cx=1280,cy=540,pitch=1,ht_datum=None,gcp_std=1,
cam_gen_opt.extend(['--parse-ecef'])
cam_gen_opt.extend(['--refine-camera'])
cam_gen_args = [img]
- print(cam_gen_opt+cam_gen_args)
+ #print(cam_gen_opt+cam_gen_args)
out = run_cmd('cam_gen',cam_gen_args+cam_gen_opt,msg='Running camgen command for image {}'.format(os.path.basename(img)))
return out
@@ -221,7 +230,6 @@ def rpc2map (img,imgx,imgy,imgz=0):
mx,my = rpc.localization(imgx,imgy,imgz)
return mx,my
-
def get_ba_opts(ba_prefix, camera_weight=0, overlap_list=None, overlap_limit=None, initial_transform=None, input_adjustments=None, flavor='general_ba', session='nadirpinhole', gcp_transform=False,num_iterations=2000,lon_lat_lim=None,elevation_limit=None):
"""
prepares bundle adjustment cmd for ASP
@@ -300,7 +308,7 @@ def get_ba_opts(ba_prefix, camera_weight=0, overlap_list=None, overlap_limit=Non
ba_opt.extend(['--elevation-limit',str(elevation_limit[0]),str(elevation_limit[1])])
return ba_opt
-def mapproject(img,outfn,session='rpc',dem='WGS84',tr=None,t_srs='EPSG:4326',cam=None,ba_prefix=None):
+def mapproject(img,outfn,session='rpc',dem='WGS84',tr=None,t_srs='EPSG:4326',cam=None,ba_prefix=None,extent=None):
"""
orthorectify input image over a given DEM using ASP's mapproject program.
See mapproject documentation here: https://stereopipeline.readthedocs.io/en/latest/tools/mapproject.html
@@ -322,6 +330,8 @@ def mapproject(img,outfn,session='rpc',dem='WGS84',tr=None,t_srs='EPSG:4326',cam
if pinhole session, this will be the path to pinhole camera model
ba_prefix: str
Bundle adjustment output for RPC camera.
+ extent: str
+ Projection extent within which to limit mapprojection
Returns
----------
out: str
@@ -332,12 +342,24 @@ def mapproject(img,outfn,session='rpc',dem='WGS84',tr=None,t_srs='EPSG:4326',cam
map_opt.extend(['--t_srs',t_srs])
if ba_prefix:
map_opt.extend(['--bundle-adjust-prefix',ba_prefix])
- if tr:
+ if extent is not None:
+ xmin,ymin,xmax,ymax = extent.split(' ')
+ map_opt.extend(['--t_projwin', xmin,ymin,xmax,ymax])
+ if tr is not None:
map_opt.extend(['--tr',tr])
+
+ # for SkySat and Doves, limit to integer values, and 0 as no-data
+ map_opt.extend(['--nodata-value',str(0)])
+ map_opt.extend(['--ot','UInt16'])
+
if cam:
map_args = [dem,img,cam,outfn]
+ if '.xml' in cam:
+ print("Input is DG, will use all threads")
+ map_opt.extend(['--threads',str(iolib.cpu_count())])
else:
map_args = [dem,img,outfn]
+
out = run_cmd('mapproject',map_opt+map_args)
return out
@@ -400,7 +422,7 @@ def dem_mosaic(img_list,outfn,tr=None,tsrs=None,stats=None,tile_size=None):
out = run_cmd('dem_mosaic',dem_mosaic_args+dem_mosaic_opt)
return out
-def get_stereo_opts(session='rpc',ep=0,threads=4,ba_prefix=None,align='Affineepipolar',xcorr=2,std_mask=0.5,std_kernel=-1,lv=5,corr_kernel=[21,21],rfne_kernel=[35,35],stereo_mode=0,spm=1,cost_mode=2,corr_tile_size=1024,mvs=False):
+def get_stereo_opts(session='rpc',ep=0,threads=4,ba_prefix=None,align='Affineepipolar',xcorr=2,std_mask=0.5,std_kernel=-1,lv=5,corr_kernel=[21,21],rfne_kernel=[35,35],stereo_mode='asp_bm',spm=1,cost_mode=2,corr_tile_size=1024,mvs=False):
"""
prepares stereo cmd for ASP
See ASP's stereo documentation here: https://stereopipeline.readthedocs.io/en/latest/correlation.html
@@ -428,8 +450,8 @@ def get_stereo_opts(session='rpc',ep=0,threads=4,ba_prefix=None,align='Affineepi
tempelate window size for stereo correlation (default is [21,21])
rfne_kernel: list
tempelate window size for sub-pixel optimization (default is [35,35])
- stereo_mode: int
- 0 for block matching, 1 for SGM, 2 for MGM (default is 0)
+ stereo_mode: str
+ asp_bm for block matching, asp_sgm for SGM, asp_mgm for MGM (default is asp_bm)
spm: int
subpixel mode, 0 for parabolic localisation, 1 for adaptavie affine and 2 for simple affine (default is 1)
cost_mode: int
@@ -448,7 +470,8 @@ def get_stereo_opts(session='rpc',ep=0,threads=4,ba_prefix=None,align='Affineepi
# session_args
stereo_opt.extend(['-t', session])
stereo_opt.extend(['-e',str(ep)])
- stereo_opt.extend(['--threads', str(threads)])
+ stereo_opt.extend(['--threads-multiprocess', str(threads)])
+ stereo_opt.extend(['--threads-singleprocess', str(threads)])
if ba_prefix:
stereo_opt.extend(['--bundle-adjust-prefix', ba_prefix])
# stereo is a python wrapper for 3/4 stages
@@ -468,7 +491,7 @@ def get_stereo_opts(session='rpc',ep=0,threads=4,ba_prefix=None,align='Affineepi
# stereo_corr_args:
# parallel stereo is generally not required with input SkySat imagery
# So all the mgm/sgm calls are done without it.
- stereo_opt.extend(['--stereo-algorithm', str(stereo_mode)])
+ stereo_opt.extend(['--stereo-algorithm', stereo_mode])
# the kernel size would depend on the algorithm
stereo_opt.extend(['--corr-kernel', str(corr_kernel[0]), str(corr_kernel[1])])
stereo_opt.extend(['--corr-tile-size', str(corr_tile_size)])
@@ -484,7 +507,7 @@ def get_stereo_opts(session='rpc',ep=0,threads=4,ba_prefix=None,align='Affineepi
- median-filter-size, --texture-smooth-size (I guess these are set to some defualts for sgm/mgm ?)
"""
# stereo_tri_args:
- disp_trip = 2500
+ disp_trip = 10000
if not mvs:
stereo_opt.extend(['--num-matches-from-disp-triplets', str(disp_trip)])
stereo_opt.extend(['--unalign-disparity'])
@@ -509,7 +532,7 @@ def convergence_angle(az1, el1, az2, el2):
conv_ang = np.rad2deg(np.arccos(np.sin(np.deg2rad(el1)) * np.sin(np.deg2rad(el2)) + np.cos(np.deg2rad(el1)) * np.cos(np.deg2rad(el2)) * np.cos(np.deg2rad(az1 - az2))))
return conv_ang
-def get_pc_align_opts(outprefix, max_displacement=100, align='point-to-plane', source=True, threads=n_cpu,trans_only=False):
+def get_pc_align_opts(outprefix, max_displacement=100, align='point-to-plane', source=True, threads=n_cpu,trans_only=False,initial_align=None):
"""
prepares ASP pc_align ICP cmd
See pc_align documentation here: https://stereopipeline.readthedocs.io/en/latest/tools/pc_align.html
@@ -545,6 +568,8 @@ def get_pc_align_opts(outprefix, max_displacement=100, align='point-to-plane', s
pc_align_opts.extend(['--save-inv-transformed-reference-points'])
if trans_only:
pc_align_opts.extend(['--compute-translation-only'])
+ if initial_align:
+ pc_align_opts.extend(['--initial-transform',initial_align])
pc_align_opts.extend(['-o', outprefix])
return pc_align_opts
@@ -571,6 +596,7 @@ def get_point2dem_opts(tr, tsrs,threads=n_cpu):
point2dem_opts.extend(['--t_srs', tsrs])
point2dem_opts.extend(['--threads',str(threads)])
point2dem_opts.extend(['--errorimage'])
+ point2dem_opts.extend(['--nodata-value',str(-9999.0)])
return point2dem_opts
def get_total_shift(pc_align_log):
@@ -593,7 +619,7 @@ def get_total_shift(pc_align_log):
total_shift = np.float(max_alignment_string[0].split(':',15)[-1].split('m')[0])
return total_shift
-def dem_align(ref_dem, source_dem, max_displacement, outprefix, align, trans_only=False, threads=n_cpu):
+def dem_align(ref_dem, source_dem, max_displacement, outprefix, align, trans_only=False, threads=n_cpu,initial_align=None):
"""
This function implements the full DEM alignment workflow using ASP's pc_align and point2dem programs
See relevent doumentation here: https://stereopipeline.readthedocs.io/en/latest/tools/pc_align.html
@@ -636,7 +662,7 @@ def dem_align(ref_dem, source_dem, max_displacement, outprefix, align, trans_onl
pc_align_vec = '-inverse-transform.txt'
print("Aligning clouds via the {} method".format(align))
- pc_align_opts = get_pc_align_opts(outprefix,max_displacement,align=align,source=source,trans_only=trans_only,threads=threads)
+ pc_align_opts = get_pc_align_opts(outprefix,max_displacement,align=align,source=source,trans_only=trans_only,initial_align=initial_align,threads=threads)
pc_align_log = run_cmd('pc_align', pc_align_opts + pc_align_args)
print(pc_align_log)
# this try, except block checks for 2 things.
@@ -825,6 +851,44 @@ def compute_cam_px_reproj_err_stats(content_line,idx):
stats = malib.get_stats_dict(np.sqrt(px**2+py**2),full=True)
return stats
+def compute_cam_px_reproj_err_stats_alt(content_fn,idx):
+ """
+ Compute discriptive pixel reprojection error stats for all points in a given camera and return as dict
+ Parameters
+ -----------
+ content_line: list
+ list of str, each string containing 1 line contents of run-final_residuals_no_loss_function_raw_pixels.txt
+ idx: np.array
+ point indices for which reprojection error needs to be read
+ Returns
+ -----------
+ stats: dictionary
+ cumulative descriptive stats for all pixels viewed from a given camera
+ """
+ with open(content_fn,'r') as f:
+ content = f.readlines()
+ content = [x.strip() for x in content]
+ try:
+
+ px,py = read_px_error(content,idx)
+ stats = malib.get_stats_dict(np.sqrt(px**2+py**2),full=True)
+ except ValueError:
+ stats = {'count': 0,
+ 'min': 0.0,
+ 'max': 0.0,
+ 'ptp': 0.0,
+ 'mean': 0.0,
+ 'std': 0.0,
+ 'nmad': 0.0,
+ 'med': 0.0,
+ 'median': 0.0,
+ 'p16': 0.0,
+ 'p84': 0.0,
+ 'spread': 0.0,
+ 'mode': 0.0}
+ pass
+ return stats
+
def camera_reprojection_error_stats_df(pixel_error_fn):
"""
Return dataframe of descriptive stats for pixel reprojection errors corresponding to each camera
@@ -874,4 +938,408 @@ def camera_reprojection_error_stats_df(pixel_error_fn):
# dataframe is good to go
return stats_df
+def produce_m(lon,lat,m_meridian_offset=0):
+ """
+ Produce M matrix which facilitates conversion from Lon-lat (NED) to ECEF coordinates
+ From https://github.com/visionworkbench/visionworkbench/blob/master/src/vw/Cartography/Datum.cc#L249
+ This is known as direction cosie matrix
+
+ Parameters
+ ------------
+ lon: numeric
+ longitude of spacecraft
+ lat: numeric
+ latitude of spacecraft
+ m_meridian_offset: numeric
+ set to zero
+ Returns
+ -----------
+ R: np.array
+ 3 x 3 rotation matrix representing the m-matrix aka direction cosine matrix
+ """
+ if lat < -90:
+ lat = -90
+ if lat > 90:
+ lat = 90
+
+ rlon = (lon + m_meridian_offset) * (np.pi/180)
+ rlat = lat * (np.pi/180)
+ slat = np.sin(rlat)
+ clat = np.cos(rlat)
+ slon = np.sin(rlon)
+ clon = np.cos(rlon)
+
+ R = np.ones((3,3),dtype=float)
+ R[0,0] = -slat*clon
+ R[1,0] = -slat*slon
+ R[2,0] = clat
+ R[0,1] = -slon
+ R[1,1] = clon
+ R[2,1] = 0.0
+ R[0,2] = -clon*clat
+ R[1,2] = -slon*clat
+ R[2,2] = -slat
+ return R
+
+def convert_ecef2NED(asp_rotation,lon,lat):
+ """
+ convert rotation matrices from ECEF to North-East-Down convention
+ Parameters
+ -------------
+ asp_rotation: np.array
+ 3 x 3 rotation matrix from ASP
+ lon: numeric
+ longitude for computing m matrix
+ lat: numeric
+ latitude for computing m matrix
+
+ Returns
+ --------------
+ r_ned: np.array
+ 3 x 3 NED rotation matrix
+ """
+ m = produce_m(lon,lat)
+ r_ned = np.matmul(np.linalg.inv(m),asp_rotation)
+ #r_ned = np.matmul(np.transpose(m),asp_rotation)
+ #r_ned = np.matmul(m,asp_rotation)
+ return r_ned
+
+def ned_rotation_from_tsai(tsai_fn):
+ """
+ return yaw pitch and roll angles from a ASP tsai file
+ This is experimental and only tested for one SkySat dataset, will remove this message when get consistent results for other datasets
+
+ Parameters
+ ------------
+ tsai_fn: str
+ path to tsai file
+
+ Returns
+ ------------
+ yaw,pitch,roll: numeric
+ yaw pitch and roll angle in degrees (order of rotation assumed: Yaw, Pitch, Roll)
+ """
+ from scipy.spatial.transform import Rotation as R
+
+ #coordinate conversion step
+ from pyproj import Transformer
+ ecef_proj = 'EPSG:4978'
+ geo_proj = 'EPSG:4326'
+ ecef2wgs = Transformer.from_crs(ecef_proj,geo_proj)
+
+ # read tsai files
+ asp_dict = asp.read_tsai_dict(tsai_fn)
+
+ # get camera position
+ cam_cen = asp_dict['cam_cen_ecef']
+ lat,lon,h = ecef2wgs.transform(*cam_cen)
+ #print(lat,lon)
+ # get camera rotation angle
+ rot_mat = np.reshape(asp_dict['rotation_matrix'],(3,3))
+
+ #rotate about z axis by 90 degrees
+ #https://math.stackexchange.com/questions/651413/given-the-degrees-to-rotate-around-axis-how-do-you-come-up-with-rotation-matrix
+ rot_z = np.zeros((3,3),float)
+ angle = np.pi/2
+ rot_z[0,0] = np.cos(angle)
+ rot_z[0,1] = -1 * np.sin(angle)
+ rot_z[1,0] = np.sin(angle)
+ rot_z[1,1] = np.cos(angle)
+ rot_z[2,2] = 1
+
+
+
+ #return np.matmul(rot_z,convert_ecef2NED(rot_mat,lon,lat))
+ return R.from_matrix(np.matmul(rot_z,np.linalg.inv(convert_ecef2NED(rot_mat,lon,lat)))).as_euler('ZYX',degrees=True)
+
+
+def prepare_virtual_gcp(init_reproj_fn,cnet_fn,refdem,out_gcp,dem_crs='EPSG:32644',dh_threshold = 0.75,mask_glac=True):
+ """
+ *** This is experimental and not tested apart from the Chamoli multi-sensor, multi-orbit dataset***
+ Prepare virtual GCP network from initially triangulated pointcloud
+ Parameters
+ ------------
+ init_reproj_fn: str
+ path to initial reprojection error file
+ cnet_fn: str
+ path to initially triangulated control network
+ refdem: str
+ path to refdem
+ out_gcp: str
+ Path to output GCP file
+ dem_crs: str
+ CRS for input DEM
+ ## This should not be required, we should get rid of this
+ dh_threshold: numeric
+ absolute dh threshold between triangulated points and refrence DEM height to select as virtual GCP
+ mask_glac: bool
+ mask out points within a glacier (**Not implemented rn**)
+
+
+ """
+ print("Initiating logic to compute virtual GCP file")
+
+ print("Step 1: Reading inital reprojection error file......")
+ init_gdf = _pointmap2gdf(init_reproj_fn,proj=dem_crs)
+
+ print("Step 2: Reading reference DEM........")
+ dem_ds = iolib.fn_getds(refdem)
+
+ print("Step 3: Sampling heights from reference DEM and computing elevation residual")
+ map_x = init_gdf.geometry.x.values
+ map_y = init_gdf.geometry.y.values
+ init_gdf['dem_height'] = _sample_ndimage(iolib.ds_getma(dem_ds),dem_ds.GetGeoTransform(),map_x,map_y)
+ init_gdf['dh'] = np.abs(init_gdf['dem_height'] - init_gdf['height_above_datum'])
+
+ print(f"Step 4: Applying absolute input dh threshold of {np.round(dh_threshold,2)} m..............")
+ mask = init_gdf['dh'] <= dh_threshold
+ fltr_gdf = init_gdf[mask]
+ print(f"From total of {len(init_gdf)} points, {len(fltr_gdf)} points fall within dh_threshold ")
+
+ print("Step 5: Preparing GCPs indices")
+ filtered_idx = fltr_gdf.index.values
+ mask_5_view = fltr_gdf[' num_observations'] >= 5
+ five_view_idx = fltr_gdf[mask_5_view].index.values
+
+ mask_4_view = fltr_gdf[' num_observations'] == 4
+ four_view_idx = fltr_gdf[mask_4_view].index.values
+
+ mask_3_view = fltr_gdf[' num_observations'] == 3
+ three_view_idx = fltr_gdf[mask_3_view].index.values
+
+ mask_2_view = fltr_gdf[' num_observations'] == 2
+ two_view_idx = fltr_gdf[mask_2_view].index.values
+
+ print("Step 6: Reading control network")
+ with open(cnet_fn,'r') as f:
+ content = f.readlines()
+ content = [x.strip() for x in content]
+
+ print("Step 7: Writing GCP to disk")
+ #outfn = os.path.splitext(cnet_fn)[0]+'_opt3_gcp.gcp'
+ counter = 1
+
+ view_count = []
+ with open (out_gcp,'w') as f:
+ for idx,line in enumerate(tqdm(content)):
+ if idx not in filtered_idx:
+ continue
+ else:
+
+ num_img = line.count('.tif')
+
+ view_count.append(num_img)
+
+ new_str = f"{counter} {line.split(' ',1)[1]}"
+ if idx in five_view_idx:
+ #print(new_str)
+ new_str = new_str.split(' 1 1 1 ')[0] + ' 0.5 0.5 0.5 '+new_str.split(' 1 1 1 ')[1]
+
+
+ elif idx in four_view_idx:
+ new_str = new_str.split(' 1 1 1 ')[0] + ' 1.2 1.2 1.2 '+new_str.split(' 1 1 1 ')[1]
+ elif idx in three_view_idx:
+ new_str = new_str.split(' 1 1 1 ')[0] + ' 1.8 1.8 1.8 '+new_str.split(' 1 1 1 ')[1]
+
+ elif idx in two_view_idx:
+ new_str = new_str.split(' 1 1 1 ')[0] + ' 2.2 2.2 2.2 '+new_str.split(' 1 1 1 ')[1]
+
+
+
+ #final_gcp_list.append(new_str)
+ counter = counter + 1
+ f.write(new_str+'\n')
+ # save a copy of initial parameters incase needed later
+ out_reproj_fn = os.path.splitext(init_reproj_fn)[0]+'_gcp_material.csv'
+ out_cnet_fn = os.path.splitext(cnet_fn)[0]+'_gcp_material.csv'
+ shutil.copy2(init_reproj_fn,out_reproj_fn)
+ shutil.copy2(cnet_fn,out_cnet_fn)
+
+# Helper functions for virtual GCP function
+
+def _df2gdf(df,proj="EPSG:32644",sort_ascending=False):
+ #import geopandas as gpd
+ df = df.rename(columns={'# lon':'lon',' lat':'lat',' height_above_datum':'height_above_datum',' mean_residual':'mean_residual'})
+ gdf = gpd.GeoDataFrame(df,
+ geometry=gpd.points_from_xy(df.lon, df.lat),
+ crs='EPSG:4326')
+ gdf = gdf.to_crs(proj)
+ if sort_ascending:
+ gdf = gdf.sort_values('mean_residual',ascending=True)
+ return gdf
+
+def _pointmap2gdf(pointmap,proj='EPSG:32644',sort_ascending=False):
+ df = pd.read_csv(pointmap,skiprows=[1])
+ return _df2gdf(df,proj,sort_ascending)
+
+def _mapToPixel(mX, mY, geoTransform):
+ """Convert map coordinates to pixel coordinates based on geotransform
+
+ Accepts float or NumPy arrays
+ GDAL model used here - upper left corner of upper left pixel for mX, mY (and in GeoTransform)
+ """
+ mX = np.asarray(mX)
+ mY = np.asarray(mY)
+ if geoTransform[2] + geoTransform[4] == 0:
+ pX = ((mX - geoTransform[0]) / geoTransform[1]) - 0.5
+ pY = ((mY - geoTransform[3]) / geoTransform[5]) - 0.5
+ else:
+ pX, pY = applyGeoTransform(mX, mY, invertGeoTransform(geoTransform))
+ #return int(pX), int(pY)
+ return pX, pY
+
+def _sample_ndimage(dem_ma,dem_gt,map_x,map_y,r='bilinear'):
+ """
+ sample values from the dem masked array for the points in map_x, map_y coordinates
+ dem_ma: Masked numpy array, prefer the dem to be conitnous though
+ gt: geotransform of dem/input array
+ map_x: x_coordinate array
+ map_y: y_coordinate array
+ r: resampling algorithm for decimal px location
+ out: array containing sampled values at zip(map_y,map_x)
+ """
+ import scipy.ndimage
+ #convert map points to px points using geotransform information
+ img_x,img_y = _mapToPixel(map_x,map_y,dem_gt)
+ #prepare input for sampling function
+ yx = np.array([img_y,img_x])
+ # sample the array
+ sampled_pts = scipy.ndimage.map_coordinates(dem_ma, yx, order=1,mode='nearest')
+ return sampled_pts
+
+
+def ipfind_ipmatch(img1,img2,subpixel=False,clear_matchfile=True):
+ """
+ Find match points between two images using SIFT operator in ASP
+ Parameters
+ -------------
+ img1: str
+ path to first image
+ img2: str
+ path to second image
+ subpixel: bool
+ if True, coordinates with subpixel precision are returned
+ clear_matchfile: bool
+ if True, will wipe out the ASP produced matchfile from disk
+ Returns
+ --------------
+ match_img1: np.array
+ array containing matchpoints coordinates in img1 as (x,y) tuples
+ match_img2: np.array
+ array containing matchpoints coordinates in img2 as (x,y) tuples
+ """
+ base1 = os.path.splitext(img1)[0]
+ base2 = os.path.splitext(img2)[0]
+ #asp.run_cmd('ipfind', ['--normalize','--ip-per-tile','2000',img1])
+ #asp.run_cmd('ipfind', ['--normalize','--ip-per-tile','2000',img2])
+ asp.run_cmd('ipfind', ['--normalize',img1])
+ asp.run_cmd('ipfind', ['--normalize',img2])
+ ip1 = base1+'.vwip'
+ ip2 = base2+'.vwip'
+ asp.run_cmd('ipmatch',[img1,ip1,img2,ip2])
+ match_fn = base1+'__'+os.path.basename(base2)+'.match'
+ match_img1,match_img2 = read_match_file(match_fn)
+ match_img1 = pd.DataFrame(match_img1)
+ match_img2 = pd.DataFrame(match_img2)
+ os.remove(ip1)
+ os.remove(ip2)
+ if subpixel:
+ match_img1 = np.array(list(zip(match_img1[0].values,match_img1[1].values)))
+ match_img2 = np.array(list(zip(match_img2[0].values,match_img2[1].values)))
+ else:
+ match_img1 = np.array(list(zip(match_img1[2].values,match_img1[3].values)))
+ match_img2 = np.array(list(zip(match_img2[2].values,match_img2[3].values)))
+ if clear_matchfile:
+ os.remove(match_fn)
+ return match_img1,match_img2
+
+
+def read_ip_record(mf):
+ """
+ Read one IP record from the binary match file.
+ #### Reading ip and MP is borrowed from the solution which Amaury Dehecq shared on the ASP mailing list
+ #### All credits to Amaury (amaury.dehecq at univ-grenoble-alpes.fr)
+
+ Information comtained are x, y, xi, yi, orientation, scale, interest, polarity, octave, scale_lvl, desc
+ (Oleg/Scott to explain?)
+ Input: - mf, file handle to the in put binary file (in 'rb' mode)
+ Output: - iprec, array containing the IP record
+ """
+ x, y = np.frombuffer(mf.read(8), dtype=np.float32)
+ xi, yi = np.frombuffer(mf.read(8), dtype=np.int32)
+ orientation, scale, interest = np.frombuffer(mf.read(12), dtype=np.float32)
+ polarity, = np.frombuffer(mf.read(1), dtype=np.int8) # or np.bool?
+ octave, scale_lvl = np.frombuffer(mf.read(8), dtype=np.uint32)
+ ndesc, = np.frombuffer(mf.read(8), dtype=np.uint64)
+ desc = np.frombuffer(mf.read(int(ndesc * 4)), dtype=np.float32)
+ iprec = [x, y, xi, yi, orientation, scale, interest, polarity, octave, scale_lvl, ndesc]
+ iprec.extend(desc)
+ return iprec
+
+def read_match_file(match_file):
+ """
+ Read a full binary match file. First two 8-bits contain the number of IPs in each image. Then contains the record for each IP, image1 first, then image2.
+ #### Reading ip and MP is borrowed from the solution which Amaury Dehecq shared on the ASP mailing list
+ #### All credits to Amaury (amaury.dehecq at univ-grenoble-alpes.fr)
+
+ Input:
+ - match_file: str, path to the match file
+ Outputs:
+ - two arrays, containing the IP records for image1 and image2.
+ """
+
+ # Open binary file in read mode
+ mf = open(match_file,'rb')
+
+ # Read record length
+ size1 = np.frombuffer(mf.read(8), dtype=np.uint64)[0]
+ size2 = np.frombuffer(mf.read(8), dtype=np.uint64)[0]
+
+ # Read record for each image
+ im1_ip = [read_ip_record(mf) for i in range(size1)]
+ im2_ip = [read_ip_record(mf) for i in range(size2)]
+
+ # Close file
+ mf.close()
+
+ return im1_ip, im2_ip
+
+
+def virtual_gcp_ba(img_list,cam_list,overlap_list,session,ba_prefix,
+ refdem,out_gcp,dem_crs='EPSG:32644',dh_threshold = 0.75,mask_glac=True,
+ prepare_matchfiles=False):
+ # step 1: prepare matchfiles
+ ## Assume for now exists in a directory
+
+ # step 2: run bundle adjust with zero iterations and only 1 pass
+ ## this will produce the pointmap file and the cnet.csv file #init_reproj_fn,#cnet_fn
+ cnet_ba_opt = get_ba_opts(
+ ba_prefix, session=session,num_iterations=0,num_pass=1,overlap_list=overlap_list,camera_weight=0)
+ ba_args = img_list + cam_list
+ print("Building control network and pointmap files for virtual GCP creation")
+ run_cmd('bundle_adjust', cnet_ba_opt + ba_args)
+ try:
+ cnet_fn = glob.glob(ba_prefix+'*cnet.csv')[0]
+ except:
+ print("No control network found, exiting")
+ sys.exit()
+
+ try:
+ init_reproj_fn = glob.glob(ba_prefix+'*initial*no_loss_*pointmap*.csv')[0]
+ except:
+ print("No initial error pointmap found,exiting")
+ sys.exit()
+
+
+ # step 3: Run the function from above which will generate the gcp
+
+ prepare_virtual_gcp(init_reproj_fn,cnet_fn,refdem,out_gcp,dem_crs,dh_threshold,mask_glac)
+
+ # Finally run the bundle adjustment with the GCPs
+ gcp_bundle_adjust_opt = get_ba_opts(
+ ba_prefix, session=session,num_iterations=400,num_pass=1,overlap_list=overlap_list,camera_weight=0)
+ print("Running final bundle adjustment using virtual GCPs")
+ ba_args = img_list + cam_list + [outgcp]
+ run_cmd('bundle_adjust',gcp_bundle_adjust_opt + ba_args)
+ print("Tada, you are done !!")
diff --git a/skysat_stereo/bundle_adjustment_lib.py b/skysat_stereo/bundle_adjustment_lib.py
new file mode 100644
index 0000000..2c4f058
--- /dev/null
+++ b/skysat_stereo/bundle_adjustment_lib.py
@@ -0,0 +1,237 @@
+#! /usr/bin/env python
+import os,sys,glob,shutil
+import subprocess
+import argparse
+from distutils.spawn import find_executable
+from pygeotools.lib import iolib,malib
+import geopandas as gpd
+import numpy as np
+from datetime import datetime
+import pandas as pd
+from multiprocessing import cpu_count
+
+def run_cmd(bin, args, **kw):
+ # Note, need to add full executable
+ # from dshean/vmap.py
+ #binpath = os.path.join('/home/sbhushan/src/StereoPipeline/bin',bin)
+ binpath = find_executable(bin)
+ if binpath is None:
+ msg = ("Unable to find executable %s\n"
+ "Install ASP and ensure it is in your PATH env variable\n"
+ "https://ti.arc.nasa.gov/tech/asr/intelligent-robotics/ngt/stereo/")
+ sys.exit(msg)
+ # binpath = os.path.join('/opt/StereoPipeline/bin/',bin)
+ call = [binpath, ]
+ print(call)
+ call.extend(args)
+ print(call)
+ # print(type(call))
+ # print(' '.join(call))
+ try:
+ code = subprocess.call(call, shell=False)
+ except OSError as e:
+ raise Exception('%s: %s' % (binpath, e))
+ if code != 0:
+ raise Exception('ASP step ' + kw['msg'] + ' failed')
+
+
+def get_ba_opts(ba_prefix, ip_per_tile=4000,camera_weight=None,translation_weight=0.4,rotation_weight=0,fixed_cam_idx=None,overlap_list=None, robust_threshold=None, overlap_limit=None, initial_transform=None, input_adjustments=None, flavor='general_ba', session='nadirpinhole', gcp_transform=False,num_iterations=2000,num_pass=2,lon_lat_limit=None,elevation_limit=None):
+ ba_opt = []
+ # allow CERES to use multi-threads
+ ba_opt.extend(['--threads', str(cpu_count())])
+ #ba_opt.extend(['--threads', '1'])
+ ba_opt.extend(['-o', ba_prefix])
+
+ # keypoint-finding args
+ # relax triangulation error based filters to account for initial camera errors
+ ba_opt.extend(['--min-matches', '4'])
+ ba_opt.extend(['--disable-tri-ip-filter'])
+ ba_opt.extend(['--force-reuse-match-files'])
+ ba_opt.extend(['--ip-per-tile', str(ip_per_tile)])
+ ba_opt.extend(['--ip-inlier-factor', '0.2'])
+ ba_opt.extend(['--ip-num-ransac-iterations', '1000'])
+ ba_opt.extend(['--skip-rough-homography'])
+ ba_opt.extend(['--min-triangulation-angle', '0.0001'])
+
+ # Save control network created from match points
+ ba_opt.extend(['--save-cnet-as-csv'])
+
+ # Individually normalize images to properly stretch constrant
+ # Helpful in keypoint detection
+ ba_opt.extend(['--individually-normalize'])
+
+ if robust_threshold is not None:
+ # make the solver focus more on mininizing very high reporjection errors
+ ba_opt.extend(['--robust-threshold', str(robust_threshold)])
+
+ if camera_weight is not None:
+ # this generally assigns weight to penalise movement of camera parameters (Default:0)
+ ba_opt.extend(['--camera-weight', str(camera_weight)])
+ else:
+ # this is more fine grained, will pinalize translation but allow rotation parameters update
+ ba_opt.extend(['--translation-weight',str(translation_weight)])
+ ba_opt.extend(['--rotation-weight',str(rotation_weight)])
+
+ if fixed_cam_idx is not None:
+ # parameters for cameras at the specified indices will not be floated during optimisation
+ ba_opt.extend(['--fixed-camera-indices',' '.join(fixed_cam_idx.astype(str))])
+ ba_opt.extend(['-t', session])
+
+ # filter points based on reprojection errors before running a new pass
+ ba_opt.extend(['--remove-outliers-params', '75 3 5 6'])
+
+ # How about adding num random passes here ? Think about it, it might help if we are getting stuck in local minima :)
+ if session == 'nadirpinhole':
+ ba_opt.extend(['--inline-adjustments'])
+ # write out a new camera model file with updated parameters
+
+ # specify number of passes and maximum iterations per pass
+ ba_opt.extend(['--num-iterations', str(num_iterations)])
+ ba_opt.extend(['--num-passes', str(num_pass)])
+ #ba_opt.extend(['--parameter-tolerance','1e-14'])
+
+ if gcp_transform:
+ ba_opt.extend(['--transform-cameras-using-gcp'])
+
+ if initial_transform:
+ ba_opt.extend(['--initial-transform', initial_transform])
+ if input_adjustments:
+ ba_opt.extend(['--input-adjustments', input_adjustments])
+
+ # these 2 parameters determine which image pairs to use for feature matching
+ # only the selected pairs are used in formation of the bundle adjustment control network
+ # video is a sequence of overlapping scenes, so we use an overlap limit
+ # triplet stereo uses list of overlapping pairs
+ if overlap_limit:
+ ba_opt.extend(['--overlap-limit',str(overlap_limit)])
+ if overlap_list:
+ ba_opt.extend(['--overlap-list', overlap_list])
+
+ # these two params are not used generally.
+ if lon_lat_limit:
+ ba_opt.extend(['--lon-lat-limit',str(lon_lat_limit[0]),str(lon_lat_limit[1]),str(lon_lat_limit[2]),str(lon_lat_limit[3])])
+ if elevation_limit:
+ ba_opt.extend(['--elevation-limit',str(elevation_limit[0]),str(elevation_limit[1])])
+
+ return ba_opt
+
+def bundle_adjust_stable(img,ba_prefix,cam=None,session='rpc',initial_transform=None,
+ input_adjustments=None,overlap_list=None,gcp=None,
+ mode='full_triplet',bound=None,camera_param2float='trans+rot',
+ dem=None,num_iter=2000,num_pass=2):
+ """
+ """
+ img_list = sorted(glob.glob(os.path.join(img,'*.tif')))
+ if len(img_list) < 2:
+ img_list = sorted(glob.glob(os.path.join(img, '*.tiff')))
+ #img_list = [os.path.basename(x) for x in img_list]
+ if os.path.islink(img_list[0]):
+ img_list = [os.readlink(x) for x in img_list]
+ if overlap_list is not None:
+ # need to remove images and cameras which are not optimised during bundle adjustment
+ # read pairs from input overlap list
+ initial_count = len(img_list)
+ with open(overlap_list) as f:
+ content = f.readlines()
+ content = [x.strip() for x in content]
+ l_img = [x.split(' ')[0] for x in content]
+ r_img = [x.split(' ')[1] for x in content]
+ total_img = l_img + r_img
+ uniq_idx = np.unique(total_img, return_index=True)[1]
+ img_list = [total_img[idx] for idx in sorted(uniq_idx)]
+ print(f"Out of the initial {initial_count} images, {len(img_list)} will be orthorectified using adjusted cameras")
+
+ if cam is not None:
+ #cam = os.path.abspath(cam)
+ if 'run' in os.path.basename(cam):
+ cam_list = [glob.glob(cam+'-'+os.path.splitext(os.path.basename(x))[0]+'*.tsai')[0] for x in img_list]
+ print("No of cameras is {}".format(len(cam_list)))
+
+ else:
+ cam_list = [glob.glob(os.path.join(cam,os.path.splitext(os.path.basename(x))[0]+'*.tsai'))[0] for x in img_list]
+ if gcp is not None:
+ gcp_list = sorted(glob.glob(os.path.join(args.gcp, '*.gcp')))
+ if bound:
+ bound = gpd.read_file(args.bound)
+ geo_crs = {'init':'epsg:4326'}
+ if bound.crs is not geo_crs:
+ bound = bound.to_crs(geo_crs)
+ lon_min,lat_min,lon_max,lat_max = bound.total_bounds
+ if camera_param2float == 'trans+rot':
+ cam_wt = 0
+ else:
+ # this will invoke adjustment with rotation weight of 0 and translation weight of 0.4
+ cam_wt = None
+ print(f"Camera weight is {cam_wt}")
+
+ if dem:
+ dem = iolib.fn_getma(dem)
+ dem_stats = malib.get_stats_dict(dem)
+ min_elev,max_elev = [dem_stats['min']-500,dem_stats['max']+500]
+ dem = None
+ if mode == 'full_triplet':
+ if overlap_list is None:
+ print(
+ "Attempted bundle adjust will be expensive, will try to find matches in each and every pair")
+ # the concept is simple
+ #first 3 cameras, and then corresponding first three cameras from next collection are fixed in the first go
+ # these serve as a kind of #GCP, preventing a large drift in the triangulated points/camera extrinsics during optimization
+ img_time_identifier_list = np.array([os.path.basename(img).split('_')[1] for img in img_list])
+ img_time_unique_list = np.unique(img_time_identifier_list)
+ second_collection_list = np.where(img_time_identifier_list == img_time_unique_list[1])[0][[0,1,2]]
+ fix_cam_idx = np.array([0,1,2]+list(second_collection_list))
+ print(type(fix_cam_idx))
+ round1_opts = get_ba_opts(
+ ba_prefix, session=session,num_iterations=num_iter,num_pass=num_pass,
+ fixed_cam_idx=fix_cam_idx,overlap_list=overlap_list,camera_weight=cam_wt)
+ # enter round2_opts here only ?
+ if session == 'nadirpinhole':
+ ba_args = img_list+ cam_list
+ else:
+ ba_args = img_list
+ print("Running round 1 bundle adjustment for given triplet stereo combination")
+ run_cmd('bundle_adjust', round1_opts+ba_args)
+
+ # Save the first and foremost bundle adjustment reprojection error file
+ init_residual_fn_def = sorted(glob.glob(ba_prefix+'*initial*residuals*pointmap*.csv'))[0]
+ init_residual_fn = os.path.splitext(init_residual_fn_def)[0]+'_initial_reproj_error.csv'
+ init_per_cam_reproj_err = sorted(glob.glob(ba_prefix+'-*initial_residuals_raw_pixels.txt'))[0]
+ init_per_cam_reproj_err_disk = os.path.splitext(init_per_cam_reproj_err)[0]+'_initial_per_cam_reproj_error.txt'
+ init_cam_stats = sorted(glob.glob(ba_prefix+'-*initial_residuals_stats.txt'))[0]
+ init_cam_stats_disk = os.path.splitext(init_cam_stats)[0]+'_initial_camera_stats.txt'
+ shutil.copy2(init_residual_fn_def,init_residual_fn)
+ shutil.copy2(init_per_cam_reproj_err,init_per_cam_reproj_err_disk)
+ shutil.copy2(init_cam_stats,init_cam_stats_disk)
+
+ if session == 'nadirpinhole':
+ identifier = os.path.basename(cam_list[0]).split('_',14)[0][:2]
+ print(ba_prefix+'-{}*.tsai'.format(identifier))
+ cam_list = sorted(glob.glob(os.path.join(ba_prefix+ '-{}*.tsai'.format(identifier))))
+ ba_args = img_list+cam_list
+ fixed_cam_idx2 = np.delete(np.arange(len(img_list),dtype=int),fix_cam_idx)
+ round2_opts = get_ba_opts(ba_prefix, overlap_list=overlap_list,session=session,
+ fixed_cam_idx=fixed_cam_idx2,camera_weight=cam_wt)
+ else:
+ # round 1 is adjust file
+ # Only camera model parameters for the first three stereo pairs float in this round
+ input_adjustments = ba_prefix
+ round2_opts = get_ba_opts(
+ ba_prefix, overlap_limit, input_adjustments=ba_prefix, flavor='2round_gcp_2', session=session,
+ elevation_limit=[min_elev,max_elev],lon_lat_limit=[lon_min,lat_min,lon_max,lat_max])
+ ba_args = img_list+gcp_list
+
+
+ print("running round 2 bundle adjustment for given triplet stereo combination")
+ run_cmd('bundle_adjust', round2_opts+ba_args)
+
+ # Save state for final condition reprojection errors for the sparse triangulated points
+ final_residual_fn_def = sorted(glob.glob(ba_prefix+'*final*residuals*pointmap*.csv'))[0]
+ final_residual_fn = os.path.splitext(final_residual_fn_def)[0]+'_final_reproj_error.csv'
+ shutil.copy2(final_residual_fn_def,final_residual_fn)
+ final_per_cam_reproj_err = sorted(glob.glob(ba_prefix+'-*final_residuals_raw_pixels.txt'))[0]
+ final_per_cam_reproj_err_disk = os.path.splitext(final_per_cam_reproj_err)[0]+'_final_per_cam_reproj_error.txt'
+ final_cam_stats = sorted(glob.glob(ba_prefix+'-*final_residuals_stats.txt'))[0]
+ final_cam_stats_disk = os.path.splitext(final_cam_stats)[0]+'_final_camera_stats.txt'
+ shutil.copy2(final_per_cam_reproj_err,final_per_cam_reproj_err_disk)
+ shutil.copy2(final_cam_stats,final_cam_stats_disk)
+
diff --git a/skysat_stereo/misc_geospatial.py b/skysat_stereo/misc_geospatial.py
index a41ed84..19ed2db 100644
--- a/skysat_stereo/misc_geospatial.py
+++ b/skysat_stereo/misc_geospatial.py
@@ -2,12 +2,14 @@
import matplotlib
matplotlib.use('Agg')
+import os,sys,glob
import numpy as np
import pandas as pd
import geopandas as gpd
from imview import pltlib
import matplotlib.pyplot as plt
-from pygeotools.lib import iolib,warplib
+from pygeotools.lib import iolib,geolib,warplib,malib
+from demcoreg import dem_mask
def shp_merger(shplist):
"""
@@ -56,3 +58,79 @@ def plot_composite_fig(ortho,dem,count,nmad,outfn,product='triplet'):
pltlib.iv(nmad,ax=ax[3],cmap='inferno',clim=(0,10),label='Elevation NMAD (m)',skinny=False)
plt.tight_layout()
f.savefig(outfn,dpi=300,bbox_inches='tight',pad_inches=0.1)
+
+def clip_raster_by_shp_disk(r_fn,shp_fn,invert=False):
+ """
+ # this is a lightweight version of directly being used from https://github.com/dshean/pygeotools/blob/master/pygeotools/clip_raster_by_shp.py
+ # meant to limit subprocess calls
+ """
+ if not os.path.exists(r_fn):
+ sys.exit("Unable to find r_fn: %s" % r_fn)
+ if not os.path.exists(shp_fn):
+ sys.exit("Unable to find shp_fn: %s" % shp_fn)
+ #Do the clipping
+ r, r_ds = geolib.raster_shpclip(r_fn, shp_fn,extent='raster',invert=invert)
+ out_fn = os.path.splitext(r_fn)[0]+'_shpclip.tif'
+ iolib.writeGTiff(r, out_fn, r_ds)
+
+def ndvtrim_function(src_fn):
+ """
+ # this is a direct port from https://github.com/dshean/pygeotools/blob/master/pygeotools/trim_ndv.py
+ # intended to make it a function
+ """
+ if not iolib.fn_check(src_fn):
+ sys.exit("Unable to find src_fn: %s" % src_fn)
+
+ #This is a wrapper around gdal.Open()
+ src_ds = iolib.fn_getds(src_fn)
+ src_gt = src_ds.GetGeoTransform()
+
+ print("Loading input raster into masked array")
+ bma = iolib.ds_getma(src_ds)
+
+ print("Computing min/max indices for mask")
+ edge_env = malib.edgefind2(bma, intround=True)
+
+ print("Updating output geotransform")
+ out_gt = list(src_gt)
+ #This should be OK, as edge_env values are integer multiples, and the initial gt values are upper left pixel corner
+ #Update UL_X
+ out_gt[0] = src_gt[0] + src_gt[1]*edge_env[2]
+ #Update UL_Y, note src_gt[5] is negative
+ out_gt[3] = src_gt[3] + src_gt[5]*edge_env[0]
+ out_gt = tuple(out_gt)
+
+
+ out_fn = os.path.splitext(src_fn)[0]+'_trim.tif'
+ print("Writing out: %s" % out_fn)
+ #Extract valid subsection from input array
+ #indices+1 are necessary to include valid row/col on right and bottom edges
+ iolib.writeGTiff(bma[edge_env[0]:edge_env[1]+1, edge_env[2]:edge_env[3]+1], out_fn, src_ds, gt=out_gt)
+ bma = None
+
+def dem_mask_disk(mask_list,dem_fn):
+ """
+ This is lightweight version ported from here for convinence: https://github.com/dshean/demcoreg/blob/master/demcoreg/dem_mask.py
+ """
+ dem_ds = iolib.fn_getds(dem_fn)
+ print(dem_fn)
+ #Get DEM masked array
+ dem = iolib.ds_getma(dem_ds)
+ print("%i valid pixels in original input tif" % dem.count())
+ newmask = dem_mask.get_mask(dem_ds,mask_list,dem_fn=dem_fn)
+ #Apply mask to original DEM - use these surfaces for co-registration
+ newdem = np.ma.array(dem, mask=newmask)
+ #Check that we have enough pixels, good distribution
+ min_validpx_count = 100
+ min_validpx_std = 10
+ validpx_count = newdem.count()
+ validpx_std = newdem.std()
+ print("%i valid pixels in masked output tif to be used as ref" % validpx_count)
+ print("%0.2f std in masked output tif to be used as ref" % validpx_std)
+ #if (validpx_count > min_validpx_count) and (validpx_std > min_validpx_std):
+ if (validpx_count > min_validpx_count):
+ out_fn = os.path.splitext(dem_fn)[0]+"_ref.tif"
+ iolib.writeGTiff(newdem, out_fn, src_ds=dem_ds)
+ else:
+ print("Not enough valid pixels!")
+
\ No newline at end of file
diff --git a/skysat_stereo/skysat.py b/skysat_stereo/skysat.py
index 886710b..b61ed57 100644
--- a/skysat_stereo/skysat.py
+++ b/skysat_stereo/skysat.py
@@ -6,15 +6,16 @@
from skysat_stereo import asp_utils
import numpy as np
import pandas as pd
-import gdal
+from osgeo import gdal
import os,sys,glob
from shapely import wkt
-import gdalconst
-from progressbar import ProgressBar
+from osgeo import gdalconst
import re
from tqdm import tqdm
from datetime import datetime
from multiprocessing import cpu_count
+from p_tqdm import p_map
+import itertools
def skysat_footprint(img_fn,incrs=None):
@@ -47,8 +48,8 @@ def skysat_footprint(img_fn,incrs=None):
mx,my = asp_utils.rpc2map(img_fn,img_x,img_y,img_z)
coord_list = list(zip(mx,my))
footprint_poly = Polygon(coord_list)
- geo_crs = {'init':'epsg:4326'}
- footprint_shp = gpd.GeoDataFrame(index=[0],geometry=[footprint_poly],crs=geo_crs)
+ geo_crs = 'EPSG:4326'
+ footprint_shp = gpd.GeoDataFrame({'img':[img_fn],'geometry':[footprint_poly]},crs=geo_crs)
if incrs:
footprint_shp = footprint_shp.to_crs(incrs)
return footprint_shp
@@ -137,7 +138,8 @@ def crop_sim_res_extent(img_list, outfol, vrt=False,rpc=False):
list containing the two warped images, first entry (left image) is the image which was of finer resolution (more nadir) initially
If the images do not intersect, two None objects are returned in the list
"""
- resample_alg = 'lanczos'
+ #resample_alg = 'lanczos'
+ resample_alg = 'cubic'
img1 = img_list[0]
img2 = img_list[1]
img1_ds = iolib.fn_getds(img1)
@@ -273,7 +275,7 @@ def video_mvs(img_folder,t,cam_fol=None,ba_prefix=None,dem=None,sampling_interva
stereo_args = [ref_image] + source_images + [ref_camera] + source_cameras
if block == 1:
spm = 2
- stereo_mode = 0
+ stereo_mode = 'asp_bm'
corr_tile_size = 1024
if texture == 'low':
rfne_kernel = [21, 21]
@@ -285,7 +287,7 @@ def video_mvs(img_folder,t,cam_fol=None,ba_prefix=None,dem=None,sampling_interva
lv = 5
else:
spm = 2
- stereo_mode = 2
+ stereo_mode = 'asp_mgm'
corr_tile_size = 6400
if texture == 'low':
rfne_kernel = [21, 21]
@@ -453,7 +455,7 @@ def prep_video_stereo_jobs(img_folder,t,threads=4,cam_fol=None,ba_prefix=None,de
if block == 1:
print("Performing block matching")
spm = 2 #Bayes EM
- stereo_mode = 0 #Block matching
+ stereo_mode = 'asp_bm' #Block matching
cost_mode = 2 #NCC
corr_tile_size = 1024
if texture == 'low':
@@ -467,7 +469,7 @@ def prep_video_stereo_jobs(img_folder,t,threads=4,cam_fol=None,ba_prefix=None,de
else:
cost_mode = 4 #Preffered MGM cost-mode
spm = 2 # Bayes EM
- stereo_mode = 2 #MGM
+ stereo_mode = 'asp_mgm' #MGM
corr_tile_size = 6400
if texture == 'low':
rfne_kernel = [21, 21]
@@ -482,7 +484,164 @@ def prep_video_stereo_jobs(img_folder,t,threads=4,cam_fol=None,ba_prefix=None,de
job_list.append(stereo_opt + stereo_args)
return job_list
-def triplet_stereo_job_list(overlap_list,t,img_list,threads=4,ba_prefix=None,cam_fol=None,dem=None,texture='high',crop_map=True,outfol=None,block=0,entry_point='pprc'):
+def prepare_stereo_jobs_wrapper(img1,img2,img_list,outfolder,t,threads=2,crop_map=False,ba_prefix=None,
+ cam_fol=None,dem=None,block=False,texture='normal',entry_point='pprc'):
+ """
+ pairwise job preparation wrapper, intended to help in parallelization
+ Parameters
+ ------------
+ img1: str
+ path to first image
+ img2: str
+ path to second image
+ img_list: str
+ master list containing path to all input images
+ outfolder: str
+ path to stereo folder
+ t: str
+ Session to use for stereo processing
+ threads: int
+ number of threads to use for 1 pairwise processing
+ ba_prefix: str
+ ba_prefix for locating the refined tsai camera models, or for locating the *.adjust files for RPC bundle adjusted cameras
+ cam_fol: str
+ Folder containing tsai camera models (None if using RPC models or using bundle adjusted tsai cameras
+ dem: str
+ Path to DEM used for mapprojection
+ texture: str
+ use option 'low' input image texture is low, 'normal' for normal textured images. This is used for determining the correlation and refinement kernel
+ crop_map: bool
+ crop images to map extent if True. Cropping to common resolution and extent should give best results in mapprojected images
+ block: int
+ Select 0 for the defualt MGM matching, 1 for block matching
+ entry_point: str
+ Select stage from which to start ASP processing (pprc,corr,rfne,fltr,tri)
+ """
+
+ IMG1 = os.path.splitext(os.path.basename(img1))[0]
+ IMG2 = os.path.splitext(os.path.basename(img2))[0]
+ out = outfolder + '/' + IMG1 + '__' + IMG2
+
+ # camera session
+ if 'rpc' in t:
+ rpc = True
+ else:
+ rpc = False
+ # https://www.geeksforgeeks.org/python-finding-strings-with-given-substring-in-list/
+ try:
+ img1 = [x for x in img_list if re.search(IMG1, x)][0]
+ img2 = [x for x in img_list if re.search(IMG2, x)][0]
+
+
+ except BaseException:
+ print("Images not found")
+ return
+
+ if 'map' in t:
+ out = out + '_map'
+ try:
+ if crop_map:
+
+ in_img1, in_img2 = crop_sim_res_extent([img1, img2], out,rpc=rpc)
+
+ else:
+ in_img1, in_img2 = [img1,img2]
+
+ except BaseException:
+ return
+
+ else:
+ in_img1 = img1
+ in_img2 = img2
+
+ out = os.path.join(out, 'run')
+ IMG1 = os.path.splitext(os.path.basename(in_img1))[0]
+ IMG2 = os.path.splitext(os.path.basename(in_img2))[0]
+ if 'map' in t:
+ IMG1 = IMG1.split('_map',15)[0]
+ IMG2 = IMG2.split('_map',15)[0]
+
+ # look for camera files
+ if 'pinhole' in t:
+ if ba_prefix:
+ cam1 = glob.glob(
+ os.path.abspath(ba_prefix) + '-' + IMG1 + '*.tsai')[0]
+ cam2 = glob.glob(
+ os.path.abspath(ba_prefix) + '-' + IMG2 + '*.tsai')[0]
+ else:
+ cam1 = glob.glob(os.path.join(os.path.abspath(cam_fol),'*'+IMG1 + '*.tsai'))[0]
+ cam2 = glob.glob(os.path.join(os.path.abspath(cam_fol),'*'+IMG2 + '*.tsai'))[0]
+ stereo_args = [in_img1, in_img2, cam1, cam2, out]
+ align = 'AffineEpipolar'
+ ba = None
+
+ # for rpc model
+ elif 'rpc' in t:
+ stereo_args = [in_img1, in_img2, out]
+ align = 'AffineEpipolar'
+ if ba_prefix:
+ ba = os.path.abspath(ba_prefix)
+ else:
+ ba = None
+
+ # add DEM if orhtorectified
+ if 'map' in t:
+ stereo_args.append(dem)
+ align = 'None'
+
+ # set stereo parameters
+ if block == 1:
+ print("Performing block matching")
+ xcorr = 2
+ spm = 2
+ stereo_mode = 'asp_bm'
+ cost_mode = 2
+ corr_tile_size = 1024
+ if texture == 'low':
+ rfne_kernel = [21, 21]
+ corr_kernel = [35, 35]
+ lv = 5
+ else:
+ rfne_kernel = [15, 15]
+ corr_kernel = [21, 21]
+ lv = 5
+
+ else:
+ xcorr = -1
+ cost_mode = 4
+ spm = 9
+ stereo_mode = 'asp_mgm'
+ corr_tile_size = 6400
+ if texture == 'low':
+ rfne_kernel = [21, 21]
+ corr_kernel = [9, 9]
+ lv = 5
+ else:
+ rfne_kernel = [15, 15]
+ corr_kernel = [7, 7]
+ lv = 5
+
+ # entry_point logic
+ if entry_point == 'pprc':
+ ep = 0
+ elif entry_point == 'corr':
+ ep = 1
+ elif entry_point == 'rfne':
+ ep = 3
+ elif entry_point == 'fltr':
+ ep = 4
+ elif entry_point == 'tri':
+ ep = 5
+
+ # Prepare stereo options
+ stereo_opt = asp_utils.get_stereo_opts(session=t,ep = ep, threads=threads,ba_prefix=ba,
+ align=align,corr_kernel=corr_kernel,lv=lv,rfne_kernel=rfne_kernel,stereo_mode=stereo_mode,
+ spm=spm,cost_mode=cost_mode,corr_tile_size=corr_tile_size,xcorr=xcorr)
+ #print(stereo_opt)
+ return stereo_opt + stereo_args
+
+
+def triplet_stereo_job_list(overlap_list,t,img_list,threads=4,ba_prefix=None,cam_fol=None,dem=None,texture='high',crop_map=True,outfol=None,block=0,entry_point='pprc',cross_track=False):
"""
Builds subprocess job list for triplet collection pairwise implementation
@@ -523,127 +682,29 @@ def triplet_stereo_job_list(overlap_list,t,img_list,threads=4,ba_prefix=None,cam
print(img_list)
l_img_list = []
r_img_list = []
- triplet_df = prep_trip_df(overlap_list)
+ triplet_df = prep_trip_df(overlap_list,cross_track=cross_track)
+ if not os.path.exists(outfol):
+ os.makedirs(outfol)
df_list = [x for _, x in triplet_df.groupby('identifier_text')]
for df in df_list:
outfolder = os.path.join(outfol, df.iloc[0]['identifier_text'])
img1_list = df.img1.values
img2_list = df.img2.values
- pbar = ProgressBar()
print("preparing stereo jobs")
- for i, process in enumerate(pbar(img1_list)):
- img1 = img1_list[i]
- img2 = img2_list[i]
- IMG1 = os.path.splitext(os.path.basename(img1))[0]
- IMG2 = os.path.splitext(os.path.basename(img2))[0]
- out = outfolder + '/' + IMG1 + '__' + IMG2
- if 'rpc' in t:
- rpc = True
- else:
- rpc = False
- # https://www.geeksforgeeks.org/python-finding-strings-with-given-substring-in-list/
- try:
- img1 = [x for x in img_list if re.search(IMG1, x)][0]
- img2 = [x for x in img_list if re.search(IMG2, x)][0]
-
- except BaseException:
- continue
- if 'map' in t:
- out = out + '_map'
- try:
- if crop_map:
- in_img1, in_img2 = crop_sim_res_extent([img1, img2], out,rpc=rpc)
- else:
- in_img1, in_img2 = [img1,img2]
- except BaseException:
- continue
- else:
- in_img1 = img1
- in_img2 = img2
- out = os.path.join(out, 'run')
- IMG1 = os.path.splitext(os.path.basename(in_img1))[0]
- IMG2 = os.path.splitext(os.path.basename(in_img2))[0]
- if 'map' in t:
- IMG1 = IMG1.split('_map',15)[0]
- IMG2 = IMG2.split('_map',15)[0]
- if 'pinhole' in t:
- if ba_prefix:
- cam1 = glob.glob(
- os.path.abspath(ba_prefix) + '-' + IMG1 + '*.tsai')[0]
- cam2 = glob.glob(
- os.path.abspath(ba_prefix) + '-' + IMG2 + '*.tsai')[0]
- else:
- cam1 = glob.glob(os.path.join(os.path.abspath(cam_fol),'*'+IMG1 + '*.tsai'))[0]
- cam2 = glob.glob(os.path.join(os.path.abspath(cam_fol),'*'+IMG2 + '*.tsai'))[0]
- stereo_args = [in_img1, in_img2, cam1, cam2, out]
- align = 'AffineEpipolar'
- ba = None
- elif 'rpc' in t:
- stereo_args = [in_img1, in_img2, out]
- align = 'AffineEpipolar'
- if ba_prefix:
- ba = os.path.abspath(ba_prefix)
- else:
- ba = None
- if 'map' in t:
- stereo_args.append(dem)
- align = 'None'
- if block == 1:
- print("Performing block matching")
- spm = 2
- stereo_mode = 0
- cost_mode = 2
- corr_tile_size = 1024
- if texture == 'low':
- rfne_kernel = [21, 21]
- corr_kernel = [35, 35]
- lv = 5
- else:
- rfne_kernel = [15, 15]
- corr_kernel = [21, 21]
- lv = 5
- else:
- cost_mode = 4
- spm = 2
- stereo_mode = 2
- corr_tile_size = 6400
- if texture == 'low':
- rfne_kernel = [21, 21]
- corr_kernel = [9, 9]
- lv = 5
- else:
- rfne_kernel = [15, 15]
- corr_kernel = [7, 7]
- lv = 5
- #write out file for dense matches logic
- # if mapprojected stereo, then need to update overlap list
- if 'map' in t:
- l_img_list.append(os.path.basename(in_img1).split('_warp.tif',15)[0]+'.tif')
- r_img_list.append(os.path.basename(in_img2).split('_warp.tif',15)[0]+'.tif')
- # entry_point logic
- if entry_point == 'pprc':
- ep = 0
- elif entry_point == 'corr':
- ep = 1
- elif entry_point == 'rfne':
- ep = 3
- elif entry_point == 'fltr':
- ep = 4
- elif entry_point == 'tri':
- ep = 5
- # Prepare stereo options
- stereo_opt = asp_utils.get_stereo_opts(session=t,ep = ep, threads=threads,ba_prefix=ba,align=align,corr_kernel=corr_kernel,lv=lv,rfne_kernel=rfne_kernel,stereo_mode=stereo_mode,spm=spm,cost_mode=cost_mode,corr_tile_size=corr_tile_size)
- job_list.append(stereo_opt + stereo_args)
- overlap_new = os.path.join(outfol,'overlap_list_as_per_dense_ba.pkl')
- df_out = pd.DataFrame({'img1':l_img_list,'img2':r_img_list})
- print("Saving modified overlap pkl as per dense match criteria at {}".format(overlap_new))
- if not os.path.exists(outfol):
- os.makedirs(outfol)
- #df.to_pickle(overlap_new)
- #return concatenated job list
- return job_list
+ num_img = len(img1_list)
+ job_list_ = p_map(prepare_stereo_jobs_wrapper,img1_list,img2_list,[img_list]*num_img,
+ [outfolder]*num_img,[t]*num_img,[threads]*num_img,[crop_map]*num_img,[ba_prefix]*num_img,
+ [cam_fol]*num_img,[dem]*num_img,[block]*num_img,[texture]*num_img,[entry_point]*num_img)
+
+ print(type(job_list_))
+ job_list.append(job_list_)
+
+
+
+ return list(itertools.chain.from_iterable(job_list))
+
-def prep_trip_df(overlap_list, true_stereo=True):
+def prep_trip_df(overlap_list, true_stereo=True,cross_track=False):
"""
Prepare dataframe from input plckle file containing overlapping images with percentages
Parameters
@@ -676,9 +737,10 @@ def prep_trip_df(overlap_list, true_stereo=True):
df['time2'] = [os.path.basename(x).split('_', 15)[1] for x in df.img2.values]
if true_stereo:
# returned df has only those pairs which form true stereo
- df = df[df['date1'] == df['date2']]
df = df[df['time1'] != df['time2']]
- df = df[df['sat1'] == df['sat2']]
+ if not cross_track:
+ df = df[df['date1'] == df['date2']]
+ df = df[df['sat1'] == df['sat2']]
# filter to overlap percentage of around 5%
df['overlap_perc'] = df['overlap_perc'] * 100
df = df[(df['overlap_perc'] > 2)]
@@ -737,30 +799,21 @@ def sort_img_list(img_list):
list of triplet stereo images
Returns
----------
- for_img_list: list
- list containing filenames for forward images
- nadir_img_list: list
- list containing filenames for nadir images
- aft_img_list: list
- list containing filenames for aft images
- for_time: str
- the single time for all forward viewing images
- nadir_time: str
- the single time for all nadir viewing images
- aft_time: str
- the single time for all aft viewing images
+ sorted_img_list: list
+ list of list containing filenames for images captured at 1 pushframe timestamp
+ time_list: list
+ list of strings containing timestamps
"""
#list of unique image acquisition time list
- time_list = sorted(list(np.unique(np.array([os.path.basename(img).split('_',15)[1] for img in img_list]))))
- for_time = time_list[0]
- nadir_time = time_list[1]
- aft_time = time_list[2]
+ time_list = sorted(list(np.unique(np.array([os.path.basename(img).split('_',15)[0]+'_'+os.path.basename(img).split('_',15)[1] for img in img_list]))))
+
#make seperate image list
#https://stackoverflow.com/questions/2152898/filtering-a-list-of-strings-based-on-contents
- for_img_list = [k for k in img_list if for_time in k]
- nadir_img_list = [k for k in img_list if nadir_time in k]
- aft_img_list = [k for k in img_list if aft_time in k]
- return (for_img_list,nadir_img_list,aft_img_list,for_time,nadir_time,aft_time)
+ sorted_img_list = []
+ for time in time_list:
+ sorted_img_list.append([k for k in img_list if time in k])
+
+ return (sorted_img_list,time_list)
def res_sort(img_list):
"""
@@ -817,3 +870,51 @@ def filter_video_dem_by_nmad(ds_list,min_count=2,max_nmad=5):
count_filt_c = np.ma.array(count_filt,mask = invalid_mask)
dem_filt = np.ma.array(dem,mask = invalid_mask)
return dem_filt,count_filt_c,nmad_filt_c
+
+
+def modernize_frame_index(frame_index_fn,return_frame_index=True,outfn=None):
+ """
+ Update frame_index to what ASP understands currently, i.e.,
+ Update name columns and geometry columns
+
+ Parameters
+ -------------
+ frame_index_fn: string
+ path to frame_index
+ outfn (Optional): string
+ path to output frame_index filename
+ """
+ from shapely import wkt
+ from shapely.geometry.polygon import orient
+
+ def _correct_geom(row):
+ return wkt.loads(row['geom'])
+ frame_index = pd.read_csv(frame_index_fn)
+ frame_index['geom'] = frame_index.apply(_correct_geom,axis=1)
+
+ # orient the Polygon geometry
+ updated_geomlist_asp_convention = [orient(test_geom,-1) for test_geom in frame_index['geom'].values]
+
+ # remove the space between POLYGON and ((#
+ # this might not be required in the new release
+ updated_geomlist_asp_convention = [f"POLYGON(({str(test_geom).split(' ((')[1]}" for test_geom in updated_geomlist_asp_convention]
+
+ # remove the repeated last coordinate
+ updated_geomlist_asp_convention = [','.join(test_geom.split(',')[:-1])+'))' for test_geom in updated_geomlist_asp_convention]
+
+ # update geometry column
+ frame_index['geom'] = updated_geomlist_asp_convention
+
+ # update name
+ frame_index['name'] = [os.path.splitext(name)[0] for name in frame_index.filename.values]
+ print(os.path.splitext(frame_index.filename.values[0])[0])
+
+ # writeout
+ if not outfn:
+ outfn = os.path.splitext(frame_index_fn)[0] + '_with_orient.csv'
+ frame_index.to_csv(outfn,index=False)
+
+ if return_frame_index:
+ return frame_index
+
+
diff --git a/skysat_stereo/skysat_stereo_workflow.py b/skysat_stereo/skysat_stereo_workflow.py
new file mode 100644
index 0000000..8adb442
--- /dev/null
+++ b/skysat_stereo/skysat_stereo_workflow.py
@@ -0,0 +1,639 @@
+#! /usr/bin/env python
+
+import os,sys,glob,re,shutil
+import numpy as np
+import geopandas as gpd
+import pandas as pd
+from pygeotools.lib import iolib,malib
+from tqdm import tqdm
+from p_tqdm import p_umap
+from skysat_stereo import skysat
+from skysat_stereo import asp_utils as asp
+from rpcm import geo
+from skysat_stereo import misc_geospatial as misc
+from shapely.geometry import Polygon
+import itertools
+from osgeo import osr
+from pyproj import Transformer
+
+
+def prepare_stereopair_list(img_folder,perc_overlap,out_fn,aoi_bbox=None,cross_track=False):
+ """
+ """
+ from p_tqdm import p_map
+ geo_crs = 'EPSG:4326'
+ # populate img list
+ try:
+ img_list = sorted(glob.glob(os.path.join(img_folder,'*.tif')))
+ print("Number of images {}".format(len(img_list)))
+ except:
+ print ("No images found in the directory. Make sure they end with a .tif extension")
+ sys.exit()
+ out_shp = os.path.splitext(out_fn)[0]+'_bound.gpkg'
+ n_proc = iolib.cpu_count()
+ shp_list = p_map(skysat.skysat_footprint,img_list,num_cpus=2*n_proc)
+ merged_shape = misc.shp_merger(shp_list)
+ bbox = merged_shape.total_bounds
+ merged_shape = misc.shp_merger(shp_list)
+ bbox = merged_shape.total_bounds
+ print (f'Bounding box lon_lat is:{bbox}')
+ print (f'Bounding box lon_lat is:{bbox}')
+ bound_poly = Polygon([[bbox[0],bbox[3]],[bbox[2],bbox[3]],[bbox[2],bbox[1]],[bbox[0],bbox[1]]])
+ bound_shp = gpd.GeoDataFrame(index=[0],geometry=[bound_poly],crs=geo_crs)
+ bound_centroid = bound_shp.centroid
+ cx = bound_centroid.x.values[0]
+ cy = bound_centroid.y.values[0]
+ pad = np.ptp([bbox[3],bbox[1]])/6.0
+ lat_1 = bbox[1]+pad
+ lat_2 = bbox[3]-pad
+ #local_ortho = '+proj=ortho +lat_0={} +lon_0={}'.format(cy,cx)
+ local_aea = "+proj=aea +lat_1={} +lat_2={} +lat_0={} +lon_0={} +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs".format(lat_1,lat_2,cy,cx)
+ print ('Local Equal Area coordinate system is : {} \n'.format(local_aea))
+ print('Saving bound shapefile at {} \n'.format(out_shp))
+ bound_shp.to_file(out_shp,driver='GPKG')
+
+ # condition to check bbox_aoi
+ if aoi_bbox is not None:
+ bbox = gpd.read_file(aoi_bbox)
+ mask = merged_shape.to_crs(bbox.crs).intersects(bbox)
+ img_list = merged_shape[mask].img.values
+
+ img_combinations = list(itertools.combinations(img_list,2))
+ n_comb = len(img_combinations)
+ perc_overlap = np.ones(n_comb,dtype=float)*perc_overlap
+ proj = local_aea
+ tv = p_map(skysat.frame_intsec, img_combinations, [proj]*n_comb, perc_overlap,num_cpus=4*n_proc)
+ # result to this contains truth value (0 or 1, overlap percentage)
+ truth_value = [tvs[0] for tvs in tv]
+ overlap = [tvs[1] for tvs in tv]
+ valid_list = list(itertools.compress(img_combinations,truth_value))
+ overlap_perc_list = list(itertools.compress(overlap,truth_value))
+ print('Number of valid combinations are {}, out of total {} input images making total combinations {}\n'.format(len(valid_list),len(img_list),n_comb))
+ with open(out_fn, 'w') as f:
+ img1_list = [x[0] for x in valid_list]
+ img2_list = [x[1] for x in valid_list]
+ for idx,i in enumerate(valid_list):
+ #f.write("%s %s\n" % i)
+ f.write(f"{os.path.abspath(img1_list[idx])} {os.path.abspath(img2_list[idx])}\n")
+ out_fn_overlap = os.path.splitext(out_fn)[0]+'_with_overlap_perc.pkl'
+ img1_list = [x[0] for x in valid_list]
+ img2_list = [x[1] for x in valid_list]
+ out_df = pd.DataFrame({'img1':img1_list,'img2':img2_list,'overlap_perc':overlap_perc_list})
+ out_df.to_pickle(out_fn_overlap)
+
+ out_fn_stereo = os.path.splitext(out_fn_overlap)[0]+'_stereo_only.pkl'
+ stereo_only_df = skysat.prep_trip_df(out_fn_overlap,cross_track=cross_track)
+ stereo_only_df.to_pickle(out_fn_stereo)
+ out_fn_stereo_ba = os.path.splitext(out_fn_overlap)[0]+'_stereo_only.txt'
+ stereo_only_df[['img1','img2']].to_csv(out_fn_stereo_ba,sep=' ',header=False,index=False)
+
+ return stereo_only_df, out_df
+
+def skysat_preprocess(img_folder,mode,sampling=None,frame_index=None,product_level='l1a',
+ sampler=5,overlap_pkl=None,dem=None,outdir=None):
+ """
+ """
+ from p_tqdm import p_map
+ if not os.path.exists(outdir):
+ try:
+ os.makedir(outdir)
+ except:
+ os.makedirs(outdir)
+ if mode == 'video':
+ frame_index = skysat.parse_frame_index(frame_index,True)
+ product_level = 'l1a'
+ num_samples = len(frame_index)
+ frames = frame_index.name.values
+ outdf = os.path.join(outdir,os.path.basename(frame_index))
+ if sampling == 'sampling_interval':
+ print("Hardcoded sampling interval results in frame exclusion at the end of the video sequence based on step size, better to chose the num_images mode and the program will equally distribute accordingly")
+ idx = np.arange(0,num_samples,sampler)
+ outdf = '{}_sampling_inteval_{}.csv'.format(os.path.splitext(outdf)[0],sampler)
+ else:
+ print("Sampling {} from {} of the input video sequence".format(sampler,num_samples))
+ idx = np.linspace(0,num_samples-1,sampler,dtype=int)
+ outdf = '{}_sampling_inteval_aprox{}.csv'.format(os.path.splitext(outdf)[0],idx[1]-idx[0])
+
+ sub_sampled_frames = frames[idx]
+ sub_df = frame_index[frame_index['name'].isin(list(sub_sampled_frames))]
+ sub_df.to_csv(outdf,sep=',',index=False)
+
+ #this is camera/gcp initialisation
+ n = len(sub_sampled_frames)
+ img_list = [glob.glob(os.path.join(img_folder,'{}*.tiff'.format(frame)))[0] for frame in sub_sampled_frames]
+ pitch = [1]*n
+ out_fn = [os.path.join(outdir,'{}_frame_idx.tsai'.format(frame)) for frame in sub_sampled_frames]
+ out_gcp = [os.path.join(outdir,'{}_frame_idx.gcp'.format(frame)) for frame in sub_sampled_frames]
+ frame_index = [frame_index]*n
+ camera = [None]*n
+ gcp_factor = 4
+
+ elif mode == 'triplet':
+ df = pd.read_pickle(overlap_pkl)
+ img_list = list(np.unique(np.array(list(df.img1.values)+list(df.img2.values))))
+ img_list = [os.path.splitext(os.path.basename(img))[0] for img in img_list]
+ cam_list = [glob.glob(os.path.join(img_folder,'{}*.tif'.format(img)))[0] for img in img_list]
+ n = len(img_list)
+ if product_level == 'l1b':
+ pitch = [0.8]*n
+ else:
+ pitch = [1.0]*n
+ out_fn = [os.path.join(outdir,'{}_rpc.tsai'.format(frame)) for frame in img_list]
+ out_gcp = [os.path.join(outdir,'{}_rpc.gcp'.format(frame)) for frame in img_list]
+ camera = cam_list
+ frame_index = [None]*n
+ img_list = cam_list
+ gcp_factor = 8
+
+ fl = [553846.153846]*n
+ cx = [1280]*n
+ cy = [540]*n
+ ht_datum = [malib.get_stats_dict(iolib.fn_getma(dem))['median']]*n # use this value for height where DEM has no-data
+ gcp_std = [1]*n
+ datum = ['WGS84']*n
+ refdem = [dem]*n
+ n_proc = 30
+ #n_proc = cpu_count()
+ print("Starting camera resection procedure")
+ cam_gen_log = p_map(asp.cam_gen,img_list,fl,cx,cy,pitch,ht_datum,gcp_std,out_fn,out_gcp,datum,refdem,camera,frame_index,num_cpus = n_proc)
+ print("writing gcp with basename removed")
+ # count expexted gcp
+ print(f"Total expected GCP {gcp_factor*n}")
+ asp.clean_gcp(out_gcp,outdir)
+ return cam_gen_log
+
+def execute_skysat_orhtorectification(images,outdir,data='triplet',dem='WGS84',tr=None,tsrs=None,del_opt=False,cam_folder=None,ba_prefix=None,
+ mode='science',session=None,overlap_list=None,frame_index_fn=None,copy_rpc=1,orthomosaic=0):
+ """
+ """
+ from p_tqdm import p_map
+ if mode == 'browse':
+ """
+ this block creates low-res orthomosaics from RPC info for browsing purpose only
+ """
+ for_img_list,nadir_img_list,aft_img_list,for_time,nadir_time,aft_time = skysat.sort_img_list(images)
+ for_out_dir = os.path.join(outdir,'for_map_browse')
+ nadir_out_dir = os.path.join(outdir,'nadir_map_browse')
+ aft_out_dir = os.path.join(outdir,'aft_map_browse')
+ for_out_list = [os.path.join(for_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in for_img_list]
+ nadir_out_list = [os.path.join(nadir_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in nadir_img_list]
+ aft_out_list = [os.path.join(aft_out_dir,os.path.splitext(os.path.basename(img))[0]+'_browse_map.tif') for img in aft_img_list]
+ for_count,nadir_count,aft_count = [len(for_img_list), len(nadir_img_list), len(aft_img_list)]
+ print("Performing orthorectification for forward images {}".format(for_time))
+ for_map_log = p_map(asp.mapproject,for_img_list,for_out_list,[session]*for_count,['WGS84']*for_count,[None]*for_count,
+ ['EPSG:4326']*for_count,[None]*for_count,[None]*for_count,[None]*for_count)
+ print("Performing orthorectification for nadir images {}".format(nadir_time))
+ nadir_map_log = p_map(asp.mapproject,nadir_img_list,nadir_out_list,[session]*nadir_count,['WGS84']*nadir_count,[None]*nadir_count,
+ ['EPSG:4326']*nadir_count,[None]*nadir_count,[None]*nadir_count,[None]*nadir_count)
+ print("Performing orthorectification for aft images {}".format(aft_time))
+ aft_map_log = p_map(asp.mapproject,aft_img_list,aft_out_list,[session]*aft_count,['WGS84']*aft_count,[None]*aft_count,
+ ['EPSG:4326']*aft_count,[None]*aft_count,[None]*aft_count,[None]*aft_count)
+ ortho_log = os.path.join(outdir,'low_res_ortho.log')
+ print("Orthorectification log saved at {}".format(ortho_log))
+ with open(ortho_log,'w') as f:
+ total_ortho_log = for_map_log+nadir_map_log+aft_map_log
+ for log in itertools.chain.from_iterable(total_ortho_log):
+ f.write(log)
+
+ # after orthorectification, now do mosaic
+ for_out_mos = os.path.join(outdir,'for_map_mos_{}m.tif'.format(tr))
+ for_map_list = sorted(glob.glob(os.path.join(for_out_dir,'*.tif')))
+ nadir_out_mos = os.path.join(outdir,'nadir_map_mos_{}m.tif'.format(tr))
+ nadir_map_list = sorted(glob.glob(os.path.join(nadir_out_dir,'*.tif')))
+ aft_out_mos = os.path.join(outdir,'aft_map_mos_{}m.tif'.format(tr))
+ aft_map_list = sorted(glob.glob(os.path.join(aft_out_dir,'*.tif')))
+ print("Preparing forward browse orthomosaic")
+ for_mos_log = asp.dem_mosaic(for_map_list,for_out_mos,tr,tsrs,stats='first',tile_size=None)
+ print("Preparing nadir browse orthomosaic")
+ nadir_mos_log = asp.dem_mosaic(nadir_map_list, nadir_out_mos, tr, tsrs,stats='first',tile_size=None)
+ print("Preparing aft browse orthomosaic")
+ aft_mos_log = asp.dem_mosaic(aft_map_list, aft_out_mos, tr, tsrs,stats='first',tile_size=None)
+ ## delete temporary files
+ if del_opt:
+ [shutil.rmtree(x) for x in [for_out_dir,nadir_out_dir,aft_out_dir]]
+ #Save figure to jpeg ?
+ fig_title = os.path.basename(images[0]).split('_',15)[0]+'_'+for_time+'_'+nadir_time+'_'+aft_time
+ fig,ax = plt.subplots(1,3,figsize=(10,10))
+ pltlib.iv_fn(for_out_mos,full=True,ax=ax[0],cmap='gray',scalebar=True,title='Forward')
+ pltlib.iv_fn(nadir_out_mos,full=True,ax=ax[1],cmap='gray',scalebar=True,title='NADIR')
+ pltlib.iv_fn(aft_out_mos,full=True,ax=ax[2],cmap='gray',scalebar=True,title='Aft')
+ plt.tight_layout(rect=[0, 0.03, 1, 0.95])
+ fig.suptitle(fig_title)
+ browse_img_fn = os.path.join(outdir,'browse_img_{}_{}m.jpg'.format(fig_title,tr))
+ fig.savefig(browse_img_fn,dpi=300,bbox_inches='tight',pad_inches=0.1)
+ print("Browse figure saved at {}".format(browse_img_fn))
+
+ if mode == 'science':
+ img_list = images
+ if overlap_list is not None:
+ # need to remove images and cameras which are not optimised during bundle adjustment
+ # read pairs from input overlap list
+ initial_count = len(img_list)
+ with open(overlap_list) as f:
+ content = f.readlines()
+ content = [x.strip() for x in content]
+ l_img = [x.split(' ')[0] for x in content]
+ r_img = [x.split(' ')[1] for x in content]
+ total_img = l_img + r_img
+ uniq_idx = np.unique(total_img, return_index=True)[1]
+ img_list = [total_img[idx] for idx in sorted(uniq_idx)]
+
+ print(f"Out of the initial {initial_count} images, {len(img_list)} will be orthorectified using adjusted cameras")
+
+
+ if frame_index_fn is not None:
+ frame_index = skysat.parse_frame_index(frame_index_fn)
+ img_list = [glob.glob(os.path.join(dir,'{}*.tiff'.format(frame)))[0] for frame in frame_index.name.values]
+ print("no of images is {}".format(len(img_list)))
+ img_prefix = [os.path.splitext(os.path.basename(img))[0] for img in img_list]
+ out_list = [os.path.join(outdir,img+'_map.tif') for img in img_prefix]
+ session_list = [session]*len(img_list)
+ dem_list = [dem]*len(img_list)
+ tr_list = [tr]*len(img_list)
+ if frame_index_fn is not None:
+ # this hack is for video
+ df = skysat.parse_frame_index(frame_index_fn)
+ trunc_df = df[df['name'].isin(img_prefix)]
+ tr_list = [str(gsd) for gsd in trunc_df.gsd.values]
+ srs_list = [tsrs]*len(img_list)
+
+ if session == 'pinhole':
+ if ba_prefix:
+ cam_list = [glob.glob(os.path.abspath(ba_prefix)+'-'+os.path.splitext(os.path.basename(x))[0]+'*.tsai')[0] for x in img_list]
+ print("No of cameras is {}".format(len(cam_list)))
+ else:
+ print(os.path.join(os.path.abspath(cam_folder),os.path.splitext(os.path.basename(img_list[0]))[0]+'*.tsai'))
+ cam_list = [glob.glob(os.path.join(os.path.abspath(cam_folder),os.path.splitext(os.path.basename(x))[0]+'*.tsai'))[0] for x in img_list]
+ else:
+ cam_list = [None]*len(img_list)
+ if ba_prefix:
+ # not yet implemented
+ ba_prefix_list = [ba_prefix]*len(img_list)
+
+ print("Mapping given images")
+ ortho_logs = p_map(asp.mapproject,img_list,out_list,session_list,dem_list,tr_list,srs_list,cam_list,
+ [None]*len(img_list),[None]*len(img_list),num_cpus=int(iolib.cpu_count()/4))
+ ortho_log = os.path.join(outdir,'ortho.log')
+ print("Saving Orthorectification log at {}".format(ortho_log))
+ with open(ortho_log,'w') as f:
+ for log in ortho_logs:
+ f.write(log)
+ if copy_rpc == 1:
+ print("Copying RPC from native image to orthoimage in parallel")
+ copy_rpc_out = p_map(skysat.copy_rpc,img_list,out_list,num_cpus=iolib.cpu_count())
+ if orthomosaic == 1:
+ print("Will also produce median, weighted average and highest resolution orthomosaic")
+ if data == 'triplet':
+ # sort images based on timestamps and resolutions
+ img_list, time_list = skysat.sort_img_list(out_list)
+ res_sorted_list = skysat.res_sort(out_list)
+
+ # define mosaic prefix containing timestamps of inputs
+ mos_prefix = '_'.join(np.unique([t.split('_')[0] for t in time_list]))+'__'+'_'.join(np.unique([t.split('_')[1] for t in time_list]))
+
+ # define output filenames
+ res_sorted_mosaic = os.path.join(outdir,'{}_finest_orthomosaic.tif'.format(mos_prefix))
+ median_mosaic = os.path.join(outdir,'{}_median_orthomosaic.tif'.format(mos_prefix))
+ wt_avg_mosaic = os.path.join(outdir,'{}_wt_avg_orthomosaic.tif'.format(mos_prefix))
+ indi_mos_list = [os.path.join(outdir,f'{time}_first_orthomosaic.tif') for time in time_list]
+
+
+ print("producing finest resolution on top mosaic, per-pixel median and wt_avg mosaic")
+ all_3_view_mos_logs = p_map(asp.dem_mosaic, [res_sorted_list]*3, [res_sorted_mosaic,median_mosaic,wt_avg_mosaic],
+ ['None']*3, [None]*3, ['first','median',None],[None]*3,num_cpus=4)
+
+ print("producing idependent mosaic for different views in parallel")
+ indi_mos_count = len(time_list)
+ if indi_mos_count>3:
+ tile_size = 400
+ else:
+ tile_size = None
+
+ indi_mos_log = p_map(asp.dem_mosaic,img_list, indi_mos_list, ['None']*indi_mos_count, [None]*indi_mos_count,
+ ['first']*indi_mos_count,[tile_size]*indi_mos_count)
+
+ # write out log files
+ out_log = os.path.join(outdir,'science_mode_ortho_mos.log')
+ total_mos_log = all_3_view_mos_logs+indi_mos_log
+ print("Saving orthomosaic log at {}".format(out_log))
+ with open(out_log,'w') as f:
+ for log in itertools.chain.from_iterable(total_mos_log):
+ f.write(log)
+ if data == 'video':
+ res_sorted_list = skysat.res_sort(out_list)
+ print("producing orthomasaic with finest on top")
+ res_sorted_mosaic = os.path.join(outdir,'video_finest_orthomosaic.tif')
+ print("producing orthomasaic with per-pixel median stats")
+ median_mosaic = os.path.join(outdir,'video_median_orthomosaic.tif')
+ print("producing orthomosaic with weighted average statistics")
+ wt_avg_mosaic = os.path.join(outdir,'video_wt_avg_orthomosaic.tif')
+ print("Mosaicing will be done in parallel")
+ all_3_view_mos_logs = p_map(asp.dem_mosaic, [res_sorted_list]*3, [res_sorted_mosaic,median_mosaic,wt_avg_mosaic], ['None']*3, [None]*3, ['first','median',None],[None]*3)
+ out_log = os.path.join(outdir,'science_mode_ortho_mos.log')
+ print("Saving orthomosaic log at {}".format(out_log))
+ with open(out_log,'w') as f:
+ for log in all_3_view_mos_logs:
+ f.write(log)
+
+def execute_skysat_stereo(img,outfol,mode,session='rpc',dem=None,texture='high',
+ sampling_interval=None,cam_folder=None,ba_prefix=None,writeout_only=False,mvs=0,block=1,crop_map=0,
+ full_extent=1,entry_point='pprc',threads=2,overlap_pkl=None,frame_index=None,job_fn=None,cross_track=False):
+ """
+ """
+ from p_tqdm import p_map
+ img = os.path.abspath(img)
+ try:
+ img_list = sorted(glob.glob(os.path.join(img, '*.tif')))
+ temp = img_list[1]
+ except BaseException:
+ img_list = sorted(glob.glob(os.path.join(img, '*.tiff')))
+ if len(img_list) == 0:
+ print("No images in the specified folder, exiting")
+ sys.exit()
+
+ if mode == 'video':
+ # assume for now that we are still operating on a fixed image interval method
+ # can accomodate different convergence angle function method here.
+ frame_gdf = skysat.parse_frame_index(frame_index)
+ # for now hardcording sgm,mgm,kernel params, should accept as inputs.
+ # Maybe discuss with David with these issues/decisions when the overall
+ # system is in place
+ if mvs == 1:
+ job_list = skysat.video_mvs(img,t=session,cam_fol=cam_folder,ba_prefix=ba_prefix,dem=dem,
+ sampling_interval=sampling_interval,texture=texture,
+ outfol=outfol,block=block,frame_index=frame_gdf)
+
+ else:
+ if full_extent == 1:
+ full_extent = True
+ else:
+ full_extent = False
+ job_list = skysat.prep_video_stereo_jobs(img,t=session,cam_fol=cam_folder,ba_prefix=ba_prefix,
+ dem=dem,sampling_interval=sampling_interval,texture=texture,outfol=outfol,block=block,
+ frame_index=frame_gdf,full_extent=full_extent,entry_point=entry_point)
+ elif mode == 'triplet':
+ if crop_map == 1:
+ crop_map = True
+ else:
+ crop_map = False
+
+ job_list = skysat.triplet_stereo_job_list(cross_track=cross_track,t=session,
+ threads = threads,overlap_list=overlap_pkl, img_list=img_list, ba_prefix=ba_prefix,
+ cam_fol=cam_folder, dem=dem, crop_map=crop_map,texture=texture, outfol=outfol, block=block,
+ entry_point=entry_point)
+ if not writeout_only:
+ # decide on number of processes
+ # if block matching, Plieades is able to handle 30-40 4 threaded jobs on bro node
+ # if MGM/SGM, 25 . This stepup is arbitrariry, research on it more.
+ # next build should accept no of jobs and stereo threads as inputs
+
+ print(job_list[0])
+ n_cpu = iolib.cpu_count()
+ # no of parallel jobs with user specified threads per job
+ #jobs = int(n_cpu/threads)
+ # this seems to break with new paralle_stereo setup
+ # setting hardcoded value of 20 for now
+ jobs = 20
+ stereo_log = p_map(asp.run_cmd,['parallel_stereo']*len(job_list), job_list, num_cpus=jobs)
+ stereo_log_fn = os.path.join(outfol,'stereo_log.log')
+ print("Consolidated stereo log saved at {}".format(stereo_log_fn))
+ else:
+ print(f"Writng jobs at {job_fn}")
+ with open(job_fn,'w') as f:
+ for idx,job in enumerate(tqdm(job_list)):
+ try:
+ job_str = 'stereo ' + ' '.join(job) + '\n'
+ f.write(job_str)
+ except:
+ continue
+
+
+def gridding_wrapper(pc_list,tr,tsrs=None):
+ from p_tqdm import p_map
+ if tsrs is None:
+ print("Projected Target CRS not provided, reading from the first point cloud")
+
+ #fetch the PC-center.txt file instead
+ # should probably make this default after more tests and confirmation with Oleg
+ pc_center = os.path.splitext(pc_list[0])[0]+'-center.txt'
+ with open(pc_center,'r') as f:
+ content = f.readlines()
+ X,Y,Z = [np.float(x) for x in content[0].split(' ')[:-1]]
+ ecef_proj = 'EPSG:4978'
+ geo_proj = 'EPSG:4326'
+ ecef2wgs = Transformer.from_crs(ecef_proj,geo_proj)
+ clat,clon,h = ecef2wgs.transform(X,Y,Z)
+ epsg_code = f'EPSG:{geo.compute_epsg(clon,clat)}'
+ print(f"Detected EPSG code from point cloud {epsg_code}")
+ tsrs = epsg_code
+ n_cpu = iolib.cpu_count()
+ point2dem_opts = asp.get_point2dem_opts(tr=tr, tsrs=tsrs,threads=1)
+ job_list = [point2dem_opts + [pc] for pc in pc_list]
+ p2dem_log = p_map(asp.run_cmd,['point2dem'] * len(job_list), job_list, num_cpus = n_cpu)
+ print(p2dem_log)
+
+
+def alignment_wrapper_single(ref_dem,source_dem,max_displacement,outprefix,
+ align='point-to-plane',trans_only=0,initial_align=None):
+ if trans_only == 0:
+ trans_only = False
+ else:
+ trans_only = True
+ asp.dem_align(ref_dem,source_dem,max_displacement,outprefix,align,
+ trans_only,threads=iolib.cpu_count(),initial_align=initial_align)
+
+def alignment_wrapper_multi(ref_dem,source_dem_list,max_displacement,align='point-to-plane',initial_align=None,
+ trans_only=0):
+ from p_tqdm import p_umap
+ outprefix_list=['{}_aligned_to{}'.format(os.path.splitext(source_dem)[0],os.path.splitext(os.path.basename(ref_dem))[0]) for source_dem in source_dem_list]
+ if trans_only == 0:
+ trans_only = False
+ else:
+ trans_only = True
+ n_source = len(source_dem_list)
+
+ initial_align = [initial_align]*n_source
+ ref_dem_list=[ref_dem] * n_source
+ max_disp_list=[max_displacement] * n_source
+ align_list=[align] * n_source
+ trans_list=[trans_only] * n_source
+ p_umap(asp.dem_align,ref_dem_list,source_dem_list,max_disp_list,outprefix_list,
+ align_list,trans_list,[1]*n_source,initial_align,num_cpus = iolib.cpu_count())
+
+def align_cameras_wrapper(input_camera_list,transform_txt,outfolder,rpc=0,dem='None',img_list=None):
+ from p_tqdm import p_umap
+ n_cam=len(input_camera_list)
+ if (rpc == 1) & (dem != 'None'):
+ print("Will also write RPC files")
+ rpc = True
+ else:
+ dem = None
+ img_list = [None] * n_cam
+ rpc = False
+ transform_list = [transform_txt]*n_cam
+ outfolder = [outfolder] * n_cam
+ write = [True] * n_cam
+ rpc = [rpc] * n_cam
+ dem = [dem] * n_cam
+
+ p_umap(asp.align_cameras,input_camera_list,transform_list,outfolder,write,rpc,dem,
+ img_list,num_cpus = iolib.cpu_count())
+
+
+def dem_mosaic_wrapper(dir,mode='triplet',out_folder=None,identifier=None,tile_size=None,filter_dem=1,min_video_count=2,max_video_nmad=5):
+ from p_tqdm import p_map
+ if out_folder is None:
+ out_folder = os.path.join(dir,'composite_dems')
+
+ if not os.path.exists(out_folder):
+ os.makedirs(out_folder)
+ if identifier is None:
+ identifier = ''
+ if mode == 'triplet':
+ dir_list = sorted(glob.glob(os.path.join(dir,'20*/')))
+ print(f"Number of combinations {len(dir_list)}")
+
+ def valid_disp(direc):
+ try:
+ D_sub = iolib.fn_getma(os.path.join(direc,'run-D_sub.tif'),3)
+ stats = np.percentile(D_sub.compressed(),(2,98))
+ direc_out = glob.glob(os.path.join(direc,'run*{}*-DEM.tif'.format(identifier)))[0]
+ out = (direc_out,True)
+ except:
+ out = (0,False)
+ return out
+
+
+ # find all valid DEMs
+ total_cpu = iolib.cpu_count()
+ n_proc = total_cpu - np.arange(len(dir_list))
+ #this setup is so that old pools are discarded and new ones with new number of workers are created
+ valid_dem_dir_list = []
+ for idx,direc in enumerate(tqdm(dir_list)):
+ comb_dir_list = sorted(glob.glob(os.path.join(direc,'*/')))
+ results = p_map(valid_disp,comb_dir_list,num_cpus=n_proc[idx])
+ t_val = [r[1] for r in results]
+ valid_dirs = list(itertools.compress([r[0] for r in results],t_val))
+ valid_dem_dir_list.append(valid_dirs)
+
+ # naming logic for pairwise and triplet/multiview composites
+ mdt1,t1,mdt2,t2 = [[],[],[],[]]
+ combination_out_list = []
+ if len(dir_list)>3:
+ print("Input is cross-track")
+ if dir_list[0][-1] == '/':
+ dir_list = [x[:-1] for x in dir_list]
+ for direc in dir_list:
+ combination_out_list.append(os.path.join(out_folder,os.path.basename(direc)+'_wt_avg_mos.tif'))
+ a,b,c,d = os.path.basename(direc).split('_')
+ mdt1.append(a) #master date (year month date)
+ t1.append(b) # time of day in seconds
+ mdt2.append(c)
+ t2.append(d)
+ if len(direc)>3:
+ composite_prefix = 'multiview_'+'_'.join(np.unique(mdt1+mdt2))+'__'+'_'.join(np.unique(t1+t2))
+ else:
+ composite_prefix = 'triplet_'+'_'.join(np.unique(mdt1+mdt2))+'__'+'_'.join(np.unique(t1+t2))
+
+ # produce bistereo pairwise mosaics
+ len_combinations = len(combination_out_list)
+
+
+ if len_combinations > 3:
+ # force tiled processing in case of multiview mosaicking
+ if not tile_size:
+ tile_size = 400
+ mos_log = p_map(asp.dem_mosaic,valid_dem_dir_list,combination_out_list,
+ ['None']*len_combinations,[None]*len_combinations,
+ [None]*len_combinations,[tile_size]*len_combinations)
+
+ if len_combinations > 2:
+ print("Producing triplet/multiview composites")
+ total_dem_list = list(itertools.chain.from_iterable(valid_dem_dir_list))
+ print(f"Mosaicing {len(total_dem_list)} DEM strips using median, wt_avg, count, nmad operators")
+ stats_list = [None,'median','nmad','count']
+ out_fn_list = [os.path.join(out_folder,
+ '{}_{}_mos.tif'.format(composite_prefix,stat)) for stat in ['wt_avg','median','nmad','count']]
+ composite_mos_log = p_map(asp.dem_mosaic,[total_dem_list]*4,out_fn_list,['None']*4,[None]*4,stats_list,
+ [tile_size]*4,num_cpus=4)
+ out_log_fn = os.path.join(out_folder,'skysat_triplet_dem_mos.log')
+ print("Saving triplet DEM mosaic log at {}".format(out_log_fn))
+ with open(out_log_fn,'w') as f:
+ for log in mos_log+composite_mos_log:
+ f.write(log)
+ if mode == 'video':
+ dir_list = sorted(glob.glob(os.path.join(dir,'1*/')))
+ valid_video_dir = []
+ for video_dir in dir_list:
+ try:
+ D_sub = iolib.fn_getma(os.path.join(video_dir,'run-D_sub.tif'),3)
+ stats = [np.percentile(D_sub.compressed(),(2,98)),np.mean(D_sub.compressed())]
+ DEM = glob.glob(os.path.join(video_dir,'run*{}*-DEM.tif'.format(identifier)))[0]
+ valid_video_dir.append(video_dir)
+ except:
+ continue
+ video_dem_list = [glob.glob(os.path.join(dir,f'run*{identifier}*-DEM.tif'))[0] for dir in valid_video_dir]
+ stats_list = ['median','count','nmad']
+ print('total dems are {}'.format(len(video_dem_list)))
+ out_fn_list = [os.path.join(out_folder,'video_{}_mos.tif'.format(stat)) for stat in stats_list]
+ dem_mos_log = p_map(asp.dem_mosaic,[video_dem_list]*3,out_fn_list,['None']*3,[None]*3,stats_list,[None]*3)
+ out_log_fn = os.path.join(out_folder,'skysat_video_dem_mos.log')
+ with open(out_log_fn,'w') as f:
+ for log in dem_mos_log:
+ f.write(log)
+ if filter_dem == 1:
+ print("Filtering DEM using NMAD and count metrics")
+ print(f"Filter will use min count of {min_video_count} and max NMAD of {max_video_nmad}")
+ mos_ds_list = warplib.memwarp_multi_fn(out_fn_list)
+ # Filtered array list contains dem_filtered,nmad_filtered, count_filtered in order
+ filtered_array_list = skysat.filter_video_dem_by_nmad(mos_ds_list,min_video_count,max_video_nmad)
+ trailing_str = f'_filt_max_nmad{max_video_nmad}_min_count{min_video_count}.tif'
+ out_filter_fn_list = [os.path.splitext(fn)[0]+trailing_str for fn in out_fn_list]
+ for idx,fn in enumerate(out_filter_fn_list):
+ iolib.writeGTiff(filtered_array_list[idx],fn,mos_ds_list[idx])
+
+
+
+
+def dense_match_wrapper(stereo_master_dir,ba_dir,modify_overlap=0,img_fol=None,orig_pickle=None,dense_match_pickle=None,stereo_dir=None,out_overlap_fn=None):
+ """
+ """
+ triplet_stereo_matches = sorted(glob.glob(os.path.join(stereo_master_dir,'20*/*/run*-*disp*.match')))
+ print('Found {} dense matches'.format(len(triplet_stereo_matches)))
+ if not os.path.isdir(ba_dir):
+ os.makedirs(ba_dir)
+ out_dense_match_list = [os.path.join(ba_dir,'run-'+os.path.basename(match).split('run-disp-',15)[1]) for match in triplet_stereo_matches]
+ for idx,match in tqdm(enumerate(triplet_stereo_matches)):
+ shutil.copy2(match, out_dense_match_list[idx])
+ print("Copied all files successfully")
+
+ if modify_overlap == 1:
+ orig_df = pd.read_pickle(orig_pickle)
+ dense_df = pd.read_pickle(dense_match_pickle)
+ dense_img1 = list(dense_df.img1.values)
+ dense_img2 = list(dense_df.img2.values)
+ prioirty_list = list(zip(dense_img1,dense_img2))
+ regular_img1 = [os.path.basename(x) for x in orig_df.img1.values]
+ regular_img2 = [os.path.basename(x) for x in orig_df.img2.values]
+ secondary_list = list(zip(regular_img1,regular_img2))
+ # adapted from https://www.geeksforgeeks.org/python-extract-unique-tuples-from-list-order-irrespective/
+ # note that I am using the more inefficient answer on purpose, because I want to use image pair order from the dense match overlap list
+ total_list = priority_list + secondary_list
+ final_overlap_set = set()
+ temp = [final_overlap_set.add((a, b)) for (a, b) in total_list
+ if (a, b) and (b, a) not in final_overlap_set]
+ new_img1 = [os.path.join(img_fol,pair[0]) for pair in list(final_overlap_set)]
+ new_img2 = [os.path.join(img_fol,pair[1]) for pair in list(final_overlap_set)]
+ if not out_overlap_fn:
+ out_overlap = os.path.join(ba_dir,'overlap_list_adapted_from_dense_matches.txt')
+ else:
+ out_overlap = os.path.join(ba_dir,out_overlap_fn)
+
+ print("Saving adjusted overlap list at {}".format(out_overlap))
+ with open(out_overlap,'w') as foo:
+ for idx,img1 in enumerate(new_img1):
+ out_str = '{} {}\n'.format(img1,new_img2[idx])
+ f.write(out_str)
+
+
+