Kotlin / kotlin-jupyter

Kotlin kernel for Jupyter/IPython
Apache License 2.0
1.12k stars 107 forks source link

HTML exported with broken layout if both kandy and dataframe added #414

Closed gabrielfeo closed 1 year ago

gabrielfeo commented 1 year ago

I'm not sure if this is a Kernel issue, please let me know if I should move it somewhere else. I was able to narrow it down to this peculiar scenario, but I'm able to reproduce it 100% like this.

  1. Create a Kotlin notebook with below cells
%useLatestDescriptors
%use kandy
%use dataframe
println("0")
  1. Click "Restart Kernel and Run All Cells..." and wait for outputs
  2. Click "Save and Export As..." > "HTML"

Expected

HTML is exported and displays cells on the layout of a single column

Screenshot 2023-05-12 at 18 13 15

Actual

HTML is exported and displays cells on a strange layout. Any cells coming after the println("0") cell are added further to the right of this cell.

Screenshot 2023-05-12 at 18 13 22

Note: if you re-run the first cell and export again, the exported HTML then has the expected layout. Issue occurs only on the first run of the cell, as with "restart and run all".


Environment info Python 3.11.2 ``` bash-5.2$ pip3 list Package Version ------------------------ ---------- aiofiles 22.1.0 aiosqlite 0.19.0 anyio 3.6.2 appnope 0.1.3 argon2-cffi 21.3.0 argon2-cffi-bindings 21.2.0 arrow 1.2.3 asttokens 2.2.1 attrs 23.1.0 autopep8 2.0.1 Babel 2.12.1 backcall 0.2.0 beautifulsoup4 4.12.2 bleach 6.0.0 bs4 0.0.1 certifi 2022.12.7 cffi 1.15.1 charset-normalizer 3.1.0 comm 0.1.3 debugpy 1.6.7 decorator 5.1.1 defusedxml 0.7.1 executing 1.2.0 fastjsonschema 2.16.3 fqdn 1.5.1 idna 3.4 ipykernel 6.22.0 ipython 8.13.2 ipython-genutils 0.2.0 ipywidgets 8.0.6 isoduration 20.11.0 jedi 0.18.2 Jinja2 3.1.2 json5 0.9.11 jsonpointer 2.3 jsonschema 4.17.3 jupyter 1.0.0 jupyter_client 8.2.0 jupyter-console 6.6.3 jupyter_core 5.3.0 jupyter-events 0.6.3 jupyter_server 2.5.0 jupyter_server_fileid 0.9.0 jupyter_server_terminals 0.4.4 jupyter_server_ydoc 0.8.0 jupyter-ydoc 0.2.4 jupyterlab 3.6.3 jupyterlab-pygments 0.2.2 jupyterlab_server 2.22.1 jupyterlab-widgets 3.0.7 kotlin-jupyter-kernel 0.11.0.377 MarkupSafe 2.1.2 matplotlib-inline 0.1.6 mistune 2.0.5 nbclassic 1.0.0 nbclient 0.7.4 nbconvert 7.4.0 nbformat 5.8.0 nest-asyncio 1.5.6 notebook 6.5.4 notebook_shim 0.2.3 packaging 23.1 pandocfilters 1.5.0 parso 0.8.3 pexpect 4.8.0 pickleshare 0.7.5 pip 23.1.2 platformdirs 3.5.0 prometheus-client 0.16.0 prompt-toolkit 3.0.38 protobuf 4.21.12 psutil 5.9.5 ptyprocess 0.7.0 pure-eval 0.2.2 pycodestyle 2.10.0 pycparser 2.21 Pygments 2.14.0 pyrsistent 0.19.3 python-dateutil 2.8.2 python-json-logger 2.0.7 PyYAML 6.0 pyzmq 25.0.2 qtconsole 5.4.2 QtPy 2.3.1 requests 2.28.2 rfc3339-validator 0.1.4 rfc3986-validator 0.1.1 Send2Trash 1.8.2 setuptools 65.6.3 six 1.16.0 sniffio 1.3.0 soupsieve 2.4 stack-data 0.6.2 terminado 0.17.1 tinycss2 1.2.1 tornado 6.3.1 traitlets 5.9.0 uri-template 1.2.0 urllib3 1.26.15 wcwidth 0.2.6 webcolors 1.13 webencodings 0.5.1 websocket-client 1.5.1 wheel 0.38.4 widgetsnbextension 4.0.7 y-py 0.5.9 ypy-websocket 0.8.2 ```
ileasile commented 1 year ago

Hi! Where have you done this? "Save and Export As..." I mean, what client have you used?

gabrielfeo commented 1 year ago

Hi again! I'm using jupyter-lab, but the issue also occurs with jupyter nbconvert --to html --execute.

Diffing the notebook saved after "run all" vs. the notebook saved after re-running the first cell suggests the first cell's outputs are the cause.

--- tooling/jupyter-notebooks/Untitled4.ipynb.prob  2023-05-12 18:38:01
+++ tooling/jupyter-notebooks/Untitled4.ipynb   2023-05-12 18:38:05
@@ -2,268 +2,12 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 3,
    "id": "5d5ac1ec-b509-4df3-9e3f-6e8621c326f6",
    "metadata": {
     "tags": []
    },
-   "outputs": [
-    {
-     "data": {
-      "text/html": [
-       "            <div id=\"kotlin_out_0\"/>\n",
-       "            <script type=\"text/javascript\">\n",
-       "                            if(!window.kotlinQueues) {\n",
-       "                window.kotlinQueues = {};\n",
-       "            }\n",
-       "            if(!window.kotlinQueues[\"kandyLetsPlot\"]) {\n",
-       "                var resQueue = [];\n",
-       "                window.kotlinQueues[\"kandyLetsPlot\"] = resQueue;\n",
-       "                window[\"call_kandyLetsPlot\"] = function(f) {\n",
-       "                    resQueue.push(f);\n",
-       "                }\n",
-       "            }\n",
-       "            (function (){\n",
-       "                var modifiers = [(function(script) {\n",
-       "    script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v3.1.0/js-package/distr/lets-plot.min.js\"\n",
-       "    script.type = \"text/javascript\";\n",
-       "})];\n",
-       "                var e = document.getElementById(\"kotlin_out_0\");\n",
-       "                modifiers.forEach(function (gen) {\n",
-       "                    var script = document.createElement(\"script\");\n",
-       "                    gen(script)\n",
-       "                    script.addEventListener(\"load\", function() {\n",
-       "                        window[\"call_kandyLetsPlot\"] = function(f) {f();};\n",
-       "                        window.kotlinQueues[\"kandyLetsPlot\"].forEach(function(f) {f();});\n",
-       "                        window.kotlinQueues[\"kandyLetsPlot\"] = [];\n",
-       "                    }, false);\n",
-       "                    script.addEventListener(\"error\", function() {\n",
-       "                        window[\"call_kandyLetsPlot\"] = function(f) {};\n",
-       "                        window.kotlinQueues[\"kandyLetsPlot\"] = [];\n",
-       "                        var div = document.createElement(\"div\");\n",
-       "                        div.style.color = 'darkred';\n",
-       "                        div.textContent = 'Error loading resource kandyLetsPlot';\n",
-       "                        document.getElementById(\"kotlin_out_0\").appendChild(div);\n",
-       "                    }, false);\n",
-       "                    \n",
-       "                    e.appendChild(script);\n",
-       "                });\n",
-       "            })();\n",
-       "            </script>"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "            <div id=\"kotlin_out_1\"/>\n",
-       "            <script type=\"text/javascript\">\n",
-       "                            if(!window.kotlinQueues) {\n",
-       "                window.kotlinQueues = {};\n",
-       "            }\n",
-       "            if(!window.kotlinQueues[\"DataFrame\"]) {\n",
-       "                var resQueue = [];\n",
-       "                window.kotlinQueues[\"DataFrame\"] = resQueue;\n",
-       "                window[\"call_DataFrame\"] = function(f) {\n",
-       "                    resQueue.push(f);\n",
-       "                }\n",
-       "            }\n",
-       "            (function (){\n",
-       "                var modifiers = [(function(script) {\n",
-       "    script.src = \"https://cdn.jsdelivr.net/gh/Kotlin/dataframe@3db46ccccaa1291c0627307d64133317f545e6ae/core/src/main/resources/init.js\"\n",
-       "    script.type = \"text/javascript\";\n",
-       "})];\n",
-       "                var e = document.getElementById(\"kotlin_out_1\");\n",
-       "                modifiers.forEach(function (gen) {\n",
-       "                    var script = document.createElement(\"script\");\n",
-       "                    gen(script)\n",
-       "                    script.addEventListener(\"load\", function() {\n",
-       "                        window[\"call_DataFrame\"] = function(f) {f();};\n",
-       "                        window.kotlinQueues[\"DataFrame\"].forEach(function(f) {f();});\n",
-       "                        window.kotlinQueues[\"DataFrame\"] = [];\n",
-       "                    }, false);\n",
-       "                    script.addEventListener(\"error\", function() {\n",
-       "                        window[\"call_DataFrame\"] = function(f) {};\n",
-       "                        window.kotlinQueues[\"DataFrame\"] = [];\n",
-       "                        var div = document.createElement(\"div\");\n",
-       "                        div.style.color = 'darkred';\n",
-       "                        div.textContent = 'Error loading resource DataFrame';\n",
-       "                        document.getElementById(\"kotlin_out_1\").appendChild(div);\n",
-       "                    }, false);\n",
-       "                    \n",
-       "                    e.appendChild(script);\n",
-       "                });\n",
-       "            })();\n",
-       "            </script>"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "                <style>\n",
-       "                :root {\n",
-       "    --background: #fff;\n",
-       "    --background-odd: #f5f5f5;\n",
-       "    --background-hover: #d9edfd;\n",
-       "    --header-text-color: #474747;\n",
-       "    --text-color: #848484;\n",
-       "    --text-color-dark: #000;\n",
-       "    --text-color-medium: #737373;\n",
-       "    --text-color-pale: #b3b3b3;\n",
-       "    --inner-border-color: #aaa;\n",
-       "    --bold-border-color: #000;\n",
-       "    --link-color: #296eaa;\n",
-       "    --link-color-pale: #296eaa;\n",
-       "    --link-hover: #1a466c;\n",
-       "}\n",
-       "\n",
-       ":root[theme=\"dark\"], :root [data-jp-theme-light=\"false\"], .dataframe_dark{\n",
-       "    --background: #303030;\n",
-       "    --background-odd: #3c3c3c;\n",
-       "    --background-hover: #464646;\n",
-       "    --header-text-color: #dddddd;\n",
-       "    --text-color: #b3b3b3;\n",
-       "    --text-color-dark: #dddddd;\n",
-       "    --text-color-medium: #b2b2b2;\n",
-       "    --text-color-pale: #737373;\n",
-       "    --inner-border-color: #707070;\n",
-       "    --bold-border-color: #777777;\n",
-       "    --link-color: #008dc0;\n",
-       "    --link-color-pale: #97e1fb;\n",
-       "    --link-hover: #00688e;\n",
-       "}\n",
-       "\n",
-       "p.dataframe_description {\n",
-       "    color: var(--text-color-dark);\n",
-       "}\n",
-       "\n",
-       "table.dataframe {\n",
-       "    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n",
-       "    font-size: 12px;\n",
-       "    background-color: var(--background);\n",
-       "    color: var(--text-color-dark);\n",
-       "    border: none;\n",
-       "    border-collapse: collapse;\n",
-       "}\n",
-       "\n",
-       "table.dataframe th, td {\n",
-       "    padding: 6px;\n",
-       "    border: 1px solid transparent;\n",
-       "    text-align: left;\n",
-       "}\n",
-       "\n",
-       "table.dataframe th {\n",
-       "    background-color: var(--background);\n",
-       "    color: var(--header-text-color);\n",
-       "}\n",
-       "\n",
-       "table.dataframe td {\n",
-       "    vertical-align: top;\n",
-       "}\n",
-       "\n",
-       "table.dataframe th.bottomBorder {\n",
-       "    border-bottom-color: var(--bold-border-color);\n",
-       "}\n",
-       "\n",
-       "table.dataframe tbody > tr:nth-child(odd) {\n",
-       "    background: var(--background-odd);\n",
-       "}\n",
-       "\n",
-       "table.dataframe tbody > tr:nth-child(even) {\n",
-       "    background: var(--background);\n",
-       "}\n",
-       "\n",
-       "table.dataframe tbody > tr:hover {\n",
-       "    background: var(--background-hover);\n",
-       "}\n",
-       "\n",
-       "table.dataframe a {\n",
-       "    cursor: pointer;\n",
-       "    color: var(--link-color);\n",
-       "    text-decoration: none;\n",
-       "}\n",
-       "\n",
-       "table.dataframe tr:hover > td a {\n",
-       "    color: var(--link-color-pale);\n",
-       "}\n",
-       "\n",
-       "table.dataframe a:hover {\n",
-       "    color: var(--link-hover);\n",
-       "    text-decoration: underline;\n",
-       "}\n",
-       "\n",
-       "table.dataframe img {\n",
-       "    max-width: fit-content;\n",
-       "}\n",
-       "\n",
-       "table.dataframe th.complex {\n",
-       "    background-color: var(--background);\n",
-       "    border: 1px solid var(--background);\n",
-       "}\n",
-       "\n",
-       "table.dataframe .leftBorder {\n",
-       "    border-left-color: var(--inner-border-color);\n",
-       "}\n",
-       "\n",
-       "table.dataframe .rightBorder {\n",
-       "    border-right-color: var(--inner-border-color);\n",
-       "}\n",
-       "\n",
-       "table.dataframe .rightAlign {\n",
-       "    text-align: right;\n",
-       "}\n",
-       "\n",
-       "table.dataframe .expanderSvg {\n",
-       "    width: 8px;\n",
-       "    height: 8px;\n",
-       "    margin-right: 3px;\n",
-       "}\n",
-       "\n",
-       "table.dataframe .expander {\n",
-       "    display: flex;\n",
-       "    align-items: center;\n",
-       "}\n",
-       "\n",
-       "/* formatting */\n",
-       "\n",
-       "table.dataframe .null {\n",
-       "    color: var(--text-color-pale);\n",
-       "}\n",
-       "\n",
-       "table.dataframe .structural {\n",
-       "    color: var(--text-color-medium);\n",
-       "    font-weight: bold;\n",
-       "}\n",
-       "\n",
-       "table.dataframe .dataFrameCaption {\n",
-       "    font-weight: bold;\n",
-       "}\n",
-       "\n",
-       "table.dataframe .numbers {\n",
-       "    color: var(--text-color-dark);\n",
-       "}\n",
-       "\n",
-       "table.dataframe td:hover .formatted .structural, .null {\n",
-       "    color: var(--text-color-dark);\n",
-       "}\n",
-       "\n",
-       "table.dataframe tr:hover .formatted .structural, .null {\n",
-       "    color: var(--text-color-dark);\n",
-       "}\n",
-       "\n",
-       "\n",
-       "                </style>"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    }
-   ],
+   "outputs": [],
    "source": [
     "%useLatestDescriptors\n",
     "%use kandy\n",
ileasile commented 1 year ago

Something strange is happening there: the second cell's div somehow got to the first cell's output div

image
ileasile commented 1 year ago

I would say it's converter's issue because generated HTML is obviously incorrect. it's not about incorrect styles or things like that

ileasile commented 1 year ago

Removing either dataframe's or kandy's initial output solves the problem that makes things even stranger

ileasile commented 1 year ago

Workaround: import dataframe and kandy in different cells

image
gabrielfeo commented 1 year ago

Thanks, that workaround is easy enough. Couldn't it be related to the JavaScript added by these libraries as HTML outputs?

By the way, adding them in different cells still causes some strange indentation in the HTML scripts. First image was "Restart and run all", second was re-running the cells

Screenshot 2023-05-12 at 19 13 53 Screenshot 2023-05-12 at 19 13 59
ileasile commented 1 year ago

Yep, that's strange, they become narrower)) It might be because of JS, but very unlikely... I'm not even sure this converter executes JS somehow if it's written in python

ileasile commented 1 year ago

Lol, actually the same thing happens here: cells are inserted one into another...

image
ileasile commented 1 year ago

Literally a Russian matryoshka image

ileasile commented 1 year ago

I found a problem. It's indeed in kernel! Thanks for the nice catch, I'll push the fix today

ileasile commented 1 year ago

Version 0.11.0.385

gabrielfeo commented 1 year ago

Thank you! Can confirm it's working fine on this version