Yaakulya’s Assignment 4: Loading Data & Displaying text

Concept: I always wanted to understand the graphs and math revolve behind Real Estates, so for my Data Visualization assignment, I created a data visualization using the Boston Housing dataset. (Dataset URL: https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv)
This Dataset is available to public.

The resultant visualization displays the relationship between the average number of rooms per dwelling (RM) and the median home value ($1000s) for various suburbs in Boston. Each data point on the graph represents a suburb, with the x-axis indicating the average number of rooms and the y-axis indicating the median home value. Additionally, I implemented an interactive tooltip that provides detailed information about each data point when the user hovers over it, including the suburb name, crime rate, and median home value.

To make my concept work, I found inspiration from these sources and moreover I learnt a lot about attributes and functions used for loading the required data from the datasets precisely:

Highlight of Code: One part of the code that I’m particularly proud of is the implementation of the interactive tooltip, initially I found it very difficult. This feature enhances the user experience by providing additional information about the data points in a user-friendly manner. Here’s the code snippet responsible for displaying the tooltip:

function draw() {
  // Check if mouse is over a data point
  let overPoint = false;
  for (let i = 0; i < data.getRowCount(); i++) {
    let rm = map(data.getNum(i, 5), 3, 9, 100, width - 100);
    let medv = map(data.getNum(i, 13), 5, 50, height - 100, 100);
    let d = dist(mouseX, mouseY, rm, medv);
    if (d < 5) {
      overPoint = true;
      let suburb = data.getString(i, 0);
      let crimeRate = data.getNum(i, 1);
      let medianValue = data.getNum(i, 13);
      tooltip.html(`Suburb: ${suburb}<br>Crime Rate: ${crimeRate.toFixed(2)}<br>Median Home Value: $${medianValue.toFixed(2)}k`);
      tooltip.position(rm + 20, medv - 20);
      tooltip.show();
      break;
    }
  }
  if (!overPoint) {
    tooltip.hide();
  }
}

Explanation – How this Interactive feature works?: In the draw() function, which updates the canvas continuously, the code iterates through each data point in the dataset. It calculates the distance between the mouse cursor position and the position of each data point using the dist() function. If this distance is within a threshold of 5 pixels, indicating that the mouse is hovering over a data point, the code retrieves information such as suburb name, crime rate, and median home value using functions like getString() and getNum(). These functions extract specific values from the dataset based on row and column indices. The tooltip’s content is then updated to display this information, and its position is adjusted slightly from the data point using the position() function. Finally, the tooltip is shown to the user with show(). If the mouse is not over any data point, the tooltip is hidden using hide(). This process allows for interactive display of detailed information when the user hovers over data points on the visualization.

Complete Embedded Sketch:

let data;
let tooltip;

function preload() {
  // Load the Boston Housing dataset
  data = loadTable('https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv', 'csv', 'header');
}

function setup() {
  createCanvas(800, 600);
  background(240);

  // Plot the data points with black color
  for (let i = 0; i < data.getRowCount(); i++) {
    let rm = map(data.getNum(i, 5), 3, 9, 100, width - 100);
    let medv = map(data.getNum(i, 13), 5, 50, height - 100, 100);

    fill('rgb(197,134,88)'); // Change color to black
    noStroke();
    ellipse(rm, medv, 10, 10);
  }

  // Add x and y axes
  drawAxes();

  // Add interactive tooltip
  tooltip = createDiv('');
  tooltip.style('position', 'absolute');
  tooltip.style('background-color', 'rgba(255, 255, 255, 0.8)');
  tooltip.style('padding', '8px');
  tooltip.style('border-radius', '4px');
  tooltip.hide();


}

function drawAxes() {
  // Draw x-axis
  stroke(0);
  line(100, height - 100, width - 100, height - 100);
  for (let i = 4; i <= 9; i++) {
    let x = map(i, 3, 9, 100, width - 100);
    textAlign(CENTER, CENTER);
    textSize(12);
    fill(0);
    text(i, x, height - 80);
  }
  textAlign(CENTER, CENTER);
  textSize(16);
  fill(0);
  text('Average Number of Rooms per Dwelling (RM)', width / 2, height - 40);

  // Draw y-axis
  stroke(0);
  line(100, 100, 100, height - 100);
  for (let i = 5; i <= 50; i += 5) {
    let y = map(i, 5, 50, height - 100, 100);
    textAlign(RIGHT, CENTER);
    textSize(12);
    fill(0);
    text(i, 90, y);
  }
  textAlign(CENTER, CENTER);
  textSize(19);
  fill(0)
  text('Boston Housing Dataset Visualization (Year:1970-2006)', 400, 40);
  rotate(-HALF_PI);
  textSize(16);
  text('Median Home Value ($1000s)', -height / 2, 50);
}

function draw() {
  // Check if mouse is over a data point
  let overPoint = false;
  for (let i = 0; i < data.getRowCount(); i++) {
    let rm = map(data.getNum(i, 5), 3, 9, 100, width - 100);
    let medv = map(data.getNum(i, 13), 5, 50, height - 100, 100);
    let d = dist(mouseX, mouseY, rm, medv);
    if (d < 5) {
      overPoint = true;
      let suburb = data.getString(i, 0);
      let crimeRate = data.getNum(i, 1);
      let medianValue = data.getNum(i, 13);
      tooltip.html(`Suburb: ${suburb}<br>Crime Rate: ${crimeRate.toFixed(2)}<br>Median Home Value: $${medianValue.toFixed(2)}k`);
      tooltip.position(rm + 20, medv - 20);
      tooltip.show();
      break;
    }
  }
  if (!overPoint) {
    tooltip.hide();
  }
}

Generated Output:

Reflection and Ideas for Future Work: Overall, I’m satisfied with how the assignment turned out. The visualization effectively communicates the relationship between the number of rooms in a dwelling and the median home value in different suburbs of Boston. The interactive tooltip adds an extra layer of interactivity and information, enhancing the user experience.

For future work or improvements, I could consider adding more features to the visualization, such as:

1. Implementing color encoding for an additional variable, such as crime rate or pupil-teacher ratio, to provide more insights into the data.

2. Enhancing the design of the visualization by adding axis labels, a title, and a legend to improve clarity and understanding.

3. Exploring different types of visualizations, such as scatter plots or line charts, to represent the data in alternative ways and uncover additional patterns or trends in addition working with latest datasets.

Overall, this assignment has been a valuable learning experience, and I look forward to applying these skills to future assignments ad projects.

Related P5 References:
1. https://p5js.org/reference/#/p5/map
2. https://p5js.org/reference/#/p5.Element/style
3. https://p5js.org/reference/#/p5.Table/getNum
4. https://p5js.org/reference/#/p5.Element/hide
5. https://p5js.org/reference/#/p5.Element/position
6. https://p5js.org/reference/#/p5.Table/getString

Leave a Reply