The goal of this project is to create a set of interactive and dynamic data visualizations using 311 call data from the City of Cincinnati's website allowing users to analyze and explore the data. This web app consists of an interactive Leaflet map with several viewing options and D3-powered visualizations such as bar charts, timelines, and histograms.
The project was developed using primarily JavaScript, HTML, and CSS and can be run locally by cloning the main branch of the GitHub repository and opening the index.html file in a web browser. The 311 call data was obtained from the City of Cincinnati's website, and the visualizations were created using Leaflet and D3.js.
The Leaflet and D3-powered interactive map displays 2022 Cincinnati 311 call data with several advanced features, such as a full-screen button, seamless map layer switching, and a brush tool to select specific data points. It also includes an interactive and filterable legend, multiple color scales for the data, a heat map, and tooltips for each individual data point. The map also updates if a filter is applied in any other visualization.
The timeline and histogram are were both created using D3 and feature interactive tooltips, a D3 brush for selecting specific data points, and an "Apply Filter" button to update the rest of the visualizations on the screen. The timeline shows calls over time while the histogram breaks it down into intervals, offering a more detailed view of the response time for calls. With these data visualizations, users can quickly identify patterns and trends in the 311 call data, making it easier to explore and analyze the information.
The D3 bar charts visualize Cincinnati's 311 Call data from 2022, with three separate charts showing calls by day of the week, responding agency, and ZIP code. Each chart features animated bars and tooltips for detailed information on each data point. Users can to apply filters by selecting individual bars or bar labels. By selecting multiple bars/labels, users can apply multiple filters. To remove a filter, click the selected bar/label again.
To use this web application, visit the latest deployment or clone the GitHub repo and open the index.html file in a web browser. The data should be automatically loaded and the visualizations should appear on the screen.
The Leaflet map is the main focus of this project. To change the map's background layer, select "Terrain," "Streets," or "Satellite" using the dropdown box in the top right corner. The data will appear as markers on the map, and users can create a selection using the brush, which can be enabled or disabled with the "Toggle Brush" button. The map also provides multiple views and color scales of the data based on call type, response time, time of year, or responding agency. Additionally, the call type and responding agency views have a filterable legend and the map includes a heatmap option.
To filter the data, users can click on any bar or label in the barcharts, use the map brush to make a selection, or apply a filter from the timeline or histogram. Once a filter or selection has been applied, all the visualizations will update to show only the data included in that filter. Users can apply multiple filters, and remove filters by clicking on a bar or label again or using the "Reset Charts" button. For example, if after clicking the "Park Department" bar or label in the Responding Agency barchart, the visualizations will update to only show 311 calls that were responded to by the Parks Department.
After applying a filter or selection, use the "Reset Charts" to remove all filters. Clicking the button will reset the data to include all 311 calls and refresh all visualizations. The reset button will then be disabled until another filter or selection is applied.
This web app utilizes 311 non-emergency call data obtained from the City of Cincinnati's website. The data includes a unique identifier for each request (SERVICE_REQUEST_ID), its current status (STATUS), the name of the requested service (SERVICE_NAME), its corresponding code (SERVICE_CODE), and a description of the issue (DESCRIPTION). The agency responsible for addressing the service request (AGENCY_RESPONSIBLE) and the date and time the request was submitted (REQUESTED_DATETIME) and last updated (UPDATED_DATETIME) are also included in the data.
Additionally, the data provides information about the expected completion time of the service request (EXPECTED_DATETIME), the address of the location where the service is requested (ADDRESS), and its corresponding zip code (ZIPCODE), as well as the latitude (LATITUDE) and longitude (LONGITUDE) coordinates of the location. The requested date (REQUESTED_DATE), updated date (UPDATED_DATE), and last table update date (LAST_TABLE_UPDATE) are also included in the data.
This project was made using D3, a JavaScript library used for creating interactive visualizations and data-driven graphics. D3 allows data to be bound to HTML, SVG, and CSS elements and manipulation to occur based on data links and brushes. Each of the visual components described above were made through D3 and SVG elements. Although many of the visual components appear to be similar in appearance and functionality, unique facets of the charts required modular coding practices to be utilized. The declaration of each chart was hosted within the project HTML file. Next, CSS was used to apply styling for each element, and ensure its visual appearance. The main JavaScript file preprocessed all of the data and supplied the appropriate values to each chart declaration. From here, a unique class was defined for each component, allowing distinct functionality to be established for every chart. Below is an example of this general coding practice for the line chart:
The above code snippet defines the container element for the histogram and line charts, including the SVG and "Apply Filter" button elements.
This CSS code defines the styling of this component. Here we can see that the container element takes up 43% of the screen. We can also see that the `applyTimeline` element, which contains the “Apply Filter” button is located at the upper right of the element.
After creating the element in HTML and CSS, we need to next initialize it in JavaScript:
The main JavaScript generally defines two main items for each chart: its declaration and update functionality. The chart declaration sets the size of the SVG element, as well as the data that the chart should be constructed with. The update functionality defines the interactivity of the chart, such as what happens to other charts when a bar is selected, or a brush is applied. Each element is unique and there are unique functions such as defining the color schemes for the map, the functionality of clicking a button, or the background of the map.
The class definition for each element defines the items within the SVG. D3 allows a variety of items to be created, such as titles, labels, axes, and much more. The following code shows the definition of the timeline component and the three functions associated with the class. “initVis()” defines what will appear on the chart regardless of the data supplied. This generally consists of titles and labels. “updateVis()” defines all data driven items, such as data points, x and y axis labels, and much more. For items with a brush, “brushed(selection)” defines what happens when a user selects an area of the graph. This function will normally call the update functionality discussed above in the main JavaScript.
To update and reset the charts, we defined `updateCharts` (above) and `resetCharts` (left) to handle data changes. Whenever the user applies a filter or brush, updateCharts pushes the data to all the visualizations and updates the view. Similarly, when users reset the charts, the data is reset back to the original dataset and the visualizations update accordingly.
Overall, we spent a lot of time making sure all the visualizations fit onto one screen regardless of the user's screen size. To do so, we set the height and width of each element using percentages, CSS calc(), and ratios/fractions instead of hardcoding a set number of pixels. In the end, we were able to create a responsive layout capable of fitting every visualization on the screen at the same time with no overflow. The layout even includes mobile support, allowing users to access our project and analyze the data from any device with little to no scrolling.