vl.markBar({ opacity: .8, strokeWidth: 0.7 })
.data(NYPD_Data)
.params(vl.selectInterval().bind('scales'),
vl.selectSingle('BoroughSelect')
.fields('borough')
.init({ borough: 'All' })
.bind(vl.menu(['All', 'Brooklyn', 'Manhattan', 'Queens', 'Bronx', 'Staten Island']).name('Select Borough: '))
)
.transform(
vl.calculate(
"datum.precinct >= 1 && datum.precinct <= 39 ? 'Manhattan' : " +
"datum.precinct >= 40 && datum.precinct <= 59 ? 'Bronx' : " +
"datum.precinct >= 60 && datum.precinct <= 99 ? 'Brooklyn' : " +
"datum.precinct >= 100 && datum.precinct <= 119 ? 'Queens' : " +
"'Staten Island'" )
.as('borough'),
vl.filter("datum.borough == BoroughSelect.borough || BoroughSelect.borough == 'All'"),
vl.calculate("datum.precinct == 0 || datum.precinct == 1000 || datum.precinct == '' ? 'Other' : datum.precinct")
.as("precinct_clean"),
vl.calculate("datum.board_disposition == 0 || datum.board_disposition == '' ? 'Other' : datum.board_disposition")
.as("board_disposition_clean"),
vl.aggregate([{ op: "count", as: "count" }]).groupby(["unique_mos_id", "precinct_clean"]),
vl.filter("datum.count > 1"),
vl.window({ op: "rank", as: "rank" })
.sort([{ field: "count", order: "descending" }])
.groupby(["precinct_clean"])
)
.encode(
vl.y().fieldQ("count").sort('-count').axis({ grid: true, title: "Number of Complaints" }),
vl.x().fieldO("precinct_clean").sort("ascending").axis({ grid: true, title: "Precinct" }),
vl.color()
.fieldQ("count")
.sort(vl.fieldQ("rank").order("ascending"))
.scale({domain: [5, 10, 40], range: ["blue", "white", "red"]})
.legend(true)
.title("# of Complaints/Officer"),
vl.order()
.fieldQ("rank")
.sort("ascending"),
vl.tooltip(["unique_mos_id", "precinct_clean", "count"])
)
.width(730)
.height(600)
.title({ text: "Complaints Against NYPD Officers, 1985-2020", subtitle: "Data organized per officer/ precinct. Only includes officers with 2 or more complaints. Select a borough to narrow results." })
.render()