-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improves Admin Analytics, Adds Choropleth #692
Changes from all commits
90f2185
f1d1de4
3b2f9c7
b012109
0672367
737949a
d1cb0fa
378c539
224c14a
31dc1b8
af01525
6b93139
161e587
2b091a5
18aa061
eb1a3cd
3299e46
8a44d43
87686c1
01c27d9
7b0bbc6
c02f3d4
ef546a8
3bd0fd0
331b28b
9b694d0
5293d74
2668910
4524029
ba63cdc
ef7e096
5ceac39
db87557
307b782
2fe3aeb
ab4a85a
36ec43d
92447e6
bf6691a
293cb51
67e7f99
f647e92
d7b9148
0a18175
0f9356c
9641f15
762b728
57c928d
70fc573
5ca2764
dfadf31
61a78a7
9a9ed8d
2de36d9
c8b1d65
369ea53
92f9442
1015ae1
484f533
0cbfa3d
fc545c0
800a5b6
7461cd2
edc3bd3
b924d72
145d9bf
1dea7ed
e5fff69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -109,10 +109,15 @@ object AuditTaskTable { | |
auditTasks.list | ||
} | ||
|
||
/** | ||
* Returns a count of the number of audits performed on each day since the tool was launched (11/17/2015). | ||
* | ||
* @return | ||
*/ | ||
def auditCounts: List[AuditCountPerDay] = db.withSession { implicit session => | ||
val selectAuditCountQuery = Q.queryNA[(String, Int)]( | ||
"""SELECT calendar_date::date, COUNT(audit_task_id) FROM (SELECT current_date - (n || ' day')::INTERVAL AS calendar_date | ||
|FROM generate_series(0, 30) n) AS calendar | ||
|FROM generate_series(0, current_date - '11/17/2015') n) AS calendar | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 11/17/2015 - What does this date refer to? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question! I am also wondering that. It appears to be maybe the day after the audit_task_table was first created or something, because up until 11/16/2015 there are no audits at all then on 11/16/2015 there is an absurdly large number of audits, then the data starts looking normal after that. In summary: 2 days before that date, there are no audits. The day before that date, the data is not reliable. So this is the date where reliable data begins. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. Could you add a comment in the code for this? |
||
|LEFT JOIN sidewalk.audit_task | ||
|ON audit_task.task_start::date = calendar_date::date | ||
|GROUP BY calendar_date | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package models.region | ||
|
||
import java.util.UUID | ||
|
||
import com.vividsolutions.jts.geom.Polygon | ||
import org.geotools.geometry.jts.JTS | ||
import org.geotools.referencing.CRS | ||
|
||
import math._ | ||
import models.street.{StreetEdgeAssignmentCountTable, StreetEdgeRegionTable, StreetEdgeTable, StreetEdge} | ||
import models.user.UserCurrentRegionTable | ||
import models.utils.MyPostgresDriver | ||
import models.utils.MyPostgresDriver.simple._ | ||
import play.api.Play.current | ||
|
||
import scala.slick.jdbc.{GetResult, StaticQuery => Q} | ||
import scala.slick.lifted.ForeignKeyQuery | ||
|
||
case class RegionCompletion(regionId: Int, totalDistance: Double, auditedDistance: Double) | ||
case class NamedRegionCompletion(regionId: Int, name: Option[String], totalDistance: Double, auditedDistance: Double) | ||
|
||
class RegionCompletionTable(tag: Tag) extends Table[RegionCompletion](tag, Some("sidewalk"), "region_completion") { | ||
def regionId = column[Int]("region_id", O.PrimaryKey) | ||
def totalDistance = column[Double]("total_distance") | ||
def auditedDistance = column[Double]("audited_distance") | ||
|
||
def * = (regionId, totalDistance, auditedDistance) <> ((RegionCompletion.apply _).tupled, RegionCompletion.unapply) | ||
} | ||
|
||
/** | ||
* Data access object for the sidewalk_edge table | ||
*/ | ||
object RegionCompletionTable { | ||
import MyPostgresDriver.plainImplicits._ | ||
|
||
implicit val regionCompletionConverter = GetResult[RegionCompletion](r => { | ||
RegionCompletion(r.nextInt, r.nextDouble, r.nextDouble) | ||
}) | ||
|
||
// implicit val namedRegionConverter = GetResult[NamedRegion](r => { | ||
// NamedRegion(r.nextInt, r.nextStringOption, r.nextGeometry[Polygon]) | ||
// }) | ||
|
||
case class StreetCompletion(regionId: Int, regionName: String, streetEdgeId: Int, completionCount: Int, distance: Double) | ||
implicit val streetCompletionConverter = GetResult[StreetCompletion](r => { | ||
StreetCompletion(r.nextInt, r.nextString, r.nextInt, r.nextInt, r.nextDouble) | ||
}) | ||
|
||
val db = play.api.db.slick.DB | ||
val regionCompletions = TableQuery[RegionCompletionTable] | ||
val regions = TableQuery[RegionTable] | ||
val regionTypes = TableQuery[RegionTypeTable] | ||
val regionProperties = TableQuery[RegionPropertyTable] | ||
val streetEdges = TableQuery[StreetEdgeTable] | ||
val streetEdgeAssignmentCounts = TableQuery[StreetEdgeAssignmentCountTable] | ||
val streetEdgeRegion = TableQuery[StreetEdgeRegionTable] | ||
val userCurrentRegions = TableQuery[UserCurrentRegionTable] | ||
|
||
val regionsWithoutDeleted = regions.filter(_.deleted === false) | ||
val streetEdgesWithoutDeleted = streetEdges.filter(_.deleted === false) | ||
val neighborhoods = regionsWithoutDeleted.filter(_.regionTypeId === 2) | ||
val streetEdgeNeighborhood = for { (se, n) <- streetEdgeRegion.innerJoin(neighborhoods).on(_.regionId === _.regionId) } yield se | ||
|
||
|
||
/** | ||
* Returns a list of all neighborhoods with names | ||
* @return | ||
*/ | ||
def selectAllNamedNeighborhoodCompletions: List[NamedRegionCompletion] = db.withSession { implicit session => | ||
val namedRegionCompletions = for { | ||
(_neighborhoodCompletions, _regionProperties) <- regionCompletions.leftJoin(regionProperties).on(_.regionId === _.regionId) | ||
if _regionProperties.key === "Neighborhood Name" | ||
} yield (_neighborhoodCompletions.regionId, _regionProperties.value.?, _neighborhoodCompletions.totalDistance, _neighborhoodCompletions.auditedDistance) | ||
|
||
namedRegionCompletions.list.map(x => NamedRegionCompletion.tupled(x)) | ||
} | ||
/** | ||
* | ||
*/ | ||
|
||
|
||
/** | ||
* Increments the `audited_distance` column of the corresponding region by the length of the specified street edge. | ||
* Reference: http://slick.lightbend.com/doc/2.0.0/queries.html#updating | ||
* | ||
* @param streetEdgeId street edge id | ||
* @return | ||
*/ | ||
def updateAuditedDistance(streetEdgeId: Int) = db.withTransaction { implicit session => | ||
val distToAdd: Float = streetEdgesWithoutDeleted.filter(_.streetEdgeId === streetEdgeId).groupBy(x => x).map(_._1.geom.transform(26918).length).list.head | ||
val regionId: Int = streetEdgeNeighborhood.filter(_.streetEdgeId === streetEdgeId).groupBy(x => x).map(_._1.regionId).list.head | ||
|
||
val q = for { regionCompletion <- regionCompletions if regionCompletion.regionId === regionId } yield regionCompletion | ||
|
||
val updatedDist = q.firstOption match { | ||
case Some(rC) => q.map(_.auditedDistance).update(rC.auditedDistance + distToAdd) | ||
case None => -1 | ||
} | ||
updatedDist | ||
} | ||
|
||
def initializeRegionCompletionTable() = db.withTransaction { implicit session => | ||
|
||
if (regionCompletions.length.run == 0) { | ||
// http://docs.geotools.org/latest/tutorials/geometry/geometrycrs.html | ||
val CRSEpsg4326 = CRS.decode("epsg:4326") | ||
val CRSEpsg26918 = CRS.decode("epsg:26918") | ||
val transform = CRS.findMathTransform(CRSEpsg4326, CRSEpsg26918) | ||
|
||
val neighborhoods = RegionTable.selectAllNamedNeighborhoods | ||
for (neighborhood <- neighborhoods) yield { | ||
val streets: List[StreetEdge] = StreetEdgeTable.selectStreetsByARegionId(neighborhood.regionId) | ||
val auditedStreets: List[StreetEdge] = StreetEdgeTable.selectAuditedStreetsByARegionId(neighborhood.regionId) | ||
|
||
val auditedDistance = auditedStreets.map(s => JTS.transform(s.geom, transform).getLength).sum | ||
val totalDistance = streets.map(s => JTS.transform(s.geom, transform).getLength).sum | ||
|
||
regionCompletions += RegionCompletion(neighborhood.regionId, totalDistance, auditedDistance) | ||
} | ||
} | ||
} | ||
|
||
// | ||
// /** | ||
// * Update the `task_end` column of the specified audit task row | ||
// * | ||
// * @param auditTaskId | ||
// * @param timestamp | ||
// * @return | ||
// */ | ||
// def updateTaskEnd(auditTaskId: Int, timestamp: Timestamp) = db.withTransaction { implicit session => | ||
// val q = for { task <- auditTasks if task.auditTaskId === auditTaskId } yield task.taskEnd | ||
// q.update(Some(timestamp)) | ||
// } | ||
|
||
|
||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the table initialized each time the function is called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see
if (regionCompletions.length.run == 0)
line in RegionCompletionTable. Could you confirm if this prevents it from running from than once?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I had confirmed that this didn't run multiple times using the magic of print statements. You also know that it isn't because the call takes >10 seconds to run, but there are never any 10 second lags when calling the getNeighborhoodCompletionRate after the first call.