Last active
October 26, 2017 17:11
-
-
Save marten/9582c199aa2507619802bb1284b35f91 to your computer and use it in GitHub Desktop.
Timelapse code (Processing.org and Ruby) for AutumnWatch 2017
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'csv' | |
require 'active_support/all' | |
require 'json' | |
require 'pry' | |
output = [] | |
puts "Loading subject info" | |
subjects = CSV.read("subjects.csv", headers: true) | |
subjects = subjects.map {|row| | |
metadata = JSON.load(row["metadata"]) | |
filename = metadata["Filename"] || metadata["imageid"] || metadata["image_id"] | |
binding.pry unless filename.present? | |
[ | |
row["subject_id"], | |
filename | |
] | |
} | |
subjects = subjects.index_by(&:last) | |
puts 'Loading reductions' | |
reductions = CSV.read("reductions.csv", headers: true) | |
.select {|row| row["reducer_key"] == "points" } | |
reductions = reductions.index_by {|row| row["subject_id"] } | |
puts 'Loading bird counts' | |
CSV.foreach("all_birds_over_time.csv", headers: true) do |row| | |
next unless row['site'] == "SKEL" | |
filename = row["file_name"] | |
subject_id = subjects[filename][0] | |
reduction = reductions[subject_id] | |
if reduction | |
begin | |
xs = reduction["data.T3_tool0_clusters_x"] | |
ys = reduction["data.T3_tool0_clusters_y"] | |
if xs.present? && ys.present? | |
kittiwake_clusters = JSON.load(xs).zip(JSON.load(ys)) | |
.map {|coord| {x: coord[0], y: coord[1]} } | |
else | |
kittiwake_clusters = [] | |
end | |
############## | |
xs = reduction["data.T3_tool1_clusters_x"] | |
ys = reduction["data.T3_tool1_clusters_y"] | |
if xs.present? && ys.present? | |
guillemot_clusters = JSON.load(xs).zip(JSON.load(ys)) | |
.map {|coord| {x: coord[0], y: coord[1]} } | |
else | |
guillemot_clusters = [] | |
end | |
############## | |
xs = reduction["data.T3_tool2_clusters_x"] | |
ys = reduction["data.T3_tool2_clusters_y"] | |
if xs.present? && ys.present? | |
chick_clusters = JSON.load(xs).zip(JSON.load(ys)) | |
.map {|coord| {x: coord[0], y: coord[1]} } | |
else | |
chick_clusters = [] | |
end | |
############## | |
xs = reduction["data.T3_tool3_clusters_x"] | |
ys = reduction["data.T3_tool3_clusters_y"] | |
if xs.present? && ys.present? | |
other_clusters = JSON.load(xs).zip(JSON.load(ys)) | |
.map {|coord| {x: coord[0], y: coord[1]} } | |
else | |
other_clusters = [] | |
end | |
rescue | |
binding.pry | |
end | |
else | |
kittiwake_clusters = [] | |
guillemot_clusters = [] | |
chick_clusters = [] | |
other_clusters = [] | |
end | |
output << [ | |
row["file_name"], | |
row["date"], | |
row["kittiwakes"], | |
row["guillemots"], | |
row["chicks"], | |
row["others"], | |
JSON.dump(kittiwake_clusters), | |
JSON.dump(guillemot_clusters), | |
JSON.dump(chick_clusters), | |
JSON.dump(other_clusters) | |
] | |
end | |
output = output.sort_by {|i| i[1] }.in_groups_of(5).map {|group| | |
group.compact.sort_by {|row| row[2].to_i } # find max kittiwakes | |
.last | |
} | |
puts 'Outputting data' | |
CSV.open("visualisation.csv", 'wb', headers: [:filename, :date, :kittiwakes, :guillemots, :chicks, :others, | |
:kittiwake_clusters, :guillemot_clusters, :chick_clusters, :other_clusters], write_headers: true) do |out| | |
output[0..-1].each do |row| | |
out << row | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.LinkedList; | |
PImage img; | |
int WIDTH = 1024; | |
int HEIGHT = 868; | |
Table table; | |
TableRow row; | |
JSONArray clusters; | |
JSONObject cluster; | |
int frameCounter = 0; | |
int stepSize = 1; | |
int count; | |
LinkedList<Integer> kittiChart; | |
LinkedList<Integer> guillChart; | |
LinkedList<Integer> chickChart; | |
LinkedList<Integer> otherChart; | |
float x; | |
float y; | |
int radius = 10; | |
int colWidth = 5; | |
void setup() { | |
size(1024, 868); | |
table = loadTable("/home/marten/zoo/autumnwatch2017/visualisation.csv", "header"); | |
count = table.getRowCount(); | |
kittiChart = new LinkedList<Integer>(); | |
guillChart = new LinkedList<Integer>(); | |
chickChart = new LinkedList<Integer>(); | |
otherChart = new LinkedList<Integer>(); | |
textSize(20); | |
} | |
void draw() { | |
fill(0, 255); | |
clear(); | |
row = table.getRow(frameCounter); | |
img = loadImage("/home/marten/zoo/autumnwatch2017/SKELa2015a/" + row.getString("filename")); | |
img.resize(1024, 768); | |
//image(images[i], 0, 0); | |
image(img, 0, 0); | |
fill(0, 255, 0, 160); | |
drawClusters("kittiwake_clusters"); | |
fill(255, 0, 0, 160); | |
drawClusters("guillemot_clusters"); | |
fill(255, 0, 255, 160); | |
drawClusters("chick_clusters"); | |
fill(0, 255, 255, 160); | |
drawClusters("other_clusters"); | |
addToChart(kittiChart, row.getInt("kittiwakes")); | |
addToChart(guillChart, row.getInt("guillemots")); | |
addToChart(chickChart, row.getInt("chicks")); | |
addToChart(otherChart, row.getInt("others")); | |
stroke(0, 255, 0); | |
drawChart(kittiChart, 180, HEIGHT-80, 2); | |
stroke(255, 0, 0); | |
drawChart(guillChart, 180, HEIGHT-60, 2); | |
stroke(255, 0, 255); | |
drawChart(chickChart, 180, HEIGHT-40, 2); | |
stroke(0, 255, 255); | |
drawChart(otherChart, 180, HEIGHT-20, 2); | |
fill(255); | |
drawLabels(row, 20, 790); | |
saveFrame(); | |
frameCounter += stepSize; | |
if (frameCounter >= count) { | |
exit(); | |
} | |
} | |
void addToChart(LinkedList<Integer> chart, int value) { | |
chart.addLast(value); | |
if (chart.size() > ((WIDTH-200) / colWidth)) { | |
chart.remove(); | |
} | |
} | |
void drawClusters(String key) { | |
clusters = parseJSONArray(row.getString(key)); | |
for (int i = 0; i < clusters.size(); i++) { | |
cluster = clusters.getJSONObject(i); | |
x = (cluster.getFloat("x") / 2); | |
y = (cluster.getFloat("y") / 2); | |
ellipse(x, y, 2*radius, 2*radius); | |
} | |
} | |
void drawChart(LinkedList<Integer> chart, int xPos, int yPos, int scaleFactor) { | |
int i = 0; | |
for (Integer value : chart) { | |
rect(xPos + (i * colWidth), yPos - (scaleFactor * value), colWidth, (scaleFactor * value)); | |
i++; | |
} | |
} | |
void drawLabels(TableRow row, int x, int y) { | |
text(row.getString("date").substring(0, 10), x, y-60); | |
text("Kittiwakes: " + row.getString("kittiwakes"), x, y); | |
text("Guillemots: " + row.getString("guillemots"), x, y+20); | |
text("Chicks: " + row.getString("chicks"), x, y+40); | |
text("Others: " + row.getString("others"), x, y+60); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment