Generating pastel colors - ruby

I neeed to generate random color. But I need pstel ones. Not too dark, not too bright.
I can generate colors this way:
color = (1..3).to_a.map{ ( c = rand(255).to_s(16) ).size < 2 ? "0#{c}" : c }.to_s
But it will return colors from all palette.

Try this:
start_color = 128 # minimal color amount
total_offset = 64 # sum of individual color offsets above the minimal amount
'#' +
[0, rand(total_offset), rand(total_offset), total_offset].sort.each_cons(2).map{|a,b|
"%02x" % (start_color+b-a)
}.join
Actually, here's tiny Sinatra app that you can play with and see the results instantly:
require 'sinatra'
def get_pastel start_color, total_offset
'#' +
[0, rand(total_offset), rand(total_offset), total_offset].sort.each_cons(2).map{|a,b|
"%02x" % (start_color+b-a)
}.join
end
get '/:start_color/:total_offset' do |start_color, total_offset|
(0..20).map{c = get_pastel(start_color.to_i, total_offset.to_i)
"<span style='background-color:#{c}'>#{c}</span>\n"
}.join
end
Then fire up the browser and see how it looks:
http://localhost:4567/192/64
http://localhost:4567/128/128
;)

This might give you something useful:
colour_range = 128
colour_brightness = 64
color = (1..3).to_a.map{ ( c = rand(colour_range)+colour_brightness.to_s(16) ).size < 2 ? "0#{c}" : c }.to_s
I think it will limit you to mid saturation, mid-brightness colours.

Related

Making a rectangle made out of a given set of rectangles sizes (get the size as closest as the given one)

I'm actually working on a ruby project and need some help.
I have these inputs :
sizeX and sizeY as an integer
rectangles, which is an array of arrays containing two integers.
I’ll take these values as example :
sizeX = 130
sizeY = 240
rectangles = [ [100,100], [100,150], [50,100], [50,50] ]
With the input i have, i need an algorithm that creates a new rectangle, made of the sizes given in rectangles, that will make a resulting size as closest as sizeX and sizeY. I’m gonna call the created rectangle size rectX and rectY.
This closest determination will be calculated like so :
abs(sizeX - rectX) + abs(sizeY - rectY)
So it returns the smallest total difference
Here are some rules of what the algorithm can and can’t do :
We can use multiple times the same rectangle
We can’t rotate a rectangle (In the case of the example, we can’t have 150x100)
We have to use the least rectangles possible
Here is an illustrated example of a result :
Here is another example if the rectangle [50,100] is not given in rectangles :
I have done some code, but it's not efficient, and is a pretty big mess :
# Returns the biggest cabinet from a given list
def getBiggestCabinet(cabinets)
cabinets.sort_by!{ |rect| rect.cabinetsize_w * rect.cabinetsize_h }.reverse!
return cabinets.first
end
# Returns number of cabinets that fits inside a given width & height + its gap
def getCabinetClosestMatch(width,height,cabinet)
countX = (width / cabinet.cabinetsize_w).floor
countY = (height / cabinet.cabinetsize_h).floor
gapX = width - countX * cabinet.cabinetsize_w
gapY = height - countY * cabinet.cabinetsize_h
return countX, countY, gapX, gapY
end
# Only takes on cabinet at a time
def getBestCabinetByLength(cabinets,gap,match,x_or_y)
sorted = cabinets.sort_by!{ |cabinet|
if x_or_y
return cabinet.cabinetsize_w - gap
else
return cabinet.cabinetsize_h - gap
end
}
bestLength = 0
sorted.each do |cabinet|
if x_or_y
if match.modulo(cabinet.cabinetsize_h) == 0
bestLength = cabinet.cabinetsize_h
break;
end
else
if match.modulo(cabinet.cabinetsize_w) == 0
bestLength = cabinet.cabinetsize_w
break;
end
end
end
return bestLength
end
def createCompatibleArrays(cabinets)
# group cabinets by width or height
cabinets_x = cabinets.group_by{ |c| c.caninetsize_w }.values
cabinets_y = cabinets.group_by{ |c| c.caninetsize_h }.values
return cabinets_x, cabinets_y
end
def getCabinetConfig(cabinets,width,height)
biggestCabinet = getBiggestCabinet(cabinets)
countX, countY, gapX, gapY = getCabinetClosestMatch(width,height,biggestCabinet)
current_width = width - gapX
current_height = height - gapY
cabinets = cabinets.where.not(id: biggestCabinet.id)
cabinets_gx, cabinets_gy = createCompatibleArrays(cabinets)
cabinets_gx.each do |c|
unless c[0].cabinetsize_h / 2 > gapY
end
end
end

Is it possible to do a poisson distribution with the probabilities based on integers?

Working within Solidity and the Ethereum EVM and Decimals don't exist. Is there a way I could mathematically still create a Poisson distribution using integers ? it doesnt have to be perfect, i.e rounding or losing some digits may be acceptable.
Let me preface by stating that what follows is not going to be (directly) helpful to you with etherium/solidity. However, it produces probability tables that you might be able to use for your work.
I ended up intrigued by the question of how accurate you could be in expressing the Poisson probabilities as rationals, so I put together the following script in Ruby to try things out:
def rational_poisson(lmbda)
Hash.new.tap do |h| # create a hash and pass it to this block as 'h'.
# Make all components of the calculations rational to allow
# cancellations to occur wherever possible when dividing
e_to_minus_lambda = Math.exp(-lmbda).to_r
factorial = 1r
lmbda = lmbda.to_r
power = 1r
(0...).each do |x|
unless x == 0
power *= lmbda
factorial *= x
end
value = (e_to_minus_lambda / factorial) * power
# the following double inversion/conversion bounds the result
# by the significant bits in the mantissa of a float
approx = Rational(1, (1 / value).to_f)
h[x] = approx
break if x > lmbda && approx.numerator <= 1
end
end
end
if __FILE__ == $PROGRAM_NAME
lmbda = (ARGV.shift || 2.0).to_f # read in a lambda (defaults to 2.0)
pmf = rational_poisson(lmbda) # create the pmf for a Poisson with that lambda
pmf.each { |key, value| puts "p(#{key}) = #{value} = #{value.to_f}" }
puts "cumulative error = #{1.0 - pmf.values.inject(&:+)}" # does it sum to 1?
end
Things to know as you glance through the code. Appending .to_r to a value or expression converts it to a rational, i.e., a ratio of two integers; values with an r suffix are rational constants; and (0...).each is an open-ended iterator which will loop until the break condition is met.
That little script produces results such as:
localhost:pjs$ ruby poisson_rational.rb 1.0
p(0) = 2251799813685248/6121026514868073 = 0.36787944117144233
p(1) = 2251799813685248/6121026514868073 = 0.36787944117144233
p(2) = 1125899906842624/6121026514868073 = 0.18393972058572117
p(3) = 281474976710656/4590769886151055 = 0.061313240195240384
p(4) = 70368744177664/4590769886151055 = 0.015328310048810096
p(5) = 17592186044416/5738462357688819 = 0.003065662009762019
p(6) = 1099511627776/2151923384133307 = 0.0005109436682936699
p(7) = 274877906944/3765865922233287 = 7.299195261338141e-05
p(8) = 34359738368/3765865922233287 = 9.123994076672677e-06
p(9) = 67108864/66196861914257 = 1.0137771196302974e-06
p(10) = 33554432/330984309571285 = 1.0137771196302975e-07
p(11) = 33554432/3640827405284135 = 9.216155633002704e-09
p(12) = 4194304/5461241107926203 = 7.68012969416892e-10
p(13) = 524288/8874516800380079 = 5.907792072437631e-11
p(14) = 32768/7765202200332569 = 4.2198514803125934e-12
p(15) = 256/909984632851473 = 2.8132343202083955e-13
p(16) = 16/909984632851473 = 1.7582714501302472e-14
p(17) = 1/966858672404690 = 1.0342773236060278e-15
cumulative error = 0.0

Generate hex numbers based on percentage

I'm looking for a way to generate a gradual hexadecimal color based on a percentage with Ruby.
0% = #6da94a
50% = #decc30
100% = #ce2d4a
Then programmatically generate the hexadecimal values in between those.
So I might have something like percent_to_hex(10) and that would spit out whatever hexadecimal value is 10% along the gradual gradient between 0% (green) and 50% (yellow).
Actually there is a small mistake in tralston's answer.
(x + percent * 100 * (y - x)).round
should be changed to:
(x + percent / 100.0 * (y - x)).round
Also i.to_s(16) would be a problem if you have 0 (255), as you can get a result like "ff0ff". I would recommend using "%02x" % i instead.
Here is the complete example:
def percent_to_hex(percent, start, stop)
colors = [start,stop].map do |c|
c.scan(/../).map { |s| s.to_i(16) }
end
colors_int = colors.transpose.map do |x,y|
(x + percent / 100.0 * (y - x)).round
end
colors_int.map { |i| "%02x" % i }.join("")
end
Not a very polished method, but here's a good start:
# Example input: percent_to_hex(25, "abcdef", "ffffff") => "c0daf3"
def percent_to_hex(percent, start, stop)
colors = [start,stop].map do |c|
c.scan(/../).map { |s| s.to_i(16) }
end
colors_int = colors.transpose.map do |x,y|
(x + percent * 100 * (y - x)).round
end
colors_int.map { |i| i.to_s(16) }.join("")
end
Of course if you could customize it further to add or remove the leading "#" of the hex color code, etc.

IMAGEMAGICK: Merge multiple images but keep zones with a certain color

I recently had to merge images like these:
These images represents different sorts of events happening at different locations. The idea is to merge these images in a way to keep the "hot" zones of each images (red-yellow-green) to get a global picture of what happens globally.
In my current approach, I take take the second image and extracts the red/green channel, in order to form a mask of the relevant parts, like this:
Then I merge it with the first image by using this mask so only the relevant parts gets copied over.
Here is the script used for this:
#!/bin/bash
# Extract RGB
convert b.png -colorspace RGB -separate b-sep-%d.png
# Keep red & green only
convert b-sep-2.png b-sep-0.png -compose minus -composite b-tmp-br.png
convert b-sep-2.png b-sep-1.png -compose minus -composite b-tmp-bg.png
convert b-tmp-br.png b-tmp-bg.png -compose plus -composite -level 10%,100% b-mask.png
# Composite!
composite b.png a.png b-mask.png final.png
Here is my current result so far:
As you can see, it works well for the red-yellow-green part, but the blue part is missing. The problem is that if I enlarge the mask to include the blue part, then it'll overwrite red-yellow-green parts from the first image with blue parts from the second one! This is already visible in the final result, the top left first image red part is overwritten by the green part of the second image.
Getting the blue part correctly is trickier, but I think the following algorithm should work (pseudo code):
function merge_pixel(pixel a, pixel b)
{
points = { :red => 4, :yellow => 3, :green => 2, :blue => 1, :default => 0 }
a_points = points[a.color()]
b_points = points[b.color()]
return a_points > b_points ? a : b
}
That is, when merging images, copy the pixel from image a or b depending on which color is the most important for the final image. Maybe this algorithm isn't sound (e.g how to handle the gradient part, maybe with a threshold), feel free to debunk it.
REAL QUESTION:
using imagemagick, how to:
get the desired result using any technique/whatever?
implement the algorithm from above?
You don't need to answer both questions, just finding an imagemagick way of getting the desired result is fine.
[EDIT]
Hint: I just had an idea, I think you can generate the masks (including blue parts) for both images and do some "set intersection/union/difference/whatever" of the masks to generate the appropriate "final" mask so only the real relevant parts of image b is copied over.
Ok, I did the "merge_pixel" strategy and it worked!
require 'RMagick'
include Magick
def pixel_score(p)
r, g, b = [p.red, p.green, p.blue].map{ |i| i / 256 }
is_flat = (r-g).abs < 20 && (r-b).abs < 20 && (g-b).abs < 20
is_grey = is_flat && r < 200
is_red = r >= 240 && g <= 100 # && b < 10
is_yellow = r >= 150 && g >= 100 && b <= 10
is_green = r <= 200 && g >= 200 && b <= 100
is_cyan = r <= 10 && g >= 100 && b >= 30
is_blue = r <= 10 && g <= 100 && b >= 200
if is_red
(999**8) + (r - g)
elsif is_yellow
(999**7) + (r + g)
elsif is_green
(999**6) + (g - b)
elsif is_cyan
(999**5) + (g + b)
elsif is_blue
(999**4) + (b - g)
else
(999**1) + r ** 3 + g ** 2 + b
end
end
def rmagick_merge(file_a, file_b, file_merged)
img_a = ImageList.new(file_a)
img_b = ImageList.new(file_b)
result = Image.new(img_a.columns, img_a.rows)
img_a.columns.times do |col|
img_a.rows.times do |row|
pixel_a = img_a.pixel_color(col, row)
pixel_b = img_b.pixel_color(col, row)
pixel = [pixel_a, pixel_b].sort_by{ |p| pixel_score(p) }.last
#pixel = [pixel_a, pixel_b].sort_by{ |p| [p.red - p.green, p.green, p.blue] }.first
#pixel = [pixel_a, pixel_b].sort_by{ |p| [p.red - p.green - p.blue * 100, p.green, p.blue] }.last
result.pixel_color(col, row, pixel)
end
end
result.format = "PNG"
result.write(file_merged)
end
if __FILE__ == $0
if ARGV.size < 3
puts "usage #{__FILE__} a.png b.png merged.png"
exit 1
end
rmagick_merge(ARGV[0], ARGV[1], ARGV[3])
end
Here is the result (not perfect but fine tuned for my needs on the real pictures):

Calculations on the iteration count in for loop

I was playing around with Ruby and Latex to create a color coding set for a registor. I have the following block of code. When attempting to run this, band1 = 1e+02.
I tried band1 = (BigDecimal(i) * 100).to_f, thinking maybe there was some odd floating point issue. An integer multiplied by an integer should create an integer. I tried a variety of other things as well, but to no avail.
(1..9).each do |i| #Band 1
(0..9).each do |j| #Band 2
(0..11).each do |k| #Band 3
#Band 3 Start
#these are the colors of the resistor bands
b1 = $c_band12[i]
b2 = $c_band12[j]
b3 = $c_band3[k]
b4 = "Gold"
oms = ((i*100) + (j*10)) * $mult[k]
band1 = i*100
band2 = j
band3 = $mult[k]
end
end
end
Not sure what I'm missing. Should I be using each_with_index through these iterations? I tried this:
(1..9).each_with_index {|i, indexi| #Band 1
(0..9).each_with_index {|j, indexj| #Band 2
(0..11).each_with_index {|k, indexk| #Band 3
#Band 3 Start
#these are the colors of the resistor bands
b1 = $c_band12[i]
b2 = $c_band12[j]
b3 = $c_band3[k]
b4 = "Gold"
oms = ((i*100) + (j*10)) * $mult[k]
band1 = indexk * 100
and I got the same answer. I can't see why 1*100 should equate to such a large number.
edit: Additional info: If I have this: band1=i*10
then the calculation is correct. In fact, the calculation is correct up to 99.
In your code, band1 has to be a Fixnum. Check with p band1.class. Not sure how you get "1e+02", maybe you print in some strange fashion, or you do band1 == 1e+02 which returns true in Ruby. You must use eql? to distinguish between 1 and 1.0:
1 == 1.0 # => true
1.eql?(1.0) # => false

Resources