metapost-erb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +15 -0
- data/bin/metapost-erb +44 -0
- data/examples/terrestrial-carbon-stocks.erb +99 -0
- data/examples/terrestrial-carbon-stocks.rb +9 -0
- data/lib/metapost-erb.rb +156 -0
- metadata +68 -0
data/README
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
= Metapost-erb
|
2
|
+
|
3
|
+
A simple tool to turn erb templates into metapost files, run the metapost, and open the resulting files in Preview.
|
4
|
+
|
5
|
+
Also includes some support libraries to help make drawing grids and charts easier.
|
6
|
+
|
7
|
+
NB: when I say easier, I mean easier given I know ruby much better than I know metapost. There are probably elegant ways of doing this stuff in metapost itself.
|
8
|
+
|
9
|
+
Usage:
|
10
|
+
metapost-erb filenameoferb.erb
|
11
|
+
|
12
|
+
|
13
|
+
This software is (c) 2010 Green on Black Ltd and distributed under the open source MIT [http://www.opensource.org/licenses/mit-license.php] licence. (See LICENCE for the wording).
|
14
|
+
|
15
|
+
|
data/bin/metapost-erb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require_relative '../lib/metapost-erb'
|
5
|
+
|
6
|
+
metapost_command = 'mpost'
|
7
|
+
|
8
|
+
puts "Loading template '#{ARGV[0]}'"
|
9
|
+
template = IO.readlines(ARGV[0]).join
|
10
|
+
|
11
|
+
template_directory = File.dirname(File.expand_path(ARGV[0]))
|
12
|
+
|
13
|
+
support_library = File.basename(ARGV[0],'.*')
|
14
|
+
support_module = support_library.split(/[^a-zA-Z0-9]/).map { |w| w.capitalize }.join
|
15
|
+
metapost_name = ARGV[1] || (File.basename(ARGV[0],'.*') + '.mp')
|
16
|
+
log_file_name = (File.basename(ARGV[1] || ARGV[0],'.*') + '.log')
|
17
|
+
|
18
|
+
begin
|
19
|
+
puts "Trying to load supporting library #{support_library} with module #{support_module} "
|
20
|
+
require File.join(template_directory,support_library)
|
21
|
+
include eval(support_module)
|
22
|
+
rescue LoadError => e
|
23
|
+
puts e
|
24
|
+
puts "No support library #{support_library} found"
|
25
|
+
end
|
26
|
+
|
27
|
+
puts "Compiling template"
|
28
|
+
erb = ERB.new(template)
|
29
|
+
metapost = erb.result(binding)
|
30
|
+
|
31
|
+
puts "Writing metapost to #{metapost_name}"
|
32
|
+
File.open(metapost_name,'w') do |f|
|
33
|
+
puts metapost
|
34
|
+
f.puts metapost
|
35
|
+
end
|
36
|
+
|
37
|
+
puts "Running metapost"
|
38
|
+
puts `#{metapost_command} -interaction=nonstopmode #{metapost_name}`
|
39
|
+
|
40
|
+
puts "Opening files"
|
41
|
+
logfile = IO.readlines(log_file_name).join
|
42
|
+
logfile[/files? written:(.*)/m,1].split(/.. /).map(&:strip).each do |output|
|
43
|
+
`open #{output}`
|
44
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
% Estimates of terrestrial carbon stocks from IPCC TAR 3 ("The Carbon Cycle and Atmospheric Carbon Dioxide") Table 3.2
|
2
|
+
<%= credits %>
|
3
|
+
<%
|
4
|
+
x_axis_unit_label = "btex Area $10^9$ ha etex"
|
5
|
+
x_axis_range = (0..15)
|
6
|
+
x_minor_grid_step = 1
|
7
|
+
x_major_grid_step = 5
|
8
|
+
|
9
|
+
case y_units = ARGV[1] || 'ktCO2e'
|
10
|
+
when 'ktCO2e'
|
11
|
+
y_axis_unit_label = "btex Carbon density (ktCO$_{2}$e/ha) etex"
|
12
|
+
y_axis_range = (0..3)
|
13
|
+
y_minor_grid_step = 0.1
|
14
|
+
y_major_grid_step = 1
|
15
|
+
y_axis_conversion = lambda { |c| c * (44.0/12.0)/1000.0 }
|
16
|
+
comparison_label = "100 GtCO$_{2}$e (c. 2 years of man-made emissions)"
|
17
|
+
when 'tC'
|
18
|
+
y_axis_unit_label = "btex Carbon density (tC/ha) etex"
|
19
|
+
y_axis_range = (0..800)
|
20
|
+
y_minor_grid_step = 10
|
21
|
+
y_major_grid_step = 100
|
22
|
+
y_axis_conversion = lambda { |c| c } # No conversion
|
23
|
+
comparison_label = "10 GtC (c. 1 year of man-made emissions)"
|
24
|
+
end
|
25
|
+
%>
|
26
|
+
|
27
|
+
input boxes
|
28
|
+
input TEX
|
29
|
+
prologues:=3;
|
30
|
+
outputtemplate := "%j-%3c.eps";
|
31
|
+
beginfig(1);
|
32
|
+
|
33
|
+
% Define the scaling and axes
|
34
|
+
chart_width := 10 cm;
|
35
|
+
chart_height := 10cm;
|
36
|
+
xunit := (chart_width / <%= x_axis_range.max %>);
|
37
|
+
yunit := (chart_height / <%= y_axis_range.max %> );
|
38
|
+
|
39
|
+
% Define colours
|
40
|
+
% Grid
|
41
|
+
color minor_grid_color; minor_grid_color = 0.95 white;
|
42
|
+
color major_grid_color; major_grid_color = 0.85 white;
|
43
|
+
color grid_label_color; grid_label_color = black;
|
44
|
+
|
45
|
+
% Stacks
|
46
|
+
color outer_box_color; outer_box_color = 0.3 white;
|
47
|
+
color soil_color; soil_color = (1,0.5,0.1);
|
48
|
+
color plant_color; plant_color = (0,1.0,0);
|
49
|
+
color soil_label_color; soil_label_color = soil_color * 0.9;
|
50
|
+
color plant_label_color; plant_label_color = plant_color * 0.5;
|
51
|
+
|
52
|
+
% Comparator
|
53
|
+
color comparator_box_color; comparator_box_color = black;
|
54
|
+
|
55
|
+
% Draw the grid lines
|
56
|
+
<%= grid_lines x_axis_range.step(x_minor_grid_step), y_axis_range.step(y_minor_grid_step), 'minor_grid_color' %>
|
57
|
+
<%= grid_lines x_axis_range.step(x_major_grid_step), y_axis_range.step(y_major_grid_step), 'major_grid_color' %>
|
58
|
+
|
59
|
+
% Draw the grid labels
|
60
|
+
<%= grid_labels x_axis_range.step(x_major_grid_step), y_axis_range.step(y_major_grid_step), 'grid_label_color' %>
|
61
|
+
|
62
|
+
% Draw the axes labels
|
63
|
+
label.llft( <%= x_axis_unit_label %>, (<%= x_axis_range.max %> xunit,-0.5cm) );
|
64
|
+
label.llft( <%= y_axis_unit_label %> rotated 90, (-0.75cm, <%= y_axis_range.max %> yunit) );
|
65
|
+
|
66
|
+
% Draw the stacks
|
67
|
+
<%=
|
68
|
+
chart ['soil_color','plant_color'] do
|
69
|
+
stack 'Wetlands' ,0.35 ,[ 643,43 ].map(&y_axis_conversion)
|
70
|
+
stack 'Boreal forests' ,1.37 ,[ 344,64 ].map(&y_axis_conversion)
|
71
|
+
stack 'Tropical forests' ,1.76 ,[ 123,120].map(&y_axis_conversion)
|
72
|
+
stack 'Temperate grasslands \& shrublands' ,1.25 ,[ 236,7 ].map(&y_axis_conversion)
|
73
|
+
stack 'Temperate forests' ,1.04 ,[ 96 ,57 ].map(&y_axis_conversion)
|
74
|
+
stack 'Tropical savannas \& grasslands' ,2.25 ,[ 117,29 ].map(&y_axis_conversion)
|
75
|
+
stack 'Tundra' ,0.95 ,[ 127,6 ].map(&y_axis_conversion)
|
76
|
+
stack 'Croplands' ,1.60 ,[ 80 ,2 ].map(&y_axis_conversion)
|
77
|
+
stack 'Deserts and semi deserts' ,4.55 ,[ 42 ,2 ].map(&y_axis_conversion)
|
78
|
+
|
79
|
+
stacks.each do |stack_name,boxes|
|
80
|
+
box_draw "draw #{boxes.first}.sw--#{boxes.last}.nw--#{boxes.last}.ne--#{boxes.first}.se--cycle withcolor outer_box_color"
|
81
|
+
label_box boxes.last, stack_name, :n, 'outer_box_color'
|
82
|
+
end
|
83
|
+
|
84
|
+
label_box stacks['Deserts and semi deserts'].first, "in first 1m of soil", :e, 'soil_label_color'
|
85
|
+
label_box stacks['Deserts and semi deserts'].last, "in plants", :e, 'plant_label_color'
|
86
|
+
end
|
87
|
+
%>
|
88
|
+
|
89
|
+
% Comparison
|
90
|
+
boxit.comparator();
|
91
|
+
comparator.sw = (<%= x_axis_range.max-x_minor_grid_step %> xunit, <%= y_axis_range.max-y_minor_grid_step %> yunit);
|
92
|
+
comparator.ne = (<%= x_axis_range.max %> xunit, <%= y_axis_range.max %> yunit);
|
93
|
+
draw bpath(comparator) withcolor comparator_box_color;
|
94
|
+
fill bpath(comparator) withcolor 0.9*white+0.1*comparator_box_color;
|
95
|
+
<%= label_box 'comparator', comparison_label, :e %>
|
96
|
+
|
97
|
+
endfig;
|
98
|
+
|
99
|
+
end;
|
data/lib/metapost-erb.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
module MetaPost
|
2
|
+
module Standard
|
3
|
+
|
4
|
+
def layers
|
5
|
+
@layers ||= []
|
6
|
+
end
|
7
|
+
|
8
|
+
def draw_on_layer(layer,*strings)
|
9
|
+
layers[layer] ||= []
|
10
|
+
layers[layer] << strings.flatten.join
|
11
|
+
end
|
12
|
+
|
13
|
+
def write!
|
14
|
+
result = layers.flatten.join(";\n ") + ";\n "
|
15
|
+
layers.clear
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
def x(value)
|
20
|
+
"#{value} xunit"
|
21
|
+
end
|
22
|
+
|
23
|
+
def y(value)
|
24
|
+
"#{value} yunit"
|
25
|
+
end
|
26
|
+
|
27
|
+
def labels
|
28
|
+
@labels ||= []
|
29
|
+
end
|
30
|
+
|
31
|
+
def draw_labels
|
32
|
+
labels.join(";\n")+";\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
def v(*names)
|
36
|
+
name = names.join
|
37
|
+
@variables ||= {}
|
38
|
+
return @variables[name] if @variables.has_key?(name)
|
39
|
+
variable_name = name.gsub(/[^a-zA-Z0-9]/,'')
|
40
|
+
variable_name.succ! while @variables.has_value?(variable_name)
|
41
|
+
@variables[name] = variable_name
|
42
|
+
variable_name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
module Grid
|
48
|
+
include Standard
|
49
|
+
|
50
|
+
def grid_lines(x_values,y_values = x_values,colour = 'grid')
|
51
|
+
x_values = x_values.to_a
|
52
|
+
y_values = y_values.to_a
|
53
|
+
x_min, x_max = x_values.min, x_values.max
|
54
|
+
y_min, y_max = y_values.min, y_values.max
|
55
|
+
|
56
|
+
x_values.each do |x_value|
|
57
|
+
grid_line "draw (#{x x_value}, #{y y_min})--(#{x x_value}, #{y y_max}) withcolor #{colour}"
|
58
|
+
end
|
59
|
+
|
60
|
+
y_values.each do |y_value|
|
61
|
+
grid_line "draw (#{x x_min}, #{y y_value})--(#{x x_max}, #{y y_value}) withcolor #{colour}"
|
62
|
+
end
|
63
|
+
|
64
|
+
write!
|
65
|
+
end
|
66
|
+
|
67
|
+
def grid_labels(x_values,y_values = nil,colour = 'black')
|
68
|
+
if x_values
|
69
|
+
x_values.each do |x_value|
|
70
|
+
grid_label "label.bot(btex #{x_value} etex, (#{x x_value},0)) withcolor #{colour}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if y_values
|
75
|
+
y_values.each do |y_value|
|
76
|
+
grid_label "label.lft(btex #{y_value} etex, (0,#{y y_value})) withcolor #{colour}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
write!
|
81
|
+
end
|
82
|
+
|
83
|
+
def grid_line(string)
|
84
|
+
draw_on_layer 0, string
|
85
|
+
end
|
86
|
+
|
87
|
+
def grid_label(string)
|
88
|
+
draw_on_layer 1, string
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
module Stacks
|
93
|
+
include Standard
|
94
|
+
attr_accessor :default_stack_colours
|
95
|
+
attr_accessor :stacks
|
96
|
+
attr_accessor :stack_sw_x
|
97
|
+
|
98
|
+
def stack(stack_name, width, heights, pen_color = self.default_stack_colours, fill_color = nil)
|
99
|
+
self.stacks ||= {}
|
100
|
+
self.stacks[stack_name] = []
|
101
|
+
self.stack_sw_x ||= 0
|
102
|
+
heights = [heights] unless heights.is_a?(Array)
|
103
|
+
pen_color = Array.new(heights.size,pen_color) unless pen_color.is_a?(Array)
|
104
|
+
fill_color = pen_color.map { |pen| "0.75*white+0.25*(#{pen})" } unless fill_color
|
105
|
+
fill_color = Array.new(heights.size,fill_color) unless fill_color.is_a?(Array)
|
106
|
+
result = []
|
107
|
+
height = 0
|
108
|
+
heights.each.with_index do |box_height,i|
|
109
|
+
self.stacks[stack_name] << box_name = "#{v(stack_name)}[#{i}]"
|
110
|
+
box_definition "boxit.#{box_name}()"
|
111
|
+
box_position "#{box_name}.sw = (#{x @stack_sw_x}, #{y height})"
|
112
|
+
box_position "#{box_name}.ne = (#{x(@stack_sw_x + width)}, #{y height + box_height})"
|
113
|
+
height = height + box_height
|
114
|
+
box_draw "fill bpath(#{box_name}) withcolor #{fill_color[i]}"
|
115
|
+
box_draw "draw bpath(#{box_name}) withcolor #{pen_color[i]}"
|
116
|
+
end
|
117
|
+
self.stack_sw_x = self.stack_sw_x + width
|
118
|
+
end
|
119
|
+
|
120
|
+
def chart(default_stack_colours, &block)
|
121
|
+
self.stacks = nil
|
122
|
+
self.stack_sw_x = nil
|
123
|
+
self.default_stack_colours = default_stack_colours
|
124
|
+
block.call
|
125
|
+
write!
|
126
|
+
end
|
127
|
+
|
128
|
+
def label_box(box_name,text,corner = :n, colour = "black", rotation = nil, offset = nil, label_position = nil)
|
129
|
+
rotation ||= {'ne' => '45', 'n' => '45'}[corner.to_s]
|
130
|
+
offset ||= {'ne' => "(0.5 cm, 0.5 cm)", 'n' => "(0.5 cm,0.5 cm)", 'e' => "(0.5 cm, 0 cm)"}[corner.to_s]
|
131
|
+
label_position ||= {'ne' => 'urt', 'e' => 'rt', 'n' => 'urt' }[corner.to_s]
|
132
|
+
|
133
|
+
anchor = "#{box_name}.#{corner}"
|
134
|
+
box_label arrow = "draw (#{anchor} shifted #{offset})..(#{anchor} shifted (#{offset}/10)) withcolor #{colour}"
|
135
|
+
box_label text = "label.#{label_position}( btex #{text} etex #{rotation && "rotated #{rotation}"}, (#{anchor} shifted #{offset}) ) withcolor #{colour}"
|
136
|
+
arrow + ";\n" + text + ";\n"
|
137
|
+
end
|
138
|
+
|
139
|
+
def box_definition(string)
|
140
|
+
draw_on_layer 0, string
|
141
|
+
end
|
142
|
+
|
143
|
+
def box_position(string)
|
144
|
+
draw_on_layer 1, string
|
145
|
+
end
|
146
|
+
|
147
|
+
def box_draw(string)
|
148
|
+
draw_on_layer 2, string
|
149
|
+
end
|
150
|
+
|
151
|
+
def box_label(string)
|
152
|
+
draw_on_layer 3, string
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: metapost-erb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Thomas Counsell, Green on Black Ltd
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-08-13 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: metapost-erb@greenonblack.com
|
23
|
+
executables:
|
24
|
+
- metapost-erb
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- README
|
31
|
+
- lib/metapost-erb.rb
|
32
|
+
- bin/metapost-erb
|
33
|
+
- examples/terrestrial-carbon-stocks.erb
|
34
|
+
- examples/terrestrial-carbon-stocks.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/tamc/metapost-erb
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
segments:
|
49
|
+
- 1
|
50
|
+
- 9
|
51
|
+
- 1
|
52
|
+
version: 1.9.1
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.3.6
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Helps to programatically create metapost files, making use of erb templates
|
67
|
+
test_files: []
|
68
|
+
|