The example
require 'gnuplot'
require 'gnuplot/multiplot'
def sample
x = (0..50).collect { |v| v.to_f }
mult2 = x.map {|v| v * 2 }
squares = x.map {|v| v * 4 }
Gnuplot.open do |gp|
Gnuplot::Multiplot.new(gp, layout: [2,1]) do |mp|
Gnuplot::Plot.new(mp) { |plot| plot.data << Gnuplot::DataSet.new( [x, mult2] ) }
Gnuplot::Plot.new(mp) { |plot| plot.data << Gnuplot::DataSet.new( [x, squares] ) }
end
end
end
works pretty well. But how can I send this to a file instead of the screen? Where to put plot.terminal "png enhanced truecolor" and plot.output "data.png"?
Indeed, I don't even know where I should call #terminal and #output methods since the plot object are inside a multiplot block.
As a workaround, the following would work as expected.
Gnuplot.open do |gp|
...
end
The block parameter gp in this part is passed the IO object to send the command to gnuplot through the pipe. Thus, we can send commands ("set terminal", "set output") directly to gnuplot via gp.
Gnuplot.open do |gp|
gp << 'set terminal png enhanced truecolor' << "\n"
gp << 'set output "data.png"' << "\n"
Gnuplot::Multiplot.new(gp, layout: [2,1]) do |mp|
Gnuplot::Plot.new(mp) { |plot| plot.data << Gnuplot::DataSet.new( [x, mult2] ) }
Gnuplot::Plot.new(mp) { | plot| plot.data << Gnuplot::DataSet.new( [x, squares] ) }
end
end
Related
It seems to me that there's no way of making sure REXML::Formatters::Pretty can use \t instead of white-space for the indentation strategy in the XML Tree. The only thing I can do is to define how many white spaces are used per indentation level.
Am I wrong?
Not sure why REXML library does not provide you with this option since it could definitely support it internally but you can just roll your own formatter:
module REXML
module Formatters
class Prettier < Pretty
attr_accessor :style
def initialize(indentation = 2, indent_style =" ", ie_hack=false)
#style = indent_style
super(indentation,ie_hack)
end
protected
def write_element(node, output)
output << style*#level
output << "<#{node.expanded_name}"
node.attributes.each_attribute do |attr|
output << " "
attr.write( output )
end unless node.attributes.empty?
if node.children.empty?
if #ie_hack
output << " "
end
output << "/"
else
output << ">"
# If compact and all children are text, and if the formatted output
# is less than the specified width, then try to print everything on
# one line
skip = false
if compact
if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
string = ""
old_level = #level
#level = 0
node.children.each { |child| write( child, string ) }
#level = old_level
if string.length < #width
output << string
skip = true
end
end
end
unless skip
output << "\n"
#level += #indentation
node.children.each { |child|
next if child.kind_of?(Text) and child.to_s.strip.length == 0
write( child, output )
output << "\n"
}
#level -= #indentation
output << style*#level
end
output << "</#{node.expanded_name}"
end
output << ">"
end
def write_text( node, output )
s = node.to_s()
s.gsub!(/\s/,' ')
s.squeeze!(" ")
s = wrap(s, #width - #level)
s = indent_text(s, #level, style, true)
output << (style*#level + s)
end
def write_comment( node, output)
output << style * #level
Default.instance_method(:write_comment).bind(self).call(node,output)
end
def write_cdata( node, output)
output << style * #level
Default.instance_method(:write_cdata).bind(self).call(node,output)
end
end
end
end
Now you can specify your own indentation level and a indent style e.g.
require "rexml/document"
include REXML
string = <<EOF
<mydoc>
<someelement attribute="nanoo">Text, text, text</someelement>
</mydoc>
EOF
doc = Document.new string
f = Formatters::Prettier(2,"h")
f.write(doc,$stdout)
#<mydoc>
#hh<someelement attribute='nanoo'>
#hhhhText, text, text
#hh</someelement>
#</mydoc>
I used "h" to show how the indentation works as \t will not show up in $stdout but in you case this would be
f = Formatters::Prettier(1,"\t")
I am trying to create a symlink for the created file but I get an error like File exists - (/etc/nginx/sites-available/sushant.com, /etc/nginx/sites-enabled/sushant.com) (Errno::EEXIST)
Here is my code
require 'fileutils'
open('/etc/hosts') do |f|
matches = []
vhosts = []
f.readlines.each do |lines|
matches << lines if lines =~ /.*.com/
end
matches.each do |val|
val.split.each do |x|
vhosts << x if x =~ /.*.com/
end
end
vhosts.each do |domain|
#put the path to sites-enabled
unless File.file? "/etc/nginx/sites-available/#{domain}"
open("/etc/nginx/sites-available/#{domain}", 'w') do |g|
g << "server { \n"
g << "\tlisten 80 default_server;\n"
g << "\tlisten [::]:80 default_server ipv6only=on;\n"
g << "\troot /usr/share/nginx/html;\n"
g << "\tindex index.html index.htm;\n"
g << "\tserver_name localhost;\n"
g << "\tlocation / {\n"
g << "\t\ttry_files $uri $uri/ =404;\n"
g << "\t}\n"
g << "}\n"
g << "server {\n"
g << "\tpassenger_ruby /path/to/ruby;\n"
g << "\trails_env development;\n"
g << "\tlisten 80;\n"
g << "\tserver_name #{domain};\n"
g << "\troot /usr/share/nginx/html/#{domain}/public;\n"
g << "\tpassenger_enabled on;\n"
g << "}\n"
end
File.symlink "/etc/nginx/sites-available/#{domain}", "/etc/nginx/sites-enabled/#{domain}"
end
end
p vhosts
end
Why is the EEXIST error occurs after I run the script? Am I missing out on something?
I have found out that I should have placed File.symlink "/etc/nginx/sites-available/#{domain}", "/etc/nginx/sites-enabled/#{domain}" first then the action to create the file.
I have a csv file "harvest.csv", one of the columns contains dates.
Here is what I came to (plot.rb):
require 'csv'
require 'gnuplot'
days = Array.new
mg = Array.new
csv = CSV.open("../data/harvest.csv", headers: :first_row, converters: :numeric)
csv.each do |row|
days << row[1]
mg << row[3]
end
dates = []
days.each {|n| dates << Date.strptime(n,"%Y-%m-%d")}
Gnuplot.open do |gp|
Gnuplot::Plot.new( gp ) do |plot|
plot.timefmt "'%Y%m%d'"
plot.title "Best Harvest Day"
plot.xlabel "Time"
**plot.xrange "[('2013-04-01'):('2013-06-01')]"**
plot.ylabel "Harvested"
plot.data << Gnuplot::DataSet.new( [dates,mg] ) do |ds|
ds.with = "linespoints"
ds.title = "Pollen harvested"
end
end
end
When I run plot.rb an error is raised:
line 735: Can't plot with an empty x range!
Should I convert [dates] to something else?
The format you're setting with plot.timefmt must match the one you're using in range. Right now the - are missing. Also, you need to set xdata to time to set datatype on the x axis to time.
Gnuplot::Plot.new(gp) do |plot|
plot.timefmt "'%Y-%m-%d'"
plot.title "Best Harvest Day"
plot.xlabel "Time"
plot.xdata "time"
plot.xrange '["2013-04-01":"2013-06-01"]'
plot.ylabel "Harvested"
plot.data << Gnuplot::DataSet.new([dates, mg]) do |ds|
ds.with = "linespoints"
ds.title = "Pollen harvested"
ds.using = "1:2"
end
end
I can sort a list of floats, no problem. But if I'm trying to compare floats in an object to sort objects in a list, I get this error:
`sort': comparison of HateRuby with HateRuby failed (ArgumentError)
Here's some code:
class HateRuby
attr_reader :aFloat
attr_writer :aFloat
def initialize(f)
#aFloat = f
end
end
puts "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}\n\n"
x = []
x << HateRuby.new(3.3)
x << HateRuby.new(2.2)
x << HateRuby.new(1.1)
puts "x contents:"
x.each { |f| puts "#{'%.2f' % f.aFloat}: #{f.aFloat.class}" }
x.sort { |a,b| a.aFloat <=> b.aFloat }
y = x.sort
puts "y contents:"
y.each { |f| puts "#{'%.2f' % f.aFloat}: #{f.aFloat.class}" }
This produces:
[path]/Ruby/rb3D54.tmp:21:in `sort': comparison of HateRuby with HateRuby failed (ArgumentError)
from [path]/Ruby/rb3D54.tmp:21:in `<main>'
1.9.3-p125
x contents:
3.30: Float
2.20: Float
1.10: Float
Complete(1)
I don't really hate Ruby, of course, but I am annoyed...
Thanks to anyone listening.
y = x.sort causing the error, as #sort compares object using the method <=>. But you didn't define the method. There is no HateRuby#<=> method in your class HateRuby.
While you would write collection_object.sort, an implicit block has been supplied, like collection_object.sort { |a,b| a <=> b }. This way sorting is being done.
Now see it is working :
class HateRuby
attr_reader :aFloat
attr_writer :aFloat
def initialize(f)
#aFloat = f
end
def <=>(ob)
# just for clarity I use `self`, you can remove it. as it is implicit.
self.aFloat <=> ob.aFloat
end
end
x = []
x << HateRuby.new(3.3)
x << HateRuby.new(2.2)
x << HateRuby.new(1.1)
x.sort
# => [#<HateRuby:0x9e73d2c #aFloat=1.1>,
# #<HateRuby:0x9e73d40 #aFloat=2.2>,
# #<HateRuby:0x9e73d54 #aFloat=3.3>]
You have to implement the method <=> from the Mixin Comparable:
include Comparable
and
def <=> (other)
You were very close. The sort method does not sort the array itself, it delivers a sorted copy. You have to assign a variable to it. This is your code with one line changed and one line gone:
class HateRuby
attr_reader :aFloat
attr_writer :aFloat
def initialize(f)
#aFloat = f
end
end
puts "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}\n\n"
x = []
x << HateRuby.new(3.3)
x << HateRuby.new(2.2)
x << HateRuby.new(1.1)
puts "x contents:"
x.each { |f| puts "#{'%.2f' % f.aFloat}: #{f.aFloat.class}" }
y = x.sort { |a,b| a.aFloat <=> b.aFloat } # <== This line changed
# y = x.sort # <== This line removed
puts "y contents:"
y.each { |f| puts "#{'%.2f' % f.aFloat}: #{f.aFloat.class}" }
Hey guys I've got a couple of issues with my code.
I was wondering that I am plotting
the results very ineffectively, since
the grouping by hour takes ages
the DB is very simple it contains the tweets, created date and username. It is fed by the twitter gardenhose.
Thanks for your help !
require 'rubygems'
require 'sequel'
require 'gnuplot'
DB = Sequel.sqlite("volcano.sqlite")
tweets = DB[:tweets]
def get_values(keyword,tweets)
my_tweets = tweets.filter(:text.like("%#{keyword}%"))
r = Hash.new
start = my_tweets.first[:created_at]
my_tweets.each do |t|
hour = ((t[:created_at]-start)/3600).round
r[hour] == nil ? r[hour] = 1 : r[hour] += 1
end
x = []
y = []
r.sort.each do |e|
x << e[0]
y << e[1]
end
[x,y]
end
keywords = ["iceland", "island", "vulkan", "volcano"]
values = {}
keywords.each do |k|
values[k] = get_values(k,tweets)
end
Gnuplot.open do |gp|
Gnuplot::Plot.new(gp) do |plot|
plot.terminal "png"
plot.output "volcano.png"
plot.data = []
values.each do |k,v|
plot.data << Gnuplot::DataSet.new([v[0],v[1]]){ |ds|
ds.with = "linespoints"
ds.title = k
}
end
end
end
This is one of those cases where it makes more sense to use SQL. I'd recommend doing something like what is described in this other grouping question and just modify it to use SQLite date functions instead of MySQL ones.