Lambda Labs: Class is Over

Ashley Bergsma
9 min readNov 19, 2020

I’d done it — finished the core Lambda Curriculum — I’d learned more about CSS and html, went through a rollercoaster relationship with javascript (we’re still a bit on-and-off), gotten my hands dirty in React and had even started to acquaint myself with the mysteries of computer science. I was moving into Labs, Lambda’s way of providing students with a more real-world project by working in teams for a month. Each of the projects have real-world stakeholders that bring their proposals to the students, who work to make their vision a reality.

On Friday afternoon, after finishing the last Sprint of my Computer Science module, I found out I was assigned to one of several teams working with a stakeholder from Human Rights First. Human Rights First (or HRF) was founded in 1978, originally known as the Lawyers Committee for International Human Rights, the foundation has worked for more than 40 years to defend human rights worldwide.

The task was to provide HRF with an app that allowed users to interactively view statistics on police use of force, and ultimately police brutality, in the United States. I read the project roadmap, and the goals the stakeholder had outlined for us, thinking of all the ways I could use what I had learned to accomplish them.

Thinking on the project over the weekend I didn’t realize that I was making a few assumptions about the data we would be working with. For one, I thought this kind of data would be readily available. Naively, I assumed that police municipalities had to file reports when an officer had an altercation with a civilian, especially if that altercation resulted in death.

The next Monday, meeting in our groups and setting our eyes on some code, it became quickly apparent that my assumptions were wrong. I learned that this kind of data was scarce. Even the FBI didn’t start concretely collecting this data until January 2019, and participation in reporting is up to the state and the municipality. You can read more about that here.

The available data was coming from the Washington Post, an isolated set of data recording the number of US citizens killed by police shooting since January 2015. We weren’t sure where the data was being collected from, and what parameters an incident had to have (or not have) to be included in the set.

As the data science and backend teams worked to close the gap, our 3 person frontend team (including myself) began talking about UI and functionality. Did it make sense to incorporate user accounts? How could we visualize the data we had responsibly and professionally? What had the previous group done that we liked? What did we want to change and why?

From the beginning we decided that we wanted to make the switch from MapBox to amCharts for data visualization. Our goal was to display data that relied heavily on pure numbers, a task that amCharts is built for. MapBox is a library made for highly detailed custom map creation, it’s hyper-concerned with location, a feature we didn’t need and slowed down our app. amCharts also gave us a wider range of tools for different types of visualization — pie charts, line graphs, multi-layered bar graphs and more.

Building User Stories

Creating user stories is a tool used by developers to help get us talking about the steps that need to be taken to build a piece of UI and its functionality. Putting together a collection user stories helps the team stay on track through the rest of the process, slows regression, and impedes extra tasks from being added before others have been solved for.

My group set out with a lot of user stories, they included:

  • As a user I want to be able to navigate the map without excessive clicking, or loading time
  • As a user I want to be able to narrow down the data I’m looking for
  • As a user I want to know that the data I’m viewing is verified

Some of the stories we wrote were simple, without much plot — novellas that can be worked through in an afternoon. Others were deceivingly hefty, hard to understand, and harder to begin solving for. I first got to work on this user story: “As a user I want to visualize types of force being used in different areas/communities.”

Trello Board card

At first, we kept the map from the previous group, taking time to actually learn how to incorporate amCharts into the project, and safely excise MapBox once we were comfortable to do so before removing it.

Pouring over the docs for amCharts I saw there wasn’t much information on using the library inside a React app. The examples they did have used class components (which we had decided as a group to forego using), and the rest of the examples were done using JavaScript and HTML. Knowing what I did about JSX, I was confident that with some trial and error we could start to learn and apply amCharts.

Dedicated to the Docs

To start I built a Bar Graph component — the goal of this component was to allow the user to visually see comparative data, like how many incidents a state reported in a year compared to a specific city. The bar graph is actually done using the XYChart class of charts, and it can visualize a seemingly endless amount of data concurrently.

My first struggle was with rendering the chart in a React-ive way. The examples on the amCharts docs show the graphs being instantiated in a hook called useLayoutEffect. I didn’t know much about this hook, but after some research I learned that it’s similar to our old friend, useEffect, but it differs in that it runs synchronously, painting the charts after DOM mutations have occurred.

Some sources recommended still following convention and trying to get a chart to operate using useEffect, reverting to useLayoutEffect only after there were unfixable problems. Though I attempted rendering the chart in a useEffect hook, I never got one working correctly. Some never rendered, and others rendered but their functionality was buggy at best, and non-existant at worst.

Because the charts use a lot of JavaScript-developer friendly terminology, learning to add and manipulate chart series’ is a cinch. For example, when you create a new Series class (a series is wrapper for the data — a column, a line, a wedge in a pie chart, etc) you push it onto the parent Chart class.

To make things even cleaner, a lot of ‘desired’ functionality comes default to a chart and series (like the click events on legend tags, and wedges), and many events are handled directly on the classes themselves. The things you can ask for are easily set up.

let series2 = chart.series.push(new am4charts.ColumnSeries());  
series2.dataFields.valueY = "sales2";
series2.dataFields.dateX = "date";
series2.yAxis = valueAxis1;
series2.name = "Sales";
series2.tooltipText = "{name}\\n[bold font-size: 20]${valueY}M[/]";
// ^ applies a tool tip text box that appears when you hover!

series2.fill = chart.colors.getIndex(1).lighten(0.5);
series2.strokeWidth = 0;
series2.clustered = false;
series2.toBack();

Squashing Bugs & Finding the Group’s Mentality

Working in a group is a part of every developer’s life, and should be something they push themselves to become more comfortable doing as time goes on. I’ve always considered myself a natural introvert, but I still love people, and the things that are possible when people come together, so I make an effort to push myself outside of my comfort zone regularly.

I was lucky with this group — the majority of my peers were dedicated to the project, and the process of working as a team to solve a problem. The frontend team was made up of myself and 2 other knowledgeable, driven developers. We communicated on a daily basis during the work week, and made time to solve problems together.

The first problem I came up against related to the charts — by the time we had a few charts in the project, we were seeing a console error alerting us that they were not being properly disposed of. After doing some research I found some context about Refs in the realm of React.

Though using refs is kind of conventionally discouraged in React (it’s not very React-ive after all), it can be necessary for disposing of some components, and is necessary to apply focus. I knew from reading the amCharts docs that charts that wanted to use the zoom functionality required access to browser focus. Ah-ha! I’d cracked it.

Pie Chart with refs

To prevent this problem I had to use another hook, useRef, to give each chart a reference (essentially a reference to itself) so the DOM knew what to get rid of when a chart wasn’t needed any longer, or had a state change!

Another problem that started to cause bug sometimes (and not other times) related to the use of the amCharts core theme package. To start we had been instantiating the use of a theme inside its hook — moving that above the component itself, and making sure it wasn’t declared anywhere it wasn’t actually being used, seemed to fix the problem.

Our biggest problem still resided with the data — and what displaying it could mean. You may be familiar with the rumor that Florida has a lot of crazy people responsible for a lot of crazy crimes. We see the stories in the news (like a man consuming the face of another) and say “Only in Florida.” But the truth is Florida doesn’t have any more or less than its fair share of crime, or rates of mental illness.

What they do have are a series of laws known collectively as the Sunshine Law, that hold the Florida government responsible for maintaining public records of government activity on all levels, including police activity. We hear more about Florida crime because their government is more transparent.

As a team, we worried that representing this data (mostly provided by states that participated in transparent efforts to report their police violence) would wrongfully villainize certain locales and municipalities.

Passing the Scroll…

There are a million quotes about how fleeting time is — and you never have as much as you think. Before I knew it we were writing documentation and preparing the project to be picked up by another set of hands, the month had passed. The current state of our project isn’t what we had ambitiously imagined in the beginning, but it’s a living thing, hopefully another group of developers can get it that much closer to what the stakeholder imagined.

The DS and backend teams did loads of work to try and provide more data — and have started the arduous work of painting a bigger, more complete picture. The frontend team contributed clean, functional UI. The incidents cards allow a user to see the reports we do have, and read the attached information about each. The fatality cards allow us to share the names and faces of victims of police brutality, and search through the cards with filters. To visualize statistics we built a map, bar graph, pie chart, and another class of chart, a pyramid. Currently they are being used to display static collections of data, specifically the WAPO data — connecting them to the backend should be the next goal.

Another developer on the frontend team did a beautiful job designing a UI that used the HRF’s existing color scheme. The kind of data we were displaying demanded a theme that was low-key, and professional, there wasn’t room for zinger animations and cartoonish svgs. The stakeholder was pleased with her take on the task, and suggested adding to it with a color coding system for cards. This is a task another team could take on with ease.

In the end I walked away with more experience working in a group, gained confidence learning something new and uncomfortable, and built usable pieces of UI capable of meaningful, scalable growth. I didn’t get everything done that I set out to, or thought I would. I struggled with confidence as my peers contributed line after line of code, and submitted PRs, and feeling that I was falling behind. I anguished over the stress of balancing this work with building a resume and portfolio, and maintaining balance at home. But I came out better for it — I learned to face those feelings by pushing myself to continue at my pace, and to give the self-doubt a little less time in the spotlight.

--

--

Ashley Bergsma

I’m Ash, a developer with a passion for web design, accessibility, and learning!