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

[WIP] MultiPolygons with holes #8340

Merged
merged 12 commits into from Oct 18, 2018
Merged

[WIP] MultiPolygons with holes #8340

merged 12 commits into from Oct 18, 2018

Conversation

jsignell
Copy link
Contributor

@jsignell jsignell commented Oct 17, 2018

Adding a new MultiPolygons glyph as outlined here https://github.com/bokeh/bokeh/wiki/Polygons-Patches-with-Holes#new-glyph.

multipolygons_hover

Example:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Complete Example</title>
<link rel="stylesheet" href="./bokehjs/build/css/bokeh.css" type="text/css" />
<script type="text/javascript" src="./bokehjs/build/js/bokeh.js"></script>
<script type="text/javascript" src="./bokehjs/build/js/bokeh-api.js"></script>
<!-- The order of CSS and JS imports above is important. -->
</head>

<body>
<div>
<script type="text/javascript">

var source = new Bokeh.ColumnDataSource({
    data: {
        //  i is one multipolygon
        //  j is one polygon
        //  k is either an exterior ring (0) or interior ring/hole (1:n)
        xs: [
            [ [ [1, 1, 2, 2]                             ]                    ],
            [ [ [1, 1, 3],    [1.5, 1.5, 2]              ]                    ],
            [ [ [2, 2, 4, 4], [2.5, 2.5, 3], [3.5, 3, 3] ], [ [3.5, 3.5, 4] ] ]
        ],
        ys:
            [
                [                       // multipolygon 0
                    [                   // polygon 0
                        [4, 3, 3, 4]    // exterior
                    ],
                ],
                [                       // multipolygon 1
                    [                   // polygon 0
                        [1, 3, 1],      // exterior
                        [1.5, 2, 1.5]   // hole 0
                    ],
                ],
                [                       // multipolygon 2
                    [                   // polygon 0
                        [2, 4, 4, 2],   // exterior
                        [3, 3.5, 3.5],  // hole 0
                        [2.5, 2.5, 3]   // hole 1
                    ],
                    [                   // polygon 1
                        [1, 1.5, 1.5]   // exterior
                    ]
            ]
        ]
    }
});

var plot = Bokeh.Plotting.figure({title:'New Glyph - MultiPolygons with Holes', height: 300, width: 300, tools: 'hover'});
var patchData = plot.multi_polygons(
    { field: "xs" },
    { field: "ys" },
    { source: source, fill_color:['red', 'limegreen', 'goldenrod']}
);

Bokeh.Plotting.show(plot, document.currentScript.parentElement);

</script>
</div>
</body>
</html>

@bryevdv
Copy link
Member

bryevdv commented Oct 17, 2018

Given that the New Glyph approach does not intersect with any existing codepaths, I am sorely tempted to consider this as a late add for 1.0, but "done" also means tests, a user's guide section, a contour plot example, and geojson example.... I think that's probably more than can be accomplished in a few days.

Also, I am not sure more work isn't really needed before this is truly useful for Geo work. I was trying to add a tile source under a GeoJSONDataSource scatter earlier today and gave up because one used lat/lon and the other web-mercator. We'd need to figure out how to make things work well together without users having to do alot of conversions by hand.

Most importantly, though: this is fantastic to finally be close to having, thanks for putting things together @jsignell

@jsignell
Copy link
Contributor Author

jsignell commented Oct 17, 2018

Questions:

  • Where should the center of a multipolygon with holes be? Right now I am ignoring holes when getting centers.
  • Why isn't the initial range getting set properly (see glyphs example)?
  • Is there a more efficient way to check for containment in polygon but not hole?
  • Why can't you set fill_color with a list when initializing the class?
  • Should we allow un-nested input in more simple cases? (probably not)
  • Should we raise an error if:
    • the hole isn't wound clockwise
    • two parts of a multipolygon overlap
    • a hole intersects the exterior ring

@jsignell
Copy link
Contributor Author

@bryevdv I'd be happy to push on this and try to get it in for 1.0, I'll just probably need some more help :)

@jbednar
Copy link
Contributor

jbednar commented Oct 17, 2018

Where should the center of a multipolygon with holes be? Right now I am ignoring holes when getting centers.

That sounds correct to me.

Should we raise an error if:
a hole intersects the exterior ring

It seems like intersection per se isn't a problem, e.g. a pattern like this has lots of intersections but still seems valid:

image

The same hole intersecting more than once could be a problem, depending on how it's done, but I'm not sure how to characterize what would be legal and what shouldn't be.

@bryevdv
Copy link
Member

bryevdv commented Oct 17, 2018

Where should the center of a multipolygon with holes be? Right now I am ignoring holes when getting centers.

Let's keep things simple at least for now, the center of the exterior ring

Why isn't the initial range getting set properly (see glyphs example)?

I don't think we are using the spatial index at this point? If you put all MBB of all exterior rings for each MPgon in the index in an _index_data method, then I think that would be sufficient. Tho you might need to call it yourself since you are also overriding map_data. See e.g.

https://github.com/bokeh/bokeh/blob/master/bokehjs/src/lib/models/glyphs/patches.ts#L74-L98

EDIT: looks like index_data is called by set_data so just adding the private _index_data delegate should be sufficient

Why can't you set fill_color with a list when initializing the class?

It's a DataSpec, it can either be a fixed value or a reference to a CDS column

Is there a more efficient way to check for containment in polygon but not hole?

I think just check that it is in the exterior ring but not the holes. If you spatially index the exterior rings then that will narrow down the candidates to brute force this way. More sophisticated approach might spatially index the holes too but thats complex enough that it would need to be justified.

Should we allow un-nested input in more simple cases? (probably not)

Let's say no, for now at least

Should we raise an error if:

I think interior overlap is an error, if that is easily detectable. Tho feel free to console.log any situation that you think might have unexpected or ambiguous results for users.

@bryevdv
Copy link
Member

bryevdv commented Oct 17, 2018

I'd be happy to push on this and try to get it in for 1.0, I'll just probably need some more help :)

I'm available, then. Let's try to shoot for EOB Friday, and if not no worries we will have a follow on release soon.

function traverse_data(v: any, buffers: [any, any][]): [Arrayable, any] {
// v is just a regular array of scalars
if (v.length == 0 || !(isObject(v[0]) || isArray(v[0]))) {
return [v, v.length]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bryevdv, is there a reason why we weren't setting shape to v.length in this case where v is an array?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original code that only handled 1d arrays just didn't require it (checked the length directly) So it simply was not added due to lack of necessity. I am not opposed to adding it to make things consistent, but let's make an issue and do that after 1.0 since I can't say with certainty that nothing ever conditions on the presence or absence of shape to deduce array dimension, and adding it now might beak such paths.

@bryevdv
Copy link
Member

bryevdv commented Oct 18, 2018

Merging now to get in rc3, more docs/examples to follow

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

Successfully merging this pull request may close these issues.

Patches with Holes
3 participants