Dynamically change chart properties with slider in altair? - visualization

I'm trying to make a histogram in Altair with a slider that dynamically sets the maxbins parameter in alt.Bin(). The idea is to show how bin choice can affect a histogram.
A working example of the histogram without dynamic bins is:
import pandas as pd
import numpy as np
import altair as alt
weather = pd.read_csv('https://raw.githubusercontent.com/altair-viz/vega_datasets/master/vega_datasets/_data/seattle-weather.csv')
alt.Chart(weather).mark_bar().encode(
alt.X("wind:Q",
bin=alt.Bin(maxbins=50)),
y='count()',
)
What I would like to do is something along these lines (this code produces an error saying 'maxbins.maxbins' is not of type 'number'):
import pandas as pd
import numpy as np
import altair as alt
weather = pd.read_csv('https://raw.githubusercontent.com/altair-viz/vega_datasets/master/vega_datasets/_data/seattle-weather.csv')
slider = alt.binding_range(min=0,
max=len(np.unique(weather.wind)),
step=1)
selector = alt.selection_single(name='maxbins',
fields=['wind'],
bind=slider,
init={'wind': len(np.unique(weather.wind))/5})
alt.Chart(weather).mark_bar().encode(
alt.X("wind:Q",
bin=alt.Bin(maxbins=selector.maxbins)),
y='count()',
).add_selection(
selector
)
I think that, more generally, my question is whether chart properties (rather than selections of data) can be set by a slider in Altair.

Related

How to display node attributes on a networkx graph visualized with pyvis?

I would like to display node attributes when visualized with pyvis.
import networkx
import obonet
G = obonet.read_obo('https://ftp.ebi.ac.uk/pub/databases/chebi/ontology/chebi_core.obo')
# Create smaller subgraph
H = nx.ego_graph(G, 'CHEBI:36464', 15)
H.nodes['CHEBI:24669']
>>> {'name': 'p-block molecular entity', 'subset': ['3_STAR'], 'def': '"Amain group molecular entity that contains one or more atoms of a p-block element." []', 'is_a': ['CHEBI:33579'], 'relationship': ['has_part CHEBI:33560']}
This is the data that I would like to show. For example name.
Then I plot the graph using pyvis:
from pyvis.network import Network
nt = Network('1500px', '1500px', notebook=True)
nt.from_nx(H)
nt.show('H.html')
And this is how the graph looks:
As you can see only the node labels are shown.
In order to get your node attribute displayed with the node labels, you can create a new 'label' key in your node dictionary and pass it the value of the attribute. See code below with the lite version of the dataset you provided:
import networkx as nx
import obonet
from pyvis.network import Network
G = obonet.read_obo('https://ftp.ebi.ac.uk/pub/databases/chebi/ontology/chebi_lite.obo')
# Create smaller subgraph
H = nx.ego_graph(G, 'CHEBI:36464', 15)
for n in H.nodes(data=True):
n[1]['label']=n[0]+' '+n[1]['name'] #concatenate label of the node with its attribute
nt = Network('1500px', '1500px', notebook=True)
nt.from_nx(H)
nt.show('network.html')
And the output gives:
If instead, you'd like to visualize the node attribute by hoovering over the node, you can use:
import networkx as nx
import obonet
from pyvis.network import Network
G = obonet.read_obo('https://ftp.ebi.ac.uk/pub/databases/chebi/ontology/chebi_lite.obo')
# Create smaller subgraph
H = nx.ego_graph(G, 'CHEBI:36464', 15)
for n in H.nodes(data=True):
n[1]['title']=n[1]['name'] #add hoovering to graph
nt = Network('1500px', '1500px', notebook=True)
nt.from_nx(H)
nt.show('network.html')

how to add a vector layer on top of plotly choropleth_mapbox with raster image?

I am trying to add a vector layer (geopandas) on top of choropleth_mapbox. I can easily make a new choropleth_mapbox figure as follows.
import geopandas as gpd
import requests
import plotly_express as px
from shapely.geometry import Point
# import data
data = json.loads(requests.get("http://drive.google.com/uc?id=1ex0kKZgEuhF6-92HyKLW8J1U0r_gxmDM").json())
gdf = gpd.GeoDataFrame.from_features(data["features"]).set_geometry("geometry")
# create new choropleth_mapbox
fig=px.choropleth_mapbox( gdf,
geojson=gdf.geometry,
locations=gdf.index,
color="dummy",
center={"lon": gdf.iat[0,0].centroid.x, "lat":gdf.iat[0,0].centroid.y},
mapbox_style="carto-darkmatter",
color_continuous_scale=blues,
zoom=13.5
)
and fig.show() displays the figure exactly as expected.
But if I create a figure first:
# create figure first
dummy_df = gpd.GeoDataFrame({"geometry":[Point(7.9797197,47.32547143)], "dummy":[1]})
fig=px.choropleth_mapbox( dummy_df,
geojson=dummy_df.geometry,
locations=dummy_df.index,
color="dummy",
center={"lon": gdf.iat[0,0].centroid.x, "lat":gdf.iat[0,0].centroid.y},
mapbox_style="carto-darkmatter",
color_continuous_scale=blues,
zoom=13.5
)
fig.show()
and then add the layer as follows:
fig.add_choroplethmapbox(geojson=gdf.geometry, locations=gdf.index)
I get a TypeError “object of type polygon is not JSON serialisable”
What am I doing wrong?
I have also tried add_trace(go.Choropleth(...)
but this shows empty.
What am I doing wrong? What other way to show a vector map on top of an image on top of a base layer with plotly?

CRS for HS2 snakegrid plotting in wrong location on Folium and Leaflet

I've been trying to plot some geographical date which is the HS2 snakegrid co-ordinate system
According to ESPG HS2 ESPG Geodetic Parameters Page I should be using CRS 9300 (although have also tried 9306)
When used, the location is not plotting correctly, example below uses folium to generate a basemap in WGS 84 and geopandas to add a point with the CRS changed to the HS2 9300.
The co-ordinates used should place the point just outside Euston Station but instead is plotting in Hyde Park
I've used Jupyter notebooks to run the below code, although i've also run in geodjango so i could use leaflet with proj4js string for HS2 and same thing
import folium
from folium import plugins
import geopandas as gpd
from shapely.geometry import Point
f = folium.Figure()
m = folium.Map(
location=[51.5091, -0.16006],
max_zoom = 22,
zoom_start = 16,
tiles = None,
control_scale = True,
prefer_canvas = True,
crs = 'EPSG3857',
)
folium.TileLayer('cartodbpositron', max_zoom = 22, detect_retina = True, name = 'Carto',).add_to(m)
s = gpd.GeoSeries([Point(292001.0182, 288039.0657),],)
s = s.set_crs('epsg:9300')
s.explore(name = "S", m = m, highlight = True, show = False, style_kwds={'color': 'green','fill': False},)
example output
UPDATE
I need to use HS2TN15_NTv2.gsb transformation file within pyproj
Reading the pyproj docs i should use pyproj.datadir.get_data_dir() to identify the data directory which gives \Lib\site-packages\pyproj\proj_dir\share\proj
However when i then run TransformerGroup("epsg:4258","epsg:9300") I still get the following warning
\lib\site-packages\pyproj\transformer.py:184: UserWarning: Best
transformation is not available due to missing
Grid(short_name=HS2TN15_NTv2.gsb, full_name=, package_name=, url=,
direct_download=False, open_license=False, available=False)
super().init(

How to change color in networkx graph plotted with holoviews/bokeh?

How can I change the color of individual nodes in the following example?
%pylab inline
import pandas as pd
import networkx as nx
import holoviews as hv
hv.extension('bokeh')
G = nx.Graph()
ndxs = [1,2,3,4]
G.add_nodes_from(ndxs)
G.add_weighted_edges_from([(1,2,0), (1,3,1), (1,4,-1),
(2,4,1), (2,3,-1), (3,4,10)])
hv.extension('bokeh')
%opts Graph [width=400 height=400]
padding = dict(x=(-1.1, 1.1), y=(-1.1, 1.1))
hv.Graph.from_networkx(G, nx.layout.spring_layout).redim.range(**padding)
The graph as you currently define it does not define any attributes but you could still color by the node index. To color by a particular node attribute you can use the color_index option along with a cmap. Here's how we would color by the 'index'
graph = hv.Graph.from_networkx(G, nx.layout.spring_layout)
graph.options(color_index='index', cmap='Category10').redim.range(**padding)
If you do have attributes defined on the nodes the next version of HoloViews (1.10.5) due to be released this week will be able to extract them automatically and let you use the same approach to color by those variables.
If you want to manually add node attributes until the next release you can pass in a Dataset with a single key dimension defining the node indices and any attributes you want to add defined as value dimensions, e.g.:
nodes = hv.Dataset([(1, 'A'), (2, 'B'), (3, 'A'), (4, 'B')], 'index', 'some_attribute')
hv.Graph.from_networkx(G, nx.layout.spring_layout, nodes=nodes).options(color_index='some_attribute', cmap='Category10')
Thanks to Philippjfr, here is a nice solution (using the current development version of holoviews) that uses node attributes for coloring:
%pylab inline
import pandas as pd
import networkx as nx
import holoviews as hv
hv.extension('bokeh')
G = nx.Graph()
ndxs = [1,2,3,4]
G.add_nodes_from(ndxs)
G.add_weighted_edges_from([(1,2,0), (1,3,1), (1,4,-1),
(2,4,1), (2,3,-1), (3,4,10)])
attributes = {ndx: ndx%2 for ndx in ndxs}
nx.set_node_attributes(G, attributes, 'some_attribute')
%opts Graph [width=400 height=400]
padding = dict(x=(-1.1, 1.1), y=(-1.1, 1.1))
hv.Graph.from_networkx(G, nx.layout.spring_layout)\
.redim.range(**padding)\
.options(color_index='some_attribute', cmap='Category10')

2D Range Selection Box in Chaco (Enthought)

I am trying to draw a 2D selection box on an image plot and get out the selected region. I cannot find the appropriate tool to do this.
I assumed RangeSelection2D would be appropriate for this but it seems to only actually select 1 of the 2 axes.
I could modify the BetterSelectingZoom where the box mode is similar to what I want. Does anyone know the best way or chaco tool to do this?
import enthought.traits.api as traits
import enthought.chaco.api as chaco
import enthought.chaco.tools.api as ctools
import enthought.traits.ui.api as ui
from enthought.enable.component_editor import ComponentEditor
class ImageViewer(traits.HasTraits):
plot = traits.Instance(chaco.Plot)
view = ui.View(
ui.Item('plot', editor=ComponentEditor(), show_label=False),
width=600, height=600, resizable=True)
def __init__(self, image_array, *args, **kwargs):
super(ImageViewer, self).__init__(*args, **kwargs)
pd = chaco.ArrayPlotData(imagedata=image_array)
self.plot = chaco.Plot(pd, default_origin='top left')
img_plot = self.plot.img_plot("imagedata")[0]
range_select = ctools.RangeSelection2D(component=img_plot)
range_select.left_button_selects = True
img_plot.tools.append(range_select)
range_overlay = ctools.RangeSelectionOverlay(component=img_plot)
img_plot.overlays.append(range_overlay)
if __name__ == "__main__":
import numpy as np
image = np.random.random_integers(0, 255, size=(20, 20))
imageui = ImageViewer(image)
imageui.configure_traits()
Unfortunately, there's nothing in Chaco, currently, that does what you need. That said, there's an open pull request that adds that functionality:
https://github.com/enthought/chaco/pull/162.
As that PR suggests, there's a bit of design discussion about Chaco tools, in general, that needs to happen before more tools are added.
I hope that helps,
-Tony