Musings of a dad with too much time on his hands and not enough to do. Wait. Reverse that.

Tag: python (Page 24 of 26)

Watermarking Jupyter Notebooks

Watermarked content can be annoying, but I get it: you work hard on a product and you should get credit for it. At my job, I sometimes have the same challenges–I work hard on a report or product, hand it over to the co-worker who requested it, and he takes it to upper management passing the content off, either unintentionally or otherwise, as his own. If only I could in some way watermark my work to make it clear where it originated.

Since I do a fair amount of work these days in Jupyter Notebook, I decided to take this question there and came up with three approaches:

1. The traditional image file approach

The most common approach to watermarking a web page seems to be creating an image file with your watermark and referencing that image file in your CSS. In Jupyter Notebook, you can use the IPython API to load your CSS:


1
2
3
4
5
6
7
8
from IPython.core.display import HTML


HTML('<style type="text/css">'
    'div#notebook {'
    'background-image: url("dadoverflow_wm.png");'
    'background-repeat: repeat;}'
    '</style>')

(The full notebook is here)

Alternatively, you can use this clever custom.css approach so that your watermark loads automatically in all your notebooks without any extra coding on your part.

One big drawback to this solution is that if you hand off your notebook to your customer, that image file needs to go with it. If your customer wants to get rid of your watermark, all he has to do is throw away the image file. Bummer!

2. Base64 encode that image file

Files can be embedded in a web page, so to speak, by base64 encoding them and pasting the encoding right into your HTML. You can take this approach with your watermark and then never have to worry about the image file having to travel side-by-side with your notebook. Here, I first base64 encode my image file and then use the IPython API to shove my markup, including my base64, into the CSS:


1
2
3
4
5
6
7
8
9
10
11
12
13
import base64
from IPython.core.display import HTML


with open('dadoverflow_wm.png', 'rb') as f:
    encoded_string = base64.b64encode(f.read()).decode()
   
image_url = 'data:image/png;base64,{0}'.format(encoded_string)
HTML('<style type="text/css">'
    'div#notebook {'
    'background-image: url("' + image_url + '");'
    'background-repeat: repeat;}'
    '</style>')

(The full notebook is here)

Same deal as above, you can also paste that markup in a custom.css that all your notebooks will inherit. While this eliminates your dependence on that image file, base64 strings, like this one, are huge! It is not fun dealing with such things. Fortunately, there’s yet a better solution.

3. The SVG way

SVG tags are the continuum transfunctioners of HTML–their mystery is only exceeded by their power. But you can do amazing things with SVGs, watermarking your pages among them. Here, I don’t even need to rely on an image file, base64 encode or not. I simply adjust the properties of my SVG and TEXT tags as needed to get the effect I’m after:


1
2
3
4
5
6
7
8
9
10
from IPython.core.display import HTML


svg = ("<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='600px' width='600px'>"
       "<text x='-350' y='500' fill='lightgray' font-size='80' font-family='Arial' transform='translate(30) rotate(-45 0 0)'>DadOverflow.com</text></svg>")
HTML('<style type="text/css">'
    'div#notebook {'
    'background-image: url("data:image/svg+xml;utf8,' + svg + '");'
    'background-repeat: repeat;}'
    '</style>')

 

You can find all three of these examples in my GitHub page.

Posting code frustrations

Either I’m missing something or posting code snippets on WordPress sites is just not easy–or, at least, I haven’t yet stumbled upon the trick of it.  So far, I’ve posted PowerShell and Python code snippets and I’ve used the CodeColorer plugin to jazz up the snippets a little.  Initially, this worked fine with my PowerShell snippets:

1
2
3
$birth_date = [datetime]"3/29/1916"
$death_date = [datetime]"6/23/1984"
"Tom was {0} years old when he died" -f [math]::floor((new-timespan -start $birth_date -end $death_date).Days / 365.2425)

(I’m wrapping my code with the CodeColorer syntax [ccn lang=”powershell” width=”600″] )

However, Python depends heavily on tabbing to denote if statements, for loops, and so forth and this adds another level of complexity to the snippets you post.  In HTML, to properly preserve tabs and spacing in your code, you generally have to turn the pre tag.  So, for my Python snippets, I turned to both the CodeColorer plugin and the SyntaxHighlighter TinyMCE Button to wrap my snippets in appropriately styled “pre” tags and get this:


1
2
3
4
5
6
7
8
#the old surround-the-string-with-parentheses technique
qry1 = ('SELECT fname ' +
        ',lname ' +
        ',job_title ' +
        'FROM people')

curs.execute(qry1)
curs.fetchall()

(Here, I’m wrapping my snippet with this: <pre class=”brush: python; gutter: true; first-line: 1″>[ccn lang=”python” width=”600″])

What in the world is going on with the large gray box around my code?  It appears to be a background style setting connected to the pre tag, complements of the stylesheet my theme uses. Fortunately, WordPress has a custom CSS feature, so I should be able to overwrite this behavior.

It took me a few attempts, but this is custom CSS I came up with: .preforcode pre {background: transparent}

To implement my custom class, I wrapped my “pre” tag with a div, like so (note that I think all that brush…python stuff that the SyntaxHighlighter TinyMCE Button places in the class attribute of the pre tags is nonsense, so I just removed the attribute altogether):
<div class=”preforcode”><pre>[ccn lang=”python” width=”600″]


1
2
3
4
5
6
7
8
#the old surround-the-string-with-parentheses technique
qry1 = ('SELECT fname ' +
        ',lname ' +
        ',job_title ' +
        'FROM people')

curs.execute(qry1)
curs.fetchall()

Sweet! That gray box is gone! The padding around my snippet is still there: I guess that kind of makes my snippet pop out, but I might now have to mess around with that a little and eventually add any modifications I come up with to my custom CSS. At any rate, at least the snippet looks better so, going forward, hopefully my code snippets will look a little more appealing.

Dealing with Multi-line Strings in Python

Often, I’ll have to set a multi-line string in Python, such as a long SQL statement or friendly message of some sort.  It would be easy to write one, long string but that wouldn’t be very readable or maintainable–having to scroll horizontally to read the string–nor would it be compliant with PEP8.  So, what is a coder to do?  Well, fortunately, Python has a number of ways to skin this cat:

Option 1: Concatenate your strings with plus signs

Here, I just concatenate my individual lines together with the good ol’ plus sign:


1
2
3
4
qry1 = ('SELECT fname ' +
        ',lname ' +
        ',job_title ' +
        'FROM people')

Option 2: Concatenate your strings without the plus signs

Well, it turns out you don’t need the plus signs after all to concatenate your lines together:


1
2
3
4
qry2 = ('SELECT fname '
        ',lname '
        ',job_title '
        'FROM people')

Option 3: Use backslashes for line concatenation

Here, you don’t need to surround your strings with parentheses…just use the backslash to do the concatenation work:


1
2
3
4
qry3 = 'SELECT fname ' \
        ',lname ' \
        ',job_title ' \
        'FROM people'

Option 4: (my personal favorite) Surround your multi-line string with three double-quotes

This technique makes it very easy to read the content of your multi-line string:


1
2
3
4
5
6
qry4 = """
SELECT fname
    ,lname
    ,job_title
FROM people
"""

Bonus Option (Jupyter Notebook only): Use the sql_magic keyword

If you have a long SQL statement and are working in Jupyter Notebook, consider using the sql_magic keyword from Pivotal:


1
2
3
4
5
%%read_sql df_result -c conn
SELECT fname
    ,lname
    ,job_title
FROM people

Check out these examples in action on my Jupyter Notebook.

 

« Older posts Newer posts »

© 2025 DadOverflow.com

Theme by Anders NorenUp ↑