Setting cell/column widths on a Prawn table - ruby

I'm making a little script with ruby which produces a week schedule PDF file, using Prawn as a PDF library and I'm struggling with styling the table. I'd like to set a static width for all the columns in the table so that the widths wouldn't depend on the contents of the cells.
I've read the documentation (lot of room for improvement there) from the Prawn project site and googled for a few hours, but I'm lost at how to set width for columns or cells in a table, or how to style the columns/cells in any way whatsoever. I do get a PDF file which has a grid layout though, the cells just vary in size a lot, which doesn't look that neat.
This didn't work:
Prawn::Document.generate(#filename, :page_size => 'A4', :page_layout => :landscape) do
table(course_matrix, :headers => HEADERS, :border_style => :grid, :row_colors => ['dddddd', 'eeeeee'], :column_widths => 50)
end
Here's the current version of my method to generate PDF, but it doesn't stylize the cells either:
def produce_pdf
course_matrix = DataParser.new.parse_for_pdf
Prawn::Document.generate(#filename, :page_size => 'A4', :page_layout => :landscape) do
table(course_matrix, :headers => HEADERS, :border_style => :grid, :row_colors => ['dddddd', 'eeeeee']) do |table|
table.cells.style { |cell| cell.width = 50 }
end
end
end

I do something like this:
pdf = Prawn::Document.new(
:page_size => 'A4',
:page_layout => :landscape,
:margin => [5.mm])
....
....
pdf.table(tbl_data) do
row(0).style(:background_color => 'dddddd', :size => 9, :align => :center, :font_style => :bold)
column(0).style(:background_color => 'dddddd', :size => 9, :padding_top => 20.mm, :font_style => :bold)
row(1).column(1..7).style(:size => 8, :padding => 3)
cells[0,0].background_color = 'ffffff'
row(0).height = 8.mm
row(1..3).height = 45.mm
column(0).width = 28.mm
column(1..7).width = 35.mm
row(1..3).column(6..7).borders = [:left, :right]
row(3).column(6..7).borders = [:left, :right, :bottom]
....
pdf.render()
More info here.

To set a static width for all the columns I do something like this:
REPORT_FIELDS = %w[DESCRIPTION PRICE DATE NOTE].freeze
A4_SIZE = 200.freeze
data = []
data << REPORT_FIELDS
... things happen ...
table(data, column_widths: (A4_SIZE/REPORT_FIELDS.size).mm))
In this case I wanted to set the table to fit the full page and with the cells with the same width.

Related

How to I add a hyperlink to a cell in axlsx?

With the spreadsheet gem, you can run Spreadsheet::Link.new('http://hyperlinkhere.com', 'Some words') to make a spreadsheet with a cell containing the string "Some words" with a hyperlink leading to "http://hyperlinkhere.com."
What's the axlsx equivalent?
EDIT: What if I want to write a row with more than one cell?
With spreadsheet, you can do this:
newSheetRow[13] = Spreadsheet::Link.new('url.com','text')
newSheetRow[14] = 'some text'
How do I do that with axlsx's .add_row method?
You can add both links within workbook and URLs.
p = Axlsx::Package.new
book = p.workbook
book.add_worksheet(:name => 'hyperlinks') do |sheet|
# external references
sheet.add_row ['axlsx']
sheet.add_hyperlink :location => 'https://github.com/randym/axlsx', :ref => sheet.rows.first.cells.first
# internal references
sheet.add_hyperlink :location => "'Next Sheet'!A1", :ref => 'A2', :target => :sheet
sheet.add_row ['next sheet']
end

loop through file with hashes in ruby

I have a text file located in my project directory that contains the link of sites as well as the location of the logos. For example:
img1 = {name => "logo1", link => "http://example.com", imgpath => "img/logo1.png"}
img2 = {name => "logo2", link => "http://foobar.com", imgpath => "img/foobar.png"}
img3 = {name => "logo3", link => "http://foobar.com", imgpath => "img/foobar2.png"}
What I would like to do is loop through that text file to display each image with its link. I've searched all over and I can't seem to find a good example on how to do it. Here's the for loop I've got so far in my page:
- File.open("img/logos.txt").readlines.each do |name,link,imgpath|
.col-sm-6.col-md-4.col-lg-3
.item-work
.hover
%img{:alt => "Image", :src => "img/#{imgpath}"}/
%a.lightbox-image{:href => "#{link}", :title => "Image"}/
.overlay
.info
%a{:href => "#{name}"} #{name}
I'm sort of close, the page loads all the logos except the images aren't there and the links are associated with them. I know it's because I didn't call them correctly in my %img link and %a tags but I can't seem to figure it out. How would you suggest going about doing this?
#readlines is going to give you each line of the text file as a string. Based on your comment, this would word fine:
logos.txt:
logo1,http://example.com,img/logo1.png
logo2,http://foobar.com,img/foobar.png
logo3,http://foobar.com,img/foobar2.png
Haml:
- File.open("img/logos.txt").readlines.each do |line|
- img = line.split(',').map(&:chomp)
.col-sm-6.col-md-4.col-lg-3
.item-work
.hover
%img{:alt => "Image", :src => "img/#{img[2]}"}/
%a.lightbox-image{:href => "#{img[1]}", :title => "Image"}/
.overlay
.info
%a{:href => "#{img[0]}"} #{img[0]}
The second line is creating an array of values, like so:
[1] pry(main)> line
=> "logo1,http://example.com,img/logo1.png\n"
[2] pry(main)> line.split(',').map(&:chomp)
=> ["logo1", "http://example.com", "img/logo1.png"]

I'm using the ruby gem "roo" to read xlsx file, how to return the content of one column as an array?

require 'gchart'
require 'rubygems'
require 'roo'
oo = Excelx.new("datav.xlsx")
oo.default_sheet = oo.sheets.first
2.upto(47) do |line|
data_a = [oo.cell(line,'B')]
data_b = [oo.cell(line,'E')]
chart_a = Gchart.new( :type => 'line',
:title => "A",
:theme => :keynote,
:width => 600,
:height => 500,
:data => data_a,
:line_colors => 'e0440e',
:axis_with_labels => ['x', 'y'],
:axis_range => [[0,50,20], [0,3000,500]],
:filename => "tmp/chart_a.png")
chart_b = Gchart.new( :type => 'line',
:title => "B",
:theme => :keynote,
:width => 600,
:height => 500,
:data => data_b,
:line_colors => 'e62ae5',
:axis_with_labels => ['x', 'y'],
:axis_range => [[0,50,20], [0,3000,500]],
:filename => "tmp/chart_b.png")
# Record file in filesystem
chart_a.file
chart_b.file
end
This will get every cell's content of column B and E to be the argument :data alone. How to return it as an array? If roo can't return array, then is there any else gem do this?
there is a column method that returns values of a given column as an array. Calling oo.column(2) should return you values for column B. oo.column('B') might work also. haven't tested it.
I needed the row back as a hash to be compatible with the logic I used for FasterCSV. This will give you a hash of the first row as the key and current line as the value.
def row_from_excel(s, line)
row = {}
s.first_column.upto(s.last_column) do |col|
cell_name = s.cell(1, col)
logger.debug "************* #{col} => #{cell_name} => #{s.cell(line, col)}"
row[cell_name] = s.cell(line, col)
end
row
end
s = Excelx.new(path_to_file) # or Excel.new(path_to_file)
2.upto(s.last_row) do |line|
row = row_from_excel(s, line)
end

How to force a Float to display with full precision w/o scientific notation and not as a string?

How do you force a float to display with all significant places / full precision without scientific notation in Ruby?
Presently I convert a BigDecimal to Float, BigDecimal(0.000000001453).to_f, however this yields a resultant float of 1.453e-09. If I do something like "%14.12f" % BigDecimal("0.000000001453").to_f I get a string. In this case, however, a string as output is unacceptable as I need it as an actual numeric float without scientific notation.
--- Edit---
Alright, let me give some context here, which will probably require a change of my original question.
I'm attempting to create a graph with Highstock & lazy_high_chart. Earlier today I was able to draw graphs just fine when the floats were emitting to the resultant js as full precision floats vs showing up in scientific notation. Hence I felt that the problem resides in this issue.
But after the few inputs I'm getting here, perhaps I need some further review of the source and my assumption is misplaced. I'll let you decide:
#h = LazyHighCharts::HighChart.new('graph') do |f|
hours_of_readings = 1
reading_intervals = 1 #hour
readings_per_hour = 60
readings = ModelName.order("date DESC").select('data_readings.data2, data_readings.data1, data_readings.date').limit(hours_of_readings * readings_per_hour).all
data1_and_date_series = Array.new
data2_and_date_series = Array.new
dates = Array.new
# I have been thinking that the problem lies here in the "row.data1.to_f" and
# "row.data2.to_f" and thus this is the root of my initial question in terms
# of it emitting scientific notation to the js output in the format of:
# [[1.0e-09], [1.04e-09],[9.4e-09], ... [3.68e-09]]
data1_and_date_series = readings.map{|row| [(row.date.to_i * 1000), (row.data1.to_f if BigDecimal(row.data1) != BigDecimal("-1000.0"))] }
data2_and_date_series = readings.map{|row| [(row.date.to_i * 1000), (row.data2.to_f if BigDecimal(row.data2) != BigDecimal("-1000.0"))] }
f.series(
:name => 'Data1',
:data => data1_and_date_series,
:pointStart => Time.now.to_i * 1000,
:pointEnd => hours_of_readings.hours.ago.to_i * 1000,
:pointInterval => reading_intervals.hour * 1000,
:color => 'blue'
)
f.series(
:name => 'Data2)',
:data => data2_and_date_series,
:pointStart => Time.now.to_i * 1000,
:pointEnd => hours_of_readings.hours.ago.to_i * 1000,
:pointInterval => reading_intervals.hour.to_i * 1000,
:color => 'red'
)
f.chart({:defaultSeriesType=>"spline" })
f.yAxis [
{:title => { :text => "Label 1", :margin => 10} },
{:title => { :text => "Label 2 (groups)"}, :opposite => true},
{:max => 0},
{:min => -0.000000001}
]
f.options[:xAxis] = {
:title => { :text => "Time"},
:type => "datetime"
}
f.title(:text => "Title")
f.legend(:align => 'right', :verticalAlign => 'top', :y => 75, :x => -50, :layout => 'vertical') # override the default values
end
The string representation and the actual value of a float are two different things.
What you see on screen/print-out is always a string representation, be it in scientific notation or "normal" notation. A float is converted to its string representation by to_s, puts, "%.10f" % and others.
The float value itself is independent of that. So your last sentence does not make much sense. The output is always a string.
To enforce a certain float format in Rails' to_json you can overwrite Float#encode_json, e.g.
class ::Float
def encode_json(opts = nil)
"%.10f" % self
end
end
Put this before your code above. Note that -- depending on your actual values -- you might need more sophisticated logic to produce reasonable strings.
Will this work for you -
>> 0.000000001453
=> 1.453e-09 # what you are getting right now
>> puts "%1.12f" % 0.000000001453
0.000000001453 # what you need
=> nil

How to have different headers/footers for a big table in Ruby/Prawn?

I wanna generate a pdf with ruby and the prawn(0.8.4) gem. the first page of the pdf should have a different header/footer than the following pages. The data will be shown in a table, but the table is shown on multiple pages.
Example:
first page should have an header height of 60.mm
the table starts at the first page, below the header
on the second page there should be a header with a height of 30.mm
the table continues on the second page, below the smaller header
do you see my problem?
solved.
require "rubygems"
require "prawn"
require "prawn/core"
require "prawn/layout"
require "prawn/measurement_extensions"
Prawn::Document.generate("test.pdf", :page_size => "A3", :page_layout => :landscape, :margin => 0) do
padded_box 30.mm do
move_down(40.mm)
items = 100.times.map {|i| [i, i]}
table items, :border_style => :underline_header, :headers => ["Column#1", "Column#2"]
end
page_count.times do |i|
page_num = i+1
go_to_page(page_num)
if page_num == 1
# header of first page
text_box "header#1", :at => [30.mm, 290.mm], :size => 18
image "logo.png", :at => [12.mm,(297-15.78).mm]
else
# header 2..n
text_box "header#2..n", :at => [30.mm, 290.mm], :size => 12
end
end
end

Resources