Skip to content

support hexagon (binning, tessellation) #1574

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

Closed
maxheld83 opened this issue Apr 10, 2017 · 3 comments
Closed

support hexagon (binning, tessellation) #1574

maxheld83 opened this issue Apr 10, 2017 · 3 comments
Labels
community community contribution feature something new

Comments

@maxheld83
Copy link

I understand from this issue at the plotly.js R api, that there is currently no support for hexagons and hexagon binning.

I think that would be a fantastic addition.

@jackparmer
Copy link
Contributor

@empet has made some real nice Python implementations of hex plots using shapes:

https://plot.ly/~empet/13706

image

@PlotlyUser2
Copy link

PlotlyUser2 commented Jun 3, 2018

@maxheld83 @jackparmer @etpinard

Long time ago, I've written my own implementation of the hexagon chart by using the Python plotly api. The binning itself is done by the matplotlib package.

Here is the code:

import plotly.offline as offline
import plotly.graph_objs as go
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize


def compute_hexbin(x, y, gridsize=100, bins=None, cmap=plt.cm.Blues):
    """Computes the hexagonal binning
    """
    collection = plt.hexbin(x, y, bins=bins, gridsize=gridsize)
    plt.close()

    pts_in_hexagon = collection.get_array()

    #compute colors for the svg shapes
    colors = ["#%02x%02x%02x" % (int(r), int(g), int(b)) for r, g, b, _ in 255*cmap(Normalize()(pts_in_hexagon))]

    # coordinates for single hexagonal patch
    hx = [0, .5, .5, 0, -.5, -.5]
    hy = [-.5/np.cos(np.pi/6), -.5*np.tan(np.pi/6), .5*np.tan(np.pi/6),
          .5/np.cos(np.pi/6), .5*np.tan(np.pi/6), -.5*np.tan(np.pi/6)]

    # number of hexagons needed
    m = len(collection.get_offsets())

    # scale of hexagons
    n = (x.max() - x.min()) / gridsize

    # y_scale to adjust for aspect ratio
    y_scale = (y.max() - y.min())/(x.max() - x.min())

    # coordinates for all hexagonal patches
    hxs = np.array([hx]*m)*n + np.vstack(collection.get_offsets()[:,0])
    hys = np.array([hy]*m)*n*y_scale + np.vstack(collection.get_offsets()[:,1])

    return hxs.tolist(), hys.tolist(), colors, pts_in_hexagon

N = 1000

random_x = np.random.randn(N)
random_y = np.random.randn(N)

x, y, color_list, pts_in_hexagon = compute_hexbin(random_x, random_y, gridsize=20)

shape_container = []
hover_point_x = []
hover_point_y = []

for x_list, y_list, color in zip(x, y, color_list):

    #Create the svg path based on the computed points
            
    svg_path = 'M {},{} L {},{} L {},{} L {},{} L{},{} L{},{}'\
        .format(x_list[0], y_list[0],
                x_list[1], y_list[1],
                x_list[2], y_list[2],
                x_list[3], y_list[3],
                x_list[4], y_list[4],
                x_list[4], y_list[1])

    #Create hover point from the hexagon, witch is the center of gravity
    hover_point_x.append(round((max(x_list) - min(x_list))/2+min(x_list), 2))
    hover_point_y.append(round((max(y_list) - min(y_list))/2+min(y_list), 2))

    shape_container.append({
          "fillcolor": color,
          "line": {
            "color": color,
            "width": 1.5
          },
          "path": svg_path,
          "type": "path"
        })

trace = go.Scattergl(x=hover_point_x,
                   y=hover_point_y,
                   mode='markers'
                   )

trace['marker']['colorbar'] = {"title": "Amount of points"}
trace['marker']['reversescale'] = True
trace['marker']['colorscale'] = 'Blues'
trace['marker']['color'] = pts_in_hexagon
trace['marker']['size'] = 0
trace['text'] = list(map(lambda z: 'Amount of points: {}'.format(int(z)), pts_in_hexagon))

layout = {'shapes':shape_container,
          'width': 850,
          'height': 700,
          'hovermode':'closest'}

fig = dict(data=[trace], layout=layout)

offline.plot(fig, show_link=False)

And the result is:

newplot

@gvwilson
Copy link
Contributor

Hi - this issue has been sitting for a while, so as part of our effort to tidy up our public repositories I'm going to close it. If it's still a concern, we'd be grateful if you could open a new issue (with a short reproducible example if appropriate) so that we can add it to our stack. Cheers - @gvwilson

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

No branches or pull requests

5 participants