Using the Jupyter API

The code in this notebook will be executed by JavaScript using the Jupyter API. The docs for Jupyter itself aren't easy to navigate, but the API is identical to the older IPython project, so refer to https://github.com/ipython/ipython/wiki/Dev:-URL-mapping-of-IPython-notebook for details on all that's possible.


In [1]:
## We IF-GUARD this block because we do not want to include and load the data multiple times
if !isdefined(:df)
    using DataFrames
    using JSON
    df = readtable("data.csv");
    
    # Function to set histogram thresholds after dropping outliers based on IQR
    function getSymmetricThresholds(results::DataFrame; timer::Symbol=:timers_t_done)
        summary = summarystats(results[timer])
        fw  = (summary.q75-summary.q25)*1.5

        low = round(Int64, max(summary.min, summary.q25-fw))
        high = round(Int64, min(summary.max, summary.q75+fw))+1

        thresholds::Array{Int64, 1} = []

        nthresholds=25

        range = high - low

        for i in 0:nthresholds-1
            push!(thresholds, round(Int64, low + i * range/nthresholds))
        end

        push!(thresholds, high)
        if high < round(Int64, summary.max)
            push!(thresholds, round(Int64, summary.max))
        end

        return thresholds
    end
    
    thresholds = getSymmetricThresholds(df)

    groups = by(
        df,
        :user_agent_family, 
        rows -> DataFrame(
            count = size(rows, 1),
            median = median(rows[:timers_t_done]),
            hist = JSON.json(hist(rows[:timers_t_done], thresholds)[2])
        )
    )

    sort!(groups, rev=true, cols=[:count]);
end


Out[1]:
user_agent_familycountmedianhist
1Mobile Safari877754147.0[32,1018,4282,7212,8901,9018,7763,6621,5638,4906,4083,3472,2948,2340,2165,1890,1706,1601,1398,1157,1018,937,805,704,597,5562]
2Chrome530863129.0[65,2116,6133,7217,6356,5033,3894,3216,2735,2225,1788,1558,1398,1164,993,872,711,606,563,464,437,342,322,275,246,2357]
3IE353602862.0[30,1305,4636,5553,4614,3543,2714,2141,1811,1395,1151,971,782,688,581,412,350,335,274,253,201,186,156,106,93,1079]
4Chrome Mobile314776776.0[0,1,23,60,230,594,1106,1698,2232,2663,2709,2494,2268,2082,1793,1607,1356,1140,997,835,671,612,504,402,369,3031]
5Safari171162605.0[108,1339,2476,2686,2085,1532,1262,1032,875,598,424,385,366,310,199,180,171,122,110,74,55,72,65,36,42,512]
6Firefox119843412.0[14,372,1051,1392,1398,1255,1085,832,803,575,548,383,322,267,220,156,148,115,134,99,74,82,64,38,52,505]
7Edge61503187.0[3,151,632,843,800,633,513,434,353,272,225,182,149,122,104,88,72,74,54,42,62,39,43,26,24,210]
8Amazon Silk23237599.0[0,0,0,1,15,39,84,117,133,147,145,165,155,113,141,113,108,90,78,70,67,76,53,49,49,315]
9Chrome Mobile iOS19874257.0[0,22,86,184,182,198,179,132,107,101,82,69,60,48,42,36,37,39,39,37,26,21,18,31,17,194]
10Android Browser175211886.0[0,1,0,0,0,3,17,29,43,50,66,63,76,65,80,46,64,55,52,48,44,41,52,46,32,779]
11IE Mobile2266265.5[0,0,0,0,0,2,6,10,15,18,34,30,14,15,10,6,13,5,7,2,4,4,1,2,1,27]
12Firefox Mobile2048456.0[0,0,0,0,2,4,5,8,8,9,12,13,11,13,6,10,9,10,13,7,6,10,8,7,3,30]
13Opera12312211.0[0,0,1,2,2,4,9,6,3,5,4,4,4,1,4,1,4,1,2,0,1,0,3,2,1,59]
14Other864855.5[0,0,0,3,3,5,7,8,15,14,4,4,4,1,1,1,1,1,1,1,1,1,1,1,0,8]
15PhantomJS781660.5[0,7,27,26,10,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
16(Unknown)733740.0[0,1,8,9,6,5,7,5,0,2,1,2,4,0,0,3,1,5,3,1,2,2,0,1,0,5]
17BlackBerry WebKit438684.0[0,0,0,0,1,1,1,0,2,1,2,1,3,3,4,1,3,0,2,1,0,2,2,0,1,12]
18Chrome Frame374067.0[0,0,1,4,4,5,3,4,4,2,1,0,1,0,2,0,1,1,0,1,0,1,0,0,0,2]
19Pale Moon (Firefox Variant)184797.5[0,0,0,1,1,2,0,4,1,1,2,4,0,1,0,0,0,1,0,0,0,0,0,0,0,0]
20AOL154857.0[0,0,1,1,1,1,1,0,2,2,0,1,0,1,2,0,0,0,0,0,0,0,0,0,0,2]
21Yandex Browser138513.0[0,0,0,0,0,0,3,0,0,1,1,0,0,0,1,0,1,1,0,2,0,0,0,1,0,2]
22Halebot104654.0[0,0,0,2,1,1,0,0,2,1,0,0,1,0,0,0,0,2,0,0,0,0,0,0,0,0]
23Iron102738.0[0,0,0,1,3,3,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
24Firefox Beta910278.0[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,1,0,0,0,0,1,3]
25Opera Mobile912235.0[0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,2,0,3]
26Opera Mini73835.0[0,0,0,1,1,0,1,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
27Maxthon63961.0[0,0,0,0,1,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0]
28Chromium52772.0[0,0,0,0,2,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0]
29Puffin5922.0[0,4,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
30Opera Coast36091.0[0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0]
&vellip&vellip&vellip&vellip&vellip

Browser list

The code in this cell returns the list of browsers. We can use this to create a drop-down in our JavaScript. We print the output as JSON so that JavaScript can read it easily.

We add a token in a comment that our JavaScript can use to determine which cell to use for which widget


In [5]:
# browser-list-widget
JSON.json(groups[:user_agent_family])


Out[5]:
"[\"Mobile Safari\",\"Chrome\",\"IE\",\"Chrome Mobile\",\"Safari\",\"Firefox\",\"Edge\",\"Amazon Silk\",\"Chrome Mobile iOS\",\"Android Browser\",\"IE Mobile\",\"Firefox Mobile\",\"Opera\",\"Other\",\"PhantomJS\",\"(Unknown)\",\"BlackBerry WebKit\",\"Chrome Frame\",\"Pale Moon (Firefox Variant)\",\"AOL\",\"Yandex Browser\",\"Halebot\",\"Iron\",\"Firefox Beta\",\"Opera Mobile\",\"Opera Mini\",\"Maxthon\",\"Chromium\",\"Puffin\",\"Opera Coast\",\"UC Browser\",\"moatbot\",\"webOS Browser\",\"Firefox Alpha\",\"Nokia Services (WAP) Browser\",\"SeaMonkey\"]"

Data for a browser

We now define a function that takes in a browser name as a parameter and returns the data for it


In [23]:
function getBrowserData(;browser="%browser%")
    data = groups[groups[:user_agent_family] .== browser, :]
    
    if size(data, 1) == 0
        return "{}"
    end
    
    out = Dict(
        "browser" => data[1, :user_agent_family], 
        "count" => data[1, :count], 
        "median" => data[1, :median],
        "hist" => JSON.parse(data[1, :hist])
    )
    
    JSON.json(out)
end


Out[23]:
getBrowserData (generic function with 1 method)

Note that we use a Dict

A DataFrame is great for passing data between Julia functions, but because Julia data structures are columnar, converting this to JSON gives us a terribly unwieldy structure. It's better to convert to a Dict and then JSON encode that.

As part of our token comment, we also indicate which part of the cell can be replaced with text from JavaScript. In this case, the %browser% token can be replaced with the actual name of the browser. Note that this is a convention we've just invented, so feel free to use your own convention.


In [25]:
# browser-data-widget param=%browser%
getBrowserData(browser="%browser%")


Out[25]:
"{}"

In [ ]: