diff --git a/Dockerfile.dev b/Dockerfile.dev index b02375a00..225424623 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,11 +1,3 @@ -# First build the jupyter-lite web artifact -FROM python:3.11 as builder -COPY jupyterlite/ /build/ -WORKDIR /build -RUN pip install --no-cache-dir --upgrade pip \ - && pip install --no-cache-dir -r requirements.txt && rm -f requirements.txt \ - && jupyter lite build --output-dir notebooks && tar -czf ./jupyter-lite-build.tgz notebooks - FROM ruby:3.2.2-bullseye LABEL maintainer="quepid_admin@opensourceconnections.com" @@ -38,8 +30,5 @@ RUN wget --no-check-certificate -qO - https://dl.yarnpkg.com/debian/pubkey.gpg | && apt-get update -qq && apt-get install -y --no-install-recommends nodejs yarn netcat \ && rm -rf /var/lib/apt/lists/* -# Jupyterlite, see bin/setup_jupyterlite on how this is woven into the /public webroot -COPY --from=builder /build/jupyter-lite-build.tgz /tmp/ - # Clean environment RUN apt-get clean all diff --git a/Dockerfile.prod b/Dockerfile.prod index 17e90d845..0de65fbc4 100644 --- a/Dockerfile.prod +++ b/Dockerfile.prod @@ -62,10 +62,12 @@ COPY ./Rakefile ./Rakefile COPY ./README.md ./README.md COPY ./vendor ./vendor COPY ./yarn.lock ./yarn.lock -COPY ./jupyterlite/notebooks.gz ./jupyterlite/notebooks.gz + +ADD https://github.com/o19s/quepid-jupyterlite/releases/latest/download/jupyter-lite-build.tgz ./notebooks.gz RUN mkdir -p tmp/pids +# Also unpacks the ./notebooks.gz file RUN RAILS_ENV=production SECRET_KEY_BASE=fake_out_devise bundle exec rake assets:precompile # Remove some files not needed in resulting image diff --git a/UPGRADE_RAILS_SIX.md b/UPGRADE_RAILS_SIX.md deleted file mode 100644 index ede619327..000000000 --- a/UPGRADE_RAILS_SIX.md +++ /dev/null @@ -1,30 +0,0 @@ -UPGRADE_RAILS_SIX - -Todo: -* DONE - Test out the SSL. We can remove the force_ssl methods. https://api.rubyonrails.org/classes/ActionDispatch/SSL.html -and https://github.com/rails/rails/pull/32277 and force_ssl if: :ssl_enabled? -* DONE - Check if the home_controller.rb needs a redirect to before_action :redirect_to_non_ssl ? - - Turns Out it does! - -* DONE - Confirm webpack actually being used. - IT'S NOT BEING USED, LETS WORRY ABOUT IT IN SEPERATE PR! -* DONE - The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding - - ["@babel/plugin-proposal-private-methods", { "loose": true }] - -to the "plugins" section of your Babel config. - -* Get `webpack-dev-server` to run in dev mode to enable the autoreload. https://dev.to/vvo/a-rails-6-setup-guide-for-2019-and-2020-hf5 - -* DONE - check out running `docker r rails app:update` https://selleo.com/blog/how-to-upgrade-to-rails-6 - -* DONE - check https://railsdiff.org/5.2.3/6.1.4 - -* check on application.html.erb -* DONE - bin/spring? -* DONE - bin/rails? - -* Check on node versions for prod and dev -* DONE - test:frontend doesn't run in Docker. -* DONE - Bump to Ruby 2.7.4 right before the merge ;-) -* check on bootstrap 3 to bootstrap 4 http://upgrade-bootstrap.bootply.com/ -* Check on bootstrap 4 versus 5 https://designmodo.com/migrate-bootstrap-5/ diff --git a/app/assets/javascripts/components/export_case/export_case_controller.js b/app/assets/javascripts/components/export_case/export_case_controller.js index ce09af38e..f72414466 100644 --- a/app/assets/javascripts/components/export_case/export_case_controller.js +++ b/app/assets/javascripts/components/export_case/export_case_controller.js @@ -81,7 +81,6 @@ angular.module('QuepidApp') // Snapshot Name Snapshot Time Case ID Query Text Doc ID Doc Position querySnapshotSvc.get(snapshotId).then(function() { - var snapshot = querySnapshotSvc.snapshots[snapshotId]; csv = caseCSVSvc.stringifySnapshot( ctrl.theCase, @@ -91,13 +90,12 @@ angular.module('QuepidApp') blob = new Blob([csv], { type: 'text/csv' }); - /*global saveAs */ saveAs(blob, caseCSVSvc.formatDownloadFileName(ctrl.theCase.caseName + '_snapshot.csv')); }, function (response) { - $log.debug('error fetching snapshot:'); - $log.debug(response); + $log.info('error fetching snapshot:'); + $log.info(response); }); } diff --git a/app/assets/javascripts/services/caseCSVSvc.js b/app/assets/javascripts/services/caseCSVSvc.js index d48fa9412..bcc539e76 100644 --- a/app/assets/javascripts/services/caseCSVSvc.js +++ b/app/assets/javascripts/services/caseCSVSvc.js @@ -314,6 +314,7 @@ infoArray.push(stringifyField(aCase.caseName)); infoArray.push(stringifyField(aCase.lastScore.case_id)); infoArray.push(stringifyField(query.queryText)); + dataString = infoArray.join(','); csvContent += dataString + EOL; } @@ -333,7 +334,6 @@ angular.forEach(fields, function (field) { infoArray.push(stringifyField(doc.doc[field])); }); - dataString = infoArray.join(','); csvContent += dataString + EOL; }); @@ -385,17 +385,16 @@ if (withHeader) { csvContent += self.snapshotHeaderToCSV(); } - angular.forEach(snapshot.docs, function (docs, queryId) { const queryIdToMatch = parseInt(queryId, 10); const matchingQuery = snapshot.queries.filter(function(query) { return query.queryId === queryIdToMatch; }); if (matchingQuery[0]) { - const matchingQueryText = matchingQuery[0].query_text; + const matchingQueryText = matchingQuery[0].queryText; if (matchingQueryText) { angular.forEach(docs, function (doc, idx) { - const infoArray = []; + let infoArray = []; infoArray.push(stringifyField(snapshotName)); infoArray.push(stringifyField(snapshotTime)); infoArray.push(stringifyField(caseNumber)); diff --git a/app/assets/javascripts/services/snapshotFactory.js b/app/assets/javascripts/services/snapshotFactory.js index b4ce5a49f..2584c5208 100644 --- a/app/assets/javascripts/services/snapshotFactory.js +++ b/app/assets/javascripts/services/snapshotFactory.js @@ -31,6 +31,8 @@ angular.forEach(self.queries, function(query) { query.queryId = query.query_id; delete query.query_id; + query.queryText = query.query_text; + delete query.query_text; }); angular.forEach(self.docs, function(docs, queryId) { diff --git a/bin/setup_jupyterlite b/bin/setup_jupyterlite index a34d4dfcf..7c23ac451 100755 --- a/bin/setup_jupyterlite +++ b/bin/setup_jupyterlite @@ -2,15 +2,12 @@ require 'pathname' # Update our Jupyterlite setup from the latest. +JUPYTER_BUILD_DOWNLOAD_URL = "https://github.com/o19s/quepid-jupyterlite/releases/latest/download/jupyter-lite-build.tgz" # path to your application root. APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) Dir.chdir APP_ROOT do - puts "\n== Copying Jupyter Lite Build ==" - # todo: this indirection is only because we copy it from this location in the Dockerfile.prod, we could just use the builder there too - system "bin/docker r cp /tmp/jupyter-lite-build.tgz /srv/app/jupyterlite/notebooks.gz" - - puts "\n== Extracting Jupyter Lite Build ==" - system "bin/docker r tar -xzf /srv/app/jupyterlite/notebooks.gz --directory /srv/app/public" + puts "\n== Downloading and extracting Jupyter Lite Build ==" + system "bin/docker r bash -c 'rm -rf /srv/app/public/notebooks && wget -qO- #{JUPYTER_BUILD_DOWNLOAD_URL} | tar -C /srv/app/public -zxf -'" end diff --git a/docs/jupyterlite.md b/docs/jupyterlite.md index ecd7d8a02..11a59a48b 100644 --- a/docs/jupyterlite.md +++ b/docs/jupyterlite.md @@ -1,3 +1,16 @@ +# Jupyterlite + +We package up Jupyterlite notebooks to work with Quepid via the https://github.com/o19s/quepid-jupyterlite repository. + +For development we have a `bin/setup_jupyterlite` script that grabs the release and dumps it locally. + +For prod, we bake the files in as part of building the image. + +On Heroku, we grab the version and deploy it. The version is specified in `app.json`. + + + +### Old Stuff https://github.com/innovationOUtside/ouseful_jupyterlite_utils From https://jupyterlite.readthedocs.io/en/latest/user-guide.html#how-can-i-read-content-from-python diff --git a/docs/operating_documentation.md b/docs/operating_documentation.md index 4f9baec57..b077dc451 100644 --- a/docs/operating_documentation.md +++ b/docs/operating_documentation.md @@ -10,7 +10,7 @@ This document explains how Quepid can be operated and configured. - [User Tracking](#user-tracking) - [Heathcheck Endpoint](#healthcheck) - [Database Management](#database-management) - +- [Jupyterlite Notebooks](#jupyterlite-notebooks) ## Running behind a load balancer > ⚠️ _Quepid will run in TLS (`https`) or plain `http` mode depending on the @@ -175,3 +175,7 @@ Want to monitor if Quepid is behaving? Just monitor `/healthcheck`, and you wil ## Database Management See the details in [](./database.md). + +## Jupuyterlite Notebooks + +See the details in [](./jupyterlite.md). diff --git a/jupyterlite/files/README.md b/jupyterlite/files/README.md deleted file mode 100644 index 3c8f2984f..000000000 --- a/jupyterlite/files/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Welcome to the Jupyterlite based notebooks - -Learn more at https://jupyterlite.readthedocs.io/en/latest/ - -* ./examples/Snapshot Compare.ipynb is an example of measuring baseline relevancy over time. diff --git a/jupyterlite/files/examples/Snapshot Compare With Charts.ipynb b/jupyterlite/files/examples/Snapshot Compare With Charts.ipynb deleted file mode 100644 index 2f9de475c..000000000 --- a/jupyterlite/files/examples/Snapshot Compare With Charts.ipynb +++ /dev/null @@ -1,121 +0,0 @@ -{ - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "python", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8" - }, - "kernelspec": { - "name": "python", - "display_name": "Python (Pyodide)", - "language": "python" - } - }, - "nbformat_minor": 4, - "nbformat": 4, - "cells": [ - { - "cell_type": "code", - "source": "from js import fetch\nfrom typing import List, Optional, Union\n\nimport json\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\n\nimport piplite\nawait piplite.install('seaborn')\nawait piplite.install('rbo')\n\nimport rbo\nimport seaborn as sns", - "metadata": { - "trusted": true - }, - "execution_count": 142, - "outputs": [] - }, - { - "cell_type": "code", - "source": "# Generic GET call to a JSON endpoint \nasync def get_json(url):\n resp = await fetch(url)\n resp_text = await resp.text()\n return json.loads(resp_text)", - "metadata": { - "trusted": true - }, - "execution_count": 143, - "outputs": [] - }, - { - "cell_type": "code", - "source": "# Basic Quepid API client methods\nasync def get_cases():\n response = await get_json('/api/cases')\n return [{'id': case['case_id'], 'name': case['case_name']} for case in response['all_cases']]\n\nasync def get_snapshots(case):\n response = await get_json(f'/api/cases/{case}/snapshots?shallow=true')\n return [{'id': snapshot['id'], 'name': snapshot['name']} for snapshot in response['snapshots']]\n\nasync def get_cases_with_snapshots():\n cases = await get_cases()\n cases_with_snapshots = [{\n 'id': case['id'],\n 'name': case['name'],\n 'snapshots': [ {\n 'id': snapshot['id'],\n 'name': snapshot['name']\n } for snapshot in (await get_snapshots(case['id'])) ]\n } for case in cases]\n return cases_with_snapshots\n\n# Printing all cases and their snapshots\nprint(\"CASES / SNAPSHOTS AVAILABLE\")\nprint(\"===========================\")\nfor case_and_snapshots in (await get_cases_with_snapshots()):\n print(f\"Case ID {case_and_snapshots['id']} (\\\"{case_and_snapshots['name']}\\\")\")\n for snapshot in case_and_snapshots['snapshots']:\n print(f\" - Snapshot ID {snapshot['id']} (\\\"{snapshot['name']}\\\")\")", - "metadata": { - "trusted": true - }, - "execution_count": 144, - "outputs": [ - { - "name": "stdout", - "text": "CASES / SNAPSHOTS AVAILABLE\n===========================\nCase ID 6 (\"test\")\n - Snapshot ID 1 (\"test1\")\n - Snapshot ID 2 (\"test2\")\n - Snapshot ID 3 (\"test3\")\n - Snapshot ID 4 (\"test4\")\n - Snapshot ID 5 (\"overview-boost\")\n - Snapshot ID 6 (\"all-equal\")\n", - "output_type": "stream" - } - ] - }, - { - "cell_type": "code", - "source": "# Load snapshot, return dict of queries and their (number of results, avg. score, [doc ids])\nasync def load_snapshot(case_id, snapshot_id):\n snapshot = await get_json(f'/api/cases/{case_id}/snapshots/{snapshot_id}')\n docs = snapshot['docs']\n queries = snapshot['queries']\n \n # scores are a list of dicts, group them by query\n scores_list = snapshot['scores']\n scores = {}\n for scores_dict in scores_list:\n scores[scores_dict['query_id']] = scores_dict\n \n return pd.DataFrame({\n \"num_results\": [scores[query['query_id']]['number_of_results'] for query in queries],\n \"score\": [scores[query['query_id']]['score'] for query in queries],\n \"docs\": [[doc['id'] for doc in docs[str(query['query_id'])] if doc['rated_only'] == False] for query in queries]\n },\n index=pd.Series(name='query', data=[query['query_text'] for query in queries])\n )\n\nawait load_snapshot(case_id=6, snapshot_id=5)", - "metadata": { - "trusted": true - }, - "execution_count": 161, - "outputs": [ - { - "execution_count": 161, - "output_type": "execute_result", - "data": { - "text/plain": " num_results score \\\nquery \nstar wars 781 0.2 \nstar trek 337 0.0 \npulp fiction 52 0.0 \nGhostbusters 3 1.0 \n\n docs \nquery \nstar wars [354287, 322506, 53487, 4942, 12180, 43839, 14... \nstar trek [9755, 10567, 121, 453755, 5683, 84203, 72190,... \npulp fiction [18451, 43317, 10349, 10910, 398, 19723, 17769... \nGhostbusters [2978, 620, 43074] ", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
num_resultsscoredocs
query
star wars7810.2[354287, 322506, 53487, 4942, 12180, 43839, 14...
star trek3370.0[9755, 10567, 121, 453755, 5683, 84203, 72190,...
pulp fiction520.0[18451, 43317, 10349, 10910, 398, 19723, 17769...
Ghostbusters31.0[2978, 620, 43074]
\n
" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "code", - "source": "def jaccard(l1, l2, max_n):\n if len(l1) == 0 and len(l2) == 0:\n return 1\n max_len = min(len(l1), len(l2), max_n)\n set1 = set(l1[:max_len])\n set2 = set(l2[:max_len])\n intersection = len(set1.intersection(set2))\n union = len(set1) + len(set2) - intersection\n return float(intersection) / union\n\nasync def load_snapshots(case_id1, snapshot_id1, case_id2, snapshot_id2):\n df_a = await load_snapshot(case_id1, snapshot_id1)\n df_b = await load_snapshot(case_id2, snapshot_id2)\n return df_a.merge(df_b, on='query')\n\nasync def compare(case_id1, snapshot_id1, case_id2, snapshot_id2):\n df = await load_snapshots(case_id1, snapshot_id1, case_id2, snapshot_id2)\n \n df['jaccard'] = df.apply(lambda row: jaccard(row['docs_x'], row['docs_y'], 10), axis=1)\n df['rbo'] = df.apply(lambda row: rbo.RankingSimilarity(row['docs_x'], row['docs_y']).rbo(), axis=1)\n df['score_delta'] = df['score_y'] - df['score_x']\n df.name = f\"Case {case_id1} snapshot {snapshot_id1} vs. case {case_id1} snapshot {snapshot_id2}\"\n return df\n\nawait compare(case_id1=6, snapshot_id1=5, case_id2=6, snapshot_id2=6)", - "metadata": { - "trusted": true - }, - "execution_count": 162, - "outputs": [ - { - "execution_count": 162, - "output_type": "execute_result", - "data": { - "text/plain": " num_results_x score_x \\\nquery \nstar wars 781 0.2 \nstar trek 337 0.0 \npulp fiction 52 0.0 \nGhostbusters 3 1.0 \n\n docs_x \\\nquery \nstar wars [354287, 322506, 53487, 4942, 12180, 43839, 14... \nstar trek [9755, 10567, 121, 453755, 5683, 84203, 72190,... \npulp fiction [18451, 43317, 10349, 10910, 398, 19723, 17769... \nGhostbusters [2978, 620, 43074] \n\n num_results_y score_y \\\nquery \nstar wars 781 0.623299 \nstar trek 337 0.617103 \npulp fiction 52 1.000000 \nGhostbusters 3 1.000000 \n\n docs_y jaccard \\\nquery \nstar wars [11, 12180, 354287, 322506, 53487, 181808, 181... 0.250000 \nstar trek [9755, 13475, 188927, 54138, 193, 200, 201, 15... 0.111111 \npulp fiction [680, 18451, 43317, 10349, 10910, 1262, 398, 1... 0.666667 \nGhostbusters [43074, 620, 2978] 1.000000 \n\n rbo score_delta \nquery \nstar wars 0.421587 0.423299 \nstar trek 0.302897 0.617103 \npulp fiction 0.642540 1.000000 \nGhostbusters 0.500000 0.000000 ", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
num_results_xscore_xdocs_xnum_results_yscore_ydocs_yjaccardrboscore_delta
query
star wars7810.2[354287, 322506, 53487, 4942, 12180, 43839, 14...7810.623299[11, 12180, 354287, 322506, 53487, 181808, 181...0.2500000.4215870.423299
star trek3370.0[9755, 10567, 121, 453755, 5683, 84203, 72190,...3370.617103[9755, 13475, 188927, 54138, 193, 200, 201, 15...0.1111110.3028970.617103
pulp fiction520.0[18451, 43317, 10349, 10910, 398, 19723, 17769...521.000000[680, 18451, 43317, 10349, 10910, 1262, 398, 1...0.6666670.6425401.000000
Ghostbusters31.0[2978, 620, 43074]31.000000[43074, 620, 2978]1.0000000.5000000.000000
\n
" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "code", - "source": "import matplotlib\nmatplotlib.rc_file_defaults()\n\ndef plot_compare(df):\n figure, axes = plt.subplots(1, 3, figsize=(10, 4))\n figure.suptitle(df.name)\n\n sns.barplot(ax=axes[0], x=df['score_delta'], y=df.index, width=0.3, color='darkgrey')\n axes[0].set(xlim=(-1, 1))\n axes[0].set_xlabel('Change in Score')\n axes[0].set_ylabel('')\n axes[0].set_facecolor((0.90, 0.90, 0.90))\n axes[0].grid(True)\n axes[0].spines['top'].set_visible(False)\n axes[0].spines['right'].set_visible(False)\n axes[0].spines['bottom'].set_visible(False)\n axes[0].spines['left'].set_visible(False)\n axes[0].set_axisbelow(True)\n axes[0].xaxis.grid(color='w', linestyle='solid')\n axes[0].yaxis.grid(color='w', linestyle='solid')\n \n sns.heatmap(df[['jaccard']], ax=axes[1], cmap='crest', annot=True, xticklabels=False, yticklabels=False)\n axes[1].set_xlabel('Jaccard Similiarity')\n axes[1].set_ylabel('')\n \n sns.heatmap(df[['rbo']], ax=axes[2], cmap='crest', annot=True, xticklabels=False, yticklabels=False)\n axes[2].set_xlabel('Rank Biased Overlap')\n axes[2].set_ylabel('')\n \n plt.show()\n \ndf = await compare(6, 5, 6, 6)\nplot_compare(df)", - "metadata": { - "trusted": true - }, - "execution_count": 164, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": "
", - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA5YAAAGbCAYAAAC/Cg+JAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAACUAElEQVR4nOzdd1gUV9sG8HtpSwfp2AC7KEVBEIjBKIq9xChRX0XsiagJlshrIqiJxI6xJhpBE3s30dhQrNgQjBW7WADBDigoO98ffszryoLAwiLu/cs115U9e2bmmdnlOM+eM2ckgiAIICIiIiIiIioljYoOgIiIiIiIiCo3JpZERERERESkFCaWREREREREpBQmlkRERERERKQUJpZERERERESkFCaWREREREREpBQmlkRERERERKQUJpZERERERESkFCaWREREREREpBQmlkREVGncunULEokEs2bNquhQiMpNy5Yt0bhx44oOg4ioRJhYEpFau379OoYNG4ZatWpBV1cXxsbG8PHxwbx58/DixYuKDq9Q+/btQ6tWrWBiYgIjIyO4ublh3bp1FR1WpXTs2DGEh4fjyZMnxaofHh4OiURSYNHV1S3fQNVMWloahg0bhmrVqkFXVxf29vYYNGhQRYdVKWVnZyM8PByxsbElWu/69evo06cPrKysoKenh7p162LixInlEyQRVXpaFR0AEVFF2bFjB3r27AmpVIr+/fujcePGyM3NxZEjRzBu3DhcuHABv/32W0WHWUBUVBQGDRqENm3aYNq0adDU1ERSUhLu3LlT0aFVSseOHcPkyZMxYMAAmJqaFnu9xYsXw9DQUHytqalZDtGppzt37sDHxwcAMHz4cFSrVg3379/HyZMnKziyyik7OxuTJ08G8KY3tDgSExPRsmVLVKtWDWPGjIG5uTmSk5PZzhBRoZhYEpFaunnzJr788kvY2dlh//79sLW1Fd8bMWIErl27hh07dlRghIrdunULI0aMwMiRIzFv3ryKDketffHFF7CwsKjoMD5Kw4YNg5aWFk6dOgVzc/OKDkftyGQy9OvXDw0aNMCBAwegp6dX0SERUSXAobBEpJZmzJiBzMxM/P7773JJZb46depg9OjR4uuoqCi0atUKVlZWkEqlcHR0xOLFiwusd/r0afj7+8PCwgJ6enpwcHDAwIED5erIZDJERkaiUaNG0NXVhbW1NYYNG4bHjx+/N+4lS5YgLy8PU6ZMAQBkZmZCEIRiH/fVq1fRo0cP2NjYQFdXF9WrV8eXX36Jp0+finUkEgmCg4OxdetWNG7cGFKpFI0aNcKuXbvktnX79m18/fXXqF+/PvT09GBubo6ePXvi1q1bcvWio6MhkUhw6NAhDBs2DObm5jA2Nkb//v0LHHNxzl++3377DbVr14ZUKkWzZs1w6tSpAnX279+PFi1awMDAAKampujatSsuXbokvh8eHo5x48YBABwcHMRhre8egyKCIODZs2clOv+dOnVCrVq1FL7n5eUFd3d38fXevXvxySefwNTUFIaGhqhfvz7++9//Fntf7zpx4gQ6dOiAKlWqwMDAAM7OznI/Tvz7778YMGCAOCzcxsYGAwcOxMOHD+W28/z5c3zzzTewt7eHVCqFlZUV2rRpgzNnzhTYX7t27WBiYgJ9fX34+vri6NGj743z8uXL+OeffzBu3DiYm5vj5cuXePXqVbGP89WrV5g8eTLq1q0LXV1dmJub45NPPsHevXvFOgMGDIChoSHu3buHbt26wdDQEJaWlhg7dizy8vLktjdr1ix4e3vD3Nwcenp6cHNzw8aNGwvsN//vZtWqVahfvz50dXXh5uaGQ4cOler8AcDFixfx2WefQV9fH9WqVcOMGTMK1Hnw4AEGDRoEa2tr6OrqwsXFBStWrBDfv3XrFiwtLQEAkydPFr/j4eHhhZ7DPXv24Pz58wgLC4Oenh6ys7MLnBcionexx5KI1NJff/2FWrVqwdvbu1j1Fy9ejEaNGqFLly7Q0tLCX3/9ha+//hoymQwjRowA8OYCr23btrC0tMSECRNgamqKW7duYfPmzXLbGjZsGKKjoxEUFIRRo0bh5s2bWLBgARISEnD06FFoa2sXGse+ffvQoEED7Ny5E+PGjcO9e/dQpUoVjBgxApMnT4aGRuG/F+bm5sLf3x85OTkYOXIkbGxscO/ePfz999948uQJTExMxLpHjhzB5s2b8fXXX8PIyAi//PILevTogeTkZLEH6dSpUzh27Bi+/PJLVK9eHbdu3cLixYvRsmVLXLx4Efr6+nL7Dw4OhqmpKcLDw5GUlITFixfj9u3biI2NhUQiKfb5A4DVq1fj+fPnGDZsGCQSCWbMmIHPP/8cN27cEM/fvn370L59e9SqVQvh4eF48eIF5s+fDx8fH5w5cwb29vb4/PPPceXKFaxZswZz584VeyDzL8SLUqtWLWRmZsLAwADdunXD7NmzYW1tXeQ6AQEB6N+/P06dOoVmzZqJ5bdv38bx48cxc+ZMAMCFCxfQqVMnODs7Y8qUKZBKpbh27VqxEjNF9u7di06dOsHW1hajR4+GjY0NLl26hL///lv8AWXv3r24ceMGgoKCYGNjIw4Fv3DhAo4fPw6JRALgzdDUjRs3Ijg4GI6Ojnj48CGOHDmCS5cuoWnTpgDeJPTt27eHm5sbwsLCoKGhIf44c/jwYXh4eBQa6759+wAA1tbWaN26Nfbv3w9NTU20adMGixcvhr29fZHHGh4ejoiICAwePBgeHh549uwZTp8+jTNnzqBNmzZivby8PPj7+8PT0xOzZs3Cvn37MHv2bNSuXRtfffWVWG/evHno0qUL+vbti9zcXKxduxY9e/bE33//jY4dO8rt++DBg1i3bh1GjRoFqVSKRYsWoV27djh58qQ4GU9xzh8APH78GO3atcPnn3+OXr16YePGjfjuu+/g5OSE9u3bAwBevHiBli1b4tq1awgODoaDgwM2bNiAAQMG4MmTJxg9ejQsLS2xePFifPXVV+jevTs+//xzAICzs/N7PwOpVAp3d3fEx8dDR0cH3bt3x6JFi2BmZlbkZ0BEakogIlIzT58+FQAIXbt2LfY62dnZBcr8/f2FWrVqia+3bNkiABBOnTpV6HYOHz4sABBWrVolV75r1y6F5e8yNjYWqlSpIkilUuGHH34QNm7cKPTp00cAIEyYMKHIdRMSEgQAwoYNG4qsB0DQ0dERrl27JpadPXtWACDMnz9fLFN0TuLi4gQAwsqVK8WyqKgoAYDg5uYm5ObmiuUzZswQAAjbtm0TBKF45+/mzZsCAMHc3Fx49OiRWL5t2zYBgPDXX3+JZa6uroKVlZXw8OFDuePQ0NAQ+vfvL5bNnDlTACDcvHmzyPOSLzIyUggODhZWrVolbNy4URg9erSgpaUl1K1bV3j69GmR6z59+lSQSqXCmDFj5MpnzJghSCQS4fbt24IgCMLcuXMFAEJ6enqxYirK69evBQcHB8HOzk54/Pix3HsymUz8f0Wf55o1awQAwqFDh8QyExMTYcSIEYXuTyaTCXXr1hX8/f0LbN/BwUFo06ZNkfGOGjVK/IzbtWsnrFu3Tpg5c6ZgaGgo1K5dW8jKyipyfRcXF6Fjx45F1gkMDBQACFOmTJErb9KkieDm5iZX9u55yc3NFRo3biy0atVKrhyAAEA4ffq0WHb79m1BV1dX6N69u1j2vvMnCILg6+tb4O8oJydHsLGxEXr06CGWRUZGCgCEP//8Uy4+Ly8vwdDQUHj27JkgCIKQnp4uABDCwsKK3G++Ll26iJ9B3759hY0bNwo//PCDoKWlJXh7e8t9rkRE+TgUlojUzrNnzwAARkZGxV7n7XuMnj59ioyMDPj6+uLGjRviMNL8iV/+/vvvQofubdiwASYmJmjTpg0yMjLExc3NDYaGhjhw4ECRcWRmZuLx48eYPHkypkyZgh49emDVqlVo164d5s2bh+fPnxe6bn6P5O7du5GdnV3kfvz8/FC7dm3xtbOzM4yNjXHjxg2F5+TVq1d4+PAh6tSpA1NTU4XD+oYOHSrXG/vVV19BS0sLO3fuBFC885cvICAAVapUEV+3aNECAMT4UlJSkJiYiAEDBsj1rjg7O6NNmzbiPktj9OjRmD9/Pvr06YMePXogMjISK1aswNWrV7Fo0aIi1zU2Nkb79u2xfv16uSG069atQ/PmzVGzZk0A/zsX27Ztg0wmK3WsAJCQkICbN2/im2++KTA5UX4vJCD/eb58+RIZGRlo3rw5AMh9nqampjhx4gTu37+vcH+JiYm4evUq+vTpg4cPH4rf8aysLLRu3RqHDh0q8pgyMzMBADY2NtixYwd69eqFsWPHYunSpbh+/TpWr15d5PGampriwoULuHr1apH1gDe9h29r0aKF3HcckD8vjx8/xtOnT9GiRQuF33EvLy+4ubmJr2vWrImuXbti9+7d4lDS952/fIaGhvjPf/4jvtbR0YGHh4dcfDt37oSNjQ169+4tlmlra2PUqFHIzMzEwYMHi9xHYfI/g2bNmuHPP/9Ejx49MGXKFEydOhXHjh1DTExMqbZLRB83JpZEpHaMjY0BoMgk7F1Hjx6Fn5+feK+epaWleL9bfmLp6+uLHj16YPLkybCwsEDXrl0RFRWFnJwccTtXr17F06dPYWVlBUtLS7klMzMTDx48KDKO/Ivcty8k81+/ePECCQkJha7r4OCAkJAQLFu2DBYWFvD398fChQvl7q/Ml5/gvK1KlSpy90S+ePECkyZNQo0aNSCVSmFhYQFLS0s8efJE4Tbr1q0r99rQ0BC2trbi/YzFOX+FxZefZObHd/v2bQBA/fr1C6zbsGFDMdEpK3369IGNjY04hLAoAQEBuHPnDuLi4gC8eaRDfHw8AgIC5Or4+Phg8ODBsLa2xpdffon169eXKsm8fv06ALz3uYiPHj3C6NGjYW1tDT09PVhaWsLBwQEA5D7PGTNm4Pz586hRowY8PDwQHh4ul+zkJ3SBgYEFvuPLli1DTk6Owu9HvvzveK9eveSGdvfs2RNaWlo4duxYkccxZcoUPHnyBPXq1YOTkxPGjRuHf//9t0A9XV3dAkOe3/2OA29+6GjevDl0dXVhZmYmDi0tznccAOrVq4fs7Gykp6cDeP/5y1e9enW5xF9RfLdv30bdunULDIFv2LCh+H5pFNbO9OnTBwDe+xkQkXpiYklEasfY2BhVq1bF+fPni1X/+vXraN26NTIyMjBnzhzs2LEDe/fuxbfffgsA4sW+RCLBxo0bERcXh+DgYNy7dw8DBw6Em5ub2AMgk8lgZWWFvXv3KlzyJ+UpTNWqVQGgwL18VlZWAPDeCYBmz56Nf//9F//973/x4sULjBo1Co0aNcLdu3fl6hX26Iy3e9lGjhyJn376Cb169cL69euxZ88e7N27F+bm5qVKgIpz/koSn6rVqFEDjx49em+9zp07Q19fH+vXrwcArF+/HhoaGujZs6dYR09PD4cOHcK+ffvQr18//PvvvwgICECbNm3KbRKVXr16YenSpRg+fDg2b96MPXv2iBM2vf159urVCzdu3MD8+fNRtWpVzJw5E40aNcI///wjV3fmzJmFfs/ffkzLuwr7jmtqasLc3Py93/FPP/0U169fx/Lly9G4cWMsW7YMTZs2xbJlywps730OHz6MLl26QFdXF4sWLcLOnTuxd+9e9OnTp9Tftfedv/fFp4rvuLLtDBGpJyaWRKSWOnXqhOvXr4u9RkX566+/kJOTg+3bt2PYsGHo0KED/Pz8Cp2Cv3nz5vjpp59w+vRprFq1ChcuXMDatWsBALVr18bDhw/h4+MDPz+/AouLi0uRseQPs7t3755cef6wuuJMOuPk5ITvv/8ehw4dwuHDh3Hv3j0sWbLkveu9a+PGjQgMDMTs2bPxxRdfoE2bNvjkk0/w5MkThfXfHZqYmZmJlJSUApOxFHX+isvOzg4AkJSUVOC9y5cvw8LCAgYGBgBQoFeoNARBkJt9sygGBgbo1KkTNmzYAJlMhnXr1qFFixbixXw+DQ0NtG7dGnPmzMHFixfx008/Yf/+/e8dLv2u/CHNRf2Q8vjxY8TExGDChAmYPHkyunfvjjZt2hQ6g62trS2+/vprbN26FTdv3oS5uTl++uknuf0ZGxsr/I77+fkVOUFVYd/x3NxcZGRkFOscm5mZISgoCGvWrMGdO3fg7Oxc5Cyohdm0aRN0dXWxe/duDBw4EO3bt4efn1+h9RUNv71y5Qr09fXl4i7q/JWEnZ0drl69WuCHnMuXL4vvAyX/jpdFO0NE6oeJJRGppfHjx8PAwACDBw9GWlpagfevX78uPoohv+fg7Z6Cp0+fIioqSm6dx48fF+hNcHV1BQBxOGevXr2Ql5eHqVOnFtjn69evC03K8uUPl/z999/FMplMhqioKJiZmcnd3/WuZ8+e4fXr13JlTk5O0NDQUDjc9H00NTULHO/8+fML7VH77bff5O6dXLx4MV6/fi3OcFmc81dctra2cHV1xYoVK+TO6fnz57Fnzx506NBBLMtPMN937vPlD2l82+LFi5Geno527doVaxsBAQG4f/8+li1bhrNnz8oNgwWgsOdT0bm4fPkykpOTi9xX06ZN4eDggMjIyALHmH++FX3HASAyMlLudV5eXoEhoFZWVqhataoYl5ubG2rXro1Zs2YV6GkGFJ+/t7Vs2RJWVlZYtWoVXr58KZZHR0cjLy9PbmZXRd59PIqhoSHq1KlT6u+4RCKR+07funULW7duVVg/Li5O7t7LO3fuYNu2bWjbti00NTWLdf5KokOHDkhNTcW6devEstevX2P+/PkwNDSEr68vAIgzNBf3O961a1dIpVJERUXJJa35vb7v+wyISD3xcSNEpJZq166N1atXIyAgAA0bNkT//v3RuHFj5Obm4tixY+KU/QDQtm1b6OjooHPnzhg2bBgyMzOxdOlSWFlZISUlRdzmihUrsGjRInTv3h21a9fG8+fPsXTpUhgbG4uJjK+vL4YNG4aIiAgkJiaibdu20NbWxtWrV7FhwwbMmzcPX3zxRaFxd+3aFa1bt0ZERAQyMjLg4uKCrVu34siRI/j1118hlUoLXXf//v0IDg5Gz549Ua9ePbx+/Rp//PEHNDU10aNHjxKfw06dOuGPP/6AiYkJHB0dERcXh3379hX6QPvc3Fy0bt0avXr1QlJSEhYtWoRPPvkEXbp0Kfb5K4mZM2eiffv28PLywqBBg8THjZiYmMj1XuUn4xMnTsSXX34JbW1tdO7cWUw432VnZ4eAgAA4OTlBV1cXR44cwdq1a+Hq6ophw4YVK7YOHTrAyMgIY8eOVXj+p0yZgkOHDqFjx46ws7PDgwcPsGjRIlSvXh2ffPKJWK9hw4bw9fVFbGxsofvS0NDA4sWL0blzZ7i6uiIoKAi2tra4fPkyLly4gN27d8PY2BiffvopZsyYgVevXqFatWrYs2cPbt68Kbet58+fo3r16vjiiy/g4uICQ0ND7Nu3D6dOncLs2bPF/S1btgzt27dHo0aNEBQUhGrVquHevXs4cOAAjI2N8ddffxUar1QqxcyZMxEYGIhPP/0U/fr1Q3JyMubNm4cWLVqIj8sojKOjI1q2bAk3NzeYmZnh9OnT4uM9Sqpjx46YM2cO2rVrhz59+uDBgwdYuHAh6tSpo/C+zcaNG8Pf31/ucSPAm+dHFvf8lcTQoUPx66+/YsCAAYiPj4e9vT02btyIo0ePIjIyUpygTE9PD46Ojli3bh3q1asHMzMzNG7cuND7bm1sbDBx4kRMmjQJ7dq1Q7du3XD27FksXboUvXv3lntUDhGRqGImoyUi+jBcuXJFGDJkiGBvby/o6OgIRkZGgo+PjzB//nzh5cuXYr3t27cLzs7Ogq6urmBvby9Mnz5dWL58udxjKs6cOSP07t1bqFmzpiCVSgUrKyuhU6dOco8fyPfbb78Jbm5ugp6enmBkZCQ4OTkJ48ePF+7fv//emJ8/fy6MHj1asLGxEXR0dAQnJye5xw0U5saNG8LAgQOF2rVrC7q6uoKZmZnw2WefCfv27ZOrB0Dh4xDs7OyEwMBA8fXjx4+FoKAgwcLCQjA0NBT8/f2Fy5cvF6iX/7iRgwcPCkOHDhWqVKkiGBoaCn379pV7FEhxzl/+40ZmzpxZID4oeJzCvn37BB8fH0FPT08wNjYWOnfuLFy8eLHAulOnThWqVasmaGhovPfRI4MHDxYcHR0FIyMjQVtbW6hTp47w3XffiY92KK6+ffsKAAQ/P78C78XExAhdu3YVqlatKujo6AhVq1YVevfuLVy5cqXAMfv6+hZrf0eOHBHatGkjGBkZCQYGBoKzs7Pc42Pu3r0rdO/eXTA1NRVMTEyEnj17Cvfv35c7rzk5OcK4ceMEFxcXcTsuLi7CokWLCuwvISFB+PzzzwVzc3NBKpUKdnZ2Qq9evYSYmJhixbtmzRrBxcVFkEqlgrW1tRAcHFysc/zjjz8KHh4egqmpqaCnpyc0aNBA+Omnn+QedRMYGCgYGBgUWDcsLEx499Lo999/F+rWrStIpVKhQYMGQlRUlMJ6+X83f/75p1i/SZMmwoEDB8Q6xT1/vr6+QqNGjQrEFxgYKNjZ2cmVpaWliX+H+e1BVFRUgXWPHTsmuLm5CTo6OsV69IhMJhPmz58v1KtXT9DW1hZq1KghfP/993LnkYjobRJBqMCZDoiI6KMXHR2NoKAgnDp1Cu7u7hUdDlG5kEgkGDFiBBYsWFDRoRARVQjeY0lERERERERKYWJJRERERERESmFiSURERERERErhPZZERERERESkFPZYEhERERERkVKYWBIREREREZFSmFgSERERERGRUphYEhERERERkVKYWBIREREREZFSmFgSERERERGRUphYEhERERERkVKYWBIREREREZFSmFgSERERERGRUphYEhERERERkVKYWBIREREREZFSmFgSERERERGRUphYEhERERERkVKYWBIREREREZFSmFgSERERERGRUphYEhERERERkVKYWBIREREREZFSmFgSERERqcihQ4fQuXNnVK1aFRKJBFu3bn3vOrGxsWjatCmkUinq1KmD6Ojoco+TiKikmFgSERERqUhWVhZcXFywcOHCYtW/efMmOnbsiM8++wyJiYn45ptvMHjwYOzevbucIyUiKhmJIAhCRQdBREREpG4kEgm2bNmCbt26FVrnu+++w44dO3D+/Hmx7Msvv8STJ0+wa9cuFURJRFQ87LEkIiIiUkJOTg6ePXsmt+Tk5JTJtuPi4uDn5ydX5u/vj7i4uDLZPhFRWdGq6ABIeampqfhYO54lEglsbGx4jJWcOh1jZRS6+5eKDoGozEX4jyp2XaemY5TaV48uRpg8ebJcWVhYGMLDw5XaLvDm33hra2u5Mmtrazx79gwvXryAnp6e0vtQVpff51V0CERlbvug0SWqr0w7cu7M7FKv+yFhYklERESkhNDQUISEhMiVSaXSCoqGiKhiMLEkIiIi9SZRbnWpVFpuiaSNjQ3S0tLkytLS0mBsbPxB9FYS0f9Tsh35GDCxJCIiIvUm+XCvCL28vLBz5065sr1798LLy6uCIiIihT7g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" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "code", - "source": "", - "metadata": {}, - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/jupyterlite/files/examples/Snapshot Compare.ipynb b/jupyterlite/files/examples/Snapshot Compare.ipynb deleted file mode 100644 index 8746b8336..000000000 --- a/jupyterlite/files/examples/Snapshot Compare.ipynb +++ /dev/null @@ -1,142 +0,0 @@ -{ - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "python", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8" - }, - "kernelspec": { - "name": "python", - "display_name": "Python (Pyodide)", - "language": "python" - } - }, - "nbformat_minor": 4, - "nbformat": 4, - "cells": [ - { - "cell_type": "markdown", - "source": "# Compare Snapshots \nTo understand the impact of changes, you can compare multiple snapshots together. The final visulaization shows you a histogram of your snapshots overlaid with each other.\nThis visualization assumes you are using the same scorer and query set for all the snapshots. It also assumes the snapshots come from the same case!\n\nPlease copy this example and customize it for your own purposes!", - "metadata": {} - }, - { - "cell_type": "markdown", - "source": "### Imports", - "metadata": {} - }, - { - "cell_type": "code", - "source": "%matplotlib inline", - "metadata": { - "trusted": true - }, - "execution_count": 1, - "outputs": [] - }, - { - "cell_type": "code", - "source": "from js import fetch\nimport pandas as pd\nfrom datetime import datetime\nimport random\nfrom matplotlib import pyplot", - "metadata": { - "trusted": true - }, - "execution_count": 2, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": "## Define the Data You Want", - "metadata": {} - }, - { - "cell_type": "code", - "source": "CASE_ID = 6 # Your Case\nSNAPSHOT_IDS = [1,2] # Your Snapshots. Use the Compare Snapshot function in Quepid to see what the specific ID's are of your snapshots.", - "metadata": { - "trusted": true - }, - "execution_count": 3, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": "### Pull data directly from Quepid's snapshot repository", - "metadata": {} - }, - { - "cell_type": "code", - "source": "\n# Retrieve from Quepid API all the snapshots\nsnapshots = []\nfor snapshot_id in SNAPSHOT_IDS:\n res = await fetch(f'/api/cases/{CASE_ID}/snapshots/{snapshot_id}.json')\n snapshots.append(await res.json())", - "metadata": { - "trusted": true - }, - "execution_count": 4, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": "### Read in data to a dataframe", - "metadata": {} - }, - { - "cell_type": "code", - "source": "queryData = []\nsnapshotNames = {}\n# faking the data (for now)\nfor snapshot in snapshots:\n queryToScoreDict = {}\n queryToNumFoundDict = {}\n snapshotNames[snapshot.id] = snapshot.name\n for snapshotScore in snapshot.scores:\n queryToScoreDict[snapshotScore.query_id] = snapshotScore.score\n queryToNumFoundDict[snapshotScore.query_id] = snapshotScore.number_of_results\n for snapshotQuery in snapshot.queries:\n queryData.append({'snapshot_id':snapshot.id, 'query':snapshotQuery.query_text, 'numfound':queryToNumFoundDict[snapshotQuery.query_id], 'score':queryToScoreDict[snapshotQuery.query_id]})\n \ndf = pd.DataFrame(queryData)\ndf", - "metadata": { - "trusted": true - }, - "execution_count": 5, - "outputs": [ - { - "execution_count": 5, - "output_type": "execute_result", - "data": { - "text/plain": " snapshot_id query numfound score\n0 1 star wars 267 1.000000\n1 1 movie about a boxer who climbs 7970 0.737585\n2 1 star trek 253 1.000000\n3 2 star wars 267 0.587157\n4 2 movie about a boxer who climbs 7970 0.737585\n5 2 star trek 253 0.642821", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
snapshot_idquerynumfoundscore
01star wars2671.000000
11movie about a boxer who climbs79700.737585
21star trek2531.000000
32star wars2670.587157
42movie about a boxer who climbs79700.737585
52star trek2530.642821
\n
" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "markdown", - "source": "## Create a histogram to compare snapshots\n\nThe snapshots that are represented in fill color.", - "metadata": {} - }, - { - "cell_type": "code", - "source": "for snapshot_id in SNAPSHOT_IDS:\n pyplot.hist(df.loc[df['snapshot_id'] == snapshot_id]['score'], 20, alpha=0.5, label=f'{snapshotNames[snapshot_id]} ({snapshot_id})')\npyplot.legend(loc='upper right')\npyplot.show()", - "metadata": { - "trusted": true - }, - "execution_count": 6, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": "", - "image/png": "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AIYhAAIAABiGAAgAAGAYlwmACxcuVOfOneXp6anIyEjt2rWryr7r16/XsGHDFBAQIB8fH0VFRemjjz5y6pOWliabzea0eXp6NvRhAAAANDmXCICrV69WYmKiZs6cqT179igsLEwxMTE6ffr0Dftv375dw4YN06ZNm7R7924NHTpUsbGxys3Ndern4+OjoqIix3b8+PHGOBwAAIAm1bKpC6iJefPmaeLEiRo/frwkafHixdq4caNSU1P1zDPPXNd/wYIFTq9feuklbdiwQR988IEiIiIc7TabTUFBQQ1aOwAAQHPT7FcAL126pN27dys6OtrR5ubmpujoaGVnZ9dojsrKSp07d07+/v5O7WVlZerUqZNCQkI0atQo7d+/v9p5ysvLZbfbnTYAAABX0+wD4DfffKOKigoFBgY6tQcGBqq4uLhGc8yZM0dlZWUaPXq0oy00NFSpqanasGGD3nnnHVVWVmrQoEE6ceJElfMkJyfL19fXsYWEhNTtoAAAAJpQsw+AP9TKlSv1wgsvaM2aNWrXrp2jPSoqSmPHjlV4eLgGDx6s9evXKyAgQEuWLKlyrqSkJJWWljq2wsLCxjgEAACAetXs7wFs27atWrRooZKSEqf2kpKSm96/l56eroSEBK1du9bpEvKNtGrVShERETpy5EiVfTw8POTh4VHz4gEAAJqhZr8C6O7urn79+ikrK8vRVllZqaysLEVFRVU5btWqVRo/frxWrVqlkSNH3vR9KioqtHfvXgUHB9dL3QAAAM1Vs18BlKTExETFx8erf//+GjBggBYsWKDz5887PhWclJSkkydPasWKFZKuXvaNj49XSkqKIiMjHfcKenl5ydfXV5L04osvauDAgerWrZvOnj2rV155RcePH1dCQkLTHCQAAEAjcYkAOGbMGH399deaMWOGiouLFR4eri1btjg+GFJUVKSCggJH/6VLl+rKlSuaNGmSJk2a5GiPj49XWlqaJOnMmTOaOHGiiouLddttt6lfv37auXOnevbs2ajHBgAA0NhcIgBK0uTJkzV58uQb7rsW6q7ZunXrTeebP3++5s+fXw+VAQAAuJZmfw8gAAAA6hcBEAAAwDAEQAAAAMMQAAEAAAxDAAQAADAMARAAAMAwBEAAAADDEAABAAAMQwAEAAAwDAEQAADAMARAAAAAwxAAAQAADEMABAAAMAwBEAAA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" - }, - "metadata": {} - }, - { - "output_type": "display_data", - "data": { - "text/plain": "
" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "code", - "source": "", - "metadata": {}, - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/jupyterlite/files/examples/Snapshot Jaccard.ipynb b/jupyterlite/files/examples/Snapshot Jaccard.ipynb deleted file mode 100644 index c4edd43eb..000000000 --- a/jupyterlite/files/examples/Snapshot Jaccard.ipynb +++ /dev/null @@ -1,199 +0,0 @@ -{ - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "python", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8" - }, - "kernelspec": { - "name": "python", - "display_name": "Python (Pyodide)", - "language": "python" - } - }, - "nbformat_minor": 4, - "nbformat": 4, - "cells": [ - { - "cell_type": "markdown", - "source": "# Snapshot Jaccard Similarity\n\nTo understand the impact of changes, you can compare the Jaccard Similarity of snapshots.\n\nPlease copy this example and customize it for your own purposes!", - "metadata": {} - }, - { - "cell_type": "markdown", - "source": "### Imports", - "metadata": {} - }, - { - "cell_type": "code", - "source": "import pandas as pd\nimport io\nfrom js import fetch", - "metadata": { - "trusted": true - }, - "execution_count": 1, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": "## Define the Data You Want", - "metadata": {} - }, - { - "cell_type": "code", - "source": "CASE_ID = 6 # Your Case\nSNAPSHOT_IDS = [1,2] # Your Snapshots. Use the Compare Snapshot function in Quepid to see what the specific ID's are of your snapshots.", - "metadata": { - "trusted": true - }, - "execution_count": 2, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": "### Jaccard Subroutines", - "metadata": {} - }, - { - "cell_type": "code", - "source": "## Calculation of Jaccard Similarity of List 1 and 2\n\ndef jaccard_similarity(list1, list2):\n print(list1, list2)\n if list1 == list2: \n print('the lists are same')\n return float(1.0)\n intersection = len(list(set(list1).intersection(list2)))\n union = (len(set(list1)) + len(set(list2))) - intersection\n return float(intersection) / union", - "metadata": { - "trusted": true - }, - "execution_count": 3, - "outputs": [] - }, - { - "cell_type": "code", - "source": "## Construction of a comparable list from Snapshot blob\n\ndef construct_comparable_list_from_snapshot_blob(snapshot):\n for data in snapshot:\n record = data.split(\"\\n\")\n #print(record)\n df = pd.DataFrame(record)\n df[['query','docid','rating']] = df[0].str.split(',',expand=True)\n ratings_df= df[['query','docid','rating']]\n \n # Drop first row as its just column names\n ratings_mod_df = ratings_df.drop(index=ratings_df.index[0])\n \n # Remove '?' if using ispy else the next step can be ignored\n ratings_mod_df['docid'] = ratings_mod_df['docid'].str.split('?').str.get(0)\n #print(ratings_mod_df.head(10))\n \n return ratings_mod_df", - "metadata": { - "trusted": true - }, - "execution_count": 4, - "outputs": [] - }, - { - "cell_type": "code", - "source": "## Subroutine for calculating Jaccard Similarity between 2 Snapshots\n\ndef jaccard_similarity(A, B):\n # Compute Jaccard Similarity\n nominator = set(A).intersection(set(B))\n denominator = set(A).union(set(B))\n Jacc_similarity = len(nominator)/len(denominator)\n #print(Jacc_similarity) \n return (Jacc_similarity) ", - "metadata": { - "trusted": true - }, - "execution_count": 5, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": "### Pull data directly from Quepid's snapshot repository to calculate Jaccard Similarity", - "metadata": {} - }, - { - "cell_type": "code", - "source": "# Retrieve from Quepid API from Case id - 6 and Snapshot id - 1\nrating_snapshot_1 = []\nres = await fetch(f'/api/export/ratings/{CASE_ID}.csv?file_format=basic_snapshot&snapshot_id={SNAPSHOT_IDS[0]}')\nrating_snapshot_1.append(await res.text())\n#print(rating_snapshot_1)\n\n# Retrieve from Quepid API from Case id - 6 and Snapshot id - 2\nrating_snapshot_2 = []\nres = await fetch(f'/api/export/ratings/{CASE_ID}.csv?file_format=basic_snapshot&snapshot_id={SNAPSHOT_IDS[1]}')\nrating_snapshot_2.append(await res.text())\n#print(rating_snapshot_2)", - "metadata": { - "tags": [], - "trusted": true - }, - "execution_count": 6, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": "### Read and transform data in a dataframe", - "metadata": {} - }, - { - "cell_type": "code", - "source": "df1 = construct_comparable_list_from_snapshot_blob(rating_snapshot_1)\ndf2 = construct_comparable_list_from_snapshot_blob(rating_snapshot_2)\ndf1 = df1.groupby('query')['docid'].apply(list).reset_index(name=\"results\")\ndf2 = df2.groupby('query')['docid'].apply(list).reset_index(name=\"results\")\n\ndf_jaccard = df1[['query']].copy()\ndf_jaccard['baseline_results'] = df1['results']\ndf_jaccard['comparison_results'] = df2['results']\ndf_jaccard['baseline_count'] = df_jaccard.apply(lambda row: len(row.baseline_results), axis = 1)\ndf_jaccard['comparison_count'] = df_jaccard.apply(lambda row: len(row.comparison_results), axis = 1)", - "metadata": { - "tags": [], - "trusted": true - }, - "execution_count": 7, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": "### Add column with jaccard similarity", - "metadata": {} - }, - { - "cell_type": "code", - "source": "df_jaccard['jaccard_similarity'] = df_jaccard.apply(lambda row:jaccard_similarity(row.baseline_results, row.comparison_results), axis = 1)", - "metadata": { - "trusted": true - }, - "execution_count": 8, - "outputs": [] - }, - { - "cell_type": "code", - "source": "df_jaccard.head(10)", - "metadata": { - "trusted": true - }, - "execution_count": 9, - "outputs": [ - { - "execution_count": 9, - "output_type": "execute_result", - "data": { - "text/plain": " query \\\n0 \n1 movie about a boxer who climbs \n2 star trek \n3 star wars \n\n baseline_results \\\n0 [None] \n1 [45317, 826, 46838, 683716, 769, 570731, 680, ... \n2 [193, 199, 188927, 200, 13475, 152, 201, 154, ... \n3 [11, 12180, 181808, 330459, 348350, 140607, 18... \n\n comparison_results baseline_count \\\n0 [None] 1 \n1 [45317, 826, 46838, 683716, 769, 570731, 680, ... 10 \n2 [13363, 193, 199, 154, 152, 174, 157, 168, 188... 10 \n3 [12180, 322506, 85, 1895, 18046, 11, 330459, 1... 10 \n\n comparison_count jaccard_similarity \n0 1 1.000000 \n1 10 1.000000 \n2 10 0.666667 \n3 10 0.538462 ", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
querybaseline_resultscomparison_resultsbaseline_countcomparison_countjaccard_similarity
0[None][None]111.000000
1movie about a boxer who climbs[45317, 826, 46838, 683716, 769, 570731, 680, ...[45317, 826, 46838, 683716, 769, 570731, 680, ...10101.000000
2star trek[193, 199, 188927, 200, 13475, 152, 201, 154, ...[13363, 193, 199, 154, 152, 174, 157, 168, 188...10100.666667
3star wars[11, 12180, 181808, 330459, 348350, 140607, 18...[12180, 322506, 85, 1895, 18046, 11, 330459, 1...10100.538462
\n
" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "markdown", - "source": "### Export data as CSV for reporting and sharing purpose", - "metadata": {} - }, - { - "cell_type": "code", - "source": "df_jaccard.to_csv('jaccard_similarity_results.csv', encoding='utf-8', index=False)", - "metadata": { - "trusted": true - }, - "execution_count": 10, - "outputs": [] - }, - { - "cell_type": "code", - "source": "df_jaccard['jaccard_similarity'].mean()", - "metadata": { - "trusted": true - }, - "execution_count": 11, - "outputs": [ - { - "execution_count": 11, - "output_type": "execute_result", - "data": { - "text/plain": "0.8012820512820512" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "code", - "source": "", - "metadata": {}, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": "", - "metadata": {}, - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/jupyterlite/files/examples/jaccard_similarity_results.csv b/jupyterlite/files/examples/jaccard_similarity_results.csv deleted file mode 100644 index 43b956ee0..000000000 --- a/jupyterlite/files/examples/jaccard_similarity_results.csv +++ /dev/null @@ -1,67 +0,0 @@ -query,baseline_results,comparison_results,baseline_count,comparison_count,jaccard_similarity -,[None],[None],1,1,1.0 -300,"['17927', '1271', '11064', '10439', '2179', '9889', '10153', '53182', '308266', '335788']","['17927', '1271', '11064', '10439', '2179', '9889', '10153', '53182', '308266', '335788']",10,10,1.0 -300 rise of an empire,"['53182', '98', '1891', '554152', '522627', '11', '11064', '914', '10439', '347026']",['53182'],10,1,0.1 -a lego movie,"['137106', '324849', '280217', '251471', '274862', '504997', '244007', '24128', '284', '393629']","['137106', '324849', '280217', '251471', '274862', '504997', '244007', '24128', '284', '393629']",10,10,1.0 -annie,"['1700', '1162', '25209', '627', '703', '103', '688', '248', '862', '492188']","['1700', '1162', '25209', '627', '703', '103', '688', '248', '862', '492188']",10,10,1.0 -battlestar galactica,['148980'],['148980'],1,1,1.0 -black swan,"['44214', '128578', '5693', '84332', '411019', '117', '27322', '22586', '483', '33364']","['44214', '128578', '5693', '84332', '411019', '117', '27322', '22586', '483', '33364']",10,10,1.0 -christmas vacation,"['5825', '80278', '771', '9479', '41521', '10437', '11153', '15250', '632', '400155']","['5825', '80278', '771', '9479', '41521', '10437', '11153', '15250', '632', '400155']",10,10,1.0 -cocoon,"['15389', '11285']","['15389', '11285']",2,2,1.0 -contact,"['14278', '679', '73', '82702', '199', '137113', '68730', '686', '35691', '174772']","['14278', '679', '73', '82702', '199', '137113', '68730', '686', '35691', '174772']",10,10,1.0 -crocodile dundee,"['9671', '9290', '29715', '16305', '10539', '177699', '13022', '8974', '30062', '9825']","['9671', '9290', '29715', '16305', '10539', '177699', '13022', '8974', '30062', '9825']",10,10,1.0 -crocodile dundee 2,"['9671', '9290', '29715', '16305', '39862', '10539', '414419', '177699', '142061', '41662']","['9671', '9290', '39862']",10,3,0.3 -crocodile dundee ii,"['9671', '9290', '29715', '16305', '315839', '11046', '11324', '515001', '10539', '240']","['9671', '9290']",10,2,0.2 -crouching tiger hidden dragon,"['263341', '166428', '10191', '82702', '10674', '252', '87827', '13938', '9461', '22752']",['263341'],10,1,0.1 -dark knight,"['155', '49026', '142061', '123025', '14919', '13851', '183011', '471474', '268', '539']","['142061', '123025', '14919', '13851', '49026', '183011', '471474', '155', '268', '539']",10,10,1.0 -die hard,"['562', '1572', '1573', '1571', '47964', '13063', '4836', '398818', '176', '157336']","['1572', '13063', '1573', '562', '4836', '398818', '1571', '176', '157336', '137113', '1572', '13063', '1573', '562', '4836', '398818', '1571', '176', '157336', '137113']",10,20,0.8181818181818182 -emma,"['673', '375262', '914', '378107', '12445', '12104', '246741', '406997', '122', '14160']","['673', '375262', '914', '378107', '12445', '12104', '246741', '406997', '122', '14160']",10,10,1.0 -fight club,"['550', '440777', '14840', '2108', '13973', '315839', '152532', '79120', '10784', '26555']","['14840', '550', '2108', '13973', '315839', '152532', '79120', '10784', '26555', '19931']",10,10,0.8181818181818182 -forest gump,"['13', '6844', '363683', '764', '1523', '792', '3170', '22067', '132363', '8358']","['13', '6844', '363683', '764', '1523', '792', '3170', '22067', '132363', '8358']",10,10,1.0 -forrest gump,"['13', '6844', '28', '11036', '1939', '592', '923', '16323', '314365', '38765']","['13', '6844', '28', '11036', '1939', '592', '923', '16323', '314365', '38765']",10,10,1.0 -french connection,"['1051', '975', '527641', '530915', '76', '382127', '19067', '2062', '58227', '11773']","['1051', '975', '527641', '530915', '76', '382127', '19067', '2062', '58227', '11773']",10,10,1.0 -grand budapest,"['120467', '33680', '209185', '342473', '11', '562', '942', '20379', '420817', '31527']","['120467', '33680', '209185', '342473', '11', '562', '942', '20379', '420817', '31527']",10,10,1.0 -her,"['564766', '487283', '244007', '14840', '19542', '470044', '705', '278', '50014', '38']","['564766', '487283', '244007', '14840', '19542', '470044', '705', '278', '50014', '38']",10,10,1.0 -how to train dragon,"['82702', '166428', '10191', '845', '3482', '10674', '11893', '9461', '22752', '13938']","['82702', '166428', '10191', '845', '49444', '6623', '184315']",10,7,0.3076923076923077 -how to train your dragon,"['82702', '10191', '166428', '845', '76', '11558', '16999', '3482', '6687', '22798']","['82702', '166428', '10191']",10,3,0.3 -how to train your dragon 2,"['82702', '166428', '10191', '845', '76', '11558', '49444', '16999', '70006', '3482']","['82702', '166428', '10191', '49444']",10,4,0.4 -indiana jones,"['89', '87', '85', '217', '5693', '13008', '13259', '455980', '278', '1891']","['85', '87', '89', '5693', '13008', '13259', '455980', '278', '1891', '426']",10,10,0.8181818181818182 -jobs,"['1779', '321697', '17483', '323272', '50014', '115782', '296096', '44639', '346648', '5719']","['1779', '321697', '17483', '323272', '50014', '115782', '296096', '44639', '346648', '5719']",10,10,1.0 -kill bill,"['393', '414419', '24', '324786', '10774', '967', '218', '595', '497', '996']","['414419', '393', '24', '324786', '10774', '967', '218', '595', '497', '996', '414419', '393', '24', '46691', '8141', '315']",10,16,0.7692307692307693 -kill bill 2,"['414419', '393', '24', '324786', '260513', '10774', '967', '625', '218', '595']","['414419', '393', '24', '324786', '260513', '10774', '967', '625', '218', '595']",10,10,1.0 -kung fury,"['49444', '228150', '9502', '166428', '376290', '38077', '247', '9509', '464502', '38575']","['49444', '228150', '9502', '166428', '376290', '38077', '247', '9509', '464502', '38575']",10,10,1.0 -last temptation of christ,"['11051', '23830', '615', '527641', '30973', '782', '665', '116', '14503', '12568']","['11051', '615', '14503', '2428', '11051', '23830', '615', '527641', '30973', '782', '665', '116', '14503', '12568']",10,14,0.9090909090909091 -lego batman,"['324849', '137106', '142061', '251471', '14919', '123025', '504997', '45162', '280217', '364']","['324849', '137106', '142061', '251471', '14919', '123025', '504997', '45162', '280217', '364']",10,10,1.0 -life aquatic,"['421', '487283', '297556', '570731', '14002', '238', '278', '13', '14160', '339877']","['421', '487283', '297556', '570731', '14002', '238', '278', '13', '14160', '339877']",10,10,1.0 -life is beautiful,"['14002', '83860', '152742', '453', '27322', '34308', '501907', '50646', '11362', '570731']","['14002', '83860', '152742', '453', '27322', '34308', '501907', '50646', '11362', '570731']",10,10,1.0 -mad max fury road,"['76341', '8810', '9355', '9659', '244786', '228150', '4148', '412202', '11576', '166428']",['76341'],10,1,0.1 -martian,"['9849', '286217', '14011', '34086', '3166', '32307']","['9849', '286217', '14011', '34086', '3166', '32307']",6,6,1.0 -matrix,"['603', '10999', '55931', '604', '1857', '605', '4247']","['603', '10999', '55931', '604', '1857', '605', '4247']",7,7,1.0 -message in bottle,"['10207', '530915', '8393', '359940', '931', '1090', '43896', '9374', '13685', '13996']","['10207', '359940', '931', '1090', '43896', '9374', '13996', '301355', '71373', '10047']",10,10,0.5384615384615384 -mr smith goes to washington,"['3083', '500', '787', '1883', '49471', '522212', '10315', '16391', '73575', '27322']","['3083', '787']",10,2,0.2 -murray saves christmas,"['9647', '5825', '10149', '175555', '26386', '424', '9479', '14840', '10437', '15250']","['9647', '5825', '10149', '175555', '26386', '10433', '10719', '17352', '9647', '5825', '10149', '175555', '26386', '10433', '81182', '13358', '340402', '44718']",10,18,0.29411764705882354 -oceans 11,"['33627', '14277', '1777', '283552', '9829', '9282', '8619', '72113', '13016', '71']","['33627', '14277', '1777', '283552', '9829', '9282', '8619', '72113', '13016', '71']",10,10,1.0 -oceans eleven,"['33627', '639', '283552', '8619', '612', '11031', '299', '11446', '14433', '161']","['33627', '639', '283552', '8619', '612', '11031', '299', '11446', '14433', '161']",10,10,1.0 -psycho,"['539', '1359', '5720', '10576', '168366', '27723', '276839', '85141', '35683', '11252']","['539', '1359', '5720', '10576', '168366', '27723', '276839', '85141', '35683', '11252', '539', '1359', '5720', '10576', '27723', '35683', '11252', '10726']",10,18,0.9090909090909091 -pulp fiction,"['680', '18451', '43317', '10349', '487283', '157336', '27205', '324857', '1891', '152601']","['680', '18451', '43317', '10349', '487283', '157336', '27205', '324857', '1891', '152601']",10,10,1.0 -raiders lost ark,"['62128', '85', '326215', '334543', '13001', '295196', '638', '352504', '679', '153']","['62128', '85']",10,2,0.2 -raiders of the lost ark,"['62128', '85', '326215', '334543', '13001', '295196', '638', '679', '153', '50014']","['62128', '85']",10,2,0.2 -rambo,"['1368', '1369', '7555', '1370', '522938', '13258', '28448', '61410', '64328', '6280']","['1368', '1369', '7555', '1370', '522938', '13258', '28448', '61410', '64328', '6280']",10,10,1.0 -rocky,"['1366', '36685', '1374', '1367', '1246', '312221', '39495', '85', '296096', '8963']","['1366', '36685', '1374', '1367', '1246', '312221', '39495', '85', '296096', '8963']",10,10,1.0 -rocky horror,"['36685', '1366', '1374', '1367', '1246', '21208', '312221', '39495', '85', '296096']","['36685', '1366', '1374', '1367', '1246', '21208', '312221', '39495', '85', '296096']",10,10,1.0 -shawshank redemption,"['278', '11321', '142061', '513285', '38234', '450766', '8053', '227306', '187', '446021']","['278', '11321', '142061', '513285', '38234', '450766', '8053', '227306', '187', '446021']",10,10,1.0 -social network,"['37799', '18467', '38408', '10774', '2640', '12626', '14275', '12104', '3175', '414425']","['37799', '18467', '38408', '10774', '2640', '12626', '14275', '12104', '3175', '414425']",10,10,1.0 -sound of music,"['15121', '756', '872', '10784', '56680', '11644', '48392', '5123', '109264', '447332']","['15121', '756', '872', '10784', '56680', '11644', '48392', '5123', '109264', '570731']",10,10,0.8181818181818182 -space jam,"['2300', '470333', '11093', '157336', '348', '782', '9549', '9016', '37094', '13363']","['2300', '470333', '11093', '157336', '348', '782', '9549', '9016', '37094', '13363']",10,10,1.0 -star wars,"['11', '12180', '181808', '330459', '348350', '140607', '1895', '1893', '1894', '181812']","['12180', '322506', '85', '1895', '18046', '11', '330459', '181808', '348350', '140607']",10,10,0.5384615384615384 -star wars new hope,"['330459', '12180', '85', '322506', '13416', '278', '11474', '140607', '1895', '18046']","['330459', '85', '13416', '140607']",10,4,0.4 -the godfather,"['238', '240', '242', '400', '18973', '29464', '9835', '75579', '244007', '570731']","['238', '240', '400', '18973', '29464', '242', '9835', '75579', '244007', '570731']",10,10,1.0 -the green mile,"['497', '9285', '65', '11575', '490132', '548786', '24739', '508763', '28', '33364']","['497', '9285', '65', '11575', '490132', '548786', '24739', '508763', '28', '103']",10,10,0.8181818181818182 -the martian,"['286217', '9849', '14011', '244007', '570731', '278', '238', '34086', '240', '424']","['9849', '286217', '14011', '244007', '570731', '278', '238', '34086', '240', '424']",10,10,1.0 -top gun,"['744', '7304', '376290', '1430', '25209', '650', '36593', '407862', '101', '5915']","['744', '7304', '376290', '1430', '25209', '650', '36593', '407862', '101', '5915']",10,10,1.0 -tree of life,"['8967', '429762', '25016', '16958', '931', '493922', '512196', '72358', '487283', '995']","['429762', '8967', '16958', '931', '493922', '512196', '72358', '995', '138', '15250']",10,10,0.6666666666666666 -war games,"['396', '101299', '131634', '14278', '70160', '860', '315839', '935', '28', '515001']","['396', '101299', '131634', '14278', '70160', '860', '315839', '935', '28', '515001']",10,10,1.0 -wargames,['860'],['860'],1,1,1.0 -wolf of wall st.,"['33909', '106646', '101299', '925', '31225', '12104', '89708', '9461', '27503', '222935']","['33909', '106646', '101299', '13369', '77953']",10,5,0.25 -wolf of wall street,"['106646', '33909', '39037', '1988', '9586', '103370', '925', '12104', '540901', '13197']","['33909', '106646', '39037', '1988', '9586', '103370', '540901', '11363', '77948', '59108']",10,10,0.5384615384615384 -wolf wall street,"['33909', '106646', '39037', '9586', '1988', '103370', '925', '12104', '13197', '540901']","['33909', '106646', '39037', '9586', '1988', '103370', '13197', '540901', '10673', '11363']",10,10,0.6666666666666666 diff --git a/jupyterlite/notebooks.gz b/jupyterlite/notebooks.gz deleted file mode 100644 index d2a9e9687..000000000 Binary files a/jupyterlite/notebooks.gz and /dev/null differ diff --git a/jupyterlite/requirements.txt b/jupyterlite/requirements.txt deleted file mode 100644 index 094d85ade..000000000 --- a/jupyterlite/requirements.txt +++ /dev/null @@ -1,48 +0,0 @@ -# Contents below from https://github.com/jupyterlite/demo/blob/main/requirements.txt - -# Core modules (mandatory) -jupyterlite-core==0.1.0 -jupyterlab~=3.5.1 - -# Python kernel (optional) -jupyterlite-pyodide-kernel==0.0.6 - -# JavaScript kernel (optional) -jupyterlite-javascript-kernel==0.1.0b21 - -# Language support (optional) -jupyterlab-language-pack-fr-FR -jupyterlab-language-pack-zh-CN - -# SQLite kernel (optional) -jupyterlite-xeus-sqlite==0.2.1 -# P5 kernel (optional) -jupyterlite-p5-kernel==0.1.0 -# Lua kernel (optional) -jupyterlite-xeus-lua==0.3.1 - -# JupyterLab: Fasta file renderer (optional) -jupyterlab-fasta>=3,<4 -# JupyterLab: Geojson file renderer (optional) -jupyterlab-geojson>=3,<4 -# JupyterLab: guided tour (optional) -jupyterlab-tour -# JupyterLab: dark theme -jupyterlab-night -# JupyterLab: Miami nights theme (optional) -jupyterlab_miami_nights - -# Python: ipywidget library for Jupyter notebooks (optional) -ipywidgets>=8.0.0,<9 -# Python: ipyevents library for Jupyter notebooks (optional) -ipyevents>=2.0.1 -# Python: interative Matplotlib library for Jupyter notebooks (optional) -ipympl>=0.8.2 -# Python: ipycanvas library for Jupyter notebooks (optional) -ipycanvas>=0.9.1 -# Python: ipyleaflet library for Jupyter notebooks (optional) -ipyleaflet - -# Python: plotting libraries (optional) -plotly>=5,<6 -bqplot \ No newline at end of file diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake index fc445524d..d35d4843e 100644 --- a/lib/tasks/assets.rake +++ b/lib/tasks/assets.rake @@ -6,11 +6,18 @@ require 'zlib' namespace :assets do desc 'Unpack Jupyterlite assets' task jupyterlite: :environment do - notebooks_gz = Rails.root.join('jupyterlite/notebooks.gz') + notebooks_gz = Rails.root.join('notebooks.gz') destination = Rails.public_path + unless File.exist?(notebooks_gz) + puts 'Downloading latest Quepid Notebooks from https://github.com/o19s/quepid-jupyterlite' + system "wget -O #{notebooks_gz} https://github.com/o19s/quepid-jupyterlite/releases/latest/download/jupyter-lite-build.tgz" + end + puts "Unpacking Jupyterlite into #{destination}" system "tar -xzf #{notebooks_gz} --directory #{destination}" + + File.delete(notebooks_gz) end # Hook into existing assets:precompile task