Multiple histograms in Julia using Plots.jl - julia

I am working with a large number of observations and to really get to know it I want to do histograms using Plots.jl
My question is how I can do multiple histograms in one plot as this would be really handy. I have tried multiple things already, but I am a bit confused with the different plotting sources in julia (plots.jl, pyplot, gadfly,...).
I don't know if it would help for me to post some of my code, as this is a more general question. But I am happy to post it, if needed.

There is an example that does just this:
using Plots
pyplot()
n = 100
x1, x2 = rand(n), 3rand(n)
# see issue #186... this is the standard histogram call
# our goal is to use the same edges for both series
histogram(Any[x1, x2], line=(3,0.2,:green), fillcolor=[:red :black], fillalpha=0.2)
I looked for "histograms" in the Plots.jl repo, found this related issue and followed the links to the example.

With Plots, there are two possibilities to show multiple series in one plot:
First, you can use a matrix, where each column constitutes a separate series:
a, b, c = randn(100), randn(100), randn(100)
histogram([a b c])
Here, hcat is used to concatenate the vectors (note the spaces instead of commas).
This is equivalent to
histogram(randn(100,3))
You can apply options to the individual series using a row matrix:
histogram([a b c], label = ["a" "b" "c"])
(Again, note the spaces instead of commas)
Second, you can use plot! and its variants to update a previous plot:
histogram(a) # creates a new plot
histogram!(b) # updates the previous plot
histogram!(c) # updates the previous plot
Alternatively, you can specify which plot to update:
p = histogram(a) # creates a new plot p
histogram(b) # creates an independent new plot
histogram!(p, c) # updates plot p
This is useful if you have several subplots.
Edit:
Following Felipe Lema's links, you can implement a recipe for histograms that share the edges:
using StatsBase
using PlotRecipes
function calcbins(a, bins::Integer)
lo, hi = extrema(a)
StatsBase.histrange(lo, hi, bins) # nice edges
end
calcbins(a, bins::AbstractVector) = bins
#userplot GroupHist
#recipe function f(h::GroupHist; bins = 30)
args = h.args
length(args) == 1 || error("GroupHist should be given one argument")
bins = calcbins(args[1], bins)
seriestype := :bar
bins, mapslices(col -> fit(Histogram, col, bins).weights, args[1], 1)
end
grouphist(randn(100,3))
Edit 2:
Because it is faster, I changed the recipe to use StatsBase.fit for creating the histogram.

Related

How can you make a stacked area / line chart in Julia with Plots.jl?

I would like to create a stacked area chart, similar to this for example, in Julia using Plots.
I know / suppose that you can do this if you directly use the Gadfly or PyPlot backends in Julia, but I was wondering if there was a recipe for this. If not, how can you contribute to the Plots Recipes? Would be a useful addition.
There's a recipe for something similar in
https://docs.juliaplots.org/latest/examples/pgfplots/#portfolio-composition-maps
For some reason the thumbnail looks broken now though (but the code works).
The exact plot in the matlab example can be produced by
plot(cumsum(Y, dims = 2)[:,end:-1:1], fill = 0, lc = :black)
As a recipe that would look like
#userplot AreaChart
#recipe function f(a::AreaChart)
fillto --> 0
linecolor --> :black
seriestype --> :path
cumsum(a.args[1], dims = 2)[:,end:-1:1]
end
If you want to contribute a recipe to Plots you can open a pull request on Plots, or, eg. on StatsPlots - there's a good description of contributing here: https://docs.juliaplots.org/latest/contributing/
It's a bit of reading, but very generally useful as an introduction to contributing to Julia packages.
You can read this thread in the Julia discourse forum where the question is developed in deep.
One solution posted there using Plots is :
# a simple "recipe" for Plots.jl to get stacked area plots
# usage: stackedarea(xvector, datamatrix, plotsoptions)
#recipe function f(pc::StackedArea)
x, y = pc.args
n = length(x)
y = cumsum(y, dims=2)
seriestype := :shape
# create a filled polygon for each item
for c=1:size(y,2)
sx = vcat(x, reverse(x))
sy = vcat(y[:,c], c==1 ? zeros(n) : reverse(y[:,c-1]))
#series (sx, sy)
end
end
a = [1,1,1,1.5,2,3]
b = [0.5,0.6,0.4,0.3,0.3,0.2]
c = [2,1.8,2.2,3.3,2.5,1.8]
sNames = ["a","b","c"]
x = [2001,2002,2003,2004,2005,2006]
plotly()
stackedarea(x, [a b c], labels=reshape(sNames, (1,3)))
(by user NiclasMattsson)
Other ways presented there include using the VegaLite.jl package.

bokeh axis limits fail when mixing x_range with y_range across multiple plots

I'm trying to visualize a high-dim point set x (here of dim (6 x 42)) in a series of 2D scatter plots (x[1] vs x[2] etc.) using bokeh. [edit2] See this nice example from scikit-opt as a reference. When x[1] occurs in two plots it should interact with the same range and the plots should rescale simultaneously. I have accomplished this, but I don't get it to scale correctly. Here's a minimal example: [edit2]
import bokeh
import bokeh.io
import numpy as np
import bokeh.plotting
bokeh.io.output_notebook()
# That's my fictional dataset
x = np.random.randn(6, 42)
x[2] *= 10
# Build the pairwise scatter plots
kw = dict(plot_width=165, plot_height=165)
# `ranges` stores the range in each dimension,
# used as both, x- and y-range depending on
# where the variable is.
figs, ranges = {}, {}
for r, row in enumerate(x):
for c, col in enumerate(x):
if r is not c:
fig = bokeh.plotting.figure(
x_range=ranges.get(c, None), y_range=ranges.get(r, None),
**kw)
fig.scatter(x=col, y=row)
fig.xaxis.axis_label = f'Dim {c}'
fig.yaxis.axis_label = f'Dim {r}'
if c not in ranges:
ranges[c] = fig.x_range
if r not in ranges:
ranges[r] = fig.y_range
figs[f'{r}_{c}'] = fig
else:
break
# Setup the plotting layout
plots = [[]]
for r, row in enumerate(x):
for c, col in enumerate(x):
if r is not c:
plots[-1].append(figs[f'{r}_{c}'])
else:
plots.append([])
break
staircase = bokeh.layouts.gridplot(plots, **kw)
bokeh.plotting.show(staircase)
.. into an ipython notebook (>=py3.6), bokeh sets the scale for dim 1, and 2 correctly. Then, it starts to set the scale for the following dimensions as in dim 2. Notice that I scaled dim 2 10-fold to make this point.
Interactively, I can rescale the plot back to optimal settings. However, I'd like to do that by default. What options do I have inside bokeh to rescale? I played a bit with fig.xaxis.bounds, but unsuccessfully. Thanks for your help!
Epilogue:
Following #bigreddot's answer, I added the lines:
for i, X in enumerate(x):
ranges[i].start = X.min()
ranges[i].end = X.max()
to fix the starting ranges. I still think that the behaviour is a bug.
From your code and description I still can't quite tell what you are hoping to accomplish. [1] But I will state that the default DataRange1d ranges that plot's use automatically make space for all renderers, across all plots they are shared by. In this sense, I see exactly what I would expect when I run your code. If you want something different, there are two things you could control:
DataRange1d has a .renderers property. If you only want the "auto" ranging to be over a subset of the renderers, then you can explicitly set this property to the list you want. Renderers are returned by the glyph functions, e.g. fig.scatter
Don't use the "auto" ranges. You can also set the x_range and y_range yourself to be Range1d objects. These have start and end properties that you can set, and these will be the definite bounds of the range, e.g. x-range=Range1d(0, 10)
[1] The ranges are linked in what I would consider an odd way, and I can't tell if that is intended. But that is a result of your looping/python code and not Bokeh.

How to put 2 boxplot in one graph in R without additional libraries?

I have this kind of dataset
Defect.found Treatment Program
1 Testing Counter
1 Testing Correlation
0 Inspection Counter
3 Testing Correlation
2 Inspection Counter
I would like to create two boxplotes, one boxplot of detected defects per program and one boxplot of detected defects per technique but in one graph.
Meaning having:
boxplot(exp$Defect.found ~ exp$Treatment)
boxplot(exp$Defect.found ~ exp$Program)
In a joined graph.
Searching on Stackoverflow I was able to create it but with lattice library typing:
bwplot(exp$Treatment + exp$Program ~ exp$Defects.detected)
but i would like to know if its possible to create the graph without additional libraries like ggplot and lattice
Prepare the plot window to receive two plots in one row and two columns (default is obviously one row and one column):
par(mfrow = c(1, 2))
My suggestion is to avoid using the word exp, because it is already used for the exponential function. Use for instance mydata.
Defects found against treatment (frame = F suppresses the external box):
with(mydata, plot(Defect.found ~ Treatment, frame = F))
Defects found against program (ylab = NA suppresses the y label because it is already shown in the previous plot):
with(mydata, plot(Defect.found ~ Program, frame = F, ylab = NA))

Graphing a polynomial output of calc.poly

I apologize first for bringing what I imagine to be a ridiculously simple problem here, but I have been unable to glean from the help file for package 'polynom' how to solve this problem. For one out of several years, I have two vectors of x (d for day of year) and y (e for an index of egg production) data:
d=c(169,176,183,190,197,204,211,218,225,232,239,246)
e=c(0,0,0.006839425,0.027323127,0.024666883,0.005603878,0.016599262,0.002810977,0.00560387 8,0,0.002810977,0.002810977)
I want to, for each year, use the poly.calc function to create a polynomial function that I can use to interpolate the timing of maximum egg production. I want then to superimpose the function on a plot of the data. To begin, I have no problem with the poly.calc function:
egg1996<-poly.calc(d,e)
egg1996
3216904000 - 173356400*x + 4239900*x^2 - 62124.17*x^3 + 605.9178*x^4 - 4.13053*x^5 +
0.02008226*x^6 - 6.963636e-05*x^7 + 1.687736e-07*x^8
I can then simply
plot(d,e)
But when I try to use the lines function to superimpose the function on the plot, I get confused. The help file states that the output of poly.calc is an object of class polynomial, and so I assume that "egg1996" will be the "x" in:
lines(x, len = 100, xlim = NULL, ylim = NULL, ...)
But I cannot seem to, based on the example listed:
lines (poly.calc( 2:4), lty = 2)
Or based on the arguments:
x an object of class "polynomial".
len size of vector at which evaluations are to be made.
xlim, ylim the range of x and y values with sensible defaults
Come up with a command that successfully graphs the polynomial "egg1996" onto the raw data.
I understand that this question is beneath you folks, but I would be very grateful for a little help. Many thanks.
I don't work with the polynom package, but the resultant data set is on a completely different scale (both X & Y axes) than the first plot() call. If you don't mind having it in two separate panels, this provides both plots for comparison:
library(polynom)
d <- c(169,176,183,190,197,204,211,218,225,232,239,246)
e <- c(0,0,0.006839425,0.027323127,0.024666883,0.005603878,
0.016599262,0.002810977,0.005603878,0,0.002810977,0.002810977)
egg1996 <- poly.calc(d,e)
par(mfrow=c(1,2))
plot(d, e)
plot(egg1996)

R, graph of binomial distribution

I have to write own function to draw the density function of binomial distribution and hence draw
appropriate graph when n = 20 and p = 0.1,0.2,...,0.9. Also i need to comments on the graphs.
I tried this ;
graph <- function(n,p){
x <- dbinom(0:n,size=n,prob=p)
return(barplot(x,names.arg=0:n))
}
graph(20,0.1)
graph(20,0.2)
graph(20,0.3)
graph(20,0.4)
graph(20,0.5)
graph(20,0.6)
graph(20,0.7)
graph(20,0.8)
graph(20,0.9)
#OR
graph(20,scan())
My first question : is there any way so that i don't need to write down the line graph(20,p) several times except using scan()?
My second question :
I want to see the graph in one device or want to hit ENTER to see the next graph. I wrote
par(mfcol=c(2,5))
graph(20,0.1)
graph(20,0.2)
graph(20,0.3)
graph(20,0.4)
graph(20,0.5)
graph(20,0.6)
graph(20,0.7)
graph(20,0.8)
graph(20,0.9)
but the graph is too tiny. How can i present the graphs nicely with giving head line n=20 and p=the value which i used to draw the graph?[though it can be done by writing mtext() after calling the function graphbut doing so i have to write a similar line few times. So i want to do this including in function graph. ]
My last question :
About comment. The graphs are showing that as the probability of success ,p is increasing the graph is tending to right, that is , the graph is right skewed.
Is there any way to comment on the graph using program?
Here a job of mapply since you loop over 2 variables.
graph <- function(n,p){
x <- dbinom(0:n,size=n,prob=p)
barplot(x,names.arg=0:n,
main=sprintf(paste('bin. dist. ',n,p,sep=':')))
}
par(mfcol=c(2,5))
mapply(graph,20,seq(0.1,1,0.1))
Plotting base graphics is one of the times you often want to use a for loop. The reason is because most of the plotting functions return an object invisibly, but you're not interested in these; all you want is the side-effect of plotting. A loop ignores the returned obects, whereas the *apply family will waste effort collecting and returning them.
par(mfrow=c(2, 5))
for(p in seq(0.1, 1, len=10))
{
x <- dbinom(0:20, size=20, p=p)
barplot(x, names.arg=0:20, space=0)
}

Resources