Skip to content

Instantly share code, notes, and snippets.

@marten
Last active October 26, 2017 17:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marten/9582c199aa2507619802bb1284b35f91 to your computer and use it in GitHub Desktop.
Save marten/9582c199aa2507619802bb1284b35f91 to your computer and use it in GitHub Desktop.
Timelapse code (Processing.org and Ruby) for AutumnWatch 2017
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
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