Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0

Showing posts with label hash. Show all posts
Showing posts with label hash. Show all posts

Sunday, 5 January 2014

Revisiting json load and save for ruby-2.0

Since ruby-2.0 Struct to Hash is supported (to_h) so I thought I would give it a go with JRubyArt. The first thing you need to do is to set jruby to run in 2.0 mode, this is easily achieved by setting the compatibility version in your .jrubyrc:-
compat.version=2.0
But there are other ways to do it!
The json:-
{
  "bubbles": [
    {
      "x": 160,
      "y": 103,
      "diameter": 43.19838,
      "label": "Happy"
    },
    {
      "x": 372,
      "y": 137,
      "diameter": 52.42526,
      "label": "Sad"
    },
    {
      "x": 273,
      "y": 235,
      "diameter": 61.14072,
      "label": "Joyous"
    },
    {
      "x": 121,
      "y": 179,
      "diameter": 44.758068,
      "label": "Melancholy"
    }
  ]
}

The sketch:-
# This example demonstrates how easily "sketch data" can be retrieved from a json file
# in ruby-processing. Note this sketch re-uses the Bubble class from the bubble library. 
# The BubbleData class, can load, store and create instances of Bubble (and request them
# to display and/or show their label, when 'mouse over').
# @author Martin Prout, after Daniel Shiffmans version for processing, updated for ruby-2.0
# 
load_library :bubble
require "json"


attr_reader :bubble_data

def setup()
  size(640, 360)
  # initialize bubble_data with 'key' and read data from 'file path'
  @bubble_data = BubbleData.new "bubbles"
  bubble_data.load_data "data/data.json"
end

def draw
  background 255
  # draw the bubbles and display a bubbles label whilst mouse over
  bubble_data.display mouse_x, mouse_y
end

def mouse_pressed
  # create a new instance of bubble, where mouse was clicked
  bubble_data.create_new_bubble(mouse_x, mouse_y)
end




class BubbleData
  include Enumerable

  MAX_BUBBLE = 10

  attr_reader :key, :path, :bubbles

  # @param key String for top level hash

  def initialize key
    @key = key
    @bubbles = []
  end

  def each &block
    bubbles.each &block
  end

  def create_new_bubble x, y
    self << Bubble.new(x, y, rand(40 .. 80), "new label")
    save_data
    load_data path
  end

  def display x, y
    self.each do |bubble|
      bubble.display
      bubble.rollover(x, y)
    end
  end

  # @param path to json file

  def load_data path
    @path = path
    source_string = open(path, "r"){ |file| file.read }
    data = JSON.parse(source_string)[key]
    bubbles.clear
    # iterate the bubble_data array, and create an array of bubbles
    data.each do |point|
      self << Bubble.new(
        point["x"],
        point["y"],
        point["diameter"],
        point["label"])
    end
  end

  def << bubble
    bubbles << bubble
    bubbles.shift if bubbles.size > MAX_BUBBLE
  end

  private

  def save_data
    hash = { key => self.map{ |point| point.to_h } }
    json = JSON.pretty_generate(hash)      # generate pretty output
    open(path, 'w') { |f| f.write(json) }
  end
end

The bubble library:-
# The bubble library, include BubbleStruct

class Bubble
  include Processing::Proxy

  attr_reader :data, :over

  # Create  the Bubble
  def initialize(x, y, diameter, label)
    @data = BubbleStruct.new(x, y, diameter, label)
    @over = false
  end

  # Checking if mouse is over the Bubble
  def rollover(px, py)
    d = dist(px,py,data.x,data.y)
    @over = (d < data.diameter/2)? true : false
  end

  # Display the Bubble
  def display
    stroke(0)
    stroke_weight(2)
    no_fill
    ellipse(data.x, data.y, data.diameter, data.diameter)
    if (over)
      fill(0)
      text_align(CENTER)
      text(data.label, data.x, data.y + data.diameter/2 + 20)
    end
  end

  def to_h
    data.to_h # Struct to Hash since ruby-2.0
  end

end

BubbleStruct = Struct.new(:x, :y, :diameter, :label)

Thursday, 14 March 2013

Translating a Word counting sketch to ruby-processing

Here is a sketch that was based on a prototype by Daniel Schiffman to illustrate the use of the processing HashInt class, I can't see the HashInt class catching on really, particularly not for rubyists where alternative options abound. Anyway I liked the sketch and I think sometimes less is more, in later versions Schiffman sorts the words according to their frequency (to show off IntClass functionality), however to my mind it spoils the sketch!
class Word
  # A helper to keep track of word frequency.
  attr_accessor :word
  attr_reader :count
  def initialize word
    @word = word
    @count = 1
  end

  def increment
    @count += 1
  end
end

################################
# This sketch is translated from a vanilla processing sketch by Daniel Schiffman
# that was designed to demonstrate the use IntHash class in vanilla processing.
# Similar results can easily be obtained using more idiomatic ruby. Here IntHash 
# has been replaced by a String => Word hash (as used in a Schiffman prototype). 
# Read about concordance here:-
# http://en.wikipedia.org/wiki/Concordance_(publishing)
################################

attr_reader :concordance, :lines, :tokens, :counter

def setup
  size 640, 360
  @counter = 0
  @concordance = {}
  # Open a file, read its contents, and 'scan' for words using a regex.
  # Include words with apostrophe eg Harker's (alt. source 'hamlet.txt')
  @tokens = File.read(data_path("dracula.txt")).scan(/[\w'-]+/)
  text_font(create_font("Georgia", 24))
end

def draw
  background 51
  fill 255
  s = (tokens[counter] == "I")? tokens[counter] : tokens[counter].downcase
  @counter = (counter + 1) % tokens.length
  if (concordance.has_key?(s))
    # Get the word object and increase the count
    # We access objects from a Hash via its key, the String
    w = concordance[s]
    w.increment    # increment word count
  else
    # Otherwise make a new Word instance and add it to 
    # the Hash using the word String as the key
    concordance[s] = Word.new(s)
  end

  # x and y will be used to locate each word
  x = 0
  y = height - 10

  # Look at each word
  concordance.values.each do |w|
    # Only display words that appear 3 times
    if (w.count > 3)  # access word count
      # The size is the count
      fsize = constrain(w.count, 0, 100)
      text_size(fsize)
      text(w.word, x, y)
      # Move along the x-axis
      x += text_width(w.word) + 1
    end

    # If x gets to the end, move y
    # If y == 0 we are done
    if (y == 0)
      no_loop
    else
      if (x > width)
        x = 0
        y = (y < 0)? 0 : y - 100
      end
    end
  end
end

Followers

About Me

My photo
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2