Skip to content

Commit

Permalink
label rmagick fix, color librart reset before creating graph, better …
Browse files Browse the repository at this point in the history
…legend width calculation and changeable font size
  • Loading branch information
akwiatkowski committed Nov 12, 2011
1 parent a7e1b38 commit 2a43fac
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 14 deletions.
1 change: 1 addition & 0 deletions DOCUMENTATION.md
Expand Up @@ -72,6 +72,7 @@ Font size:

options[:layers_font_size] - size of font used for values in graph
options[:axis_font_size] - size of font used in axis
options[:legend_font_size] - size of font used in legend
options[:axis_label_font_size] - size of font used in options[:x_axis_label] and options[:y_axis_label]

Sometime because of axis options and large amount of data, axis can be put densely on graph. Turning this option graph size will be enlarged to maintain set distanced between axis.
Expand Down
123 changes: 118 additions & 5 deletions DOCUMENTATION.textile
Expand Up @@ -542,15 +542,128 @@ file_name = 'samples/readme/12_aa_false.png'



h2. Font size

p. You can set various font sizes.

# options[:layers_font_size] - size of font used for values in graph, keep in mind that layer_options[:value_labels]
must be enabled to see any result

# options[:axis_font_size] - size of font used in axis

# options[:axis_label_font_size] - size of font used in options[:x_axis_label] and options[:y_axis_label], to see
any result at least one of them must be set


<pre>
<code>
@simple_data_array = [
{ :x => 0, :y => 0 },
{ :x => 1, :y => 1 },
{ :x => 2, :y => 2 },
{ :x => 3, :y => 2 },
{ :x => 4, :y => 1 },
{ :x => 5, :y => 0 },
]

@tg = TechnicalGraph.new(
{
:x_axis_label => 'parameter',
:y_axis_label => 'value',
:layers_font_size => 14,
:axis_font_size => 18,
:axis_label_font_size => 48
})
@tg.add_layer(@simple_data_array, {:value_labels => true})
@tg.render
file_name = 'samples/readme/13_font_sizes.png'
@tg.image_drawer.save_to_file(file_name)
</code>
</pre>

!https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/13_font_sizes.png((13) Font size)!



h2. Legend

p. If you want to use legend you only have to set labels for layers and turn legend enabled by using:

# options[:legend] - turn on legend, on default auto position mode is enabled

# layer_options[:label] - label used for legend

Position of legend is calculated automatic - 8 corner places are checked for distance to all graph points. Point
which has longest distance is used for legend position.

Every layer has own color which can be set by user using code below. If you don't set there is bank of some fixed colors
and random color generator.

<pre>
<code>
layer_options[:color] = '#FF0000' # color in format #RRGGBB
</code>
</pre>

Graph sample code:

<pre>
<code>
@simple_data_array = [
{ :x => 0, :y => 0 },
{ :x => 1, :y => 1 },
{ :x => 2, :y => 2 },
{ :x => 3, :y => 2 },
{ :x => 4, :y => 1 },
{ :x => 5, :y => 0 },
]

@simple_data_array_second = @simple_data_array.collect{|a| {:x => a[:x] + 0.31, :y => a[:y] + 0.21 }}
@simple_data_array_third = @simple_data_array.collect{|a| {:x => a[:x] * 0.99 + 0.23, :y => a[:y] * 1.2 - 0.12 }}

@tg = TechnicalGraph.new(
{
:legend => true
})
@tg.add_layer(@simple_data_array, {:label => 'simple', :color => '#FFFF00'})
@tg.add_layer(@simple_data_array_second, {:label => 'offset', :color => '#00FFFF'})
@tg.add_layer(@simple_data_array_third, {:label => 'scaled', :color => '#FF00FF'})
@tg.render
file_name = 'samples/readme/14_simple_legend.png'
@tg.image_drawer.save_to_file(file_name)
</code>
</pre>

!https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/14_simple_legend.png((14) Legend)!

You can turn off auto position if you like:

<pre>
<code>
options[:legend_auto] = false
options[:legend_x] = 100
options[:legend_y] = 100
</code>
</pre>

There are also other useful parameters

# options[:legend_width] - width of longest label in pixels used for setting proper distance while drawing on right border
default 100 and is enlarged auto. using font size

# options[:legend_margin] - graph margin used not to draw legend on border, default 50









h2. TODO

# Font sizes
# Axis density checking algorithm: sample when it us useful
# Layer labels: used in legend
# Layer colors, random colors
# Legend with set position
# Legend with auto position
# Smoother:
# Noise removal
# Adjusting axis to zero
2 changes: 1 addition & 1 deletion lib/technical_graph/data_layer.rb
Expand Up @@ -30,7 +30,7 @@ def initialize(d = [], options = { }, technical_graph = nil)
@data_params = options

@data_params[:color] ||= GraphColorLibrary.instance.get_color
@data_params[:label] ||= ''
@data_params[:label] ||= ' '
# default true, write values near dots
@data_params[:value_labels] = false if options[:value_labels] == false

Expand Down
5 changes: 5 additions & 0 deletions lib/technical_graph/graph_color_library.rb
Expand Up @@ -42,6 +42,11 @@ class GraphColorLibrary
FAIL_COLOR = 'black'

def initialize
reset
end

# Reset color bank
def reset
@colors = BASIC_COLORS + ADDITIONAL_COLORS.sort { rand }
end

Expand Down
31 changes: 26 additions & 5 deletions lib/technical_graph/graph_image_drawer.rb
Expand Up @@ -110,6 +110,7 @@ def initialize(technical_graph)
options[:axis_font_size] ||= 10
options[:layers_font_size] ||= 10
options[:axis_label_font_size] ||= 10
options[:legend_font_size] ||= 10

# legend
options[:legend] = false if options[:legend].nil?
Expand Down Expand Up @@ -166,6 +167,10 @@ def legend_width
options[:legend_width]
end

def legend_height
options[:legend_height]
end

def legend_margin
options[:legend_margin]
end
Expand Down Expand Up @@ -193,6 +198,9 @@ def pre_image_create_calculations

# Create background image
def crate_blank_graph_image
# reset color banks
GraphColorLibrary.instance.reset
# calculate some stuff :]
pre_image_create_calculations
# create drawing proxy
@drawer = drawing_class.new(self)
Expand Down Expand Up @@ -242,16 +250,28 @@ def post_dot_drawn(bx, by)
end
end

# height of 1 layer
ONE_LAYER_LEGEND_HEIGHT = 15
# height of 1 layer without font size
ONE_LAYER_LEGEND_SPACER = 5

def one_layer_legend_height
options[:legend_font_size] + ONE_LAYER_LEGEND_SPACER
end

# Enlarge legend's width using legend labels sizes
def recalculate_legend_size
layers.each do |l|
w = l.label.size * options[:legend_font_size]
options[:legend_width] = w if w > legend_width
end

options[:legend_height] = layers.size * one_layer_legend_height
end

# Choose best location
def recalculate_legend_position
return unless legend_auto_position
logger.debug "Auto position calculation, drawn points #{@drawn_points.size}"

legend_height = layers.size * ONE_LAYER_LEGEND_HEIGHT

# check 8 places:
positions = [
{ :x => legend_margin, :y => 0 + legend_margin }, # top-left
Expand Down Expand Up @@ -296,6 +316,7 @@ def recalculate_legend_position
# Render legend on graph
def render_data_legend
return unless draw_legend?
recalculate_legend_size
recalculate_legend_position

x = legend_x
Expand All @@ -311,7 +332,7 @@ def render_data_legend
h[:y] = y

legend_data << h
y += ONE_LAYER_LEGEND_HEIGHT
y += one_layer_legend_height
end

drawer.legend(legend_data)
Expand Down
3 changes: 2 additions & 1 deletion lib/technical_graph/graph_image_drawer_rasem.rb
Expand Up @@ -119,11 +119,12 @@ def render_data_layer(l, coords)

def legend(legend_data)
_s = self
legend_text_offset = (options[:legend_font_size] / 2.0).round - 4

@image.group do
legend_data.each do |l|
circle(l[:x], l[:y], 2, { :stroke => l[:color], :fill => l[:color], :stroke_width => 1 })
text(l[:x] + 5, l[:y], l[:label], { :fill => l[:color] })
text(l[:x] + 5, l[:y] + legend_text_offset, l[:label], { :fill => l[:color], 'font-size' => "#{_s.options[:legend_font_size]}px" })
end
end
end
Expand Down
5 changes: 4 additions & 1 deletion lib/technical_graph/graph_image_drawer_rmagick.rb
Expand Up @@ -186,16 +186,19 @@ def render_data_layer(l, coords)


def legend(legend_data)
legend_text_offset = (options[:legend_font_size] / 2.0).round - 4

legend_data.each do |l|
plot = axis_draw_object
plot_text = layer_no_stroke(plot)

plot.fill(l[:color])
plot.stroke(l[:color])
plot_text.fill(l[:color])
plot_text.pointsize(options[:legend_font_size])

plot.circle(l[:x], l[:y], l[:x] + 2, l[:y])
plot_text.text(l[:x] + 5, l[:y], l[:label])
plot_text.text(l[:x] + 5, l[:y] + legend_text_offset, l[:label])

plot.draw(@image)
plot_text.draw(@image)
Expand Down
51 changes: 50 additions & 1 deletion test/test_technical_readme.rb
Expand Up @@ -270,7 +270,7 @@ class TestTechnicalReadme < Test::Unit::TestCase
end

should 'test antialiasing' do
#return if DO_NOT_RUN_OLD_TESTS
return if DO_NOT_RUN_OLD_TESTS

@tg = TechnicalGraph.new(
{
Expand Down Expand Up @@ -298,6 +298,55 @@ class TestTechnicalReadme < Test::Unit::TestCase
File.exist?(file_name).should == true
end


should 'test font sizes' do
return if DO_NOT_RUN_OLD_TESTS

@tg = TechnicalGraph.new(
{
:x_axis_label => 'parameter',
:y_axis_label => 'value',
:layers_font_size => 14,
:axis_font_size => 18,
:axis_label_font_size => 48,
:drawer_class => :rmagick
})
@tg.add_layer(@simple_data_array, {:value_labels => true})
@tg.render
file_name = 'samples/readme/13_font_sizes.png'
@tg.image_drawer.save_to_file(file_name)

# test
@tg.image_drawer.to_format(@tg.best_output_format).class.should == String
File.exist?(file_name).should == true
end


should 'test layer labels, colors and legend' do
#return if DO_NOT_RUN_OLD_TESTS

@simple_data_array_second = @simple_data_array.collect{|a| {:x => a[:x] + 0.31, :y => a[:y] + 0.21 }}
@simple_data_array_third = @simple_data_array.collect{|a| {:x => a[:x] * 0.99 + 0.23, :y => a[:y] * 1.2 - 0.12 }}

@tg = TechnicalGraph.new(
{
:legend => true,
:legend_font_size => 20,
:drawer_class => :rmagick
})
@tg.add_layer(@simple_data_array, {:label => 'simple', :color => '#FFFF00'})
@tg.add_layer(@simple_data_array_second, {:label => 'offset', :color => '#00FFFF'})
@tg.add_layer(@simple_data_array_third, {:label => 'scaled', :color => '#FF00FF'})

@tg.render
file_name = 'samples/readme/14_simple_legend.png'
@tg.image_drawer.save_to_file(file_name)

# test
@tg.image_drawer.to_format(@tg.best_output_format).class.should == String
File.exist?(file_name).should == true
end


end
end

0 comments on commit 2a43fac

Please sign in to comment.