vericast / theto Goto Github PK
View Code? Open in Web Editor NEWWorkflow automation for exploring location data
License: BSD 3-Clause "New" or "Revised" License
Workflow automation for exploring location data
License: BSD 3-Clause "New" or "Revised" License
When a new data source is updated, it is supposed to update the plot bounds so the plot contains everything. The ymin attribute seems to be incorrectly assigned, resulting in plots that only show part of the data points.
Bokeh now has the option to auto-hide toolbars:
plot.toolbar.autohide = True
This should be the default behavior.
Starting in line 256 of coordinate_utils.py:
if not (-90.0 <= value[0] <= 90.0):
raise ValueError(
' '.join([
'The second element of the list is assumed to be latitude (y-coordinates),',
'but this element is outside acceptable bounds (-90.0, 90.0)'
])
)
That should actually read value[1]
, since latitude is supposed to be the second value of the tuple.
It sometimes may be desireble for a collection of shapes to be treated as a single multipolygon. This could be accomplished by allowing Theto to recognize lists as a collection of items to convert, and then including the functionality for geohashes and points to be converted to multipolygons and multipoints. After that, the rest of the pipeline should work the same.
When using a tile service provider, Theto calculates the bounds of the map using the loaded data sources. It looks like this process was calibrated using pretty granular data. When using data across a larger distance, it ends up setting points right along the border of the map. Case in point:
There's one point near Chattanooga, one near Asheville, and one between Asheville and Knoxville, but then there's one way over on the far left of the graph, and one on the far right near Greenville, both half cut off by the border of the plot area. In this case, the map should have zoomed out a little more to make it easier to notice these points.
shape_to_coords
in the coordinate_utils
moduel assumes that if something is a shapely object it is a polygon, yielding this traceback:
131 if not hasattr(v, 'exterior'):
132 v = v.buffer(0)
--> 133 x_dict['exterior'] = [round(x, precision) for x in v.exterior.coords.xy[0]]
134 x_dict['holes'] = [[round(y, precision) for y in x.coords.xy[0]] for x in v.interiors]
135 y_dict['exterior'] = [round(x, precision) for x in v.exterior.coords.xy[1]]
Something just like an "auto" keyword argument?
Theto throws an error when attempting to plot a MultiLineString well known text data type. MWE below:
wkts = ['MULTILINESTRING ((0 0, 1 1), (2 0, 2 1))']
(
Theto(api_key=None)
.add_source(wkts, label='a')
.prepare_plot(plot_width=400, map_type='carto_light')
.add_layer('a', fill_color='yellow', line_color='black', alpha=0.5)
.render_plot('notebook')
)
The following error is produced:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-2-07450c06b8a0> in <module>
5 (
6 Theto(api_key=None)
----> 7 .add_source(wkts, label='a')
8 .prepare_plot(plot_width=400, map_type='carto_light')
9 .add_layer('a', fill_color='yellow', line_color='black', alpha=0.5)
/opt/maxpoint/envs/analysis-preview-py3-115.0-5968/lib/python3.6/site-packages/theto/theto.py in add_source(self, data, label, uid, column_name, **kwargs)
256 processed_data = [coordinate_utils.import_geojson(v, self.precision) for v in raw_data]
257 else:
--> 258 processed_data = [coordinate_utils.process_input_value(v) for v in raw_data]
259
260 processed_data_transformed = [coordinate_utils.to_webmercator(v) for v in processed_data]
/opt/maxpoint/envs/analysis-preview-py3-115.0-5968/lib/python3.6/site-packages/theto/theto.py in <listcomp>(.0)
256 processed_data = [coordinate_utils.import_geojson(v, self.precision) for v in raw_data]
257 else:
--> 258 processed_data = [coordinate_utils.process_input_value(v) for v in raw_data]
259
260 processed_data_transformed = [coordinate_utils.to_webmercator(v) for v in processed_data]
/opt/maxpoint/envs/analysis-preview-py3-115.0-5968/lib/python3.6/site-packages/theto/coordinate_utils.py in process_input_value(value)
288 return loads(value)
289 else:
--> 290 raise ValueError('String inputs must be either a geohash or well-known text.')
291 elif type(value) in (tuple, list):
292 if validate_latlon_pair(value):
ValueError: String inputs must be either a geohash or well-known text.
Theto currently does a lot of work to calculate the appropriate bounds for a plot. This is not only unnecessary overhead, but it also makes it so the maps can't automatically readjust when data is filtered.
If this change is made, there also needs to be an option for the user to set whether they want the plot to readjust when data is filtered.
The attribution
argument needs to be provided for WMTSTileSource
calls.
Theto tries to send the raw data to be rendered in javascript. When the raw data is a string or array, this is fine, but when it is a shapely object, bokeh doesn't know what to do with it.
Current definition:
def to_webmercator(pol):
return shapely_transform(webmercator_project, pol)
Needed definition:
def to_webmercator(pol):
return shapely_transform(webmercator_project, pol).buffer(0)
This will avoid invalid geometries.
See the last comment in this thread:
The map type is missing an "n". It should read "stamen_watercolor".
This issue is used to collect wording, formatting and other changes that need to be made to the demo notebook.
The current categorical palette uses the Bokeh colorblind8 palette, which is very limited. Something like this could work better:
from bokeh.palettes import Plasma256
from numpy import unique
def colorize_numeric_list(string_list):
unique_values, numeric_list = unique(string_list, return_indices=True)
n_seeds = max(numeric_list) + 1
n_skips = int(len(Plasma256) / n_seeds) * 2
palette = Plasma256[::n_skips]
palette = [x for y in list(zip(palette, reversed(palette))) for x in y]
colors = [palette[j] for j in numeric_list]
return colors
The interleaving from different ends of the continuous palette better ensures visual differentiation. The colorblind palette is probably still the best course for cases that involve 8 or fewer categories.
Multipolygons currently can't be processed. It requires this kind of workaround:
from pandas import DataFrame
from shapely.wkt import loads
new_shapes = list()
new_labels = list()
for _, row in df.iterrows():
shape = loads(row['polygonWKT'])
if hasattr(shape, '__len__'):
for shape_part in shape:
new_shapes.append(shape_part)
new_labels.append(row['metadata'])
else:
new_shapes.append(shape)
new_labels.append(row['metadata'])
df = DataFrame({'polygonWKT': new_shapes, 'newMetadata': new_labels})
@schaunwheeler , it was fun to talk to you today! For some reason I'm not able to send our meeting notes by email (it just bounces!), so I'm filing this issue, but maybe it's information generally useful to Theto users anyway. In any case, Schaun met with me and @philippjfr to discuss possible synergies between Theto and GeoViews, given that both of these tools offer Bokeh-based visualization tools for shapes in a geographic context.
We agreed that theto provides several types of functionality not currently available from GeoViews and its companion libraries, and to record those we filed some issues on our projects:
geoviews#372: Allow data to be provided as geohashes
geoviews#371: Document how to use well-known text with GeoViews
holoviews#4079: Generate Panel widgets for selecting between sub-elements automatically
Since then, Philipp has already made a stab at geohash support (holoviz/geoviews#373), and the WKT support is just a matter of documentation rather than coding, which leaves the last item (widgets) as something for us to address, and it's one that I'm very excited about. Thanks for releasing Theto and inspiring us!
This raises an error:
from shapely.wkt import loads
wkts = ['LINESTRING (-95.590228 41.853669, -95.589349 41.853491, -95.589288 41.853451, -95.58691399999999 41.852906, -95.589308 41.853464, -95.589349 41.853491, -95.590199 41.853673)']
shps = [loads(wkt) for wkt in wkts]
(
Theto(api_key=None)
.add_source(shps, label='a')
.prepare_plot(plot_width=400, map_type='carto_light')
.add_layer('a', fill_color='yellow', line_color='black', alpha=0.5)
.render_plot('notebook')
)
This avoid the error:
shps = [loads(wkt).buffer(1e-06) for wkt in wkts]
I don't know why, since that buffer call already happens internally in coordinate_utils.shape_to_nested_list
. But apparently doing it beforehand does the trick.
Current animation functionality sits on top of the slider widget. So the data source contains a column that labels records in terms of state, and then the slider cycles through those states in order. This means you can show progression through states, but it doesn't allow us to see the previous states at the same time.
This could easily be accomplished by slightly changing the javascript for the slider widget to filter for <= instead of just ==. While we're at it, we should probably include the option for accumulated previous states to have different visual attributes than the current state.
Functionality currently supports Google Maps and Bing Maps. Add OSM.
The tile providers in bokeh_utils.py are currently handled as a global dictionary. This causes problems because Bokeh requires that a tile source object be created new each time it is used. If we try to use them over again in the same workflow it sometimes causes errors. The current code should be replaced with:
def get_tile_source(name):
tiles = {
'osmb&w': WMTSTileSource(url=OSMBW_URL),
'osm': WMTSTileSource(url=OSM_URL),
'esri': WMTSTileSource(url=ESRI_URL),
'wikipedia': WMTSTileSource(url=WIKI_URL),
'stamentoner': WMTSTileSource(url=STAMENTONER_URL),
'stamenterrain': WMTSTileSource(url=STAMENTERRAIN_URL),
'cartodb': WMTSTileSource(url=CARTODB_URL)
}
if name not in tiles:
raise ValueError('map_type not in list of supported tile providers')
return tiles[name]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.