Skip to content

Commit

Permalink
resolves #5 support multi plots
Browse files Browse the repository at this point in the history
  • Loading branch information
ggrossetie committed Sep 13, 2023
1 parent d2bee78 commit 59bb433
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: pip install ipython
- run: pip install ipython plotly
- name: Test
run: |
npm t
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: pip install ipython
- run: pip install ipython plotly
- name: Test
run: |
npm t
Expand Down
43 changes: 40 additions & 3 deletions spec/dynamic-notebook.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ print('hello')
`
const registry = asciidoctor.Extensions.create()
dynamicNotebookExt.register(registry)
const doc = asciidoctor.load(input, {extension_registry: registry})
const doc = asciidoctor.load(input, { extension_registry: registry })
const html = doc.convert()
expect(html).to.equal(`<div class="listingblock">
<div class="content">
Expand Down Expand Up @@ -48,7 +48,7 @@ invalid_python
const registry = asciidoctor.Extensions.create()
dynamicNotebookExt.register(registry)
try {
const doc = asciidoctor.load(input, {extension_registry: registry})
const doc = asciidoctor.load(input, { extension_registry: registry })
expect.fail('Should throw an error when fail-on-error attribute is define')
} catch (err) {
// OK
Expand All @@ -65,7 +65,7 @@ invalid_python
`
const registry = asciidoctor.Extensions.create()
dynamicNotebookExt.register(registry)
const doc = asciidoctor.load(input, {extension_registry: registry})
const doc = asciidoctor.load(input, { extension_registry: registry })
const html = doc.convert()
expect(html).to.equal(`<div class="listingblock">
<div class="content">
Expand All @@ -88,5 +88,42 @@ NameError: name 'invalid_python' is not defined</pre>
</div>
</details>`)
})
it('should output more than one Plotly charts', () => {
const input = `
:dynamic-blocks:
[%dynamic%raw,python]
----
import plotly.express as px
figs = []
figs.append(px.line(px.data.gapminder().query("country=='Canada'"), x="year", y="lifeExp", title='Life expectancy in Canada'))
figs.append(px.line(px.data.gapminder().query("continent=='Oceania'"), x="year", y="lifeExp", color='country'))
for fig in figs:
fig.show()
----
`
const registry = asciidoctor.Extensions.create()
dynamicNotebookExt.register(registry)
const doc = asciidoctor.load(input, { extension_registry: registry })
const html = doc.convert()
expect(html).to.contains(`<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">import plotly.express as px
figs = []
figs.append(px.line(px.data.gapminder().query("country=='Canada'"), x="year", y="lifeExp", title='Life expectancy in Canada'))
figs.append(px.line(px.data.gapminder().query("continent=='Oceania'"), x="year", y="lifeExp", color='country'))
for fig in figs:
fig.show()</code></pre>
</div>
</div>
<details class="dynamic-py-result dynamic-py-result-plotly dynamic-py-result-plotly-grid">
<summary class="title">Results</summary>`)
const blocksCount = Array.from(html.matchAll(/<div id="[^"]+" class="plotly-graph-div" .*<\/script>/gm), (m) => m[0]).length
expect(blocksCount).to.eq(2)
})
})
})
23 changes: 17 additions & 6 deletions src/dynamic-notebook-processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const plotterShowRx = /plotter.show\(\)/g
const pyvistaContainerRx = /^var container = document\.querySelector\('.content'\);$/m
const pyvistaScriptRx = /(?<script><script .*<\/script>)/ms
const pyvistaFaviconRx = /n\.setAttribute\("href","https:\/\/kitware.github.io\/vtk-js\/icon\/favicon-".concat\(t,"x"\).concat\(t,".png"\)\),/
const plotlyPlotRx = /<div id="[^"]+" class="plotly-graph-div" .*<\/script>/gm

const ipythonTemplate = (pyCodes) => {
return `from IPython.core.interactiveshell import InteractiveShell
Expand Down Expand Up @@ -72,10 +73,8 @@ module.exports.register = function register(registry) {
const ipython = ipythonTemplate(blocks.map((b) => {
const code = b.getContent()
.replaceAll(conumRx, '')
.replaceAll(figShowRx, `import sys
fig.write_html(file=sys.stdout, include_plotlyjs=False)`)
.replaceAll(plotterShowRx, `import sys
sys.stdout.write(plotter.export_html(None).getvalue())`)
.replaceAll(figShowRx, `import sys; fig.write_html(file=sys.stdout, include_plotlyjs=False)`)
.replaceAll(plotterShowRx, `import sys; sys.stdout.write(plotter.export_html(None).getvalue())`)
return JSON.stringify(code)
}))
logger.info('processing dynamic blocks...')
Expand All @@ -101,12 +100,12 @@ sys.stdout.write(plotter.export_html(None).getvalue())`)
}
const exampleBlock = self.createExampleBlock(block, '', attrs, {'content_model': 'compound'})
exampleBlock.setTitle('Results')
// option for raw content (Plotly)
const result = response[index]
let source = result.stdout.toString('utf8')
if (result.success === false && block.hasAttribute("fail-on-error")) {
throw new ExecutionError(result.stderr.toString('utf8') + " " + result.stdout.toString('utf8'))
}
// option for raw content (Plotly or PyVista)
if (block.isOption('raw')) {
if (block.getAttribute('output') === 'pyvista') {
logger.debug(source)
Expand All @@ -128,7 +127,19 @@ resizeObserver.observe(document.getElementById('pyvista-${index}'))
${script}`, {role: 'dynamic-py-result'}))
}
} else {
exampleBlock.append(self.createPassBlock(exampleBlock, source, {role: 'dynamic-py-result'}))
exampleBlock.addRole('dynamic-py-result')
let content = ''
const plotlyBlocks = Array.from(source.matchAll(plotlyPlotRx), (m) => m[0])
if (plotlyBlocks) {
exampleBlock.addRole('dynamic-py-result-plotly')
if (plotlyBlocks.length > 1) {
exampleBlock.addRole('dynamic-py-result-plotly-grid')
}
content = plotlyBlocks.join('\n')
} else {
content = source
}
exampleBlock.append(self.createPassBlock(exampleBlock, content))
}
} else {
exampleBlock.append(self.createLiteralBlock(exampleBlock, source, {role: 'dynamic-py-result'}))
Expand Down

0 comments on commit 59bb433

Please sign in to comment.