Back
Featured image of post Publishing blog posts from PWeave

Publishing blog posts from PWeave

This blog started mostly as an archive for R-related things as I was starting to use R as my main tool / language for data analysis. For a while, I’ve been also using Python. Looking for a literate programming alterative in Python I found Pweave. So I’d like to also use this blog as an archive for Python-related things, starting with how to use PWeave to write blog posts. Yeah, I guess I can keep using RMarkdown to write Python-related blog posts, but I find Python support still limited and therefore I prefer to write the posts in the main editor I use to write python code (currently Atom).

PWeave

Using PWeave you can write using several formats and then compile the notebook into, also, several formats (e.g. markdown, html). It seems it was inspired by Sweave, which was the most common literate programming approach for R users before RmarkDown came to the scene.

I would use either the pmd format (markdown + python code chuncks) or simply python scripts, compiled into a notebook using PWeave (similar to knitr’s spin).

Blogdown integration

If you are not using a different container for images, in blogdown they are located in the static/post directory that is then published as /post by netlify. So tipically an image is referenced from html or markdown files as /post/post_dir/figure-html/x.png

PWeave on the other hand by default generates images in the ./images directory.

So, to get it to work, you can change the figures directory, for example, using the command line args.

Assuming the post .pmd source file is located in the standard directory content/post and considering the imagens need to be in the static/post directory, let’s change it to that. That way, the figures will be generated in the correct location and you just need to add the files and push the changes to the repository for netlify to process them.

However, you need to change the generated markdown file, to amend the location of the figures. Changing it from the relative path (../../post) to the absolute path (/post), since that will be the location in netlify. Alternatively, realizing that netlify arranges the file by year/month/post_title/index.html you could try to fix the reference also to a relative path. But that seems like a silly option in comparison, and error-prone in case the date is not available or who knows.

So, then you would have to do something like:

  • cd to the directory where the blog source is located (BLOG_PATH/content/post)
  • pweave -f markdown 2017-11-01_Publishing_From_PWeave.pmd --figure-directory=/post/2017-11-01_Publishing_From_PWeave
  • sed -i 's+++g' ./2017-11-01_Publishing_From_PWeave.md

I guess this is pretty trivial to configure using, for example, atom-shell-commands. Although I am not sure if it is possible to run both commands above with only one atom-shell-command. And it seems you cannot avoid using two commands, because Pweave will do what you tell him in the --figure-directory, but that would be either a relative path (in which case would be relative to the directory where the output file is being generated) or an absolute path. And none of those options will ever match the directory structure within netlify (/post/post_dir).

PWeave supported features

Matplotlib plots

It supports matplotlib plots.

# Import the necessary libraries
import matplotlib.pyplot as plt
import pandas as pd

# Initialize Figure and Axes object
fig, ax = plt.subplots()

# Load in data
tips = pd.read_csv("https://raw.githubusercontent.com/mwaskom/seaborn-data/master/tips.csv")

# Create violinplot
ax.violinplot(tips["total_bill"], vert=False)

# Show the plot
plt.show()

\

# And this from the official matplotlib examples
# https://matplotlib.org/3.1.1/tutorials/introductory/sample_plots.html

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(19680801)
data = np.random.randn(2, 100)

fig, axs = plt.subplots(2, 2, figsize=(5, 5))
axs[0, 0].hist(data[0])
axs[1, 0].scatter(data[0], data[1])
axs[0, 1].plot(data[0], data[1])
axs[1, 1].hist2d(data[0], data[1])

plt.show()

\

Mathjax

The easy way …

this is how blogdown does it. Wrap it up in a ‘math inline’ css class. it becomes somewhat verbose, but it works. otherwise you would have to mess with Hugo, including the proper libraries and so on in the header.html or footer.html or something like that, …, or even worse, not generating a markdown file but an html file, which PWeave does for you, but then you would have to deal with getting the yaml headers rigth in the html file, and getting rid of the html headers jibber-jabber, so that dates and summary are properly displayed in the blog entries page

\(y=x^2\)

\(w(n) = \alpha - \beta\cos\frac{2\pi n}{N-1}\), where

\(\alpha=0.54\) and \(\beta=0.46\)

Interactive plots via bokeh

Sort of native support. Pweave has a couple of functions to help you out here. They include the proper headers in the html file and include Bokeh’s output properly unescaped in the generated file.

Just a warning, it works if you pweave into an html file. That makes sense, but if you want to pweave it into a markdown file, the pweave.bokeh.show function will not do the trick. That’s because they use IPython.display.display_html (see here). It seems at some point they were experimenting in providing support also for markdown (display_markdown was imported but its usage commented out). So, if you need to include Bokeh plots in markdown generated files (like in my case, files that later will be converted into html by other tool -Hugo via netlify in my case-, otherwise, perhaps it makes no sense at all), then you have to work a little bit more. Here’s the example:

# Original example taken from http://mpastell.com/pweave/bokeh.html
# This works smoothly if you pweave into html (md2html)
from bokeh.plotting import figure
from pweave.bokeh import output_pweave, show

# but if you are generating a markdown file, this line does not work
#output_pweave()

# So let's just tweak the original function to make it work for markdown
# https://github.com/mpastell/Pweave/blob/master/pweave/bokeh/__init__.py

# For it to work, all the output should be within a single container (div)
from IPython.display import display_markdown
display_markdown('<div>', raw=True)

# Then just do the same from output_pweave(), but with display_markdown
from bokeh.resources import CDN
out = CDN.render_css()
out += CDN.render_js()
from IPython.display import display_markdown
display_markdown(out, raw=True)

x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]
p = figure(title="simple line example", x_axis_label='x', y_axis_label='y')
p.line(x, y, legend="Temp.", line_width=2)

# but if you are generating a markdown file, this line does not work either
#show(p)

# So let's just tweak the original function to make it work for markdown
# https://github.com/mpastell/Pweave/blob/master/pweave/bokeh/__init__.py
from bokeh.embed import components
from IPython.display import display_markdown
script, div = components(p)
out = script
out+= div
display_markdown(out, raw=True)

# Do not forget to close the div
display_markdown('</div>', raw=True)
---------------------------------------------------------------------------ModuleNotFoundError
Traceback (most recent call last)<ipython-input-1-2f8bd52361da> in
<module>
      1 # Original example taken from
http://mpastell.com/pweave/bokeh.html
      2 # This works smoothly if you pweave into html (md2html)
----> 3 from bokeh.plotting import figure
      4 from pweave.bokeh import output_pweave, show
      5
ModuleNotFoundError: No module named 'bokeh'

So, yeah, it works. But it is somewhat cumbersome. It would be better that Pweave would detect the target file and fix the output accordingly. Maybe a PR?

Interactive plots via plotly

For Plotly, as fas as I know, there is no native support. You can nonetheless try to include Plotly as follows.

First, take advantage of the plotly.offline.plot function, to generate the HTML for the plot, making sure you use the output_type="div" and not the default standalone HTML file. Also, you would need to let it include_plotlyjs. Either by include_plotlyjs=True, which creates a fully standalone plot that you can use offline, because it includes all the Plotly script (the downside is that the file size would be > 3MB), or by setting include_plotlyjs="cdn", which includes in the div a link to the plotly script (but then to view the file you need to be online).

Then, you need to use display_html from IPython.display with raw=True to include the code in the output file. Otherwise, Pweave would escape it and you would lose all the html markup. Ok, here’s a weird thing: if you pweave the pmd to html, display_html works, but if you want to generate a markdown file it seems you need to use display_markdown (weird in the sense that I do not like it).

And I think that’s it. Here’s the example.

# Basic plotly example from the official web page
import plotly
import plotly.graph_objects as go
fig = go.Figure(
    data=[go.Bar(y=[2, 1, 3])], layout_title_text="A Figure Displaying Itself"
)

plotly_div = plotly.offline.plot(
    fig,
    include_plotlyjs="cdn",
    show_link=False,
    output_type='div'
)

#from IPython.display import display_html
#display_html(plotly_div, raw=True)
from IPython.display import display_markdown
display_markdown(plotly_div, raw=True)
            <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>    
        <div id="e4b8f7f8-0d4d-4b6f-ade0-83d2d49cda61" class="plotly-graph-div" style="height:100%; width:100%;"></div>
        <script type="text/javascript">
            
                window.PLOTLYENV=window.PLOTLYENV || {};
                
            if (document.getElementById("e4b8f7f8-0d4d-4b6f-ade0-83d2d49cda61")) {
                Plotly.newPlot(
                    'e4b8f7f8-0d4d-4b6f-ade0-83d2d49cda61',
                    [{"type": "bar", "y": [2, 1, 3]}],
                    {"template": {"data": {"bar": [{"error_x": {"color": "#2a3f5f"}, "error_y": {"color": "#2a3f5f"}, "marker": {"line": {"color": "#E5ECF6", "width": 0.5}}, "type": "bar"}], "barpolar": [{"marker": {"line": {"color": "#E5ECF6", "width": 0.5}}, "type": "barpolar"}], "carpet": [{"aaxis": {"endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f"}, "baxis": {"endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f"}, "type": "carpet"}], "choropleth": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "type": "choropleth"}], "contour": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "contour"}], "contourcarpet": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "type": "contourcarpet"}], "heatmap": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "heatmap"}], "heatmapgl": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "heatmapgl"}], "histogram": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "histogram"}], "histogram2d": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "histogram2d"}], "histogram2dcontour": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "histogram2dcontour"}], "mesh3d": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "type": "mesh3d"}], "parcoords": [{"line": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "parcoords"}], "pie": [{"automargin": true, "type": "pie"}], "scatter": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatter"}], "scatter3d": [{"line": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatter3d"}], "scattercarpet": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scattercarpet"}], "scattergeo": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scattergeo"}], "scattergl": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scattergl"}], "scattermapbox": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scattermapbox"}], "scatterpolar": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatterpolar"}], "scatterpolargl": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatterpolargl"}], "scatterternary": [{"marker": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "type": "scatterternary"}], "surface": [{"colorbar": {"outlinewidth": 0, "ticks": ""}, "colorscale": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "type": "surface"}], "table": [{"cells": {"fill": {"color": "#EBF0F8"}, "line": {"color": "white"}}, "header": {"fill": {"color": "#C8D4E3"}, "line": {"color": "white"}}, "type": "table"}]}, "layout": {"annotationdefaults": {"arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1}, "coloraxis": {"colorbar": {"outlinewidth": 0, "ticks": ""}}, "colorscale": {"diverging": [[0, "#8e0152"], [0.1, "#c51b7d"], [0.2, "#de77ae"], [0.3, "#f1b6da"], [0.4, "#fde0ef"], [0.5, "#f7f7f7"], [0.6, "#e6f5d0"], [0.7, "#b8e186"], [0.8, "#7fbc41"], [0.9, "#4d9221"], [1, "#276419"]], "sequential": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]], "sequentialminus": [[0.0, "#0d0887"], [0.1111111111111111, "#46039f"], [0.2222222222222222, "#7201a8"], [0.3333333333333333, "#9c179e"], [0.4444444444444444, "#bd3786"], [0.5555555555555556, "#d8576b"], [0.6666666666666666, "#ed7953"], [0.7777777777777778, "#fb9f3a"], [0.8888888888888888, "#fdca26"], [1.0, "#f0f921"]]}, "colorway": ["#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52"], "font": {"color": "#2a3f5f"}, "geo": {"bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white"}, "hoverlabel": {"align": "left"}, "hovermode": "closest", "mapbox": {"style": "light"}, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": {"angularaxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}, "bgcolor": "#E5ECF6", "radialaxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}}, "scene": {"xaxis": {"backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white"}, "yaxis": {"backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white"}, "zaxis": {"backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white"}}, "shapedefaults": {"line": {"color": "#2a3f5f"}}, "ternary": {"aaxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}, "baxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}, "bgcolor": "#E5ECF6", "caxis": {"gridcolor": "white", "linecolor": "white", "ticks": ""}}, "title": {"x": 0.05}, "xaxis": {"automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": {"standoff": 15}, "zerolinecolor": "white", "zerolinewidth": 2}, "yaxis": {"automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": {"standoff": 15}, "zerolinecolor": "white", "zerolinewidth": 2}}}, "title": {"text": "A Figure Displaying Itself"}},
                    {"responsive": true}
                )
            };
            
        </script>
    </div>

Other html widgets ???

Other alternatives for literate programming in python

Check this out

knitpy

knitpy

A port of knitr, but …

  • it seems there is no active development and it still lack many features
  • no support in atom (syntax, etc.)

Python handout

Python handout

  • It’s like knitr’s spin, that compiles python scripts into markdown
  • I like that it uses """ for the text, which makes it clearer than using normal comments (like pweave, that also supports compiling python scripts)
  • I don’t like that you sort of need to expllicitly import and use handout within the document.

Codebraid

codebraid looks like full-featured

  • uses pandoc
  • supports also multiple languages, python, julia, javascript, R

more?

https://pypi.org/project/antiweb/0.2.2/

Session Info

from sinfo import sinfo
sinfo_html = sinfo(html=True)
display_markdown(sinfo_html.data, raw=True)
Click to view module versions
-----
matplotlib  3.2.1
numpy       1.18.1
pandas      1.0.3
plotly      4.6.0
sinfo       0.3.1
-----
Click to view dependency modules
attr                19.3.0
backcall            0.1.0
colorama            0.4.3
concurrent          NA
cycler              0.10.0
cython_runtime      NA
dateutil            2.8.1
decorator           4.4.2
defusedxml          0.6.0
encodings           NA
entrypoints         0.3
genericpath         NA
importlib_metadata  1.6.0
ipykernel           5.2.0
ipython_genutils    0.2.0
ipywidgets          7.5.1
jedi                0.15.2
jinja2              2.11.1
jsonschema          3.2.0
kiwisolver          1.2.0
markupsafe          1.1.1
matplotlib          3.2.1
mistune             0.8.4
mpl_toolkits        NA
nbconvert           5.6.1
nbformat            5.0.4
nt                  NA
ntpath              NA
nturl2path          NA
numpy               1.18.1
opcode              NA
pandas              1.0.3
pandocfilters       NA
parso               0.6.2
pickleshare         0.7.5
plotly              4.6.0
posixpath           NA
prompt_toolkit      3.0.5
pvectorc            NA
pweave              0.30.3
pydoc_data          NA
pyexpat             NA
pygments            2.6.1
pyparsing           2.4.7
pyrsistent          NA
pytz                2019.3
retrying            NA
sinfo               0.3.1
six                 1.14.0
sre_compile         NA
sre_constants       NA
sre_parse           NA
testpath            0.4.4
tornado             6.0.4
traitlets           4.3.3
wcwidth             NA
zipp                NA
zmq                 19.0.0
-----
IPython             7.13.0
jupyter_client      6.1.2
jupyter_core        4.6.3
notebook            6.0.3
-----
Python 3.7.6 | packaged by conda-forge | (default, Mar 23 2020, 22:22:21) [MSC v.1916 64 bit (AMD64)]
Windows-10-10.0.18362-SP0
4 logical CPU cores, Intel64 Family 6 Model 142 Stepping 9, GenuineIntel
-----
Session information updated at 2020-04-13 23:56
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy