Skip to content

Latest commit

 

History

History
909 lines (648 loc) · 20.7 KB

DOCUMENTATION.textile

File metadata and controls

909 lines (648 loc) · 20.7 KB

How to use it

All these examples are generated using spec/readme/technical_readme_spec.rb . There are some differences: filename is without path and is used rmagick renderer. Github has issues with SVG files.

Default graph size

In this documentation I lowered default graph size so it looks nicer here. If you would like to do this insert something like this at the beginning of your code:


GraphImageDrawer.width = 400
GraphImageDrawer.height = 300

Simple graph

First thing we need to have data to show on graph, for example something like:


@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 },
]

If you want to put this data on graph you need to create TechnicalGraph object


@tg = TechnicalGraph.new

and add a layer.


@tg.add_layer(@simple_data_array)

We added data, but we don’t see anything. Now we have to render graph and save it to file.


file_name = '01_simplest.png'
@tg.save_to_file(file_name)

And we got our first graph with one layer, without changing any options, a bit raw.

(01) simple graph

More layers

Maybe example with two layers?


@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_b = [
  { :x => 0.5, :y => 0.5 },
  { :x => 1.5, :y => 0.5 },
  { :x => 2.5, :y => 1.5 },
  { :x => 3.5, :y => 1.0 },
  { :x => 4.5, :y => 1.5 },
  { :x => 5.5, :y => 1.5 },
]

@tg = TechnicalGraph.new
@tg.add_layer(@simple_data_array)
@tg.add_layer(@simple_data_array_b)

file_name = '02_two_layers.png'
@tg.save_to_file(file_name)

(02) simple graph

Ranges

By default ranges are calculated automatically so all points are visible. You can override ranges setting.


@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_min => -2,
    :x_max => 10,
    :y_min => -1,
    :y_max => 10,
  })

@tg.add_layer(@simple_data_array)

file_name = '03_changed_ranges.png'
@tg.save_to_file(file_name)

(03) changed ranges

Keep in mind that ranges can be changed while rendering graph, but you can be sure – they can be only enlarged and all points will be visible. Unless…

Fixed ranges

You can turn off automatic range enlargement algorithm by using:


options[:xy_behaviour] = :fixed

Example:


@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_min => 1,
    :x_max => 2,
    :y_min => 1,
    :y_max => 2,
    :xy_behaviour => :fixed,
  })

@tg.add_layer(@simple_data_array)

file_name = '04_changed_ranges_fixed.png'
@tg.save_to_file(file_name)

(04) changed ranges

Axis interval – fixed quantity

Axis can be calculated using two algorithms:

  1. fixed interval – axis are placed every precise distance,
  2. fixed amount – there is fixed amount of axis on graph.

Keep in mind that there is X (parameter) and Y (value) axis. If you want to set fixed amount, you should set options[:x_axis_fixed_interval] and/or options[:y_axis_fixed_interval] to false, like in the example below.


@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_fixed_interval => false,
    :y_axis_fixed_interval => false,
    :y_axis_count => 20,
    :x_axis_count => 20,
  })

@tg.add_layer(@simple_data_array)

file_name = '05_axis_fixed_amount.png'
@tg.save_to_file(file_name)

(05) fixed axis count

Axis interval – fixed interval

Axis can be calculated using two algorithms:

  1. fixed interval – axis is every some distance,
  2. fixed count – there is fixed amount of axis on graph.

Keep in mind that where is X (parameter) and Y (value) axis. If you want to set fixed interval you should set options[:x_axis_fixed_interval] and/or options[:y_axis_fixed_interval] to true, like in the example below.


@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_fixed_interval => true,
    :y_axis_fixed_interval => true,
    :y_axis_interval => 0.8,
    :x_axis_interval => 0.6,
  })
@tg.add_layer(@simple_data_array)
  
file_name = '06_axis_fixed_interval.png'
@tg.save_to_file(file_name)

(06) fixed axis interval

Axis labels

You can add label to X and Y axis. using options[:x_axis_label] and options[:y_axis_label], and you can choose font size using options[:axis_label_font_size].


@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',
    :axis_label_font_size => 16
  })
@tg.add_layer(@simple_data_array)
  
file_name = '07_axis_label.png'
@tg.save_to_file(file_name)

(07) axis labels

Float numbers and value labels

By default all float number are shown with two digits after dot precision. You can override it using options[:truncate_string] like in example below. If you want to have values near graph points you can use proper layer options.

Layers have also options, and it is useful for this example to turn on value labels to true – layer_options[:value_labels] = true .


@float_data_array = [
  { :x => 0, :y => 0 },
  { :x => 0.111, :y => 0.123 },
  { :x => 0.222, :y => 1.456 },
  { :x => 0.333, :y => 2.8756 },
  { :x => 0.555, :y => 1.042 },
  { :x => 0.888, :y => 0.988 },
]

@tg = TechnicalGraph.new(
  {
    :truncate_string => "%.3f"
  })
@layer_params = {
  :value_labels => true
}
@tg.add_layer(@float_data_array, @layer_params)

file_name = '08a_truncate_string.png'
@tg.save_to_file(file_name)

(08a) displaying float numbers


@float_data_array = [
  { :x => 0, :y => 0 },
  { :x => 0.111, :y => 0.123 },
  { :x => 0.222, :y => 1.456 },
  { :x => 0.333, :y => 2.8756 },
  { :x => 0.555, :y => 1.042 },
  { :x => 0.888, :y => 0.988 },
]

@tg = TechnicalGraph.new(
  {
    :truncate_string => "%.1f"
  })
@layer_params = {
  :value_labels => true
}
@tg.add_layer(@float_data_array, @layer_params)

file_name = '08b_truncate_string.png'
@tg.save_to_file(file_name)

(08b) displaying float numbers

Graph image size

It would be very silly if this library had hard coded image size. You can change it using options[:width] and options[:height].


@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(
  {
    :width => 400,
    :height => 300
  })
@tg.add_layer(@simple_data_array)

file_name = '09_image_size.png'
@tg.save_to_file(file_name)

(09) image size

Colours

If you think you have better artistic taste feel free to change colours used in graph :) Keep in mind that hatch color is available only in rmagick renderer. Some short info about renderers is located in README.

There are three color options per graph:

  • options[:background_color] – background color of image
  • options[:background_hatch_color] – background hatch color, used only in RMagick renderer
  • options[:axis_color] – color of axis, default #000000

And one layer options:

  • layer_options[:color] – it is color of layer

@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(
  {
    :background_color => '#000000',
    :background_hatch_color => '#222222',
    :axis_color => '#FFFFFF'
  })
@tg.add_layer(@simple_data_array, {:color => '#0000FF'})

file_name = '10_colors.png'
@tg.save_to_file(file_name)

(10) colors

Image render

There were two render classes since version 0.4.0: Rasem and RMagick. Now it is more complicated.

If you want SVG file you a very happy man, everything works and SVG looks good. If you want PNG you can use chunky_png but you are missing some important features like texts, dots, … You can install rmagick and technical_graph will use power of rmagick to create very nice PNG graphs.

Anti-aliasing

Anti-aliasing is only available using RMagick renderer. By default it is disabled.


options[:antialias] = true

Sample graph without anti-aliasing has 11kB, with 69kB. Does size matter to you?


@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(
  {
    :antialias => true,
    :drawer_class => :rmagick
  })
@tg.add_layer(@simple_data_array)

file_name = '12_aa_true.png'
@tg.save_to_file(file_name)

# only for size comparison
@tg = TechnicalGraph.new(
  {
    :antialias => false,
    :drawer_class => :rmagick
  })
@tg.add_layer(@simple_data_array)

file_name = '12_aa_false.png'
@tg.save_to_file(file_name)

With anti-alias

(12) Anti-aliasing enabled

Without anti-alias

(12) Anti-aliasing disabled

Font size

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

@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 => 24
  })
@tg.add_layer(@simple_data_array, {:value_labels => true})

file_name = '13_font_sizes.png'
@tg.save_to_file(file_name)

(13) Font size

Legend

If you want to use legend you only have to set labels for layers and enable it by using:

  • options[:legend] – set to true to enable legend, by default auto position mode is enabled
  • layer_options[:label] – label used for legend

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

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


layer_options[:color] = '#FF0000' # color in format #RRGGBB

Graph sample 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 => '#AA7722'})
@tg.add_layer(@simple_data_array_second, {:label => 'offset', :color => '#00AA55'})
@tg.add_layer(@simple_data_array_third, {:label => 'scaled', :color => '#3322BB'})

file_name = '14_simple_legend.png'
@tg.save_to_file(file_name)

(14) Legend

If you like you can turn off auto position:


options[:legend_auto] = false
options[:legend_x] = 100
options[:legend_y] = 100

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 is 100 and it is enlarged auto. using font size
  • options[:legend_margin] – graph margin used not to draw legend on border, default 50

Smoothing

Useful when origin of data is a bit noisy. For best results you can add two layers: one raw, and second with smoothing enabled.


@tg = TechnicalGraph.new(
  {
    :width => 1000,
    :height => 750,
    :legend => true,
    :x_axis_label => "Parameter",
    :y_axis_label => "Value"
  }
)
max = 100

@layer_data = Array.new
(0..max).each do |i|
  x = -10.0 + (20.0 * i.to_f / max.to_f)
  y = 10.0 * Math.cos(i.to_f * (2.0 * 3.14 / max.to_f))

  y += rand * 2.0

  @layer_data << { :x => x, :y => y }
end

# adding simple layer
@layer_params = {
  :label => 'raw',
  :value_labels => false,
  :simple_smoother => false,
  :simple_smoother_level => 1,
  :simple_smoother_strategy => :gauss,
  :simple_smoother_x => false,
}
@layer_params_b = @layer_params.clone.merge(
  {
    :label => 'smoothed - level 3',
    :simple_smoother_level => 3,
    :simple_smoother => true
  })
@layer_params_e = @layer_params.clone.merge(
  {
    :label => 'smoothed - level 50',
    :simple_smoother_level => 50,
    :simple_smoother => true
  })

@tg.add_layer(@layer_data.clone, @layer_params)
@tg.add_layer(@layer_data.clone, @layer_params_b)
@tg.add_layer(@layer_data.clone, @layer_params_e)


file_name = '15_smoothing.png'
@tg.save_to_file(file_name)

(15) Smoothing

Noise removal

Useful when origin of data is a bit noisy. For best results you can add two layers: one raw, and second with noise removal. It can be used with smoothing.


@tg = TechnicalGraph.new(
  {
    :legend => true
  }
)
max = 250

@layer_data = Array.new
(0..max).each do |i|
  x = -10.0 + (20.0 * i.to_f / max.to_f)
  y = -10.0 + (20.0 * i.to_f / max.to_f)
  @layer_data << { :x => x, :y => y }
end

# custom spikes
[3, 36, 99, 187, 204].each do |i|
  offset = 5.0
  offset *= -1.0 if rand(100) % 2 == 1
  @layer_data[i][:y] += offset
end

# some random spikes
150.times do
  i = rand(@layer_data.size)
  offset = rand(80).to_f / 10.0
  offset *= -1.0 if rand(100) % 2 == 1

  @layer_data[i][:y] += offset
end

# adding simple layer
@layer_params = {
  :label => 'raw',
  :value_labels => false,
}
@layer_params_b = @layer_params.clone.merge(
  {
    :label => 'n.r. level 3, window 10',
    :noise_removal_window_size => 10,
    :noise_removal_level => 3,
    :noise_removal => true
  })
@layer_params_e = @layer_params.clone.merge(
  {
    :label => 'n.r level 10, window 30',
    :noise_removal_window_size => 10,
    :noise_removal_level => 30,
    :noise_removal => true
  })

@tg.add_layer(@layer_data.clone, @layer_params)
@tg.add_layer(@layer_data.clone, @layer_params_b)
@tg.add_layer(@layer_data.clone, @layer_params_e)


file_name = '16_noise_removal.png'
@tg.save_to_file(file_name)

(16) Noise removal

Axis interval enlargement

In case of large amount of data axis can be squeezed and graph is unreadable. You can set axis enlargement to help in these situations. When distance between axis is lower than set in options[:x_axis_min_distance] or options[:y_axis_min_distance] image dimensions are enlarged to maintain proper axis distances. There is default distance for X and Y axis of 30 pixels.

Possible options:

  • options[:axis_density_enlarge_image] – enable both axis (X, Y)
  • options[:x_axis_density_enlarge_image] – enable only X axis
  • options[:y_axis_density_enlarge_image] – enable only Y axis
  • options[:x_axis_min_distance] – minimum distance for X axis
  • options[:y_axis_min_distance] – minimum distance for Y axis

@tg = TechnicalGraph.new(
  {
    :x_axis_density_enlarge_image => true,
    :x_axis_min_distance => 30,
    :x_axis_interval => 1.0,
    :x_axis_fixed_interval => true,
    :width => 100
  }
)
max = 20

@layer_data = Array.new
(0..max).each do |i|
  x = -10.0 + (20.0 * i.to_f / max.to_f)
  y = -10.0 + rand(2000).to_f / 100.0
  @layer_data << { :x => x, :y => y }
end

@tg.add_layer(@layer_data)


file_name = '17_axis_enlargement.png'
@tg.save_to_file(file_name)

(17) Axis enlargement

Advanced smoothing parameters

The best way is to experiment with all parameters and choose which fit best.

Possible options:

  • layer_options[:simple_smoother] – set true to enable
  • layer_options[:simple_smoother_level] – higher → more smooth
  • layer_options[:simple_smoother_x] – use X offset smoothing, slower but a little better quality

@tg = TechnicalGraph.new(
  {
    :width => 1600,
    :height => 1200,
    :legend => true,
    :x_axis_label => "Parameter",
    :y_axis_label => "Value",
    :drawer_class => README_RENDERED,
  }
)
max = 200

@layer_data = Array.new
(0..max).each do |i|
  x = -10.0 + (20.0 * i.to_f / max.to_f)
  y = 10.0 * Math.cos(i.to_f * (2.0 * 3.14 / max.to_f))

  y += rand * 2.0

  @layer_data << { :x => x, :y => y }
end

# adding simple layer
@layer_params = {
  :label => 'raw',
  :value_labels => false
}

@layer_params_smooth_wox = @layer_params.clone.merge(
  {
    :label => 'without X smoothing',
    :simple_smoother => true,
    :simple_smoother_level => 5,
    :simple_smoother_strategy => :gauss,
    :simple_smoother_x => false,
  }
)

@layer_params_smooth_wx = @layer_params.clone.merge(
  {
    :label => 'with X smoothing',
    :simple_smoother => true,
    :simple_smoother_level => 5,
    :simple_smoother_x => true,
  }
)

@tg.add_layer(@layer_data.clone, @layer_params_smooth_wox)
@tg.add_layer(@layer_data.clone, @layer_params_smooth_wx)
@tg.add_layer(@layer_data.clone, @layer_params)

file_name = '18_adv_smoothing.png'
@tg.save_to_file(file_name)

(18) Smoothing 2

Adjusting axis to zero

Axis are placed automatically. It would look better if axis were located on zeroes. Fortunately it is enabled by default, but check out how it would look.

Possible options:

  • layer_options[:adjust_axis_to_zero] – set true to enable

@tg = TechnicalGraph.new({:adjust_axis_to_zero => false})
max = 200

@layer_data = Array.new
(0..max).each do |i|
  x = -10.0 + (20.0 * i.to_f / max.to_f) + 0.11
  y = 10.0 * Math.cos(i.to_f * (2.0 * 3.14 / max.to_f))

  y += rand * 2.0

  @layer_data << { :x => x, :y => y }
end

@tg.add_layer(@layer_data)

file_name = '19_axis_not_adjust.png'
@tg.save_to_file(file_name)

(19) Not adjusted axis