block by michalskop 712126d1f7843a22179f

Users' behaviour (answering VAA) - VolebníKalkulačka.cz

Full Screen

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
  font: 12px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}
.line {
  fill: none;
  stroke: #bbb;
  stroke-width: 1px;
  opacity: .5;
}
.line.active {
  stroke-width: 5px;
  stroke: #444;
  opacity: 1;
}
.quantile {
  fill: green;
  stroke: green;
}
.median {
  fill: red;
  stroke: red;
}
.info {
    background-color: #D9EDF7;
    border-color: #BCE8F1;
    color: #3A87AD;
    border: 1px solid rgba(0, 0, 0, 0);
    border-radius: 4px;
    margin-bottom: 20px;
    padding: 15px;
    position:absolute;
    top:0;
    left: 90px;
    max-width: 350px;
}
</style>
<div id="chart"></div>
<div class="info">
  Movement of <a href="//volebnikalkulacka.cz">Volební kalkulačka</a>'s users between questions (sample of about 1000 weekend users, 2014-05-09 18:43:56 - 2014-05-11 16:42:11); 1st attempt only when multiple attempts.
</div>

<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.6/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>

<script>

var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
    
var x = d3.scale.linear()
    .range([0, width])
    .domain([0,32]);
var y = d3.scale.linear()
    .range([height, 0])
    .domain([0,900]);
    
var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");
var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)
 .append("text")
  .attr("x", x(31))
  .attr("dx", ".71em")
  .style("text-anchor", "end")
  .text("Question");
  
svg.append("g")
  .attr("class", "y axis")
  .call(yAxis)
 .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("Time (seconds)");

svg.append("g")
  .attr("class", "y axis")
  .attr("transform", "translate(" + width + ",0)")
  .call(yAxis)
 .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("Time (seconds)");

var line = d3.svg.line()
    .x(function(d) { return x(d[1]); })
    .y(function(d) { return y(d[0]); });

d3.json("page.json", function(error, data) {
  i = 0;
  pdata = [];
  p30data = [];
  $.each(data, function(index, d) {
   if (i > 0 & i < 1100) {
   svg.append("path")
     .datum(d)
     .attr("d",line)
     .attr("class","line")
     .attr("title",d.name)
     .on("mouseover", function() {
          d3.select(this)
            .classed("active", true )
        })
     .on("mouseout",  function() {
          d3.select(this)
            .classed("active", false)
        });
   pdata.push(d[d.length-1]);
   }
   $.each(d, function (ii,dd) {
     if (dd[1] == 30)
       p30data.push(dd[0]);
   });
   i++; 
  });
 
  qd = [];
  md = [];
  md.push([d3.quantile(p30data.sort(function(a, b){return a-b}),0.5),30]);
  qd.push([d3.quantile(p30data.sort(function(a, b){return a-b}),0.75),30]);
  qd.push([d3.quantile(p30data.sort(function(a, b){return a-b}),0.25),30]);
  
  svg.selectAll('.ends')
    .data(pdata)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0]) })
    .attr("r", 1)

  svg.selectAll('.quantile')
    .data(qd)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0]) })
    .attr("class","quantile")
    .attr("r", 4)
  svg.selectAll('.median')
    .data(md)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0]) })
    .attr("class","median")
    .attr("r", 6)

});

</script>
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-8592359-13', 'ocks.org');
  ga('send', 'pageview');

</script>

page.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
  font: 12px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}
.line {
  fill: none;
  stroke: #bbb;
  stroke-width: 1px;
  opacity: .5;
}
.line.active {
  stroke-width: 5px;
  stroke: #444;
  opacity: 1;
}
.quantile {
  fill: green;
  stroke: green;
}
.median {
  fill: red;
  stroke: red;
}
.info {
    background-color: #D9EDF7;
    border-color: #BCE8F1;
    color: #3A87AD;
    border: 1px solid rgba(0, 0, 0, 0);
    border-radius: 4px;
    margin-bottom: 20px;
    padding: 15px;
    position:absolute;
    top:0;
    left: 90px;
    max-width: 350px;
}
</style>

<div id="chart"></div>
<div class="info">
  Movement of <a href="//volebnikalkulacka.cz">Volební kalkulačka</a>'s users between questions (sample of about 1000 weekend users, 2014-05-09 18:43:56 - 2014-05-11 16:42:11); 1st attempt only when multiple attempts.
</div>

<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.6/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>

<script>

var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 960 - margin.left - margin.right,
    height = 1000 - margin.top - margin.bottom;
    
var x = d3.scale.linear()
    .range([0, width])
    .domain([0,32]);
var y = d3.scale.linear()
    .range([height, 0])
    .domain([0,900]);
    
var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");
var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)
 .append("text")
  .attr("x", x(31))
  .attr("dx", ".71em")
  .style("text-anchor", "end")
  .text("Question");
  
svg.append("g")
  .attr("class", "y axis")
  .call(yAxis)
 .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("Time (seconds)");

svg.append("g")
  .attr("class", "y axis")
  .attr("transform", "translate(" + width + ",0)")
  .call(yAxis)
 .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("Time (seconds)");

var line = d3.svg.line()
    .x(function(d) { return x(d[1]); })
    .y(function(d) { return y(d[0]); });

d3.json("page.json", function(error, data) {
  i = 0;
  pdata = [];
  p30data = [];
  $.each(data, function(index, d) {
   if (i > 0 & i < 1100) {
   svg.append("path")
     .datum(d)
     .attr("d",line)
     .attr("class","line")
     .attr("title",d.name)
     .on("mouseover", function() {
          d3.select(this)
            .classed("active", true )
        })
     .on("mouseout",  function() {
          d3.select(this)
            .classed("active", false)
        });
   pdata.push(d[d.length-1]);
   }
   $.each(d, function (ii,dd) {
     if (dd[1] == 30)
       p30data.push(dd[0]);
   });
   i++; 
  });
 
  qd = [];
  md = [];
  md.push([d3.quantile(p30data.sort(function(a, b){return a-b}),0.5),30]);
  qd.push([d3.quantile(p30data.sort(function(a, b){return a-b}),0.75),30]);
  qd.push([d3.quantile(p30data.sort(function(a, b){return a-b}),0.25),30]);
  
  svg.selectAll('.ends')
    .data(pdata)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0]) })
    .attr("r", 1)

  svg.selectAll('.quantile')
    .data(qd)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0]) })
    .attr("class","quantile")
    .attr("r", 4)
  svg.selectAll('.median')
    .data(md)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0]) })
    .attr("class","median")
    .attr("r", 6)

});

</script>

page.py

# -*- coding: utf-8 -*-

# python 3

import csv
import json
import datetime

def label2values(s):
  li = s.split('-')
  if s == '':
    return False
  if li[0] == 'label':
    return int(li[1])
  if li[0] == 'load':
    return 0
  if li[0] == 'important':
    return False
  if li[0] == 'unload':
    return False
  if li[0] == 'header':
    return False
  if li[0] == 'submit':
    return 31
  if li[0] == 'indicator':
    return int(li[1])
  if li[0] == 'carousel':
    if li[2] == 'left':
      return -1
    elif li[2] == 'last':
      return 31
    else:
      return -2
  

tdata = {}
with open('click_page.txt','r') as f:
  csvreader = csv.reader(f,delimiter="\t")
  for row in csvreader:
    try:
      tdata[row[0]]
    except:
      tdata[row[0]] = []
    t = datetime.datetime.strptime(row[2],"%Y-%m-%d %H:%M:%S")
    q = label2values(row[3])
    if q is not False:
      tdata[row[0]].append([t,q])

sdata = tdata.copy()
for ksession in tdata:
  #print(ksession)
  try:
    start = sdata[ksession][0][0]
    #print(ksession,start)
    i = 0
    for row in sdata[ksession]:
      #print(row)
      row[0] = (row[0] - start).seconds
        
      if row[1] == -2:    #arrow right
        try:
          row[1] = sdata[ksession][i-1][1] + 1
          #print("i-2:",sdata[ksession][i-1])
        except:
          nothing = 0 #do not know what to do else
      if row[1] == -1:    #arrow left
        try:
          row[1] = sdata[ksession][i-1][1] - 1
          #print("i-1:",sdata[ksession][i-1])
        except:
          nothing = 0 #do not know what to do else
            
      #print (row)
      i = i + 1
  except:
    del(sdata[ksession])
#  raise(Exception,'')

# print(sdata)

# remove other trials
for ksession in sdata:
  i = 0
  rm = False
  for row in sdata[ksession]:
    if (row[1] == 0) and (row[0] > 100):
      rm = i
      #print(ksession)
      break
    i = i + 1
  if rm is not False:
    del sdata[ksession][rm:]

#differences
# first, make session->question = time
pdata = {}
for ksession in sdata: 
  pdata[ksession] = {}
  for row in sdata[ksession]:
    pdata[ksession][row[1]] = row[0]

ddata = {}
for ksession in pdata:
  ddata[ksession] = []
  print (ksession)
  for keyq in sorted(pdata[ksession]):
    try:
      ddata[ksession].append([pdata[ksession][keyq] - pdata[ksession][keyq - 1],keyq-1])
    except:
      nothing = 0 # more complicating, ignoring
  if len(ddata[ksession]) == 0:
    del ddata[ksession]

print('total number of sessions: ' + str(len(rawdata)))

#save files 
with open('page.json', 'w') as outfile:
  json.dump(sdata, outfile)
with open('page_diff.json', 'w') as outfile:
  json.dump(ddata, outfile)

page_diff.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}
.line {
  fill: none;
  stroke: #bbb;
  stroke-width: 2px;
  opacity: .1;
}
.line.active {
  stroke-width: 5px;
  stroke: #444;
  opacity: 1;
}
.quantile {
  fill: green;
  stroke: green;
}
.median {
  fill: red;
  stroke: red;
}
.info {
    background-color: #D9EDF7;
    border-color: #BCE8F1;
    color: #3A87AD;
    border: 1px solid rgba(0, 0, 0, 0);
    border-radius: 4px;
    margin-bottom: 20px;
    padding: 15px;
    position:absolute;
    top:0;
    left: 90px;
    max-width: 350px;
}
</style>

<div id="chart"></div>
<div class="info">
  Duration of <a href="//volebnikalkulacka.cz">Volební kalkulačka</a>'s users to answer questions (sample of about 1000 weekend users, 2014-05-09 18:43:56 - 2014-05-11 16:42:11); Showing medians and quartiles. Only 100 users shown by lines.
</div>

<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.6/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>

<script>

var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 1500 - margin.left - margin.right,
    height = 1000 - margin.top - margin.bottom;
    
var x = d3.scale.linear()
    .range([0, width])
    .domain([0,31]);
var y = d3.scale.linear()
    .range([height, 0])
    .domain([0,60]);
    
var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");
var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)
 .append("text")
  .attr("x", x(31))
  .attr("dx", ".71em")
  .style("text-anchor", "end")
  .text("Question");
  
svg.append("g")
  .attr("class", "y axis")
  .call(yAxis)
 .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("Time (seconds)");

var line = d3.svg.line()
    .x(function(d) { return x(d[1]); })
    .y(function(d) { return y(d[0]); });

d3.json("page_diff.json", function(error, data) {
  i = 0;
  pdata = [];
  qdata = {}
  $.each(data, function(index, d) {
   if (i > 500 & i < 600) {
   svg.append("path")
     .datum(d)
     .attr("d",line)
     .attr("class","line")
     .attr("title",d.name)
     .on("mouseover", function() {
          d3.select(this)
            .classed("active", true )
        })
    .on("mouseout",  function() {
          d3.select(this)
            .classed("active", false)
        });
   }
   $.each(d, function (ii,dd) {
     pdata.push(dd);
     if (typeof(qdata[dd[1]]) == "undefined"){
       qdata[dd[1]] = []
     }
     qdata[dd[1]].push(dd[0]);
   });
   //}
   i++; 
  });
  qd = [];
  md = [];
  $.each(qdata, function(i,d) {
    md.push([d3.quantile(d.sort(function(a, b){return a-b}),0.5),parseInt(i)]);
    qd.push([d3.quantile(d.sort(function(a, b){return a-b}),0.75),parseInt(i)]);
    qd.push([d3.quantile(d.sort(function(a, b){return a-b}),0.25),parseInt(i)]);
  });
  
  
  svg.selectAll('.ends')
    .data(pdata)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0] + Math.random() -0.5) })
    .attr("r", 1)
    
  svg.selectAll('.quantile')
    .data(qd)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0]) })
    .attr("class","quantile")
    .attr("r", 4)
  svg.selectAll('.median')
    .data(md)
    .enter().append('circle')
    .attr("cx", function(d) {return x(d[1]) })
    .attr("cy", function(d) {return y(d[0]) })
    .attr("class","median")
    .attr("r", 6)
});

</script>