Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inconsistency in cube_round #13

Open
michaelschaub opened this issue Feb 7, 2019 · 1 comment
Open

inconsistency in cube_round #13

michaelschaub opened this issue Feb 7, 2019 · 1 comment

Comments

@michaelschaub
Copy link

michaelschaub commented Feb 7, 2019

There is an inconsistency in the cube_round function and the coordinate generation of the hexagon, resulting in some unexpected behavior when converting from hexagons to x,y, coordinates and back

A small illustration of this

a = HexagonCubic(0,0,0)
points = [b for b in vertices(a)]

gives the output:

6-element Array{Tuple{Float64,Float64},1}:
 (0.8660254037844387, 0.49999999999999994)
 (6.123233995736766e-17, 1.0)
 (-0.8660254037844385, 0.5000000000000003)
 (-0.8660254037844388, -0.4999999999999997)
 (-1.8369701987210297e-16, -1.0)
 (0.8660254037844384, -0.5000000000000004)

These are the corners of a hexagon centered around the point (0,0) (default options).
But center(a) will give

center(a)
(1.0, 1.0)

which is outside the above listed points (because of the default arguments of center).

Things get also confused if we to take the above points and infer back the nearest cubic hexagon.
If we do this we we get the following

for p in points
      display(cube_round(p[1],p[2]))
end

HexagonCubic(0, 0, 0)
HexagonCubic(-1, 1, 0)
HexagonCubic(-1, 1, 0)
HexagonCubic(-1, 2, -1)
HexagonCubic(0, 1, -1)
HexagonCubic(0, 1, -1)

Note again that this is 'off' as the cube_round function implicitly assumes a center at (1,1) of the Hexagon(0,0,0), as this is the default of the center function -- and there is no way to tell cube_round to avoid doing this. One way to fix this would be to allow passing an argument to cubic_round that sets the (x,y) offset explicitly for the invoked center function. Or make both defaults in center and vertices compatible.

@dgleich
Copy link

dgleich commented Apr 30, 2020

Thanks for posted this. I think this is a similar issue that arises when manually trying to hex bin data. Here's a simple example that shows the issue... This is code is based on what's in https://github.com/RalphAS/HexBinPlots.jl and also in Gadfly.jl (https://github.com/GiovineItalia/Gadfly.jl/blob/58fac08c7f1a6c7d7a388c3f7b59fccba6582e49/src/statistics.jl#L1222-L1228)

Here's the buggy code, which seems like it ought to work!

module MyHexBin
# heavily based on HexBinPlots, but designed to correct some issue
using Plots
function myhexbin(x,y;nbins=50)
  xbins = ybins = nbins
  xmin, xmax = extrema(x)
  ymin, ymax = extrema(y)
  xspan, yspan = xmax - xmin, ymax - ymin
  xsize, ysize = xspan / xbins, yspan / ybins
  counts = Dict{(Tuple{Int, Int}), Int}()

  x0 = xmin - xspan/2
  y0 = ymin - yspan/2

  @inbounds for i in eachindex(x)
    h = convert(HexagonOffsetOddR,
                cube_round(x[i] - x0,y[i] - y0,xsize, ysize))

    idx = (h.q, h.r)
    counts[idx] = 1 + get(counts,idx,0)
  end

  nhex = length(counts)
  xh = zeros(nhex)
  yh = zeros(nhex)
  vh = zeros(Int,nhex)
  k = 0
  for (idx, cnt) in counts
    k += 1
    xx,yy = Hexagons.center(HexagonOffsetOddR(idx[1], idx[2]),
                            xsize, ysize, x0, y0)
    xh[k] = xx # FIX bug by adding xsize
    yh[k] = yy # FIX bug by adding ysize
    vh[k] = cnt
  end

  nhex = length(xh)
  xsh = Vector{Float64}()
  ysh = Vector{Float64}()
  for k in eachindex(xh)
    hp = hexpoints(xh[k],yh[k],xsize,ysize)
    append!(xsh,[p[1] for p in hp])
    push!(xsh,hp[1][1])
    push!(xsh,NaN)
    append!(ysh,[p[2] for p in hp])
    push!(ysh,hp[1][2])
    push!(ysh,NaN)
  end

  plot(xsh,ysh,seriestype=:shape)
end

using Hexagons
end # end Module MyHexBin
using Plots
x=[1,2.0]
y=[1,2.0]
hh = MyHexBin.myhexbin(x,y,nbins=50)
scatter!(x,y,legend=false)

Here's the fixed code that manually adjusts the center by xsize

module MyHexBin
# heavily based on HexBinPlots, but designed to correct some issue
using Plots
function myhexbin(x,y;nbins=50)
  xbins = ybins = nbins
  xmin, xmax = extrema(x)
  ymin, ymax = extrema(y)
  xspan, yspan = xmax - xmin, ymax - ymin
  xsize, ysize = xspan / xbins, yspan / ybins
  counts = Dict{(Tuple{Int, Int}), Int}()

  x0 = xmin - xspan/2
  y0 = ymin - yspan/2

  @inbounds for i in eachindex(x)
    h = convert(HexagonOffsetOddR,
                cube_round(x[i] - x0,y[i] - y0,xsize, ysize))

    idx = (h.q, h.r)
    counts[idx] = 1 + get(counts,idx,0)
  end

  nhex = length(counts)
  xh = zeros(nhex)
  yh = zeros(nhex)
  vh = zeros(Int,nhex)
  k = 0
  for (idx, cnt) in counts
    k += 1
    xx,yy = Hexagons.center(HexagonOffsetOddR(idx[1], idx[2]),
                            xsize, ysize, x0, y0)
    xh[k] = xx + xsize # FIX bug by adding xsize
    yh[k] = yy + ysize # FIX bug by adding ysize
    vh[k] = cnt
  end

  nhex = length(xh)
  xsh = Vector{Float64}()
  ysh = Vector{Float64}()
  for k in eachindex(xh)
    hp = hexpoints(xh[k],yh[k],xsize,ysize)
    append!(xsh,[p[1] for p in hp])
    push!(xsh,hp[1][1])
    push!(xsh,NaN)
    append!(ysh,[p[2] for p in hp])
    push!(ysh,hp[1][2])
    push!(ysh,NaN)
  end

  plot(xsh,ysh,seriestype=:shape)
end

using Hexagons
end # end Module MyHexBin
using Plots
x=[1,2.0]
y=[1,2.0]
hh = MyHexBin.myhexbin(x,y,nbins=50)
scatter!(x,y,legend=false)

Alternative fixes include offsetting the points before cube_round by xsize, ysize. But yes, I agree it would be nice to have other fixes for this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants