Skip to content

Instantly share code, notes, and snippets.

@mitio
Created July 13, 2019 12:22
Show Gist options
  • Save mitio/bfbcb5458ad543a41c1a5467b0a1b6db to your computer and use it in GitHub Desktop.
Save mitio/bfbcb5458ad543a41c1a5467b0a1b6db to your computer and use it in GitHub Desktop.
Graphs OBD data exported from Auto Doctor and generates HTML. Depends on https://metricsgraphicsjs.org/ and D3.js. Usage: `ruby graph-obd-data *.csv`
#!/usr/bin/env ruby
require 'csv'
require 'time'
require 'cgi'
require 'erb'
require 'json'
template =
<<~HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= start_time %> - <%= end_time %> (<%= CGI.h filename %>)</title>
<link rel="stylesheet" type="text/css" href="metrics-graphics-2.15.6/dist/metricsgraphics.css">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="metrics-graphics-2.15.6/dist/metricsgraphics.min.js"></script>
</head>
<body>
<% datapoints.keys.each do |group| %>
<div id="<%= sanitize_key(group) %>"></div>
<% end %>
<script type="text/javascript">
<% datapoints.each do |group, group_datapoints| %>
var combined = <%= group_datapoints.values.to_json %>;
for (var i = 0; i < combined.length; i++) {
for (var j = 0; j < combined[i].length; j++) {
combined[i][j]['date'] = new Date(combined[i][j]['date']);
}
}
MG.data_graphic({
title: <%= group.to_json %>,
data: combined,
width: <%= width || 1000 %>,
height: 200,
y_extended_ticks: true,
legend: <%= group_datapoints.keys.to_json %>,
target: document.getElementById(<%= sanitize_key(group).to_json %>),
area: false,
});
<% end %>
</script>
</body>
</html>
HTML
def sanitize_key(string)
string.strip.downcase.gsub /\W+/, '-'
end
only_o2 = width = nil
ARGV.each do |arg|
case arg
when '--only-o2' then only_o2 = true
when /--width=(\d+)/ then width = $1.to_i
end
end
ARGV.each do |sensors_data_path|
next if sensors_data_path.start_with? '--'
filename = File.basename sensors_data_path
start_time = end_time = nil
datapoints = {}
CSV.foreach(sensors_data_path, headers: true) do |row|
time = Time.parse row['Time']
start_time ||= time
end_time = time
row.to_h.keys.each do |key|
next if key == 'Time'
next if key == 'Bank 1 - Sensor 2 (O2S): Short Term Fuel Trim [%]' # Has no data.
next if only_o2 && key !~ /Oxygen Sensor/
group =
case key
when /Oxygen Sensor/ then 'Oxygen Sensors'
else key
end
datapoints[group] ||= {}
datapoints[group][key] ||= []
datapoints[group][key] << {date: time.to_f * 1000, value: (row[key] || 0).to_f}
end
end
generated_html = ERB.new(template).result(binding)
bytes_written = File.write "#{filename}.html", generated_html
puts "Generated #{filename}.html (#{bytes_written} bytes)"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment