Class: Gruff::Line

Inherits:
Base
  • Object
show all
Defined in:
lib/gruff/line.rb

Overview

Here's how to make a Gruff::Line.

g = Gruff::Line.new
g.title = "A Line Graph"
g.data 'Fries', [20, 23, 19, 8]
g.data 'Hamburgers', [50, 19, 99, 29]
g.write("line.png")

There are also other options described below, such as #baseline_value, #baseline_color, #hide_dots=, and #hide_lines=.

Constant Summary

Constants inherited from Base

Base::DEFAULT_MARGIN, Base::DEFAULT_TARGET_WIDTH, Base::LABEL_MARGIN, Base::LEGEND_MARGIN

Instance Attribute Summary collapse

Attributes inherited from Base

#bold_title, #bottom_margin, #center_labels_over_point, #colors, #font_color, #has_left_labels, #hide_legend, #hide_line_markers, #hide_line_numbers, #hide_title, #label_max_size, #label_stagger_height, #label_truncation_style, #labels, #left_margin, #legend_at_bottom, #legend_box_size, #legend_font_size, #legend_margin, #marker_color, #marker_font_size, #marker_shadow_color, #maximum_value, #minimum_value, #no_data_message, #right_margin, #sort, #sorted_drawing, #title, #title_font, #title_font_size, #title_margin, #top_margin, #use_data_label, #x_axis_increment, #x_axis_label, #y_axis_increment, #y_axis_label

Instance Method Summary collapse

Methods inherited from Base

#add_color, #data, #font=, #margins=, #replace_colors, #theme=, #theme_37signals, #theme_greyscale, #theme_keynote, #theme_odeo, #theme_pastel, #theme_rails_keynote, #to_blob, #to_image, #write

Constructor Details

#initialize(*args) ⇒ Line

Call with target pixel width of graph (800, 400, 300), and/or false to omit lines (points only).

g = Gruff::Line.new(400) # 400px wide with lines
g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)

The preferred way is to call #hide_dots= or #hide_lines= instead.

Raises:

  • (ArgumentError)

71
72
73
74
75
76
77
78
79
# File 'lib/gruff/line.rb', line 71

def initialize(*args)
  raise ArgumentError, 'Wrong number of arguments' if args.length > 2

  if args.empty? || (!args.first.is_a?(Numeric) && !args.first.is_a?(String))
    super()
  else
    super args.shift
  end
end

Instance Attribute Details

#dot_radius=(value) ⇒ Object (writeonly)

Sets the attribute dot_radius

Parameters:

  • value

    the value to set the attribute dot_radius to.


26
27
28
# File 'lib/gruff/line.rb', line 26

def dot_radius=(value)
  @dot_radius = value
end

#dot_style=(value) ⇒ Object (writeonly)

default is 'circle', other options include square.


29
30
31
# File 'lib/gruff/line.rb', line 29

def dot_style=(value)
  @dot_style = value
end

#hide_dots=(value) ⇒ Object (writeonly)

Hide parts of the graph to fit more data points, or for a different appearance.


32
33
34
# File 'lib/gruff/line.rb', line 32

def hide_dots=(value)
  @hide_dots = value
end

#hide_lines=(value) ⇒ Object (writeonly)

Hide parts of the graph to fit more data points, or for a different appearance.


32
33
34
# File 'lib/gruff/line.rb', line 32

def hide_lines=(value)
  @hide_lines = value
end

#line_width=(value) ⇒ Object (writeonly)

Dimensions of lines and dots; calculated based on dataset size if left unspecified.


25
26
27
# File 'lib/gruff/line.rb', line 25

def line_width=(value)
  @line_width = value
end

#maximum_x_value=(value) ⇒ Object (writeonly)

accessors for support of xy data.


38
39
40
# File 'lib/gruff/line.rb', line 38

def maximum_x_value=(value)
  @maximum_x_value = value
end

#minimum_x_value=(value) ⇒ Object (writeonly)

accessors for support of xy data.


35
36
37
# File 'lib/gruff/line.rb', line 35

def minimum_x_value=(value)
  @minimum_x_value = value
end

#reference_line_default_color=(value) ⇒ Object (writeonly)

Sets the attribute reference_line_default_color

Parameters:

  • value

    the value to set the attribute reference_line_default_color to.


18
19
20
# File 'lib/gruff/line.rb', line 18

def reference_line_default_color=(value)
  @reference_line_default_color = value
end

#reference_line_default_width=(value) ⇒ Object (writeonly)

Sets the attribute reference_line_default_width

Parameters:

  • value

    the value to set the attribute reference_line_default_width to.


19
20
21
# File 'lib/gruff/line.rb', line 19

def reference_line_default_width=(value)
  @reference_line_default_width = value
end

#reference_linesObject

Allow for reference lines ( which are like baseline … just allowing for more & on both axes ).


17
18
19
# File 'lib/gruff/line.rb', line 17

def reference_lines
  @reference_lines
end

#show_vertical_markers=(value) ⇒ Object (writeonly)

Allow for vertical marker lines.


22
23
24
# File 'lib/gruff/line.rb', line 22

def show_vertical_markers=(value)
  @show_vertical_markers = value
end

Instance Method Details

#baseline_colorObject


53
54
55
56
57
# File 'lib/gruff/line.rb', line 53

def baseline_color
  if @reference_lines.key?(:baseline)
    @reference_lines[:baseline][:color]
  end
end

#baseline_color=(new_value) ⇒ Object


59
60
61
62
# File 'lib/gruff/line.rb', line 59

def baseline_color=(new_value)
  @reference_lines[:baseline] ||= {}
  @reference_lines[:baseline][:color] = new_value
end

#baseline_valueObject

Get the value if somebody has defined it.


41
42
43
44
45
# File 'lib/gruff/line.rb', line 41

def baseline_value
  if @reference_lines.key?(:baseline)
    @reference_lines[:baseline][:value]
  end
end

#baseline_value=(new_value) ⇒ Object

Set a value for a baseline reference line..


48
49
50
51
# File 'lib/gruff/line.rb', line 48

def baseline_value=(new_value)
  @reference_lines[:baseline] ||= {}
  @reference_lines[:baseline][:value] = new_value
end

#dataxy(name, x_data_points = [], y_data_points = [], color = nil) ⇒ Object #dataxy(name, xy_data_points = [], color = nil) ⇒ Object

Note:
  • if (x_data_points.length != y_data_points.length) an error is returned.

  • if the color argument is nil, the next color from the default theme will be used.

  • if you want to use a preset theme, you must set it before calling #dataxy.

This method allows one to plot a dataset with both X and Y data.

Examples:

g = Gruff::Line.new
g.title = "X/Y Dataset"
g.dataxy("Apples", [1,3,4,5,6,10], [1, 2, 3, 4, 4, 3])
g.dataxy("Bapples", [1,3,4,5,7,9], [1, 1, 2, 2, 3, 3])
g.dataxy("Capples", [[1,1],[2,3],[3,4],[4,5],[5,7],[6,9]])

# you can still use the old data method too if you want:
g.data("Capples", [1, 1, 2, 2, 3, 3])

# labels will be drawn at the x locations of the keys passed in.
In this example the labels are drawn at x positions 2, 4, and 6:
g.labels = {0 => '2003', 2 => '2004', 4 => '2005', 6 => '2006'}
# The 0 => '2003' label will be ignored since it is outside the chart range.

Overloads:

  • #dataxy(name, x_data_points = [], y_data_points = [], color = nil) ⇒ Object

    Parameters:

    • name (String)

      the title of the dataset.

    • x_data_points (Array) (defaults to: [])

      an array containing the x data points for the graph.

    • y_data_points (Array) (defaults to: [])

      an array containing the y data points for the graph.

    • color (String) (defaults to: nil)

      hex number indicating the line color as an RGB triplet.

  • #dataxy(name, xy_data_points = [], color = nil) ⇒ Object

    Parameters:

    • name (String)

      the title of the dataset.

    • xy_data_points (Array) (defaults to: [])

      an array containing both x and y data points for the graph.

    • color (String) (defaults to: nil)

      hex number indicating the line color as an RGB triplet.

Raises:

  • (ArgumentError)

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/gruff/line.rb', line 138

def dataxy(name, x_data_points = [], y_data_points = [], color = nil)
  # make sure it's an array
  x_data_points = Array(x_data_points)
  y_data_points = Array(y_data_points)

  raise ArgumentError, 'x_data_points is nil!' if x_data_points.empty?

  if x_data_points.all? { |p| p.is_a?(Array) && p.size == 2 }
    x_data_points, y_data_points = x_data_points.transpose
  end

  raise ArgumentError, 'x_data_points.length != y_data_points.length!' if x_data_points.length != y_data_points.length

  # call the existing data routine for the x/y data.
  store.add(name, y_data_points, color, x_data_points)
end

#drawObject


171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/gruff/line.rb', line 171

def draw
  super

  return unless data_given?

  # Check to see if more than one datapoint was given. NaN can result otherwise.
  @x_increment = (column_count > 1) ? (@graph_width / (column_count - 1).to_f) : @graph_width

  @reference_lines.each_value do |curr_reference_line|
    draw_horizontal_reference_line(curr_reference_line) if curr_reference_line.key?(:norm_value)
    draw_vertical_reference_line(curr_reference_line) if curr_reference_line.key?(:index)
  end

  if @show_vertical_markers
    (0..column_count).each do |column|
      x = @graph_left + @graph_width - column.to_f * @x_increment

      Gruff::Renderer::Line.new(color: @marker_color).render(x, @graph_bottom, x, @graph_top)
      #If the user specified a marker shadow color, draw a shadow just below it
      if @marker_shadow_color
        Gruff::Renderer::Line.new(color: @marker_shadow_color).render(x + 1, @graph_bottom, x + 1, @graph_top)
      end
    end
  end

  store.norm_data.each do |data_row|
    prev_x = prev_y = nil

    one_point = contains_one_point_only?(data_row)

    data_row.coordinates.each_with_index do |(x_data, y_data), index|
      if x_data.nil?
        #use the old method: equally spaced points along the x-axis
        new_x = @graph_left + (@x_increment * index)
        draw_label(new_x, index)
      else
        new_x = get_x_coord(x_data, @graph_width, @graph_left)
        @labels.each do |label_pos, _|
          draw_label(@graph_left + ((label_pos - @minimum_x_value) * @graph_width) / (@maximum_x_value - @minimum_x_value), label_pos)
        end
      end
      unless y_data # we can't draw a line for a null data point, we can still label the axis though
        prev_x = prev_y = nil
        next
      end

      new_y = @graph_top + (@graph_height - y_data * @graph_height)

      # Reset each time to avoid thin-line errors
      stroke_width  = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4), 5.0)
      circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 2.5), 5.0)

      if !@hide_lines && prev_x && prev_y
        Gruff::Renderer::Line.new(color: data_row.color, width: stroke_width)
                             .render(prev_x, prev_y, new_x, new_y)
      end

      if one_point || !@hide_dots
        Gruff::Renderer::Dot.new(@dot_style, color: data_row.color, width: stroke_width).render(new_x, new_y, circle_radius)
      end

      prev_x = new_x
      prev_y = new_y
    end
  end
end

#draw_horizontal_reference_line(reference_line) ⇒ Object


161
162
163
164
# File 'lib/gruff/line.rb', line 161

def draw_horizontal_reference_line(reference_line)
  level = @graph_top + (@graph_height - reference_line[:norm_value] * @graph_height)
  draw_reference_line(reference_line, @graph_left, @graph_left + @graph_width, level, level)
end

#draw_reference_line(reference_line, left, right, top, bottom) ⇒ Object


155
156
157
158
159
# File 'lib/gruff/line.rb', line 155

def draw_reference_line(reference_line, left, right, top, bottom)
  color = reference_line[:color] || @reference_line_default_color
  width = reference_line[:width] || @reference_line_default_width
  Gruff::Renderer::DashLine.new(color: color, width: width).render(left, top, right, bottom)
end

#draw_vertical_reference_line(reference_line) ⇒ Object


166
167
168
169
# File 'lib/gruff/line.rb', line 166

def draw_vertical_reference_line(reference_line)
  index = @graph_left + (@x_increment * reference_line[:index])
  draw_reference_line(reference_line, index, index, @graph_top, @graph_top + @graph_height)
end