class GR::Plot

This class offers a simple, matlab-style API built on top of the GR package. The class name Plot may be changed in the future.

Constants

FONTS
KW_ARGS

Keyword options conform to GR.jl.

PLOT_KIND

Plot kinds conform to GR.jl

Attributes

last_plot[RW]
args[RW]
kvs[RW]
scheme[RW]

Public Class Methods

new(*raw_args) click to toggle source
# File lib/gr/plot.rb, line 91
def initialize(*raw_args)
  @kvs = raw_args.last.is_a?(Hash) ? raw_args.pop : {}
  @args = plot_args(raw_args) # method name is the same as Julia/Python

  # Check keyword options.
  kvs.each_key { |k| warn "Unknown keyword: #{k}" unless KW_ARGS.include? k }

  # label(singular form) is a original keyword arg which GR.jl does not have.
  kvs[:labels] ||= [kvs[:label]] if kvs.has_key? :label

  # Don't use ||= here, because we need to tell `false` from `nil`
  kvs[:size]    = [600, 450]   unless kvs.has_key? :size
  kvs[:ax]      = false        unless kvs.has_key? :ax
  kvs[:subplot] = [0, 1, 0, 1] unless kvs.has_key? :subplot
  kvs[:clear]   = true         unless kvs.has_key? :clear
  kvs[:update]  = true         unless kvs.has_key? :update

  @scheme     = 0
  @background = 0xffffff
  # @handle     = nil           # This variable will be used in gr_meta

  self.class.last_plot = self
end

Public Instance Methods

colorbar(off = 0, colors = 256) click to toggle source
# File lib/gr/plot.rb, line 571
def colorbar(off = 0, colors = 256)
  GR.savestate
  viewport = kvs[:viewport]
  zmin, zmax = kvs[:zrange]
  mask = (GR::OPTION_Z_LOG | GR::OPTION_FLIP_Y | GR::OPTION_FLIP_Z)
  options = if kvs.has_key?(:zflip)
              (GR.inqscale | GR::OPTION_FLIP_Y)
            elsif kvs.has_key?(:yflip)
              GR.inqscale & ~GR::OPTION_FLIP_Y
            else
              GR.inqscale
            end
  GR.setscale(options & mask)
  h = 0.5 * (zmax - zmin) / (colors - 1)
  GR.setwindow(0, 1, zmin, zmax)
  GR.setviewport(viewport[1] + 0.02 + off, viewport[1] + 0.05 + off,
                 viewport[2], viewport[3])
  l = linspace(1000, 1255, colors).map(&:round)
  GR.cellarray(0, 1, zmax + h, zmin - h, 1, colors, l)
  GR.setlinecolorind(1)
  diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
  charheight = [0.016 * diag, 0.012].max
  GR.setcharheight(charheight)
  if kvs[:scale] & GR::OPTION_Z_LOG == 0
    ztick = auto_tick(zmin, zmax)
    GR.axes(0, ztick, 1, zmin, 0, 1, 0.005)
  else
    GR.setscale(GR::OPTION_Y_LOG)
    GR.axes(0, 2, 1, zmin, 0, 1, 0.005)
  end
  GR.restorestate
end
draw_axes(kind, pass = 1) click to toggle source
# File lib/gr/plot.rb, line 324
def draw_axes(kind, pass = 1)
  viewport = kvs[:viewport]
  vp = kvs[:vp]
  ratio = kvs[:ratio]
  xtick, xorg, majorx = kvs[:xaxis]
  ytick, yorg, majory = kvs[:yaxis]
  drawgrid = kvs.has_key?(:grid) ? kvs[:grid] : true
  xtick = 10 if kvs[:scale] & GR::OPTION_X_LOG != 0
  ytick = 10 if kvs[:scale] & GR::OPTION_Y_LOG != 0
  GR.setlinecolorind(1)
  diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
  GR.setlinewidth(1)
  ticksize = 0.0075 * diag
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
    charheight = [0.024 * diag, 0.012].max
    GR.setcharheight(charheight)
    ztick, zorg, majorz = kvs[:zaxis]
    if pass == 1 && drawgrid
      GR.grid3d(xtick, 0, ztick, xorg[0], yorg[1], zorg[0], 2, 0, 2)
      GR.grid3d(0, ytick, 0, xorg[0], yorg[1], zorg[0], 0, 2, 0)
    else
      GR.axes3d(xtick, 0, ztick, xorg[0], yorg[0], zorg[0], majorx, 0, majorz, -ticksize)
      GR.axes3d(0, ytick, 0, xorg[1], yorg[0], zorg[0], 0, majory, 0, ticksize)
    end
  else
    charheight = [0.018 * diag, 0.012].max
    GR.setcharheight(charheight)
    if %i[heatmap nonuniformheatmap shade].include?(kind)
      ticksize = -ticksize
    elsif drawgrid
      GR.grid(xtick, ytick, 0, 0, majorx, majory)
    end
    if kvs.has_key?(:xticklabels) || kvs.has_key?(:yticklabels)
      fx = if kvs.has_key?(:xticklabels)
             GRCommons::Fiddley::Function.new(
               :void, %i[double double string double]
             ) do |x, y, _svalue, value|
               label = value < 0 ? '' : kvs[:xticklabels][value] || ''
               GR.textext(x, y, label)
             end
           else
             GRCommons::Fiddley::Function.new(
               :void, %i[double double string double]
             ) do |x, y, _svalue, value|
               GR.textext(x, y, value.to_s)
             end
           end
      fy = if kvs.has_key?(:yticklabels)
             GRCommons::Fiddley::Function.new(
               :void, %i[double double string double]
             ) do |x, y, _svalue, value|
               label = value < 0 ? '' : kvs[:yticklabels][value] || ''
               GR.textext(x, y, label)
             end
           else
             GRCommons::Fiddley::Function.new(
               :void, %i[double double string double]
             ) do |x, y, _svalue, value|
               GR.textext(x, y, value.to_s)
             end
           end
      GR.axeslbl(xtick, ytick, xorg[0], yorg[0], majorx, majory, ticksize, fx, fy)
    else
      GR.axes(xtick, ytick, xorg[0], yorg[0], majorx, majory, ticksize)
    end
    GR.axes(xtick, ytick, xorg[1], yorg[1], -majorx, -majory, -ticksize)
  end

  if kvs.has_key?(:title)
    GR.savestate
    GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
    text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title].to_s)
    GR.restorestate
  end
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
    xlabel = (kvs[:xlabel] || '').to_s
    ylabel = (kvs[:ylabel] || '').to_s
    zlabel = (kvs[:zlabel] || '').to_s
    GR.titles3d(xlabel, ylabel, zlabel)
  else
    if kvs.has_key?(:xlabel)
      GR.savestate
      GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_BOTTOM)
      text(0.5 * (viewport[0] + viewport[1]), vp[2] + 0.5 * charheight, kvs[:xlabel].to_s)
      GR.restorestate
    end
    if kvs.has_key?(:ylabel)
      GR.savestate
      GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
      GR.setcharup(-1, 0)
      text(vp[0] + 0.5 * charheight, 0.5 * (viewport[2] + viewport[3]), kvs[:ylabel].to_s)
      GR.restorestate
    end
  end
end
draw_legend() click to toggle source
# File lib/gr/plot.rb, line 973
def draw_legend
  w, h = legend_size
  viewport = kvs[:viewport]
  location = kvs[:location] || 1
  num_labels = kvs[:labels].length
  GR.savestate
  GR.selntran 0
  GR.setscale 0
  px = case location
       when 11, 12, 13
         viewport[1] + 0.11
       when 8, 9, 10
         0.5 * (viewport[0] + viewport[1] - w + 0.05)
       when 2, 3, 6
         viewport[0] + 0.11
       else
         viewport[1] - 0.05 - w
       end
  py = case location
       when 5, 6, 7, 10, 12
         0.5 * (viewport[2] + viewport[3] + h - 0.03)
       when 13
         viewport[2] + h
       when 3, 4, 8
         viewport[2] + h + 0.03
       when 11
         viewport[3] - 0.03
       else
         viewport[3] - 0.06
       end
  GR.setfillintstyle(GR::INTSTYLE_SOLID)
  GR.setfillcolorind(0)
  GR.fillrect(px - 0.08, px + w + 0.02, py + 0.03, py - h)
  GR.setlinetype(GR::LINETYPE_SOLID)
  GR.setlinecolorind(1)
  GR.setlinewidth(1)
  GR.drawrect(px - 0.08, px + w + 0.02, py + 0.03, py - h)
  i = 0
  GR.uselinespec(' ')
  args.each do |_x, _y, _z, _c, spec|
    if i < num_labels
      label = kvs[:labels][i]
      label = label.to_s
      _tbx, tby = inqtext(0, 0, label)
      dy = [(tby[2] - tby[0]) - 0.03, 0].max
      py -= 0.5 * dy
    end
    GR.savestate
    mask = GR.uselinespec(spec || '')
    GR.polyline([px - 0.07, px - 0.01], [py, py]) if hasline(mask)
    GR.polymarker([px - 0.06, px - 0.02], [py, py]) if hasmarker(mask)
    GR.restorestate
    GR.settextalign(GR::TEXT_HALIGN_LEFT, GR::TEXT_VALIGN_HALF)
    if i < num_labels
      text(px, py, label)
      py -= 0.5 * dy
      i += 1
    end
    py -= 0.03
  end
  GR.selntran(1)
  GR.restorestate
end
draw_polar_axes() click to toggle source
# File lib/gr/plot.rb, line 420
def draw_polar_axes
  viewport = kvs[:viewport]
  diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
  charheight = [0.018 * diag, 0.012].max

  window = kvs[:window]
  rmin = window[2]
  rmax = window[3]

  GR.savestate
  GR.setcharheight(charheight)
  GR.setlinetype(GR::LINETYPE_SOLID)

  tick = auto_tick(rmin, rmax)
  n = ((rmax - rmin) / tick + 0.5).round
  (n + 1).times do |i|
    r = i.to_f / n
    if i.even?
      GR.setlinecolorind(88)
      GR.drawarc(-r, r, -r, r, 0, 359) if i > 0
      GR.settextalign(GR::TEXT_HALIGN_LEFT, GR::TEXT_VALIGN_HALF)
      x, y = GR.wctondc(0.05, r)
      GR.text(x, y, (rmin + i * tick).to_s) # FIXME: round. significant digits.
    else
      GR.setlinecolorind(90)
      GR.drawarc(-r, r, -r, r, 0, 359)
    end
  end
  0.step(by: 45, to: 315) do |alpha|
    sinf = Math.sin(alpha * Math::PI / 180)
    cosf = Math.cos(alpha * Math::PI / 180)
    GR.polyline([cosf, 0], [sinf, 0])
    GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_HALF)
    x, y = GR.wctondc(1.1 * cosf, 1.1 * sinf)
    GR.textext(x, y, "#{alpha}^o")
  end
  GR.restorestate
end
plot_data(_figure = true) click to toggle source
# File lib/gr/plot.rb, line 604
def plot_data(_figure = true)
  # GR.init

  # target = GR.displayname
  # if flag && target != None
  #   if target == "js" || target == "meta"
  #       send_meta(0)
  #   else
  #       send_serialized(target)
  #   end
  #   return
  # end

  kind = kvs[:kind] || :line
  GR.clearws if kvs[:clear]

  if scheme != 0
    # Not yet.
  end

  if kvs.has_key?(:font)
    name = kvs[:font]
    # 'Cmuserif-Math' => :cmuserif_math
    sym_name = name.to_s.gsub('-', '_').downcase.to_sym
    if FONTS.include?(sym_name)
      font = FONTS[sym_name]
      GR.settextfontprec(font, font > 200 ? 3 : 0)
    else
      font = GR.loadfont(name)
      if font >= 0
        GR.settextfontprec(font, 3)
      else
        warn "Unknown font name: #{name}"
      end
    end
  else
    # The following fonts are the default in GR.jl
    # Japanese, Chinese, Korean, etc. cannot be displayed.

    # GR.settextfontprec(232, 3) # CM Serif Roman
  end

  set_viewport(kind, kvs[:subplot])
  unless kvs[:ax]
    set_window(kind)
    if %i[polar polarhist].include?(kind)
      draw_polar_axes
    elsif !%i[imshow isosurface polarheatmap nonuniformpolarheatmap].include?(kind)
      draw_axes(kind)
    end
  end

  if kvs.has_key?(:colormap)
    GR.setcolormap(kvs[:colormap])
  else
    GR.setcolormap(GR::COLORMAP_VIRIDIS)
  end

  GR.uselinespec(' ')
  args.each do |x, y, z, c, spec|
    spec ||= kvs[:spec] ||= ''
    GR.savestate
    GR.settransparency(kvs[:alpha]) if kvs.has_key?(:alpha)

    case kind

    when :line
      mask = GR.uselinespec(spec)
      linewidth = kvs[:linewidth]
      # Slightly different from Julia,
      # Because the implementation of polyline and polymarker is different.
      z ||= linewidth # FIXME
      GR.polyline(x, y, z, c) if hasline(mask)
      GR.polymarker(x, y, z, c) if hasmarker(mask)

    when :step
      mask = GR.uselinespec(spec)
      if hasline(mask)
        where = kvs[:where] || 'mid'
        n = x.length
        xs = [x[0]]
        case where
        when 'pre'
          ys = [y[0]]
          (n - 1).times do |i|
            xs << x[i]     << x[i + 1]
            ys << y[i + 1] << y[i + 1]
          end
        when 'post'
          ys = [y[0]]
          (n - 1).times do |i|
            xs << x[i + 1] << x[i + 1]
            ys << y[i]     << y[i + 1]
          end
        else
          ys = []
          (n - 1).times do |i|
            xs << 0.5 * (x[i] + x[i + 1]) << 0.5 * (x[i] + x[i + 1])
            ys << y[i] << y[i]
          end
          xs << x[n - 1]
          ys << y[n - 1] << y[n - 1]
        end
        GR.polyline(xs, ys)
      end
      GR.polymarker(x, y) if hasmarker(mask)

    when :scatter
      GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
      z = z&.map { |i| i * 0.01 }
      c = c&.map { |i| normalize_color(i, *kvs[:crange]) }
      GR.polymarker(x, y, z, c)

    when :stem
      GR.setlinecolorind(1)
      GR.polyline(kvs[:window][0..1], [0, 0])
      GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
      GR.uselinespec(spec)
      x = x.to_a if narray?(x)
      y = y.to_a if narray?(y)
      x.zip(y).each do |xi, yi|
        GR.polyline([xi, xi], [0, yi])
      end
      GR.polymarker(x, y)

    when :hist
      if kvs[:horizontal]
        xmin = kvs[:window][0]
        x.length.times do |i|
          GR.setfillcolorind(989)
          GR.setfillintstyle(GR::INTSTYLE_SOLID)
          GR.fillrect(xmin, x[i], y[i], y[i + 1])
          GR.setfillcolorind(1)
          GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
          GR.fillrect(xmin, x[i], y[i], y[i + 1])
        end
      else
        ymin = kvs[:window][2]
        y.length.times do |i|
          GR.setfillcolorind(989)
          GR.setfillintstyle(GR::INTSTYLE_SOLID)
          GR.fillrect(x[i], x[i + 1], ymin, y[i])
          GR.setfillcolorind(1)
          GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
          GR.fillrect(x[i], x[i + 1], ymin, y[i])
        end
      end

    when :polarhist
      ymax = kvs[:window][3].to_f
      ρ = y.map { |i| i / ymax }
      θ = x.map { |i| i * 180 / Math::PI }
      (1...ρ.length).each do |i|
        GR.setfillcolorind(989)
        GR.setfillintstyle(GR::INTSTYLE_SOLID)
        GR.fillarc(-ρ[i], ρ[i], -ρ[i], ρ[i], θ[i - 1], θ[i])
        GR.setfillcolorind(1)
        GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
        GR.fillarc(-ρ[i], ρ[i], -ρ[i], ρ[i], θ[i - 1], θ[i])
      end

    when :polarheatmap, :nonuniformpolarheatmap
      w, h = z.shape
      cmap = colormap
      cmin, cmax = kvs[:zrange]
      data = z.map { |i| normalize_color(i, cmin, cmax) }
      data.reverse(axis: 0) if kvs[:xflip]
      data.reverse(axis: 1) if kvs[:yflip]
      colors = data * 255 + 1000
      colors = colors.transpose # Julia is column major
      case kind
      when :polarheatmap
        GR.polarcellarray(0, 0, 0, 360, 0, 1, w, h, colors)
      when :nonuniformpolarheatmap
        ymax = y.max.to_f
        ρ = y.map { |i| i / ymax }
        θ = x.map { |i| i * 180 / Math::PI }
        GR.nonuniformpolarcellarray(θ, ρ, w, h, colors)
      end
      draw_polar_axes
      kvs[:zrange] = [cmin, cmax]
      colorbar

    when :contour, :contourf
      zmin, zmax = kvs[:zrange]
      if narray?(z) && z.ndim == 2
        a, b = z.shape
        x = (1..b).to_a
        y = (1..a).to_a
        zmin, zmax = z.minmax
      elsif equal_length(x, y, z)
        x, y, z = GR.gridit(x, y, z, 200, 200)
        zmin, zmax = z.compact.minmax # compact : removed nil
      end

      # kvs[:zlim] is supposed to be Array or Range
      if kvs.has_key?(:zlim)
        zmin = kvs[:zlim].first if kvs[:zlim].first
        zmax = kvs[:zlim].last if kvs[:zlim].last
      end
      GR.setprojectiontype(0)
      GR.setspace(zmin, zmax, 0, 90)
      levels = kvs[:levels] || 0
      clabels = kvs[:clabels] || false
      if levels.is_a? Integer
        hmin, hmax = GR.adjustrange(zmin, zmax)
        h = linspace(hmin, hmax, levels == 0 ? 21 : levels + 1)
      else
        h = levels
      end
      case kind
      when :contour
        GR._contour_(x, y, h, z, clabels ? 1 : 1000)
      when :contourf
        GR._contourf_(x, y, h, z, clabels ? 1 : 0)
      end
      colorbar(0, h.length)

    when :hexbin
      nbins = kvs[:nbins] || 40
      cntmax = GR._hexbin_(x, y, nbins)
      if cntmax > 0
        kvs[:zrange] = [0, cntmax]
        colorbar
      end

    when :heatmap, :nonuniformheatmap
      case z
      when Array
        if z.all? { |zi| zi.size = z[0].size }
          w = z.size
          h = z[0].size
        else
          raise
        end
      when ->(obj) { narray?(obj) }
        w, h = z.shape
      else
        raise
      end
      cmap = colormap
      cmin, cmax = kvs[:crange]
      levels = kvs[:levels] || 256
      data = z.flatten.to_a.map { |i| normalize_color(i, cmin, cmax) } # NArray -> Array
      if kind == :heatmap
        rgba = data.map { |v| to_rgba(v, cmap) }
        GR.drawimage(0.5, w + 0.5, h + 0.5, 0.5, w, h, rgba)
      else
        colors = data.map { |i| (1000 + i * 255).round }
        GR.nonuniformcellarray(x, y, w, h, colors)
      end
      colorbar(0, levels)

    when :wireframe
      if narray?(z) && z.ndim == 2
        a, b = z.shape
        x = (1..b).to_a
        y = (1..a).to_a
      elsif equal_length(x, y, z)
        x, y, z = GR.gridit(x, y, z, 50, 50)
      end
      GR.setfillcolorind(0)
      GR._surface_(x, y, z, GR::OPTION_FILLED_MESH)
      draw_axes(kind, 2)

    when :surface
      if narray?(z) && z.ndim == 2
        a, b = z.shape
        x = (1..b).to_a
        y = (1..a).to_a
      elsif equal_length(x, y, z)
        x, y, z = GR.gridit(x, y, z, 200, 200)
      end
      if kvs[:accelerate] == false
        GR._surface_(x, y, z, GR::OPTION_COLORED_MESH)
      else
        require 'gr3'
        GR3.clear
        GR3.surface(x, y, z, GR::OPTION_COLORED_MESH)
      end
      draw_axes(kind, 2)
      colorbar(0.05)

    when :volume
      algorithm = kvs[:algorithm] || 0
      require 'gr3'
      GR3.clear
      dmin, dmax = GR3.volume(z, algorithm)
      draw_axes(kind, 2)
      kvs[:zrange] = [dmin, dmax]
      colorbar(0.05)

    when :plot3
      mask = GR.uselinespec(spec)
      GR.polyline3d(x, y, z) if hasline(mask)
      GR.polymarker3d(x, y, z) if hasmarker(mask)
      draw_axes(kind, 2)

    when :scatter3
      GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
      if c
        cmin, cmax = kvs[:crange]
        c = c.map { |i| normalize_color(i, cmin, cmax) }
        cind = c.map { |i| (1000 + i * 255).round }
        x.length.times do |i|
          GR.setmarkercolorind(cind[i])
          GR.polymarker3d([x[i]], [y[i]], [z[i]])
        end
      else
        GR.polymarker3d(x, y, z)
      end
      draw_axes(kind, 2)

    when :imshow
      plot_img(z)

    when :isosurface
      plot_iso(z)

    when :polar
      GR.uselinespec(spec)
      plot_polar(x, y)

    when :trisurf
      GR.trisurface(x, y, z)
      draw_axes(kind, 2)
      colorbar(0.05)

    when :tricont
      zmin, zmax = kvs[:zrange]
      levels = linspace(zmin, zmax, 20)
      GR.tricontour(x, y, z, levels)

    when :shade
      xform = kvs[:xform] || 5
      if x.to_a.include? Float::NAN # FIXME: Ruby is different from Julia?
        # How to check NArray?
        GR.shadelines(x, y, xform: xform)
      else
        GR.shadepoints(x, y, xform: xform)
      end

    when :bar
      0.step(x.length - 1, 2) do |i|
        GR.setfillcolorind(989)
        GR.setfillintstyle(GR::INTSTYLE_SOLID)
        GR.fillrect(x[i], x[i + 1], y[i], y[i + 1])
        GR.setfillcolorind(1)
        GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
        GR.fillrect(x[i], x[i + 1], y[i], y[i + 1])
      end
    end

    GR.restorestate
  end

  draw_legend if %i[line step scatter stem].include?(kind) && kvs.has_key?(:labels)

  if kvs[:update]
    GR.updatews
    # if GR.isinline()
    #  restore_context()
    #  return GR.show()
    # end
  end

  # flag && restore_context()
end
plot_img(img) click to toggle source
# File lib/gr/plot.rb, line 473
def plot_img(img)
  viewport = kvs[:vp].clone
  viewport[3] -= 0.05 if kvs.has_key?(:title)
  vp = kvs[:vp]

  if img.is_a? String
    width, height, data = GR.readimage(img)
  else
    height, width = img.shape
    cmin, cmax = kvs[:crange]
    data = img.map { |i| normalize_color(i, cmin, cmax) }
    data = data.map { |i| (1000 + i * 255).round }
  end

  if width * (viewport[3] - viewport[2]) < height * (viewport[1] - viewport[0])
    w = width.to_f / height * (viewport[3] - viewport[2])
    xmin = [0.5 * (viewport[0] + viewport[1] - w), viewport[0]].max
    xmax = [0.5 * (viewport[0] + viewport[1] + w), viewport[1]].min
    ymin = viewport[2]
    ymax = viewport[3]
  else
    h = height.to_f / width * (viewport[1] - viewport[0])
    xmin = viewport[0]
    xmax = viewport[1]
    ymin = [0.5 * (viewport[3] + viewport[2] - h), viewport[2]].max
    ymax = [0.5 * (viewport[3] + viewport[2] + h), viewport[3]].min
  end

  GR.selntran(0)
  GR.setscale(0)
  if kvs.has_key?(:xflip)
    tmp = xmax
    xmax = xmin
    xmin = tmp
  end
  if kvs.has_key?(:yflip)
    tmp = ymax
    ymax = ymin
    ymin = tmp
  end
  if img.is_a? String
    GR.drawimage(xmin, xmax, ymin, ymax, width, height, data)
  else
    GR.cellarray(xmin, xmax, ymin, ymax, width, height, data)
  end

  if kvs.has_key?(:title)
    GR.savestate
    GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
    text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title].to_s)
    GR.restorestate
  end
  GR.selntran(1)
end
plot_iso(v) click to toggle source
# File lib/gr/plot.rb, line 528
def plot_iso(v)
  viewport = kvs[:viewport]

  if viewport[3] - viewport[2] < viewport[1] - viewport[0]
    width = viewport[3] - viewport[2]
    centerx = 0.5 * (viewport[0] + viewport[1])
    xmin = [centerx - 0.5 * width, viewport[0]].max
    xmax = [centerx + 0.5 * width, viewport[1]].min
    ymin = viewport[2]
    ymax = viewport[3]
  else
    height = viewport[1] - viewport[0]
    centery = 0.5 * (viewport[2] + viewport[3])
    xmin = viewport[0]
    xmax = viewport[1]
    ymin = [centery - 0.5 * height, viewport[2]].max
    ymax = [centery + 0.5 * height, viewport[3]].min
  end

  GR.selntran(0)
  v = Numo::DFloat.cast(v) if v.is_a? Array
  values = ((v - v.min) / (v.max - v.min) * (2**16 - 1)).round
  values = Numo::UInt16.cast(values)
  nx, ny, nz = v.shape
  isovalue = ((kvs[:isovalue] || 0.5) - v.min) / (v.max - v.min)
  rotation = ((kvs[:rotation] || 40) * Math::PI / 180.0)
  tilt = ((kvs[:tilt] || 70) * Math::PI / 180.0)
  r = 2.5
  GR3.clear
  mesh = GR3.createisosurfacemesh(values, [2.0 / (nx - 1), 2.0 / (ny - 1), 2.0 / (nz - 1)],
                                  [-1, -1, -1],
                                  (isovalue * (2**16 - 1)).round)
  color = kvs[:color] || [0.0, 0.5, 0.8]
  GR3.setbackgroundcolor(1, 1, 1, 0)
  GR3.drawmesh(mesh, 1, [0, 0, 0], [0, 0, 1], [0, 1, 0], color, [1, 1, 1])
  GR3.cameralookat(r * Math.sin(tilt) * Math.sin(rotation),
                   r * Math.cos(tilt), r * Math.sin(tilt) * Math.cos(rotation),
                   0, 0, 0, 0, 1, 0)
  GR3.drawimage(xmin, xmax, ymin, ymax, 500, 500, GR3::DRAWABLE_GKS)
  GR3.deletemesh(mesh)
  GR.selntran(1)
end
plot_polar(θ, ρ) click to toggle source
# File lib/gr/plot.rb, line 459
def plot_polar(θ, ρ)
  window = kvs[:window]
  rmax = window[3].to_f
  ρ = ρ.map { |i| i / rmax }
  n = ρ.length
  x = []
  y = []
  n.times do |i|
    x << ρ[i] * Math.cos(θ[i])
    y << ρ[i] * Math.sin(θ[i])
  end
  GR.polyline(x, y)
end
set_viewport(kind, subplot) click to toggle source
# File lib/gr/plot.rb, line 115
def set_viewport(kind, subplot)
  mwidth, mheight, width, height = GR.inqdspsize
  dpi = width / mwidth * 0.0254
  w, h = if kvs[:figsize]
           [(0.0254 * width  * kvs[:figsize][0] / mwidth),
            (0.0254 * height * kvs[:figsize][1] / mheight)]
         elsif dpi > 200
           kvs[:size].map { |i| i * dpi / 100 }
         else
           kvs[:size]
         end

  vp = subplot.clone

  if w > h
    ratio = h / w.to_f
    msize = mwidth * w / width
    GR.setwsviewport(0, msize, 0, msize * ratio)
    GR.setwswindow(0, 1, 0, ratio)
    vp[2] *= ratio
    vp[3] *= ratio
  else
    ratio = w / h.to_f
    msize = mheight * h / height
    GR.setwsviewport(0, msize * ratio, 0, msize)
    GR.setwswindow(0, ratio, 0, 1)
    vp[0] *= ratio
    vp[1] *= ratio
  end

  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
    extent = [vp[1] - vp[0], vp[3] - vp[2]].min
    vp1 = 0.5 * (vp[0] + vp[1] - extent)
    vp2 = 0.5 * (vp[0] + vp[1] + extent)
    vp3 = 0.5 * (vp[2] + vp[3] - extent)
    vp4 = 0.5 * (vp[2] + vp[3] + extent)
  else
    vp1, vp2, vp3, vp4 = vp
  end

  left_margin = kvs.has_key?(:ylabel) ? 0.05 : 0
  right_margin = if %i[contour contourf hexbin heatmap nonuniformheatmap polarheatmap
                       nonuniformpolarheatmap surface trisurf volume].include?(kind)
                   (vp2 - vp1) * 0.1
                 else
                   0
                 end
  bottom_margin = kvs.has_key?(:xlabel) ? 0.05 : 0
  top_margin = kvs.has_key?(:title) ? 0.075 : 0

  viewport = [vp1 + (0.075 + left_margin) * (vp2 - vp1),
              vp1 + (0.95 - right_margin) * (vp2 - vp1),
              vp3 + (0.075 + bottom_margin) * (vp4 - vp3),
              vp3 + (0.975 - top_margin) * (vp4 - vp3)]

  if %i[line step scatter stem].include?(kind) && kvs[:labels]
    location = kvs[:location] || 1
    if [11, 12, 13].include?(location)
      w, h = legend_size
      viewport[1] -= w + 0.1
    end
  end

  GR.setviewport(*viewport)

  kvs[:viewport] = viewport
  kvs[:vp]       = vp
  kvs[:ratio]    = ratio

  if kvs[:backgroundcolor]
    GR.savestate
    GR.selntran(0)
    GR.setfillintstyle(GR::INTSTYLE_SOLID)
    GR.setfillcolorind(kvs[:backgroundcolor])
    if w > h
      GR.fillrect(subplot[0], subplot[1],
                  ratio * subplot[2], ratio * subplot[3])
    else
      GR.fillrect(ratio * subplot[0], ratio * subplot[1],
                  subplot[2], subplot[3])
    end
    GR.selntran(1)
    GR.restorestate
  end

  if %i[polar polarhist polarheatmap nonuniformpolarheatmap].include? kind
    xmin, xmax, ymin, ymax = viewport
    xcenter = 0.5 * (xmin + xmax)
    ycenter = 0.5 * (ymin + ymax)
    r = 0.5 * [xmax - xmin, ymax - ymin].min
    GR.setviewport(xcenter - r, xcenter + r, ycenter - r, ycenter + r)
  end
end
set_window(kind) click to toggle source
# File lib/gr/plot.rb, line 209
def set_window(kind)
  scale = 0
  unless %i[polar polarhist polarheatmap nonuniformpolarheatmap].include?(kind)
    scale |= GR::OPTION_X_LOG  if kvs[:xlog]
    scale |= GR::OPTION_Y_LOG  if kvs[:ylog]
    scale |= GR::OPTION_Z_LOG  if kvs[:zlog]
    scale |= GR::OPTION_FLIP_X if kvs[:xflip]
    scale |= GR::OPTION_FLIP_Y if kvs[:yflip]
    scale |= GR::OPTION_FLIP_Z if kvs[:zflip]
  end
  kvs[:scale] = scale

  if kvs.has_key?(:panzoom)
    xmin, xmax, ymin, ymax = GR.panzoom(*kvs[:panzoom])
    kvs[:xrange] = [xmin, xmax]
    kvs[:yrange] = [ymin, ymax]
  else
    minmax(kind)
  end

  major_count = if %i[wireframe surface plot3 scatter3 polar polarhist
                      polarheatmap nonuniformpolarheatmap trisurf volume].include?(kind)
                  2
                else
                  5
                end

  kvs[:xticks] = [kvs[:xticks], major_count] if kvs[:xticks].is_a? Numeric
  kvs[:yticks] = [kvs[:yticks], major_count] if kvs[:yticks].is_a? Numeric
  kvs[:zticks] = [kvs[:zticks], major_count] if kvs[:zticks].is_a? Numeric

  xmin, xmax = kvs[:xrange]
  if %i[heatmap polarheatmap].include?(kind) && kvs.has_key?(:xlim)
    xmin -= 0.5
    xmax += 0.5
  end
  xtick, majorx = if (scale & GR::OPTION_X_LOG) == 0
                    if !%i[heatmap polarheatmap].include?(kind) &&
                       !kvs.has_key?(:xlim) &&
                       !kvs[:panzoom]
                      xmin, xmax = GR.adjustlimits(xmin, xmax)
                    end
                    if kvs.has_key?(:xticks)
                      kvs[:xticks]
                    else
                      [auto_tick(xmin, xmax) / major_count, major_count]
                    end
                  else
                    [1, 1]
                  end
  xorg = (scale & GR::OPTION_FLIP_X) == 0 ? [xmin, xmax] : [xmax, xmin]
  kvs[:xaxis] = xtick, xorg, majorx

  ymin, ymax = kvs[:yrange]
  if %i[heatmap polarheatmap].include?(kind) && kvs.has_key?(:ylim)
    ymin -= 0.5
    ymax += 0.5
  end
  if kind == :hist
    if kvs[:horizontal] && !kvs.has_key?(:xlim)
      xmin = (scale & GR::OPTION_X_LOG) == 0 ? 0 : 1
    elsif !kvs.has_key?(:ylim)
      ymin = (scale & GR::OPTION_Y_LOG) == 0 ? 0 : 1
    end
  end
  ytick, majory = if (scale & GR::OPTION_Y_LOG) == 0
                    if !%i[heatmap polarheatmap].include?(kind) &&
                       !kvs.has_key?(:ylim) &&
                       !kvs[:panzoom]
                      ymin, ymax = GR.adjustlimits(ymin, ymax)
                    end
                    if kvs.has_key?(:yticks)
                      kvs[:yticks]
                    else
                      [auto_tick(ymin, ymax) / major_count, major_count]
                    end
                  else
                    [1, 1]
                  end
  yorg = (scale & GR::OPTION_FLIP_Y) == 0 ? [ymin, ymax] : [ymax, ymin]
  kvs[:yaxis] = ytick, yorg, majory

  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
    zmin, zmax = kvs[:zrange]
    ztick, majorz = if (scale & GR::OPTION_Z_LOG) == 0
                      zmin, zmax = GR.adjustlimits(zmin, zmax) if kvs.has_key?(:zlim)
                      if kvs.has_key?(:zticks)
                        kvs[:zticks]
                      else
                        [auto_tick(zmin, zmax) / major_count, major_count]
                      end
                    else
                      [1, 1]
                    end
    zorg = (scale & GR::OPTION_FLIP_Z) == 0 ? [zmin, zmax] : [zmax, zmin]
    kvs[:zaxis] = ztick, zorg, majorz
  end

  kvs[:window] = xmin, xmax, ymin, ymax
  if %i[polar polarhist polarheatmap nonuniformpolarheatmap trisurf].include?(kind)
    GR.setwindow(-1, 1, -1, 1)
  else
    GR.setwindow(xmin, xmax, ymin, ymax)
  end
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
    rotation = kvs[:rotation] || 40
    tilt     = kvs[:tilt]     || 60
    GR.setwindow3d(xmin, xmax, ymin, ymax, zmin, zmax)
    GR.setspace3d(-rotation, tilt, 30, 0)
  end

  kvs[:scale] = scale
  GR.setscale(scale)
end
to_svg() click to toggle source
# File lib/gr/plot.rb, line 1037
def to_svg
  ## Need IRuby improvemend.
  GR.show(false) if ENV['GKS_WSTYPE'] == 'svg'
end

Private Instance Methods

auto_tick(amin, amax) click to toggle source
# File lib/gr/plot.rb, line 1225
def auto_tick(amin, amax)
  scale = 10.0**Math.log10(amax - amin).truncate
  tick_size = [5.0, 2.0, 1.0, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01]
  i = tick_size.find_index do |tsize|
    ((amax - amin) / scale / tsize) > 7 # maximum number of tick marks
  end
  tick = tick_size[i - 1] * scale
end
colormap() click to toggle source
# File lib/gr/plot.rb, line 1052
def colormap
  # rgb
  Array.new(256) do |colorind|
    color = GR.inqcolor(1000 + colorind)
    [(color & 0xff)         / 255.0,
     ((color >> 8)  & 0xff) / 255.0,
     ((color >> 16) & 0xff) / 255.0]
  end
end
equal_length(*args) click to toggle source
# File lib/gr/plot.rb, line 1251
def equal_length(*args)
  GRCommons::GRCommonUtils.equal_length(*args)
end
fix_minmax(a, b) click to toggle source
# File lib/gr/plot.rb, line 1142
def fix_minmax(a, b)
  if a == b
    a -= a != 0 ? 0.1 * a : 0.1
    b += b != 0 ? 0.1 * b : 0.1
  end
  [a, b]
end
hasline(mask) click to toggle source
# File lib/gr/plot.rb, line 1044
def hasline(mask)
  mask == 0x00 || (mask & 0x01 != 0)
end
hasmarker(mask) click to toggle source
# File lib/gr/plot.rb, line 1048
def hasmarker(mask)
  mask & 0x02 != 0
end
inqtext(x, y, s) click to toggle source
# File lib/gr/plot.rb, line 1120
def inqtext(x, y, s)
  s = s.to_s
  if s.length >= 2 && s[0] == '$' && s[-1] == '$'
    GR.inqmathtex(x, y, s[1..-2])
  elsif s.include?('\\') || s.include?('_') || s.include?('^')
    GR.inqtextext(x, y, s)
  else
    GR.inqtext(x, y, s)
  end
end
legend_size() click to toggle source
# File lib/gr/plot.rb, line 1234
def legend_size
  scale = GR.inqscale
  GR.selntran(0)
  GR.setscale(0)
  w = 0
  h = 0
  kvs[:labels].each do |label|
    label = label.to_s
    tbx, tby = inqtext(0, 0, label)
    w = [w, tbx[2] - tbx[0]].max
    h += [tby[2] - tby[0], 0.03].max
  end
  GR.setscale(scale)
  GR.selntran(1)
  [w, h]
end
linspace(low, high, num) click to toggle source

gist.github.com/rysk-t/8d1aef0fb67abde1d259#gistcomment-1925021

# File lib/gr/plot.rb, line 1078
def linspace(low, high, num)
  [*0..(num - 1)].collect { |i| low + i.to_f * (high - low) / (num - 1) }
end
minmax(kind) click to toggle source
# File lib/gr/plot.rb, line 1150
def minmax(kind)
  xmin = ymin = zmin = cmin = Float::INFINITY
  xmax = ymax = zmax = cmax = -Float::INFINITY
  scale = kvs[:scale]
  args.each do |x, y, z, c|
    if x
      if scale & GR::OPTION_X_LOG != 0
        # duck typing for NArray
        x = x.map { |v| v > 0 ? v : Float::NAN }
      end
      x0, x1 = x.minmax
      xmin = [x0, xmin].min
      xmax = [x1, xmax].max
    elsif kind == :volume
      xmin, xmax = -1, 1
    else
      xmin = 0
      xmax = 1
    end
    if y
      if scale & GR::OPTION_Y_LOG != 0
        y = y.map { |v| v > 0 ? v : Float::NAN }
      end
      y0, y1 = y.minmax
      ymin = [y0, ymin].min
      ymax = [y1, ymax].max
    elsif kind == :volume
      ymin, ymax = -1, 1
    else
      ymin = 0
      ymax = 1
    end
    if z
      if scale & GR::OPTION_Z_LOG != 0
        z = z.map { |v| v > 0 ? v : Float::NAN }
      end
      z0, z1 = z.minmax
      zmin = [z0, zmin].min
      zmax = [z1, zmax].max
    end
    if c
      c0, c1 = c.minmax
      cmin = [c0, cmin].min
      cmax = [c1, cmax].max
    elsif z
      z0, z1 = z.minmax
      cmin = [z0, zmin].min
      cmax = [z1, zmax].max
    end
  end
  xmin, xmax = fix_minmax(xmin, xmax)
  ymin, ymax = fix_minmax(ymin, ymax)
  zmin, zmax = fix_minmax(zmin, zmax)

  # kvs[:xlim], kvs[:ylim], kvs[:zlim] is supposed to be Array or Range
  kvs[:xrange] = [(kvs[:xlim]&.first || xmin), (kvs[:xlim]&.last || xmax)]
  kvs[:yrange] = [(kvs[:ylim]&.first || ymin), (kvs[:ylim]&.last || ymax)]
  kvs[:zrange] = [(kvs[:zlim]&.first || zmin), (kvs[:zlim]&.last || zmax)]

  if kvs.has_key?(:clim)
    c0, c1 = kvs[:clim]
    c0 ||= cmin
    c1 ||= cmax
    kvs[:crange] = [c0, c1]
  else
    kvs[:crange] = [cmin, cmax]
  end
end
narray?(data) click to toggle source
# File lib/gr/plot.rb, line 1255
def narray?(data)
  GRCommons::GRCommonUtils.narray?(data)
end
normalize_color(c, cmin, cmax) click to toggle source

Normalize a color c with the range [cmin, cmax]

0 <= normalize_color(c, cmin, cmax) <= 1
# File lib/gr/plot.rb, line 1112
def normalize_color(c, cmin, cmax)
  # NOTE: narray.map{|i| normalize_color(i)} There's room for speedup.
  c = c.to_f # if c is Integer
  c = c.clamp(cmin, cmax) - cmin
  c /= (cmax - cmin) if cmin != cmax
  c
end
plot_args(args) click to toggle source
# File lib/gr/plot.rb, line 1082
def plot_args(args)
  # FIXME
  args = [args] unless args.all? do |i|
                         i.is_a?(Array) && (i[0].is_a?(Array) || narray?(i[0]))
                       end
  args.map do |xyzc|
    spec = nil
    case xyzc.last
    when String
      spec = xyzc.pop
    when Hash
      spec = xyzc.pop[:spec]
    end

    x, y, z, c = xyzc.map do |i|
      if i.is_a?(Array) || narray?(i) || i.nil?
        i
      elsif i.respond_to?(:to_a)
        # Convert an Array-like class such as Daru::Vector to an Array
        i.to_a
      else # String
        i
      end
    end
    [x, y, z, c, spec]
  end
end
text(x, y, s) click to toggle source
# File lib/gr/plot.rb, line 1131
def text(x, y, s)
  s = s.to_s
  if s.length >= 2 && s[0] == '$' && s[-1] == '$'
    GR.mathtex(x, y, s[1..-2])
  elsif s.include?('\\') || s.include?('_') || s.include?('^')
    GR.textext(x, y, s)
  else
    GR.text(x, y, s)
  end
end
to_rgba(value, cmap) click to toggle source
# File lib/gr/plot.rb, line 1062
def to_rgba(value, cmap)
  begin
    r, g, b = cmap[(value * 255).round]
    a = 1.0
  rescue StandardError # nil
    r = 0
    g = 0
    b = 0
    a = 0
  end

  ((a * 255).round << 24) + ((b * 255).round << 16) +
    ((g * 255).round << 8) + (r * 255).round
end
to_wc(wn) click to toggle source
# File lib/gr/plot.rb, line 1219
def to_wc(wn)
  xmin, ymin = GR.ndctowc(wn[0], wn[2])
  xmax, ymax = GR.ndctowc(wn[1], wn[3])
  [xmin, xmax, ymin, ymax]
end