Selecting a range of density plot in vega altair - streamlit

I'm trying to display the sum of my selection within a density plot in Vega-Altair and display it on my Streamlit page.
The transform_density() works just fine and my plot is being printed just fine, however the selection just does something unexpected.
probability_selection = alt.selection(type='interval', encodings=['x'])
kernel_density_chart = alt.Chart(df_display_reached_points_name).transform_density(
'reachedPoints',
as_=['reachedPoints', 'density'],
#bandwidth=1
).mark_area().encode(
alt.X("reachedPoints:Q"),
y='density:Q',
).properties(
width=900
).add_selection(probability_selection)
text = alt.Chart(df_display_reached_points_name).transform_filter(probability_selection).transform_density(
'reachedPoints',
as_=['reachedPoints', 'density'],
).mark_text(
align='left',
baseline='top',
).encode(
x=alt.value(5),
y=alt.value(5),
text=alt.Text('sum(density):Q'),
)
st.altair_chart(kernel_density_chart + text, use_container_width=False)
While making no selection, this imagine shows a value.
What I expected my text to display is a value of 1 when all of the data of my plot is selected. Also making a selection doesn't return the values I expect them to. For example small selections end up with a really high value, while big selections return low values.

Related

Plot not showing in Julia

I have a file named mycode.jl with following code taken from here.
using MultivariateStats, RDatasets, Plots
# load iris dataset
println("loading iris dataset:")
iris = dataset("datasets", "iris")
println(iris)
println("loaded; splitting dataset: ")
# split half to training set
Xtr = Matrix(iris[1:2:end,1:4])'
Xtr_labels = Vector(iris[1:2:end,5])
# split other half to testing set
Xte = Matrix(iris[2:2:end,1:4])'
Xte_labels = Vector(iris[2:2:end,5])
print("split; Performing PCA: ")
# Suppose Xtr and Xte are training and testing data matrix, with each observation in a column. We train a PCA model, allowing up to 3 dimensions:
M = fit(PCA, Xtr; maxoutdim=3)
println(M)
# Then, apply PCA model to the testing set
Yte = predict(M, Xte)
println(Yte)
# And, reconstruct testing observations (approximately) to the original space
Xr = reconstruct(M, Yte)
println(Xr)
# Now, we group results by testing set labels for color coding and visualize first 3 principal components in 3D plot
println("Plotting fn:")
setosa = Yte[:,Xte_labels.=="setosa"]
versicolor = Yte[:,Xte_labels.=="versicolor"]
virginica = Yte[:,Xte_labels.=="virginica"]
p = scatter(setosa[1,:],setosa[2,:],setosa[3,:],marker=:circle,linewidth=0)
scatter!(versicolor[1,:],versicolor[2,:],versicolor[3,:],marker=:circle,linewidth=0)
scatter!(virginica[1,:],virginica[2,:],virginica[3,:],marker=:circle,linewidth=0)
plot!(p,xlabel="PC1",ylabel="PC2",zlabel="PC3")
println("Reached end of program.")
I run above code with command on Linux terminal: julia mycode.jl
The code runs all right and reaches the end but the plot does not appear.
Where is the problem and how can it be solved.
As the Output section of the Plots docs says:
A Plot is only displayed when returned (a semicolon will suppress the return), or if explicitly displayed with display(plt), gui(), or by adding show = true to your plot command.
You can have MATLAB-like interactive behavior by setting the default value: default(show = true)
The first part about "when returned" is about when you call plot from the REPL (or Jupyter, etc.), and doesn't apply here.
Here, you can use one of the other options:
calling display(p) after the last plot! call (this is the most common way to do it)
calling gui() after the last plot!
adding a show = true argument to the last plot! call
setting the default to always show the plot by setting Plots.default(show = true) at the beginning of the script
Any one of these is sufficient to make the plot window appear.
The plot closes when the Julia process ends, if that's happening too soon, you can either:
Run your code as julia -i mycode.jl at the terminal - this will run your code, display the plot, and then land you at the Julia REPL. This will both keep the plot open, and let you work with the variables in your code further if you need to.
add a readline() call at the end of your program. This will keep Julia waiting for an extra press of newline/Enter/Return key, and the plot will remain in display until you press that.
(Credit to ffevotte on Julia Discourse for these suggestions.)

How to display a table and its plot side by side with an adjusted height

I’m trying to display a table and its plot side by side in a page.
The goal is that the plot’s height matches with the table’s one !
I tried with st.container and st.columns combined but it does not work (see image below).
import streamlit as st
import plotly.express as px
long_df = px.data.medals_long()
fig = px.bar(long_df, x="nation", y="count",
color="medal", title="Long-Form Input")
data_container = st.container()
with data_container:
table, plot = st.columns(2)
with table:
st.table(long_df)
with plot:
st.plotly_chart(fig, use_container_width=True)
>>> Output (in the web browser):
As you can see, the plot is much longer than the table.
Do you know how to fix this, please ?
Important detail : I'm using different tables, so the number of rows is changing constantly.
Unfortunately, neither st.columns() nor st.container has a height parameter. You can achieve this using the height parameters of the plotly figure and st.dataframe(). When we define height for the dataframe, the user can scroll down to see whole table.
height = 400 # px
fig = px.bar(
long_df, x="nation", y="count",
color="medal", title="Long-Form Input",
height=height,
)
# update margin to show title on top
fig.update_layout(margin={"t": 30, "b": 0})
data_container = st.container()
with data_container:
table, plot = st.columns(2)
with table:
# use st.dataframe instead of st.table
st.dataframe(long_df, height=height)
with plot:
st.plotly_chart(fig, use_container_width=True)
Another way of visualising data along with the table is to use st.tabs().
tab1, tab2 = st.tabs(["Data", "Chart"])
with tab1:
st.table(long_df)
with tab2:
st.plotly_chart(fig, use_container_width=True)

xticks' labels formatting in Julia Plots

Assume my Julia code is
using Plots
t = -π:1e-4:π
y = sin.(t)
plot(t,y,lw=3,legend=false)
plot!(xticks=([-π/2],["(-\\pi)/2"]))
where I want to show the parenthesis in the numerator of xticks' label while keeping its "rational" form, i.e., I don't want the numerator and the denominator to be inline. The output of the above code looks like this
One may see that the xticks' label does not include the desired parenthesis.
Here is another code to show the above function:
using Plots
t = -π:1e-4:π
y = sin.(t)
plot(t,y,lw=3,color=2,legend=false)
plot!(xticks=([-π/2],["(-π)/2"]))
which as it can be seen, the only difference with the former is in the xticks' label (in the former it is \\pi while in the latter it is π).
Now the picture looks like this:
which does not show the label in the "rational" form, i.e., both numerator and the denominator are inline which is undesired. Is there any way to overcome this issue?
Try using LaTeXStrings:
using Plots
using LaTeXStrings
gr()
t = -π:1e-4:π
y = sin.(t)
plot(t,y,lw=3,legend=false)
plot!(xticks=([-π/2],[L"\frac{(-\pi)}{2}"]))

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.

Fix layout of plot(fevd()) function

I am trying to plot FEVD (forecast error variance decomposition) for my VAR analysis. As you can see on the image, the legend screws up the graph and information. as this is an automatically created legend, I don’t know how to reposition it. I do not know much yet about plotting in R.
The only code i use to get this is :
library(vars)
var <- VAR(varTable2 , p=4 , type = "both")
plot(fevd(var, n.ahead = 10 ))
Thanks in advance
Legends do not resize well in R. You have to set your plotting window first and then chart your data.
Here's how to do it in Windows. win.graph opens a blank plotting window of the specified width. In Unix/Linux, you should look at X11() and in Mac, at quartz(). You might also consider shorter variable names.
library(vars)
data(Canada)
colnames(Canada) <-c("Long column name1","Long column name2","Long column name3","Long column name4")
var <- VAR(Canada , p=4 , type = "both")
win.graph(width=13,height=8)
plot(fevd(var, n.ahead = 10 ))

Resources