Skip to content

TimeDynamicGeoJson plugin #736

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

Merged
merged 31 commits into from
Oct 24, 2017
Merged

Conversation

halfdanrump
Copy link
Contributor

In reference to issue #722.

This is a pull request to merge in a plugin called TimeDynamicGeoJson.

  • The main bulk of the code is in folium/plugins/timedynamic_geo_json.py.
  • The class uses d3. For now I put the script import in folium/map.py, but let me know if there's a better place to do this :).
  • There's a notebook demonstrating the plugin here. I think it'd be useful to merge in that notebook as well, but it's probably better left for a later pull request.

Cheers!

folium/map.py Outdated
@@ -37,6 +41,9 @@
'https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/leaflet.markercluster.js'), # noqa
]

for js in _d3_js:

Choose a reason for hiding this comment

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

W291 trailing whitespace

import json
from jinja2 import Template

from branca.element import MacroElement, Figure, JavascriptLink, CssLink

Choose a reason for hiding this comment

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

F401 'branca.element.JavascriptLink' imported but unused
F401 'branca.element.Figure' imported but unused
F401 'branca.element.MacroElement' imported but unused
F401 'branca.element.CssLink' imported but unused

>>> GeoJson(geojson, style_function=style_function)

"""
def __init__(self, data, styledict, style_function=None, name=None,

Choose a reason for hiding this comment

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

C901 'TimeDynamicGeoJson.init' is too complex (13)

overlay=True, control=True, smooth_factor=None,
highlight_function=None):
super(TimeDynamicGeoJson, self).__init__(name=name, overlay=overlay,
control=control)

Choose a reason for hiding this comment

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

E128 continuation line under-indented for visual indent

raise ValueError('Unhandled object {!r}.'.format(data))


self.styledict = styledict

Choose a reason for hiding this comment

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

E303 too many blank lines (2)



self.styledict = styledict

Choose a reason for hiding this comment

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

W293 blank line contains whitespace


# make set of timestamps
self.timestamps = set()
for feature in self.styledict.values():

Choose a reason for hiding this comment

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

W291 trailing whitespace


{% endmacro %}
""") # noqa

Choose a reason for hiding this comment

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

W293 blank line contains whitespace

raise ValueError('Unhandled object {!r}.'.format(data))

self.styledict = styledict

Choose a reason for hiding this comment

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

W293 blank line contains whitespace


{% endmacro %}
""") # noqa

Choose a reason for hiding this comment

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

W293 blank line contains whitespace

overlay=True, control=True, smooth_factor=None,
highlight_function=None):
super(TimeDynamicGeoJson, self).__init__(name=name, overlay=overlay,
control=control)

Choose a reason for hiding this comment

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

E128 continuation line under-indented for visual indent

Copy link
Member

@ocefpaf ocefpaf left a comment

Choose a reason for hiding this comment

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

There are a lot of good ideas here but you need to use the latest master to avoid conflicts and you can reduce a lot of the code by inheriting from the GeoJson class instead of Layer.

folium/map.py Outdated
@@ -22,6 +22,10 @@

ENV = Environment(loader=PackageLoader('folium', 'templates'))

_d3_js = [
('d3', 'http://d3js.org/d3.v4.min.js'),
Copy link
Member

Choose a reason for hiding this comment

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

This should be in the plugin and not in the global map.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright.

@@ -0,0 +1,257 @@
import json
from ..map import Layer
Copy link
Member

Choose a reason for hiding this comment

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

Please use absolute imports to keep it consistent with the rest of the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

import json
from ..map import Layer
from jinja2 import Template
from branca.utilities import none_min, none_max, iter_points
Copy link
Member

Choose a reason for hiding this comment

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

These are now in folium.utilities.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it.


self.smooth_factor = smooth_factor

self._template = Template(u"""
Copy link
Member

Choose a reason for hiding this comment

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

You can probably inherit from the GeoJson class and save a lot of the duplication by only changing the template.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ocefpaf Good idea!

@ocefpaf
Copy link
Member

ocefpaf commented Sep 29, 2017

This is a pull request to merge in a plugin called TimeDynamicGeoJson.

Looks cool! Thanks for the PR!!

The class uses d3. For now I put the script import in folium/map.py, but let me know if there's a better place to do this :)

See https://github.com/python-visualization/folium/blob/master/folium/plugins/draw.py#L67-L71

There's a notebook demonstrating the plugin here. I think it'd be useful to merge in that notebook as well, but it's probably better left for a later pull request.

Not really, you can add it to the examples folder in this PR. Remember to also add some tests and an entry to the changelog.

@halfdanrump
Copy link
Contributor Author

@ocefpaf Thank you for reviewing the code! I'll implement the changes and push again :)

var datestring = new Date(parseInt(current_timestamp)*1000).toDateString();
d3.select("output#slider-value").text(datestring);
fill_map();
});

Choose a reason for hiding this comment

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

W291 trailing whitespace

{% endif %}
).addTo({{this._parent.get_name()}}
);

Choose a reason for hiding this comment

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

W293 blank line contains whitespace

).addTo({{this._parent.get_name()}}
);

{{this.get_name()}}.setStyle(function(feature) {feature.properties.style;});

Choose a reason for hiding this comment

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

E101 indentation contains mixed spaces and tabs
W191 indentation contains tabs

);

{{this.get_name()}}.setStyle(function(feature) {feature.properties.style;});

Choose a reason for hiding this comment

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

W293 blank line contains whitespace

layer._path.id = 'feature-' + layer.feature.id;
});

d3.selectAll('path').attr('stroke', 'white').attr('stroke-width', 0.8).attr('stroke-dasharray', '5,5').attr('fill-opacity', 0);

Choose a reason for hiding this comment

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

E501 line too long (143 > 120 characters)


d3.selectAll('path').attr('stroke', 'white').attr('stroke-width', 0.8).attr('stroke-dasharray', '5,5').attr('fill-opacity', 0);
fill_map();

Choose a reason for hiding this comment

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

W293 blank line contains whitespace

import folium
from branca.colormap import linear

def test_timedynamic_geo_json():

Choose a reason for hiding this comment

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

E302 expected 2 blank lines, found 1

for country in gdf.index:
pdf = pd.DataFrame({'color': np.random.normal(size=n_periods),
'opacity': np.random.normal(size=n_periods)},
index=dt_index)

Choose a reason for hiding this comment

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

E127 continuation line over-indented for visual indent

min_color = min(max_color, data['color'].min())

cmap = linear.PuRd.scale(min_color, max_color)
norm = lambda x: (x - x.min())/(x.max()-x.min())

Choose a reason for hiding this comment

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

E731 do not assign a lambda expression, use a def

).addTo({{this._parent.get_name()}}
);

{{this.get_name()}}.setStyle(function(feature) {feature.properties.style;});

Choose a reason for hiding this comment

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

E101 indentation contains mixed spaces and tabs
W191 indentation contains tabs

Copy link
Member

Choose a reason for hiding this comment

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

Mix of space and tabs are a no-no. Can you try to find the tabs and make everything spaces?

for country in gdf.index:
pdf = pd.DataFrame(
{'color': np.random.normal(size=n_periods),
'opacity': np.random.normal(size=n_periods)},

Choose a reason for hiding this comment

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

E128 continuation line under-indented for visual indent

#assert expected_timestamps in out

expected_styledict = json.dumps(styledict).replace('"', "'")
#assert expected_styledict in out

Choose a reason for hiding this comment

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

E265 block comment should start with '# '

@halfdanrump
Copy link
Contributor Author

@ocefpaf I've made the changes that you requested :). Buut:

  • I keep getting linter errors. I use pylint on my local machine
  • the test that passes locally fail on the CI. I'm trying to figure out why.

@ocefpaf
Copy link
Member

ocefpaf commented Oct 5, 2017

I keep getting linter errors. I use pylint on my local machine

Don't worry about the lints right now. We can fix those later.

the test that passes locally fail on the CI. I'm trying to figure out why.

It seems that only Python 2.7 is failing. I'll download your code an investigate it locally.

smooth_factor: float, default None
How much to simplify the polyline on each zoom level. More means
better performance and smoother look, and less means more accurate
representation. Leaflet defaults to 1.0.
Copy link
Member

Choose a reason for hiding this comment

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

You can probably remove all that, refer to the GeoJson docs, and add only what is different about this plugin.

).addTo({{this._parent.get_name()}}
);

{{this.get_name()}}.setStyle(function(feature) {feature.properties.style;});
Copy link
Member

Choose a reason for hiding this comment

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

Mix of space and tabs are a no-no. Can you try to find the tabs and make everything spaces?

figure = self.get_root()
assert isinstance(figure, Figure), ('You cannot render this Element '
'if it is not in a Figure.')
figure.header.add_child(JavascriptLink('https://d3js.org/d3.v4.min.js')) # noqa
Copy link
Member

Choose a reason for hiding this comment

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

👍

fill_map();
});

{% if this.highlight %}
Copy link
Member

Choose a reason for hiding this comment

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

Note to self: unfortunately this repetition is needed b/c of the current design we cannot extend the jinja template.

expected_timestamps = ("var timestamps = ['1454166000', '1456671600', '1459350000', "
"'1461942000', '1464620400', '1467212400', '1469890800', "
"'1472569200', '1475161200', '1477839600'];")
#assert expected_timestamps in out
Copy link
Member

Choose a reason for hiding this comment

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

Are you planning on un-commenting this part?

@ocefpaf
Copy link
Member

ocefpaf commented Oct 5, 2017

I am preparing a PR to your fork with some changes that will help you finish this PR.
One quick question, how about we name this TimeSliderChoropleth instead of TimeDynamicGeoJson?

@ocefpaf ocefpaf mentioned this pull request Oct 6, 2017
@halfdanrump
Copy link
Contributor Author

@ocefpaf

I am preparing a PR to your fork with some changes that will help you finish this PR.

Thank you!

One quick question, how about we name this TimeSliderChoropleth instead of TimeDynamicGeoJson?

It's a better name, I agree :).

@ocefpaf
Copy link
Member

ocefpaf commented Oct 6, 2017

I was not able to send #741 to your branch, so I created a new PR. I'll try to finish the docs tomorrow and get it merged so you can polish the details if you want.

@halfdanrump
Copy link
Contributor Author

I was not able to send #741 to your branch, so I created a new PR. I'll try to finish the docs tomorrow and get it merged so you can polish the details if you want.

Alright, sounds good :))

@ocefpaf
Copy link
Member

ocefpaf commented Oct 10, 2017

OK. I'll try to finalize this later this week. Thanks!

@ocefpaf ocefpaf merged commit 7bfabf3 into python-visualization:master Oct 24, 2017
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

Successfully merging this pull request may close these issues.

3 participants