Package: ultibi
the ultimate data analytics toolfor no code visualisation and collaborative exploration.Present easier.   Dig deeper.   Review together.The Ultimate BI toolWithUltibiyou can turn yourDataFrameinto a pivot table with a UI and share it across organisation. You can also define measures applicable to yourDataFrame.  This means your colleagues/consumers don't have to write any code to analyse the data.Ultibi leverages on the giants:Actix,Polarsand Rust which make this possible. We use TypeScript for the frontend.ExamplesOuruserguidePythonpip install ultibiQuickstartimportultibiasulimportpolarsasplimportosos.environ["RUST_LOG"]="info"# enable logsos.environ["ADDRESS"]="0.0.0.0:8000"# host on this address# Read Data# for more details: https://pola-rs.github.io/polars/py-polars/html/reference/api/polars.read_csv.htmldf=pl.read_csv("titanic.csv")# Convert it into an Ultibi DataSetds=ul.DataSet.from_frame(df)# By default (might change in the future)# Fields are Utf8 (non numerics) and integers# Measures are numeric columns.ds.ui()Then navigate tohttp://localhost:8000or checkouthttp://localhost:8000/swagger-uifor the OpenAPI documentation.More flexible - custom measuresimportultibiasulimportpolarsasplimportosos.environ["RUST_LOG"]="info"# enable logsos.environ["ADDRESS"]="0.0.0.0:8000"# host on this address# Read Data# for more details: https://pola-rs.github.io/polars/py-polars/html/reference/api/polars.read_csv.htmldf=pl.read_csv("titanic.csv")# Let's add some Custom/Bespoke Calculations to our UI# Standard Calculatordefsurvival_mean_age(kwargs:dict[str,str])->pl.Expr:"""Mean Age of Survivalspl.col("survived") is 0 or 1pl.col("age") * pl.col("survived") - age of survived person, otherwise 0pl.col("survived").sum() - number of survived"""returnpl.col("age")*pl.col("survived")/pl.col("survived").sum()# Also a Standard Calculatordefexample_dep_calc(kwargs:dict[str,str])->pl.Expr:returnpl.col("SurvivalMeanAge_sum")+pl.col("SouthamptonFareDivAge_sum")# When we need more involved calculations we go for a Custom Calculatordefcustom_calculator(srs:list[pl.Series],kwargs:dict[str,str])->pl.Series:"""Southampton Fare/Age*multiplier"""df=pl.DataFrame({"age":srs[0],"fare":srs[1],"e":srs[2]})# Add Indicator Column for Southamptondf=df.with_columns(pl.when(pl.col("e")=="S").then(1).otherwise(0).alias("S"))multiplier=float(kwargs.get("multiplier",1))res=df["S"]*df["fare"]/df["age"]*multiplierreturnres# inputs for the custom_calculator srs paraminputs=["age","fare","embarked"]# We return Floatsres_type=pl.Float64# We return a Series, not a scalar (which otherwise would be auto exploded)returns_scalar=Falsemeasures=[ul.BaseMeasure("SouthamptonFareDivAge",ul.CustomCalculator(custom_calculator,res_type,inputs,returns_scalar),# (Optional) - we are only interested in Southampton, so# unless other measures requested we might as well filter for Southampton only# However, if if multiple measures requested, their precompute_filters will be joined as OR.[[ul.EqFilter("embarked","S")]],# PARAMS tab of the UIcalc_params=[ul.CalcParam("mltplr","1","float")]),ul.BaseMeasure("SurvivalMeanAge",ul.StandardCalculator(survival_mean_age),aggregation_restriction="sum",),ul.DependantMeasure("A_Dependant_Measure",ul.StandardCalculator(example_dep_calc),[("SurvivalMeanAge","sum"),("SouthamptonFareDivAge","sum")],),]# Convert it into an Ultibi DataSetds=ul.DataSet.from_frame(df,bespoke_measures=measures)# By default (might change in the future)# Fields are Utf8 (non numerics) and integers# Measures are numeric columns.ds.ui()You can also wite Rust native Custom calculators measure which wouldn't be bounded by GIL! Checkout theuserguide.DataSources - In and OutOf memoryWe provide aim to support different sources of the data.scan=pl.read_csv("../frtb_engine/data/frtb/Delta.csv",dtypes={"SensitivitySpot":pl.Float64})dsource=ul.DataSource.inmemory(scan)ds=ul.DataSet.from_source(dsource)ds.prepare()# .prepare() is only relevant to FRTB dataset currentlyds.ui()If you don't want to/can't hold all your data in the process memory, you can sacrifise performance for memory with Scan/DataBaseimportpolarsasplimportultibiasul# Note that the LazyFrame query must start with scan_# and must've NOT been collectedscan=pl.scan_csv("../frtb_engine/data/frtb/Delta.csv",dtypes={"SensitivitySpot":pl.Float64})dsource=ul.DataSource.scan(scan)ds=ul.DataSet.from_source(dsource)ds.ui()Note: Naturally the later two options will be slower, because prior to computing your measures we will need to read the relevant bits of the data into the process memory.FRTB SAFRTB SAis a great usecase forultibi. FRTB SA is a set of standardised, computationally intensive rules established by the regulator. High business impact of these rules manifests in need foranalysisandvisibilitythoroughout an organisation. Note: Ultima is not a certified aggregator. Always benchmark the results against your own interpretation of the rules.
See python frtbuserguide.Polars CompatibilityUltibiPolars0.518.70.619.18LicenseLicensor:             Ultibi Ltd.
Licensed Work:        Ultima
The Licensed Work is (c) 2023 Ultibi Ltd.ultibipython library is made available for the purpose of demonstrating the possibilities offered by the Software so users can evaluate the possibilities and potential of the Software. You can choose one of the following:GNU GPL v3Proprietary License. Allows you to use the software in whichever way you want. Theselicensesare extremely affordable, and you can check out the options by reaching out to us directly, viaanatoly at ultimabi dot uk, or by visitingultimabi dot ukNo LiabilityAs far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.ContributionsAll code in this Repository is a property of the Licensor. If you make a contribution via PR or any other way, you give the Licensor a right to use your code in whatever way they deem necessary, including copying or refactoring it to a private repository, provided that a copy of your work will remain available under the current conditions.