<jupyter_start><jupyter_text>Tour of the EvCxR Jupyter KernelFor those not already familiar with Jupyter notebook, it lets you write code into "cells" like the box below. Cells can alternatively contain markdown, like this text here. Each code cell is compiled and executed separately, but variables, defined functions etc persist between cells. Printing to outputs and evaluating expressionsLets print something to stdout and stderr then return a final expression to see how that's presented. Note that stdout and stderr are separate streams, so may not appear in the same order is their respective print statements.<jupyter_code>println!("Hello world");
eprintln!("Hello error");
format!("Hello {}", "world")<jupyter_output>Hello error<jupyter_text>Assigning and making use of variablesWe define a variable `message`, then in the subsequent cell, modify the string and finally print it out. We could also do all this in the one cell if we wanted.<jupyter_code>let mut message = "Hello ".to_owned();
message.push_str("world!");
message<jupyter_output><empty_output><jupyter_text>Defining and redefining functionsNext we'll define a function<jupyter_code>pub fn fib(x: i32) -> i32 {
    if x <= 2 {0} else {fib(x - 2) + fib(x - 1)}
}
(1..13).map(fib).collect::<Vec<i32>>()<jupyter_output><empty_output><jupyter_text>Hmm, that doesn't look right. Lets redefine the function. In practice, we'd go back and edit the function above and reevalute it, but here, lets redefine it in a separate cell.<jupyter_code>pub fn fib(x: i32) -> i32 {
    if x <= 2 {2} else {fib(x - 2) + fib(x - 1)}
}
let values = (1..13).map(fib).collect::<Vec<i32>>();
values<jupyter_output><empty_output><jupyter_text>Spawning a separate thread and communicating with itWe can spawn a thread to do stuff in the background, then continue executing code in other cells.<jupyter_code>use std::sync::{Mutex, Arc};
let counter = Arc::new(Mutex::new(0i32));
std::thread::spawn({
    let counter = Arc::clone(&counter);
    move || {
        for i in 1..300 {
            *counter.lock().unwrap() += 1;
            std::thread::sleep(std::time::Duration::from_millis(100));
        }
}});
*counter.lock().unwrap()
*counter.lock().unwrap()<jupyter_output><empty_output><jupyter_text>Loading external cratesWe can load external crates. This one takes a while to compile, but once it's compiled, subsequent cells shouldn't need to recompile it, so it should be much quicker.<jupyter_code>extern crate base64;
base64::encode(&vec![1, 2, 3, 4])<jupyter_output><empty_output><jupyter_text>Customizing how types are displayedWe can also customize how our types are displayed, including presenting them as HTML. Here's an example where we define a custom display function for a type `Matrix`.<jupyter_code>use std::fmt::Debug;
pub struct Matrix<T> {pub values: Vec<T>, pub row_size: usize}
impl<T: Debug> Matrix<T> {
    pub fn evcxr_display(&self) {
        let mut html = String::new();
        html.push_str("<table>");
        for r in 0..(self.values.len() / self.row_size) {
            html.push_str("<tr>");
            for c in 0..self.row_size {
                html.push_str("<td>");
                html.push_str(&format!("{:?}", self.values[r * self.row_size + c]));
                html.push_str("</td>");
            }
            html.push_str("</tr>");            
        }
        html.push_str("</table>");
        println!("EVCXR_BEGIN_CONTENT text/html\n{}\nEVCXR_END_CONTENT", html);
    }
}
let m = Matrix {values: vec![1,2,3,4,5,6,7,8,9], row_size: 3};
m<jupyter_output><empty_output><jupyter_text>We can also return images, we just need to base64 encode them. First, we set up code for displaying RGB and grayscale images.<jupyter_code>extern crate image;
extern crate base64;
pub trait EvcxrResult {fn evcxr_display(&self);}
impl EvcxrResult for image::RgbImage {
    fn evcxr_display(&self) {
        let mut buffer = Vec::new();
        image::png::PNGEncoder::new(&mut buffer).encode(&**self, self.width(), self.height(),
            image::ColorType::RGB(8)).unwrap();
        let img = base64::encode(&buffer);
        println!("EVCXR_BEGIN_CONTENT image/png\n{}\nEVCXR_END_CONTENT", img);        
    }
}
impl EvcxrResult for image::GrayImage {
    fn evcxr_display(&self) {
        let mut buffer = Vec::new();
        image::png::PNGEncoder::new(&mut buffer).encode(&**self, self.width(), self.height(),
            image::ColorType::Gray(8)).unwrap();
        let img = base64::encode(&buffer);
        println!("EVCXR_BEGIN_CONTENT image/png\n{}\nEVCXR_END_CONTENT", img);        
    }
}
image::ImageBuffer::from_fn(256, 256, |x, y| {
    if (x as i32 - y as i32).abs() < 3 {
        image::Rgb([0, 0, 255])
    } else {
        image::Rgb([0, 0, 0])
    }
})<jupyter_output><empty_output><jupyter_text>Display of compilation errorsHere's how compilation errors are presented. Here we forgot an & and passed a String instead of an &str.<jupyter_code>let mut s = String::new();
s.push_str(format!("foo {}", 42));<jupyter_output><empty_output><jupyter_text>Seeing what variables have been definedWe can print a table of defined variables and their types with the :vars command.<jupyter_code>:vars<jupyter_output><empty_output><jupyter_text>Other built-in commands can be found via :help<jupyter_code>:help<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13199399173864063, 'fraction_numerical': 0.016522718738265114, 'mean_word_length': 4.192007797270955, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '30801', 'license': 'Apache-2.0', 'n_tokens_mistral': 1761, 'n_tokens_neox': 1687, 'n_words': 512, 'path': 'evcxr_jupyter/samples/evcxr_jupyter_tour.ipynb', 'repo_name': 'codedownio/evcxr', 'size': '5326'}