Log scale for Bokeh bar chart - bokeh

My code is below. How can I get a log scale for a bokeh hbar plot? Tried x_axis_type="log", but that returned an empty plot.
Edit: I was advised that I must set left to a low but non-zero value in order for it to work, but the new addition left = 0.001 in the code below seem to offset the zero point of the bars on the left, but does not appear as a desired log-scale where the difference between the extreme value in x is visualised as less visually extreme.
Edit (solved): My error in the edit above was that I had not explicitly set the range of the bars. I added x_range=[0.001,1000000] to the code below, and now I get the desired result. See image.
from bokeh.plotting import figure
from bokeh.io import show, output_notebook
output_notebook()
x = [1,5,9,256000]
y = ["a","b","c","d"]
p = figure(y_range=y,x_axis_type = "log",x_range=[0.001,1000000])
p.hbar(y = y, right = x, left = 0.001, height = 0.1)
show(p)

Zero is not a permissible value on a log scale, and as of version 2.3.1 Bokeh does not have anything like Matplotlib's symlog scale that linearizes around the origin. The best you will be able to to is to set left equal to some very small value (but non-zero).

Related

How do I set the scatter circle radius in holoviews?

Simple question - in bokeh you can plot circles with a radius rather than a size,such that the circles adjust when zooming in or out. Is it possible to do this with a holoviews based scatter - it doesn't have an option currently that I can see for setting the radius and I couldn't work out how to provide it in another manner (eg renders). Likely user error so apologies in advance, many thanks.
import holoviews as hv
hv.extension('bokeh')
from bokeh.plotting import figure, show
x=(1,2,3)
y=(1,2,3)
p=figure()
p.scatter(x, y, radius=0.2)
show(p) # bokeh plot working as expected
scatter=hv.Scatter((x,y)).opts(marker="circle", size=20)
scatter # holoviews plot, cannot code "radius" for code above - causes error.
All hv.Scatter plots are based around Bokeh's Scatter marker which has this section in its docstring:
Note that circles drawn with `Scatter` conform to the standard Marker
interface, and can only vary by size (in screen units) and *not* by radius
(in data units). If you need to control circles by radius in data units,
you should use the Circle glyph directly.
This means that you cannot use hv.Scatter, you have to use something else:
import holoviews as hv
import param
from holoviews.element.chart import Chart
from holoviews.plotting.bokeh import PointPlot
hv.extension('bokeh')
x = (1, 2, 3)
y = (1, 2, 3)
class Circle(Chart):
group = param.String(default='Circle', constant=True)
size = param.Integer()
class CirclePlot(PointPlot):
_plot_methods = dict(single='circle', batched='circle')
style_opts = ['radius' if so == 'size' else so for so in PointPlot.style_opts if so != 'marker']
hv.Store.register({Circle: CirclePlot}, 'bokeh')
scatter = Circle((x, y)).opts(radius=0.5)

Set the amount of visible bars in the initial plot

I have a barplot using the bokeh library, and I would like to show only the first 5 barplot and then if I want to see the rest of the bars I have to move the x axis to the right or left. I am struggling in find the information that would allow me to do so.
An example would be this:
from bokeh.plotting import figure
from bokeh.io import output_file, show
import calendar
values = [2,3,4,5,6,7,8]
days = [calendar.day_name[i-1] for i in range(1,8)]
p = figure(x_range=days,plot_height=500)
p.vbar(x=days, width=0.5, top=values, color = "#ff1200")
output_file('foo.html')
show(p)
and what I would like it would be something like this:
and then if I want to see the resting of the days I have to click on the figure and move the mouse.
Any idea?
I wasn't able to find a solution for limiting the x axis while using categorical data. Instead I made a workaround where the x axis labels are overridden by days of the week. This makes it possible to use x_range to limit the x axis.
#!/usr/bin/python3
from bokeh.plotting import figure
from bokeh.io import output_file, show
values = [2,3,4,5,6,7,8]
days = [0,1,2,3,4,5,6]
p = figure(x_range=(-0.3,4.3),plot_height=500)
p.xaxis.major_label_overrides = {0:'Monday', 1:'Tuesday', 2:'Wednesday', 3:'Thursday', 4:'Friday', 5:'Saturday', 6:'Sunday'}
p.vbar(x=days, width=0.5, top=values, color = "#ff1200")
output_file('foo.html')
show(p)

How can I eliminate extra space in a stripchart in base R?

I have created a stripchart in R using the code below:
oldFaithful <- read.table("http://www.isi-stats.com/isi/data/prelim/OldFaithful1.txt", header = TRUE)
par(bty = "n") #Turns off plot border
stripchart(oldFaithful, #Name of the data frame we want to graph
method = "stack", #Stack the dots (no overlap)
pch = 20, #Use dots instead of squares (plot character)
at = 0, #Aligns dots along axis
xlim = c(40,100)) #Extends axis to include all data
The plot contains a large amount of extra space or whitespace at the top of the graph, as shown below.
Is there a way to eliminate the extra space at the top?
Short Answer
Add the argument offset=1, as in
stripchart(oldFaithful, offset=1, ...)
Long Answer
You really have to dig into the code of stripchart to figure this one out!
When you set a ylim by calling stripchart(oldFaithful, ylim=c(p,q)) or when you let stripchart use its defaults, it does in fact set the ylim when it creates the empty plotting area.
However, it then has to plot the points on that empty plotting area. When it does so, the y-values for the points at one x-value are specified as (1:n) * offset * csize. Here's the catch, csize is based on ylim[2], so the smaller you make the upper ylim, the smaller is csize, effectively leaving the space at the top of the chart no matter the value of ylim[2].
As a quick aside, notice that you can "mess with" ylim[1]. Try this:
stripchart(oldFaithful, ylim=c(2,10), pch=20, method="stack")
OK, back to solving your problem. There is a second reason that there is space at the top of the plot, and that second reason is offset. By default, offset=1/3 which (like csize) is "shrinking" down the height of the y-values of the points being plotted. You can negate this behavior be setting offset closer or equal to one, as in offset=0.9.

Rotate labels for histogram bars - shown via: labels = TRUE

Here is shown how to label histogram bars with data values or percents using labels = TRUE. Is it also possible to rotate those labels? My goal is to rotate them to 90 degrees because now the labels over bars overrides each other and it is unreadable.
PS: please note that my goal is not to rotate y-axis labels as it is shown e.g. here
Using mtcars, here's one brute-force solution (though it isn't very brutish):
h <- hist(mtcars$mpg)
maxh <- max(h$counts)
strh <- strheight('W')
strw <- strwidth(max(h$counts))
hist(mtcars$mpg, ylim=c(0, maxh + strh + strw))
text(h$mids, strh + h$counts, labels=h$counts, adj=c(0, 0.5), srt=90)
The srt=90 is the key here, rotating 90 degrees counter-clockwise (anti-clockwise?).
maxh, strh, and strw are used (1) to determine how much to extend the y-axis so that the text is not clipped to the visible figure, and (2) to provide a small pad between the bar and the start of the rotated text. (The first reason could be mitigated by xpd=TRUE instead, but it might impinge on the main title, and will be a factor if you set the top margin to 0.)
Note: if using density instead of frequency, you should use h$density instead of h$counts.
Edit: changed adj, I always forget the x/y axes on it stay relative to the text regardless of rotation.
Edit #2: changing the first call to hist so the string height/width are calculate-able. Unfortunately, plotting twice is required in order to know the actual height/width.

How to set the hist graph properly?

Here is my data file in (update 2021: link is dead... http://s.yunio.com/87HT7f), please download it and save it as mydata.
y<-scan("mydata")
hist(y,breaks=c(0,60,70,80,90,100),freq=TRUE)
axis(2,at=seq(0,20,length.out=5),labels=c(0,5,10,15,20))
There are two problems:
1.Warning message:
In plot.histogram(r, freq = freq1, col = col, border = border, angle = angle, :
the AREAS in the plot are wrong -- rather use freq=FALSE
I just want freq not probability, times counted on the y axis, how to make the warning message vanish?
2.When run
axis(2,at=seq(0,20,length.out=5),labels=c(0,5,10,15,20))
There no 20 on y axis.
For the first problem, it is a warning, not the error. This warning says that visually areas of each bar do not correspond to their actual frequency - you can see it from the first bar that has the largest area but frequency is only 5.
For the second problem, you have to set ylim=c(0,20) inside hist() to see also number 20 because y axis is shorter than 20. Function axis() plots just labels, it doesn't change length of axis (originally there is no space for number 20).
hist(y,breaks=c(0,60,70,80,90,100),freq=TRUE,ylim=c(0,20))
axis(2,at=seq(0,20,length.out=5),labels=c(0,5,10,15,20))
Check the manual for hist:
freq:
Defaults to 'TRUE' _if and only if_ 'breaks' are equidistant
(and 'probability' is not specified).

Resources