Bokeh: use HTML in axis tick labels? - python

I am very new to Bokeh. I am trying to have clickable links on one of my plots, more precisely on the x-axis (on the ticks).
My question: is it possible to use HTML code in tick labels, for example to replace text by hypertext links?
Taking one of the examples from the documentation of Bokeh, here is my naive attempt (replacement on one of the labels, from Apples to <a>Apples</a>):
from bokeh.io import show, output_file
from bokeh.models import ColumnDataSource
from bokeh.palettes import Spectral6
from bokeh.plotting import figure
output_file("bar_colors.html")
fruits = ['<a>Apples</a>', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
counts = [5, 3, 4, 2, 4, 6]
source = ColumnDataSource(data=dict(fruits=fruits, counts=counts, color=Spectral6))
p = figure(x_range=fruits, y_range=(0,9), plot_height=350, title="Fruit Counts",
toolbar_location=None, tools="")
p.vbar(x='fruits', top='counts', width=0.9, color='color', legend="fruits", source=source)
p.xgrid.grid_line_color = None
p.legend.orientation = "horizontal"
p.legend.location = "top_center"
show(p)
It results, as you may have guessed, in a plot where I have <a>Apples</a> written as text...
How should I proceed to have a proper hypertext link?

The short answer is no. Bokeh does it's rendering on the HTML Canvas, which is a low-level bitmapped drawing area. The HTML canvas does not directly support any DOM type elements (e.g hyperlinks) on it.
There are probably a couple of ways this might be worked around:
Bokeh is extensible You could create a custom extension that renders ticks in a completely different way, i.e. by absolutely positioning real Divs on top of the canvas instead of issuing canvas drawing commands. This would require alot of bookkeeping and precise positioning. I would not describe it as trivial, and would probably need some back and forth iteration to get working, so the public mailing list would be a better place to discuss that possibility.
There is an open issue #601: Add support for click events on categorical axes that is relevant. If this were implemented, it would offer a similar capability (but without actual hyperlinks). It's possible this idea could be expanded to include any tick labels, not just categorical ones. The best place to provide your feedback on this potential feature is in the GitHub link.

Related

How to add a clear border around a graph with matplotlib.pyplot

I created a stacked barchart using matplotlib.pyplot but there is no border around the graph so the title of the graph and axes are right up against the edge of the image and get cutoff in some contexts when I use it. I would like to add a small clear or white border around the graph, axes and title. repos_amount is a pandas DataFrame.
Here is my code:
colors = ["Green", "Red","Blue"]
repos_amount[['Agency','MBS','Treasury']].plot.bar(stacked=True, color=colors, figsize=(15,7))
plt.title('Total Outstanding Fed Repos Operations', fontsize=16)
plt.ylabel('$ Billions', fontsize=12)
Here is what the graph looks like:
I tried the suggestions from the link below and I could not figure out how to make it work. I'm not good with matplotlib yet so I would need help figuring out how to apply it to my code.
How to draw a frame on a matplotlib figure
Try adding plt.tight_layout() to the bottom of your code.
Documentation indicates that this tries to fit the titles, labels etc within the subplot figure size, rather than adding items around this figure size.
It can have undesirable results if your labels or headings are too big, in which case you would then need to look into the answers in this thread to adjust the specific box size of your chart elements.

How to create a proportional (pre-defined boundaries) colour bar with bokeh?

I would like to plot a graph with a proportional colour bar on the right like graph 1, but with bokeh rather than matplotlib.
Here's the matplotlib version with a proportional (pre-defined boundaries) colour bar using matplotlib colors.BoundaryNorm(bounds, cmap.N):
But my current bokeh version has the right hand side colour bar not proportional, although I have given ticker boundaries:
My bokeh code:
ticker = FixedTicker(ticks=bounds)
bounds = [0, 5, 25, 75, 95,100]
color_bar = ColorBar(color_mapper=mapper, major_label_text_font_size='5pt',
ticker=ticker,
formatter=PrintfTickFormatter(format='%d%%'),
label_standoff=6, border_line_color=None, location=(0, 0))
I'm using bokeh as it works well with Django and it has the tools option within the bokeh library.
Please give suggestions. Thanks in advance,
I have got an answer from discourse.bokeh.org Community Suppor. There is a way but build a new feature would be even better.
The answer is here:
Bokeh 1.3.4 only has linear and log colour mappers. There is no built-in notion of a “segmented” colour mapper.
On way to do it is by creating a larger palette with 100 entries, that provides the “breaks” you want implicitly. E.g.
palette = [ "yellow" ]*5 + ["pink"]*20 + ["red"]*50 + ...
Then this palette could be used with a LinearColorMapper with low, high = (0, 100).
A segmented colour mapper would be a reasonable ask for a new feature, and also an excellent self-contained task for a new contributor. Please feel free to make a GitHub issue to discuss it.
so, the updated graph is here, happy!

Bokeh time plotting

I am experimenting with time plots such as this example from bokeh. Is it possible to create minor ticks for the x-axis? I tried all the different options inside p.xaxis.minor but none seemed useful.
Here's the code from example:
import pandas as pd
from bokeh.plotting import figure, output_file, show
AAPL = pd.read_csv(
"http://ichart.yahoo.com/table.csv?s=AAPL&a=0&b=1&c=2000&d=0&e=1&f=2010",
parse_dates=['Date']
)
output_file("datetime.html")
# create a new plot with a datetime axis type
p = figure(width=800, height=250, x_axis_type="datetime")
p.line(AAPL['Date'], AAPL['Close'], color='navy', alpha=0.5)
show(p)
And the image:
From what it seems it's automatically turned off, and the x-axis updates properly as you zoom in, but it would be great to include minor ticks for visualization purpose.
As of Bokeh 0.10, the BokehJS DatetimeTicker sets num_minor_ticks to zero on the internal tickers that it uses:
https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/ticking/datetime_ticker.coffee#L23
There is currently no simple way exposed to override this (You could write some JavaScript to reach in directly, but that would be a pain). I am not sure if this state of affairs is due to some inherent problem with minor ticks and datatime ranges, or if this was merely an oversight. Please make a new issue on the Bokeh GH issue tracker so it can be investigated:
https://github.com/bokeh/bokeh/issues

Bokeh logarithmic scale for Bar chart

I know that I can do logarithmic scales with bokeh using the plotting API:
p = figure(
tools="pan,box_zoom,reset,previewsave",
y_axis_type="log", y_range=[0.001, 10**22], title="log axis example",
x_axis_label='sections', y_axis_label='particles'
)
However, I can't figure out how to get this to apply to high level charts such as Bokeh.charts.Bar. In general I'm having a lot of trouble grokking what to relationship is between a Chart and a figure. Can anyone point me to some documentation on this or explain how to modify things which are only exposed through figure and have them affect my Chart.
I am specifically going to update the documentation describing the different Bokeh APIs this week, but for now, the three Bokeh APIs in increasing order of "level":
models interface: lowest level API, base serialization layer, must put everything together everything manually
glyphs interface (bokeh.plotting): mid-level API, easily create plots/figures centered around visual glyphs with attributes tied to data
charts interface (bokeh.charts): high level API for canned/schematic statistical charts, e.g. "BoxPlot" and "Histogram".
There is no particular relation between figure and the various chart functions, except that they both produces subclasses of Plot as output.
I am not sure it is currently possible to add a log axis to the Bar plot in "charts" interface (that would be a reasonable feature to add). However it would be simple to make a boxplot "by hand" using the middle "glyphs" interface using rect or quad glyphs. Here is a quick example:
from bokeh.plotting import figure, output_file, show
output_file("bars.html")
p = figure(title="log bar example", y_axis_type="log")
p.quad(
bottom=0, top=[10**5, 10**8, 10**3],
left=[0, 2, 4], right=[1,3,5]
)
show(p)

How to plot graphs using networkx and d3py

I am trying to visualize graphs generated from networkx, using d3py.
I used the example provided (https://github.com/mikedewar/d3py/blob/master/examples/d3py_graph.py) but all I get is the graph without node names, how do I plot node names as well?
Also, how do I change edge and node colors?
Here is a partial answer, but also read the caveat at the end.
The easiest thing is changing the node colour. If you run the example you pointed to with
with d3py.NetworkXFigure(G, width=500, height=500) as p:
p += d3py.ForceLayout()
p.css['.node'] = {'fill': 'blue', 'stroke': 'magenta'}
p.show()
then you will have blue nodes with a magenta outline (you can use any html colour you like).
For edge colour, there is a hardcoded stroke: black; in the file d3py/geoms/graph.py. You can comment it out and reinstall d3py
line = {
"stroke-width": "1px",
"stroke": "black",
}
self.css[".link"] = line
Then you can specify edge colour and width as follows:
with d3py.NetworkXFigure(G, width=500, height=500) as p:
p += d3py.ForceLayout()
p.css['.node'] = {'fill': 'blue', 'stroke': 'magenta'}
p.css['.link'] = {'stroke': 'red', 'stoke-width': '3px'}
p.show()
There does not seem to be any way to add node labels easily with d3py. Using just d3.js, it can be done relatively easily (see this example). Which leads us to the major caveat...
Caveat
As #flup already mentioned, d3py does not seem really mature (the code from their Github repository does not even run the NetworkX example, there is a missing host parameter in networkx_figure.py). There has been no activity in the repo since a couple of months, so I guess the project is maybe abandoned. You could probably reach your goal much more easily using d3.js directly.
Just in case anyone ends up here looking around at d3py. I made d3py a couple of years ago now to see what it would feel like to plot d3 graphics from Python. It was fun! But I didn't have the time to do it properly, which was a shame.
However, Rob Story did! He made vincent, which is available at https://github.com/wrobstory/vincent. It's a much better implementation, and is much better thought out. Please do check it out!
Drawing 'static' graphs with networkx.
I would suggest trying mathplotlib.
networkx itself recommends using matplotlib as a plotting supplement.
It is easy to use and draws really nice graphs.
Say you have a networkx Graph "G". You can just plot it in 3 lines of code.
>>> import matplotlib.pyplot as plt
>>> nx.draw(G)
>>> plt.show()
Further, there is a flexibility of choosing between different layouts.
>>> nx.draw_random(G)
>>> nx.draw_circular(G)
>>> nx.draw_spectral(G)
Using an nx.draw*(G) command does not render the graph, until you use the plt.show().
It is as a "plot in the mind" or an abstract representation which you could customize before really rendering it.
Drawing interactive javascript / html5 graphs-
matplotlib is useful to draw static graphs. If you want to plot interactive Javascript graphs, then here are some interesting libraries (including D3.js)
d3.js
arbor.js
cytoscape.js
raphael.js
This libraries are independent and their use with networkx is generally more useful in web applications where networkx code resides in the backend and the Javascript code lies in the front end.

Categories

Resources