<jupyter_start><jupyter_text>Note: You can see some Jupyter shortcuts at https://www.dataquest.io/blog/jupyter-notebook-tips-tricks-shortcuts/  IntroductionA one-step at a time introduction to using D3 in JupyterFirst, start with: what is DOM? -> https://www.w3schools.com/whatis/whatis_htmldom.asp<jupyter_code>from IPython.core.display import HTML
HTML('''
<h3>Hello DOM!</h3>
''')<jupyter_output><empty_output><jupyter_text>We can set style by setting a class to HTML object<jupyter_code>HTML('''
<style>
.steely {
  color: steelblue;
  font: 10px script;
}
</style>
<h2 class="steely">Hello DOM!</h2>
''')<jupyter_output><empty_output><jupyter_text>Javascript allow us to modify the DOM<jupyter_code>HTML('''
<style>
.steely {
  color: steelblue;
  font: 10px script;
}
</style>
<h2 class="steely" id="steely-DOM">Hello DOM!</h2>
<script>$("#steely-DOM").text("Hello JavaScript!!")</script>
''')<jupyter_output><empty_output><jupyter_text>---------  D3.jsStands for Data-Driven DocumentsD3.js is a Javascript library that allow us to modify the DOM with data. We can either use the online version of the library hosted at `https://d3js.org/d3.v3.min.js` or download the file locally. In our case, we have it in the folder lib.<jupyter_code># import the library - min.js refers to the minimized (unnecessary characters have been removed,)
HTML('<script src="lib/d3/d3.v3.min.js"></script>')<jupyter_output><empty_output><jupyter_text>We can create a template such that we are able to easily change our css or javascript files<jupyter_code>from string import Template
from IPython.core.display import HTML

html_template = Template('''
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    <title>D3 Example</title>
    <script src="lib/d3/d3.v3.min.js"></script>
    <style type="text/css"> $css_text </style>
</head>
<body>
<svg width="800" height="600" style="border:1px solid black">
    <!-- <rect x="10" y="10" width="100" height="100" fill="red" />  -->
    <text id="details" x="50" y="50">Hello D3</text>
</svg>

<script type="text/javascript"> $js_text </script>
</body>
''')

css_text = '''
.dots {
    fill: steelblue;
    fill-opacity: 0.75;
    stroke: none;
}

.highlight {
    fill: orange;
}
'''<jupyter_output><empty_output><jupyter_text>The general update pattern is used in pretty much every visualization that you’ll want to build with D3. It defines the behavior of elements in our data that should enter, update, or exit the screen.First, we’re binding our new array of data to our D3 selection:<jupyter_code>js_text = '''
console.log(data);

// JOIN new data with old elements.
var circles = d3.select("svg").selectAll("circle")
    .data(data); // bind the data to the circles.
'''<jupyter_output><empty_output><jupyter_text>Next, this block of code will remove all the dots that no longer exist in our new array of data:<jupyter_code>js_text += '''
// EXIT old elements not present in new data.
circles.exit().remove()
'''<jupyter_output><empty_output><jupyter_text>Here, we’re updating the position of all the dots on the screen that still exist in our new data array. Each of the SVG shapes have their own set of attributes (see https://www.dashingd3js.com/svg-basic-shapes-and-d3js). To change the position of a circle, we use `cx` and `cy`.<jupyter_code>js_text += '''
// Use scale.linear to map data to pixels:
xscale = d3.scale.linear().domain([0, 5.5]).range([0, 800]);
yscale = d3.scale.linear().domain([0, 10]).range([600, 0]);
    
// UPDATE old elements present in new data.
circles
    .attr("cx", function(d){ return xscale(d.x_val) })
    .attr("cy", function(d){ return yscale(d.y_val) })
'''<jupyter_output><empty_output><jupyter_text>Finally, we’re adding a dot for every item in our new data array that doesn’t have a corresponding circle on the screen.<jupyter_code>js_text += '''
// Use scale.linear to map data to pixels:
xscale = d3.scale.linear().domain([0, 5.5]).range([0, 800]);
yscale = d3.scale.linear().domain([0, 10]).range([600, 0]);

// ENTER new elements present in new data.
circles.enter()
    .append("circle") // for data that does not have an existing circle,
    .attr("class", "dots") // style sheet, see above
    .attr("cx", function(d){ return xscale(d.x_val) })
    .attr("cy", function(d){ return yscale(d.y_val) })
    .attr("r", 5)
    .attr("fill", "grey");
'''<jupyter_output><empty_output><jupyter_text>With templates, we can insert Python variables<jupyter_code>js_text_template = Template('''
var data = $data;
''' + js_text)
import pandas as pd 
import json, random
data = pd.DataFrame({'x_val': [0.5,1,1.5,2,2.5,3,3.5,4,4.5], 'y_val': [1,2,3,4,5,6,7,8,9]})
data.head()
js_text = js_text_template.substitute({'data': json.dumps(data.to_dict(orient='records'))})
HTML(html_template.substitute({'css_text': css_text, 'js_text': js_text}))
data['y_val'] = [random.uniform(0,10) for d in data['y_val']]
js_text = js_text_template.substitute({'data': json.dumps(data.to_dict(orient='records'))})
HTML('<script>' + js_text + '</script>')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.16117577431446045, 'fraction_numerical': 0.022489642927599134, 'mean_word_length': 5.086434573829532, 'pattern_counts': {'":': 0, '<': 76, '<?xml version=': 0, '>': 77, 'https://': 4, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '116861', 'license': 'MIT', 'n_tokens_mistral': 1841, 'n_tokens_neox': 1778, 'n_words': 495, 'path': '1. Intro - HTML, DOM, js & D3.js.ipynb', 'repo_name': 'arodriguezca/d3-jupyter-tutorial', 'size': '5069'}