diff --git a/.gitignore b/.gitignore index 83a655b..2804844 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,6 @@ venv/ # packaging/build artifacts *.egg-info/ build/ -dist/ \ No newline at end of file +dist/ +/.quarto/ +**/*.quarto_ipynb diff --git a/README.md b/README.md index d3d3594..d3278c0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ # `Py4Stats` - `Py4Stats` は、主に実証研究で用いられる、探索的データ分析および回帰結果レポート用のユーティリティライブラリで、回帰分析を中心とする分析でよく使われるR言語の機能を、Python で実装しています。本ライブラリの主な機能は [**Get started**](./INTRODUCTION.md) を、実装されている関数の一覧は [**Function reference**](./reference.md) を参照してください。 +`Py4Stats` は、主に実証研究で用いられる、探索的データ分析および回帰結果レポート用のユーティリティライブラリです。回帰分析を中心とする分析でよく使われるR言語の機能を Python で実装しています。 + +## 📚 Documentation + +Explore the full documentation (Quarto Book) at: + +- [🏠 **Full Docs**](https://hirototensho.github.io/Py4Stats/) +- [🚀 **Get Started**](https://hirototensho.github.io/Py4Stats/introduction.html) +- [📖 **API Reference**](https://hirototensho.github.io/Py4Stats/reference.html) ## Installation @@ -22,7 +30,7 @@ import py4stats as py4st ``` -[`py4stats.diagnose()`](man/diagnose.md) 関数はデータの全般的な状態についての要約を提供します。 +[`py4stats.diagnose()`](docs/docs/man/diagnose.html) 関数はデータの全般的な状態についての要約を提供します。 ``` python import pandas as pd @@ -41,7 +49,7 @@ print(py4st.diagnose(penguins).round(4)) #> 7 year int64 0 0.0000 3 0.8721 ``` -[`py4stats.compare_ols()`](man/compare_ols.md) 関数は、計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。 +[`py4stats.compare_ols()`](docs/docs/man/compare_ols.html) 関数は、計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。 ``` python @@ -75,9 +83,10 @@ compare_tab1 | df | 3 | 4 | 5 | -詳細は、[`py4stats.compare_ols()`](man//compare_ols.md) を参照してください。  +詳細は、[`py4stats.compare_ols()`](docs/docs/man/compare_ols.html) を参照してください。  *** -[Jump to **Function Get started**.](./INTRODUCTION.md) -[Jump to **Function reference**.](./reference.md) +[Jump to **Full Docs**.](https://hirototensho.github.io/Py4Stats/) +[Jump to **Get started**.](https://hirototensho.github.io/Py4Stats/introduction.html) +[Jump to **Function reference**.](https://hirototensho.github.io/Py4Stats/reference.html) diff --git a/_quarto.yml b/_quarto.yml new file mode 100644 index 0000000..677a0bb --- /dev/null +++ b/_quarto.yml @@ -0,0 +1,75 @@ +project: + type: book + output-dir: docs +book: + title: "Py4Stats" + chapters: + - index.qmd + - introduction.qmd + - reference.qmd + - part: "**EDA**" + chapters: + - man/diagnose.qmd + - man/tabyl.qmd + - man/freq_table.qmd + - man/Pareto_plot.qmd + - man/plot_category.qmd + - man/diagnose_category.qmd + - man/point_range.qmd + - man/remove_empty_constant.qmd + - man/filtering_out.qmd + - man/relocate.qmd + - man/compare_df_cols.qmd + - man/compare_group_stats.qmd + - man/plot_miss_var.qmd + - man/set_miss.qmd + - man/scale_wmean.qmd + - man/predicate_str.qmd + - man/is_dummy.qmd + - man/varidate.qmd + - part: "**Regression**" + chapters: + - man/compare_ols.qmd + - man/compare_mfx.qmd + - man/coefplot.qmd + - man/tidy.qmd + - man/tidy_test.qmd + - man/glance.qmd + - man/Blinder_Oaxaca.qmd + - part: "**heckit_helper**" + chapters: + - man/tidy_heckit.qmd + - man/Heckit_from_formula.qmd + - man/heckitmfx_compute.qmd + - part: "**building_block**" + chapters: + - man/arg_match.qmd + - man/assert_dtype.qmd + - man/is_dtype.qmd + - man/miscellaneous.qmd + - man/style_pvalue.qmd + - man/oxford_comma.qmd + - part: "**Articles**" + chapters: + - articles/release_notes.qmd + - articles/scaling_up_regression.qmd + - articles/narwhals_in_py4stats.qmd + - articles/eda_tools_development_status.qmd + - articles/narwhalsについての考察.qmd + site-url: https://github.com/Hirototensho/Py4Stats + repo-url: https://github.com/Hirototensho/Py4Stats + # repo-branch: main # main に変更したら、こちらを使います。 + repo-branch: experiment/quarto + repo-actions: [source] +format: + html: + theme: cosmo + css: theme.scss + code-link: true + callout-appearance: default # callout については https://quarto.org/docs/authoring/callouts.html を参照 + grid: + sidebar-width: 250px # サイドバー幅の最大値 + body-width: 1000px # メイン本文幅の最大値 + margin-width: 150px # 余白幅の最大値 + +number-sections: false \ No newline at end of file diff --git "a/articles/eda_tools\351\226\213\347\231\272\347\212\266\346\263\201.md" b/articles/eda_tools_development_status.qmd similarity index 97% rename from "articles/eda_tools\351\226\213\347\231\272\347\212\266\346\263\201.md" rename to articles/eda_tools_development_status.qmd index ee32c7e..7b887ac 100644 --- "a/articles/eda_tools\351\226\213\347\231\272\347\212\266\346\263\201.md" +++ b/articles/eda_tools_development_status.qmd @@ -1,7 +1,8 @@ -## eda_toolsの開発状況 -2026年1月22日 +# eda_toolsの開発状況 +2026年1月24日 + +## 関数の実装状況一覧 -**eda_toolsの開発状況** | functions | Input | Pandas | Polars | Pyarrow | 補足 | |:---------------------|:-----------------|:---------|:---------|:----------|:------------------------------------------| | Mean | pd.Series | ✅ | ❌ | ❌ | pd.DataFrame.eval() での使用を想定した関数 | @@ -42,6 +43,8 @@ | tabyl | DataFrame | ✅ | ⭕️ | ⭕️ | 一部の処理が Pandas 依存 | | weighted_mean | Series | ✅ | ✅ | ✅ | | +: 関数の実装状況一覧 {.striped .hover} + ## 凡例 - ✅ 実装済/テスト済 diff --git "a/articles/eda_tools\351\226\213\347\231\272\347\212\266\346\263\201.xlsx" "b/articles/eda_tools\351\226\213\347\231\272\347\212\266\346\263\201.xlsx" new file mode 100644 index 0000000..edb6acc Binary files /dev/null and "b/articles/eda_tools\351\226\213\347\231\272\347\212\266\346\263\201.xlsx" differ diff --git a/articles/narwhals_in_py4stats.md b/articles/narwhals_in_py4stats.qmd similarity index 95% rename from articles/narwhals_in_py4stats.md rename to articles/narwhals_in_py4stats.qmd index 6541bcc..0258885 100644 --- a/articles/narwhals_in_py4stats.md +++ b/articles/narwhals_in_py4stats.qmd @@ -20,11 +20,11 @@ 本ライブラリの動作確認は、基本的に `pandas.DataFrame` を用いて実施しています。そのため、`polars` や `pyarrow` を使用した場合には、バックエンド固有の仕様差や未検証の挙動により、一部の関数でエラーが発生する可能性があります。そのような挙動が確認された場合は、**Issue 等での報告を歓迎**します。 - また、バックエンド別の実装状況については [eda_tools開発状況](eda_tools開発状況.md) も参照して下さい。 + また、バックエンド別の実装状況については [eda_tools開発状況](eda_tools_development_status.qmd) も参照して下さい。 ## narwhals を用いた関数の返り値の型について -`py4stats.eda_tools` モジュールの関数のうち、[`py4stats.diagnose()`](../man/diagnose.md) など、第一引数にデータフレームを取る関数の返り値の型は、`to_native` 引数の値によって変化します。
+`py4stats.eda_tools` モジュールの関数のうち、[`py4stats.diagnose()`](../man/diagnose.qmd) など、第一引数にデータフレームを取る関数の返り値の型は、`to_native` 引数の値によって変化します。
 初期設定である `to_nativ = True` の場合には、第一引数に入力されたデータフレームと同じ型のデータフレームが出力され、`to_nativ = False` の場合には `narwhals.DataFrame` 型のデータフレームが出力されます。`to_nativ = False` のオプションは、主にライブラリ内部での利用や、データフレームのバックエンドに依存しない後続処理を行いたい場合を想定したオプションです。 ``` python diff --git "a/articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.md" "b/articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.qmd" similarity index 93% rename from "articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.md" rename to "articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.qmd" index c90165d..55838f8 100644 --- "a/articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.md" +++ "b/articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.qmd" @@ -10,7 +10,7 @@ Pandas の場合、2つのデータフレーム `df1` と `df2` が共通の col Pandas の場合、`df.loc[i, j] = x` という形でデータフレーム `df` の i, j 要素に値 `x` を代入することができますが、narwhals ではこれに相当する演算 `df[i, j] = x` は禁止されています。 -異なるデータフレーム間の二項演算に制約があること、そしてデータフレームへの値の代入が難しいことから、[`tabyl()`](../man/tabyl.md) 関数では、集計後の作表処理の一部を Pandas に依存しています。 +異なるデータフレーム間の二項演算に制約があること、そしてデータフレームへの値の代入が難しいことから、[`tabyl()`](../man/tabyl.qmd) 関数では、集計後の作表処理の一部を Pandas に依存しています。 ### 任意の関数でグループ別集計を行う @@ -28,8 +28,8 @@ data_nw.group_by(nw.col(group)).agg(nw.col('x').my_func()) data_nw.group_by(nw.col(group)).agg(my_func(nw.col('x'))) ```` -例えば Py4Stats では、[`Pareto_plot()`](../man/Pareto_plot.md) 関数の内部実装に使用している [`make_rank_table()`](../py4stats/eda_tools/_nw.py) 関数において、任意の `aggfunc()` 関数をグループ別集計に使うために、サブセッティングを使って `group_by()` メソッドの使用を回避するという変則的(かつ、おそらく非効率な)な実装を行なっています。 - +例えば Py4Stats では、[`Pareto_plot()`](../man/Pareto_plot.qmd) 関数の内部実装に使用している [`make_rank_table()`](../py4stats/eda_tools/_nw.py) 関数において、任意の関数をグループ別集計に使うために、サブセッティングを使って `group_by()` メソッドの使用を回避するという変則的(かつ、おそらく非効率 )な実装を行なっています。 + ``` python stat_values = [ aggfunc( @@ -63,8 +63,8 @@ result = data_nw.to_native() # -> pd.DataFrame が出力される ```python data_nw = nw.from_native(input_pd) # ここで backend が記録される data_nw2 = nw.from_native(data_nw.to_polars()) # ここで backend が上書きされる -data_nw2.implementation # -> polars -result = data_nw2.to_native() # -> pl.DataFrame が出力される +data_nw2.implementation # -> polars +result = data_nw2.to_native() # -> pl.DataFrame が出力される ``` 従って、`result` が `input_pd` と同じ型をもつことを保証するには、`data_nw` を nw.DataFrame クラスのまま維持する(≒ narwhals ベースのメソッドだけで処理を書く)必要があり、これが narwhals ベースの実装としてのあるべき姿だと思われます。 diff --git a/articles/release_notes.qmd b/articles/release_notes.qmd new file mode 100644 index 0000000..2240075 --- /dev/null +++ b/articles/release_notes.qmd @@ -0,0 +1,95 @@ +# Release Notes + +## Py4Stats v0.3.0 2026-01-23 + +### 概要(Summary) + +このリリースでは Pyt4Stats に幾つかの関数の追加を行いました。 +関数のリファクタリングとバグ修正を行いました。今回のリリースでは機能の追加や変更はありません。 + +### ✨ 主な新機能 (New Features) + +- [`diagnose_category()`](../man/diagnose_category.qmd) 関数の追加 + - データフレームのカテゴリー変数の要約を提供する関数です。 +- [`set_miss()`](../man/set_miss.qmd) 関数の追加 + - Series の非欠測要素のうち、指定された個数または割合を欠測値に置き換えます。 + +### 🛠 修正と改善(Fixes /Improvements) + +- [`compare_group_means(), compare_group_median()`](../man/compare_group_stats.qmd), [`compare_df_cols(), compare_df_stats()`](../man/compare_df_cols.qmd): コードをリファクタリングし、引数と同じクラスのデータフレームを出力できるようにしました。この変更により、返り値が `pd.DataFrame` である場合でも、index が自動では設定されなくなりました。 + + + +- [`diagnose()`](../man/diagnose.qmd): dtype 列が、polars や pyarrow における列のクラスの表記に対してより忠実になるように修正しました。 +- [`relocate()`](../man/relocate.qmd) 関数に、指定した列を最後列に配置する機能を追加し、エラーメッセージを改善しました。 +- [`assert_character()`](../man/assert_dtype.qmd) および [`assert_numeric()`](../man/assert_dtype.qmd) 系関数のエラーメッセージを改善しました。 +- その他、いくつかの関数のエラーメッセージを改善しました。 + +## Py4Stats v0.2.2 2026-01-19 + +### 概要(Summary) + +型ヒントに関する若干の修正と、バグ修正を行いました。今回のリリースでは機能の追加や変更はありません。 + +### 🛠 修正と改善(Fixes /Improvements) + +- [`building_block.assert_numeric`](../man/assert_dtype.qmd) 系関数のリファクタリングを行いました。この変更でメインモジュールの関数の動作に変更はありません。 +- [`compare_group_means()`, `compare_group_median()`](../man/compare_group_stats.qmd) のテストコードを実装しました。 +- [`tabyl()`](../man/tabyl.qmd): 第一引数 `data` と同じオブジェクト型をもつ DataFrame を出力できるように実装を修正しました。 +- [`check_that(), check_viorate()`](../man/varidate.qmd) : 第一引数 `data` と同じオブジェクト型をもつ DataFrame を出力できるように実装を修正しました。引き続きロジックのコア部分には `pd.DataFrame.eval()` を使用しており、使用方法に大きな変更はありません。 +- [`is_number()`](../man/predicate_str.qmd) 関数を修正し、pyarrow.lib.ChunkedArray オブジェクトを代入すると生じるエラーを解消しました。 + +## Py4Stats v0.2.1 2026-01-16 + +### 概要(Summary) + +このリリースでは Pyt4Stats の各モジュールに幾つかの関数の追加を行いました。 + +### ✨ 主な新機能 (New Features) + +- [`plot_category()`](../man/plot_category.qmd) 関数の追加 + - カテゴリ変数の回答分布を 100% 積み上げ横棒グラフとして描画する関数です。 +- [`plot_miss_var()`](../man/plot_miss_var.qmd) 関数の追加 + - データフレームの各変数について欠測値の量を横棒グラフとして可視化します。 +- [`relocate()`](../man/relocate.qmd) 関数の追加 + - データフレームの列を、削除することなく並べ替えます。 +- [`weighted_mean()`, `scale()`, `min_max()`](../man/scale_wmean.qmd) 関数の追加 + - それぞれ Series オブジェクトの加重平均の計算と、標準化を行う関数です。 + +### 🛠 修正と改善(Fixes /Improvements) + +- `eda_tools` の Pandas ベース実装 `eda_tools/_pands.py` に、`FutureWarning` を実装しました。 +- ユーザビリティ向上のため、[`freq_table()`](../man/freq_table.qmd) 関数に `sort_by` 引数を導入しました。 + - `sort_by = 'frequency'` なら度数分布表を頻度に応じてソートし(従来の `sort = True` に相当)、`sort_by = 'values'` なら `subset` で指定した列の値に応じてソートします(従来の `sort = False` に相当)。 + - この変更に合わせて、`sort` 引数は非推奨扱いに変更されています。 +- [`Pareto_plot()`](../man/Pareto_plot.qmd) の `aggfunc` 引数に、`np.mean` など `values` 列を1次元配列として受け取って単一の数値を返す任意の関数を使用できるように改良を行いました。 +- その他、`py4stats` ライブラリ全体のエラーメッセージ改善 +- [`building_block.assert_*`](../man/assert_dtype.qmd) 系関数の改良を行い、与えられた引数の要素数に関するアサーションと、None やリストを拒否する機能を追加しました。 +- [`cmpare_ols()`](../man/compare_ols.qmd) および [`cmpare_mfx()`](../man/compare_mfx.qmd) に stars 引数を追加し、有意性のアスタリスクの表示形式を変更できる機能を追加しました。また、その他エラーメッセージの改善を行なっています。 + +### ⚠️ 既知の制限・注意点(Notes) + +- `pyarrow.Table` を使用する場合、[`plot_category()`](../man/plot_category.qmd) 関数の一部機能が制限されます。 + +## Py4Stats v0.1.0 2026-01-11 + +### 概要(Summary) + +このリリースでは EDA モジュールの narwhals ベース実装を統合し、パフォーマンスと互換性を大幅に改善しました。いくつかの既知の挙動も修正されています。 + +### ✨ 主な新機能 (New Features) + +- `py4stats.eda_tools` が Pandas ベースの実装から narwhals ベース実装へ移行しました。 + - この変更により、複数バックエンド(pandas / polars / pyarrow)をサポートしました。 +- Pandas ベースの実装は、当面 `py4stats` ライブラリのサブモジュール `eda_tools._pandas` として維持されますが、将来的に廃止される予定です。 + +### 🛠 修正と改善(Fixes /Improvements) + +- `bilding_block` モジュールの名称を `building_block` に修正 +- `Py4Stats.building_block` モジュールの [`assert_*` 系関数](../man/assert_dtype.qmd)の出力を `AssertionError` から `ValueError` に変更しました。 +- `Py4Stats.eda_tools` モジュールの関数の bool 値の引数を中心に、型の不一致があった場合のエラーメッセージを改善しました。 + +### ⚠️ 既知の制限・注意点(Notes) + +- バックエンドの変更に伴い、[`py4st.freq_table()`](../man/freq_table.qmd)、[`py4st.diagnose()`](../man/diagnose.qmd)、[`py4st.tabyl()`](../man/tabyl.qmd) など、従来はインデックス(Index)付きの `pandas.DataFrame` データフレームが出力されていた関数で、インデックスのない `pandas.DataFrame` が出力されるように変更されました。 +- polars / pyarrow のサポートは experimental であり、一部のエッジケースで動作に違いが出る可能性があります。詳細は [Technical Notes](./narwhals_in_py4stats.qmd) および [eda_tools開発状況](./eda_tools_development_status.qmd) を参照してください。 diff --git a/articles/scaling_up_regression.md b/articles/scaling_up_regression.qmd similarity index 95% rename from articles/scaling_up_regression.md rename to articles/scaling_up_regression.qmd index 4115b61..08e1263 100644 --- a/articles/scaling_up_regression.md +++ b/articles/scaling_up_regression.qmd @@ -58,6 +58,7 @@ py4st.compare_ols(list_models = list_fitted1) # 表の作成 | nobs | 342 | 342 | 333 | | df | 3 | 4 | 5 | + この方法であれば、試したい回帰式のパターンが増えた場合でも、`list_fml` の要素を追加するだけで済むため、実行部分を変更する必要がありません。  また、回帰係数を視覚的に比較するには次のようなコードを使うと良いでしょう。 @@ -72,8 +73,7 @@ for k, mod in enumerate(list_fitted1): ax[k].set_title(f'model {k + 1}') ax[k].set_xlabel(f'coefficient (n = {mod.nobs:,.0f})') ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/c3971702-b97a-4679-ae9a-f5787b1443cb) - +![scaling_up_regression1](image/scaling_up_regression1.png) ## グループ別の回帰分析  次に、データセットのグループ別に回帰分析を行う場合を考えます。この場合、データを受け取ると回帰分析の結果を返す関数 `group_ols` を定義し、回帰式は固定しておきます。 @@ -95,7 +95,7 @@ penguins2 = penguins.groupby('species') list_fitted2 = penguins2.apply(group_ols).to_list() ``` -[`py4st.compare_ols()`](https://github.com/Hirototensho/Py4Stats/blob/main/man/compare_ols.md) で分析結果を比較できます。 +ここまでの準備ができれば、後は [`py4st.compare_ols()`](../man/compare_ols.qmd) で分析結果を比較できます。 ``` python list_groups = list(penguins2.groups.keys()) @@ -130,7 +130,7 @@ for k, mod in enumerate(list_fitted2): ax[k].set_title(list_groups[k]) ax[k].set_xlabel(f'coefficient (n = {mod.nobs:,.0f})') ``` -![Unknown-1](https://github.com/Hirototensho/Py4Stats/assets/55335752/abb362d3-f0f7-42d0-9dd5-8379e5c05b55) +![scaling_up_regression2](image/scaling_up_regression2.png) ## ブートストラップ回帰 @@ -196,7 +196,7 @@ pt.RainCloud( ax.axvline(0, ls = "--", color = '#969696'); ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/dd2a0384-4ef9-4a08-898f-fc96cc79a058) +![scaling_up_regression3](image/scaling_up_regression3.png) ### 補足 diff --git "a/articles/\351\226\213\347\231\272\350\250\230\351\214\262.md" "b/articles/\351\226\213\347\231\272\350\250\230\351\214\262.qmd" similarity index 100% rename from "articles/\351\226\213\347\231\272\350\250\230\351\214\262.md" rename to "articles/\351\226\213\347\231\272\350\250\230\351\214\262.qmd" diff --git a/docs/articles/eda_tools_development_status.html b/docs/articles/eda_tools_development_status.html new file mode 100644 index 0000000..c04efd0 --- /dev/null +++ b/docs/articles/eda_tools_development_status.html @@ -0,0 +1,1170 @@ + + + + + + + + + +eda_toolsの開発状況 – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

eda_toolsの開発状況

+
+ + + +
+ + + + +
+ + + +
+ + +

2026年1月24日

+
+

関数の実装状況一覧

+ + ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
関数の実装状況一覧
functionsInputPandasPolarsPyarrow補足
Meanpd.Seriespd.DataFrame.eval() での使用を想定した関数
Medianpd.Seriespd.DataFrame.eval() での使用を想定した関数
Maxpd.Seriespd.DataFrame.eval() での使用を想定した関数
Minpd.Seriespd.DataFrame.eval() での使用を想定した関数
Pareto_plotDataFrame
Sumpd.Seriespd.DataFrame.eval() での使用を想定した関数
check_thatDataFrame⭕️⭕️実装に pd.DataFrame.eval() を使用
check_viorateDataFrame⭕️⭕️実装に pd.DataFrame.eval() を使用
compare_df_colsDataFrame
compare_df_recordDataFrame
compare_df_statsDataFrame
compare_group_meansDataFrame
compare_group_medianDataFrame
crosstabDataFrame⭕️Pyarrow は Polars 依存の実装
diagnoseDataFrame
diagnose_categoryDataFrame
filtering_outDataFrame
freq_tableDataFrame
implies_experpd.Seriespd.DataFrame.eval() での使用を想定した関数
is_dummyDataFrame/Series
is_numberSeries
is_ymd_likeSeries
is_ymdSeries
mean_ciDataFrame/Series
mean_qiDataFrame/Series
median_qiDataFrame/Series
min_maxSeries
plot_mean_diffDataFrame
plot_median_diffDataFrame
plot_miss_varDataFrame
scaleSeries
set_missSeries
relocateDataFrame
remove_constantDataFrame
remove_emptyDataFrame
tabylDataFrame⭕️⭕️一部の処理が Pandas 依存
weighted_meanSeries
+
+
+

凡例

+
    +
  • ✅ 実装済/テスト済
  • +
  • ⭕️ 実装済/テスト済(異なるバックエンドに依存)
  • +
  • 🔼 実装済/テスト未
  • +
  • ❌ 未実装
  • +
+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/articles/narwhals_in_py4stats.html b/docs/articles/narwhals_in_py4stats.html new file mode 100644 index 0000000..e415b55 --- /dev/null +++ b/docs/articles/narwhals_in_py4stats.html @@ -0,0 +1,948 @@ + + + + + + + + + +Technical Notes: py4stats.eda_tools における narwhals ベースの実装 – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Technical Notes: py4stats.eda_tools における narwhals ベースの実装

+
+ + + +
+ + + + +
+ + + +
+ + +
+

概要

+

py4stats.eda_tools モジュールは、複数の DataFrame バックエンドに対して共通の API を提供することを目的として、narwhals ライブラリを用いて実装されています。

+

本ドキュメントでは、本モジュールの内部実装に関する前提条件や、バックエンドの違いに起因する挙動上の注意点について説明します。

+

通常の利用にあたって本ドキュメントを読む必要はありませんが、実装の詳細や挙動の違いが気になる場合には参考にしてください。

+
+
+

対応している DataFrame バックエンドについて

+

 py4stats.eda_tools モジュールの関数は、第一引数として narwhals.from_native() によって nw.DataFrame 型へ変換可能な DataFrame オブジェクトを受け取ります。

+

具体的には、以下のようなバックエンドを想定しています。

+
    +
  • pandas.DataFrame(主に動作検証を行っているバックエンド)
  • +
  • polars.DataFrame(簡易的な動作確認のみ)
  • +
  • pyarrow.Table(簡易的な動作確認のみ)
  • +
+

本ライブラリの動作確認は、基本的に pandas.DataFrame を用いて実施しています。そのため、polarspyarrow を使用した場合には、バックエンド固有の仕様差や未検証の挙動により、一部の関数でエラーが発生する可能性があります。そのような挙動が確認された場合は、Issue 等での報告を歓迎します。

+

 また、バックエンド別の実装状況については eda_tools開発状況 も参照して下さい。

+
+
+

narwhals を用いた関数の返り値の型について

+

py4stats.eda_tools モジュールの関数のうち、py4stats.diagnose() など、第一引数にデータフレームを取る関数の返り値の型は、to_native 引数の値によって変化します。
 初期設定である to_nativ = True の場合には、第一引数に入力されたデータフレームと同じ型のデータフレームが出力され、to_nativ = False の場合には narwhals.DataFrame 型のデータフレームが出力されます。to_nativ = False のオプションは、主にライブラリ内部での利用や、データフレームのバックエンドに依存しない後続処理を行いたい場合を想定したオプションです。

+
import py4stats as py4st
+import pandas as pd
+import polars as pl
+import pyarrow as pa
+import wooldridge
+mroz_pd = wooldridge.data('mroz')       # pd.DataFrame
+mroz_pl = pl.from_pandas(mroz_pd)       # pl.DataFrame
+mroz_pa = pa.Table.from_pandas(mroz_pd) # pyarrow.lib.Table
+
# to_nativ = True の場合(初期設定): 入力されたデータフレームと同じ型
+
+print(type(py4st.diagnose(mroz_pd, to_native = True)))
+#> <class 'pandas.core.frame.DataFrame'>
+
+print(type(py4st.diagnose(mroz_pl, to_native = True)))
+#> <class 'polars.dataframe.frame.DataFrame'>
+
+print(type(py4st.diagnose(mroz_pa, to_native = True)))
+#> <class 'pyarrow.lib.Table'>
+
# to_nativ = False の場合: narwhals.DataFrame 型
+
+print(type(py4st.diagnose(mroz_pd, to_native = False)))
+#> <class 'narwhals.dataframe.DataFrame'>
+
+print(type(py4st.diagnose(mroz_pl, to_native = False)))
+#> <class 'narwhals.dataframe.DataFrame'>
+
+print(type(py4st.diagnose(mroz_pa, to_native = False)))
+#> <class 'narwhals.dataframe.DataFrame'>
+
+
+

narwhals を用いた実装方針について

+

 内部実装では、関数の冒頭で

+
nw.from_native(data)
+

を用いて入力データを nw.DataFrame に変換し、以降の処理を narwhals の抽象 API 上で行っています。

+

この設計により、DataFrame バックエンドごとの差異を最小限に抑えつつ、将来的な拡張性を確保することを目的としています。

+

一方で、narwhals は各バックエンドの完全な互換性を保証するものではないため、特定の操作や型変換についてはバックエンドごとに挙動が異なる場合があります。

+
+
+

 pandas_flavor を用いた DataFrame メソッド登録について

+

py4stats.eda_tools の関数のうち、単一の DataFrame オブジェクトを引数として受け取る関数については、pandas_flavor.register_dataframe_method を用いて DataFrame メソッドとして登録されています。その結果、以下のような使い方が可能です。

+
df.diagnose()
+

ただし、pandas_flavor は pandas の拡張を前提とした仕組みであるため、このメソッド形式の呼び出しは、pandas.DataFrame を対象としています。  polars.DataFrame や pyarrow ベースのオブジェクトを使用する場合には、関数として直接呼び出す形での利用を推奨します。

+
import py4stats as py4st
+
+py4st.diagnose(df)
+
+
+

今後について

+

 py4stats.eda_tools モジュールは、今後も narwhals ベースの実装を主軸として改良・拡張を行っていく予定です。一方で、従来の pandas ベースの実装については、互換性のために当面は保持される予定ですが、機能追加は行わない予定です。バックエンドごとの挙動差や制限事項については、必要に応じて本ドキュメントを更新していきます。

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git "a/docs/articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.html" "b/docs/articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.html" new file mode 100644 index 0000000..85764dc --- /dev/null +++ "b/docs/articles/narwhals\343\201\253\343\201\244\343\201\204\343\201\246\343\201\256\350\200\203\345\257\237.html" @@ -0,0 +1,1001 @@ + + + + + + + + + +narwhals についての考察 – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

narwhals についての考察

+
+ + + +
+ + + + +
+ + + +
+ + +
+

narwhals での再現が難しい Pandas の機能

+
+

異なるデータフレーム間の二項演算

+

Pandas の場合、2つのデータフレーム df1df2 が共通の columns と index をもつ限り、df3 = df1 + df2 によって二項演算を行うことができ、このとき、columns と index をもつ要素同士が加算されます。しかし、narwhals には Pandas のような index が存在しないため、この計算は再現が困難です。

+
+
+

データフレームへの値の代入

+

Pandas の場合、df.loc[i, j] = x という形でデータフレーム df の i, j 要素に値 x を代入することができますが、narwhals ではこれに相当する演算 df[i, j] = x は禁止されています。

+

異なるデータフレーム間の二項演算に制約があること、そしてデータフレームへの値の代入が難しいことから、tabyl() 関数では、集計後の作表処理の一部を Pandas に依存しています。

+
+
+

任意の関数でグループ別集計を行う

+

自作関数を使ってグループ別集計を行いたい場合、Pandas であれば df.groupby(group)[x].agg(my_func) で行うことができます。同じく narwhals でも

+
data_nw.group_by(nw.col(group)).agg(nw.col('x').mean())
+

という形でグループ別の集計がサポートされているものの、ここで使用できる集計関数は narwhals で実装されているものに限定されるようで、次のような方法で自作関数を使用することはできません。

+
data_nw.group_by(nw.col(group)).agg(nw.col('x').my_func())
+data_nw.group_by(nw.col(group)).agg(my_func(nw.col('x')))
+

例えば Py4Stats では、Pareto_plot() 関数の内部実装に使用している make_rank_table() 関数において、任意の関数をグループ別集計に使うために、サブセッティングを使って group_by() メソッドの使用を回避するという変則的(かつ、おそらく非効率 )な実装を行なっています。

+
stat_values = [
+            aggfunc(
+                data_nw.filter(nw.col(group) == g)[values]
+                .drop_nulls().to_native()
+                ) 
+            for g in group_value
+            ]
+

また、上記の回避策のもう1つの問題として、data_nw.filter(nw.col(group) == g) では、複数の変数に基づくグループ化に対応できないことも挙げられます。make_rank_table() 関数については、Pareto_plot() 関数でパレート図を作図するときに横軸になる group が多変数だと対応できないので、group が1変数(= 引数として1つの文字列だけを受け付ける)とすることで妥協しています。

+

ただ、現時点で narwhals.GroupBy クラスに実装されているメソッドは .agg() しかなく、開発が進めばより柔軟な関数適用が可能になるのではないかと期待しています。

+
+
+
+

narwhals におけるバックエンドとその書き換え

+
+

バックエンドの基本的な理解

+

narwhals におけるバックエンドによる型変換の基本的な理解として(不正確かもしれませんが)、nw.from_native(data) の実行時に data の型に応じて backend が記録され、.to_native() メソッドを呼び出すと、記録された backend に応じて元の型に変換されます。

+

backend の情報は .select() .filter() などのメソッドを使って data_nw を加工しても保持され、これによって入力された input_pd と同じ型のデータフレームを返すことが可能になっています。

+
data_nw = nw.from_native(input_pd) # ここで backend が記録される
+data_nw.implementation       # -> Pandas
+result = data_nw.to_native() # -> pd.DataFrame が出力される
+

一方で、処理の途中で pd.DataFrame や pl.DataFrame などの native オブジェクトを経由した場合、改めて nw.from_native() を使って nw.DataFrame に変換し直したとしても、その時点で backend が上書きされるので、.to_native() メソッドを使用しても引数として入力された input_pd と同じ型に復元される保証はありません。

+
data_nw = nw.from_native(input_pd)              # ここで backend が記録される
+data_nw2 = nw.from_native(data_nw.to_polars())  # ここで backend が上書きされる
+data_nw2.implementation                         # -> polars
+result = data_nw2.to_native()                   # -> pl.DataFrame が出力される
+

従って、resultinput_pd と同じ型をもつことを保証するには、data_nw を nw.DataFrame クラスのまま維持する(≒ narwhals ベースのメソッドだけで処理を書く)必要があり、これが narwhals ベースの実装としてのあるべき姿だと思われます。

+

一方で、一部の処理が特定のバックエンド(e.g. Pandas)に依存している場合にはどうするべきでしょうか。これには次のような2つの選択肢があると考えています。

+
    +
  1. 処理が依存しているバックエンドのオブジェクト(e.g. pd.DataFrame)として出力する〔推奨〕
  2. +
  3. narwhals の仕様を迂回してバックエンドを書き換える〔非推奨ですが次節で考察〕
  4. +
+

これら2つの可能性の間での選択は、技術的な問題であると同時にユーザーとのコミュニケーションの問題です。入力と同型のデータフレームを返す関数の中に pd.DataFrame を返す関数が混ざっていることをユーザーにどう説明するのか。あるいは、narwhals の仕様を迂回をしたことで非効率性やカラムレベルでデータ型(dtype)の一貫性が失われる問題が生じたとして、それをユーザーにどう説明するのか、という問いです。

+
+
+

バックエンドの書き換え (非推奨)

+

いま、some_computation() として実装された処理の一部が Pandas に依存しており、結果が result_pd という pd.DataFrame 型のオブジェクトとして得られているとします。このとき、result_pd をもとのデータフレーム data_pl と同型にする方法の1つとして、result_pdpd.Series.to_dict() などを使って辞書のリスト(list of dict)に変換したのち、nw.from_dicts() を使って data_pl と同じバックエンドをもつ nw.DataFrame に変換するという方法があります。

+

以上の変換の実例を見てみましょう。まずは、data_pl

+
data_pl = pl.from_pandas(load_penguins())[:10, :2]
+
+data_pl = data_pl.with_columns(
+        pl.all().cast(pl.Categorical)
+    )
+print(type(data_pl))
+#> <class 'polars.dataframe.frame.DataFrame'>
+print(data_pl.schema)
+#> Schema({'species': Categorical, 'island': Categorical})
+
+data_nw_pl = nw.from_native(data_pl) # ここでバックエンドを記録、後ほど復元に使います。
+
+# 何かしらの処理の結果 pd.DataFrame に変換されたとする
+result_pd = data_nw_pl.to_pandas()
+print(type(result_pd))
+#> <class 'pandas.core.frame.DataFrame'>
+

次に、pl.DataFrame 型をもつ result_pd を pl.DataFrame に変換します。

+

ここでポイントとなるのが、nw.from_dicts() 関数の引数の (1)schema 引数と、(2)backend引数に、それぞれ data_nw_pl から取得した値を入力することで、result_pl の列が data_pl と同じく Categorical 型になるようにしています(指定しないと String 型として解釈されてしまいます)。

+
# Pandas -> polars の変換
+dict_list = [result_pd.loc[i, :].to_dict() for i in result_pd.index]
+
+result_nw_pl = nw.from_dicts(
+    dict_list, 
+    schema = data_nw_pl.schema,         # (1)
+    backend = data_nw_pl.implementation # (2)
+    )
+result_pl = result_nw_pl.to_native()
+
+print(type(result_pl))
+#> <class 'polars.dataframe.frame.DataFrame'>
+
+print(result_pl.schema)
+#> Schema({'species': Categorical, 'island': Categorical})
+

また、Series については、nw.Series.from_iterable() 関数を使うことで、次のようにバックエンドを書き換えることができます。

+
x_pl = data_pl['island']
+print(type(x_pl))
+#> <class 'polars.series.series.Series'>
+print(x_pl.dtype)
+#> Categorical
+
+x_nw = nw.from_native(x_pl, allow_series = True)
+x_pd = x_nw.to_pandas()
+print(type(x_pd))
+#> <class 'pandas.core.series.Series'>
+
x_pl2 = nw.Series.from_iterable(
+    name = x_pd.name,
+    values = x_pd.to_list(),
+    backend = x_nw.implementation,
+    dtype = x_nw.dtype
+).to_native()
+
+print(type(x_pl2))
+#> <class 'polars.series.series.Series'>
+print(x_pl2.dtype)
+#> Categorical
+

narwhals の仕様を迂回してバックエンドを書き換えることは可能ですが、この方法には次のような問題があります。 ただし、以上のような方法でバックエンドの書き換えは可能ですが、

+
    +
  1. 小さいデータフレームでない限り時間がかかる +
      +
    • 恐らく、dict_list を作成するための for ループによるもの
    • +
  2. +
  3. 上記の (1) に代入する正しい schema が用意できないと、カラムレベルでデータ型の一貫性保証できない。
  4. +
+

特に2番目の問題点については、集計処理によって列名が変わった場合には正しい schema(≒ {列名:dtype} の辞書オブジェクト)を用意することが難しくなります。そして、schema を指定できないと、pd.Categoricalpl.Categorical あるいは pl.Enum といったカテゴリー変数は文字列型に変換されてしまい、データ型の一貫性が失われます。

+

カラムレベルで型の一貫性が失われると、返り値が入力値とは異なる型になるよりも把握しづらく、また挙動の予測が難しいため、上記のような処理は採用するとしても、他に方法がないときの最終手段として扱うべきでしょう。

+ + +
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/articles/release_notes.html b/docs/articles/release_notes.html new file mode 100644 index 0000000..48867bb --- /dev/null +++ b/docs/articles/release_notes.html @@ -0,0 +1,989 @@ + + + + + + + + + +Release Notes – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Release Notes

+
+ + + +
+ + + + +
+ + + +
+ + +
+

Py4Stats v0.3.0 2026-01-23

+
+

概要(Summary)

+

このリリースでは Pyt4Stats に幾つかの関数の追加を行いました。 関数のリファクタリングとバグ修正を行いました。今回のリリースでは機能の追加や変更はありません。

+
+
+

✨ 主な新機能 (New Features)

+
    +
  • diagnose_category() 関数の追加 +
      +
    • データフレームのカテゴリー変数の要約を提供する関数です。
    • +
  • +
  • set_miss() 関数の追加 +
      +
    • Series の非欠測要素のうち、指定された個数または割合を欠測値に置き換えます。
    • +
  • +
+
+
+

🛠 修正と改善(Fixes /Improvements)

+
    +
  • compare_group_means(), compare_group_median(), compare_df_cols(), compare_df_stats(): コードをリファクタリングし、引数と同じクラスのデータフレームを出力できるようにしました。この変更により、返り値が pd.DataFrame である場合でも、index が自動では設定されなくなりました。

  • +
  • diagnose(): dtype 列が、polars や pyarrow における列のクラスの表記に対してより忠実になるように修正しました。

  • +
  • relocate() 関数に、指定した列を最後列に配置する機能を追加し、エラーメッセージを改善しました。

  • +
  • assert_character() および assert_numeric() 系関数のエラーメッセージを改善しました。

  • +
  • その他、いくつかの関数のエラーメッセージを改善しました。

  • +
+
+
+
+

Py4Stats v0.2.2 2026-01-19

+
+

概要(Summary)

+

型ヒントに関する若干の修正と、バグ修正を行いました。今回のリリースでは機能の追加や変更はありません。

+
+
+

🛠 修正と改善(Fixes /Improvements)

+
    +
  • building_block.assert_numeric 系関数のリファクタリングを行いました。この変更でメインモジュールの関数の動作に変更はありません。
  • +
  • compare_group_means(), compare_group_median() のテストコードを実装しました。
  • +
  • tabyl(): 第一引数 data と同じオブジェクト型をもつ DataFrame を出力できるように実装を修正しました。
  • +
  • check_that(), check_viorate() : 第一引数 data と同じオブジェクト型をもつ DataFrame を出力できるように実装を修正しました。引き続きロジックのコア部分には pd.DataFrame.eval() を使用しており、使用方法に大きな変更はありません。
  • +
  • is_number() 関数を修正し、pyarrow.lib.ChunkedArray オブジェクトを代入すると生じるエラーを解消しました。
  • +
+
+
+
+

Py4Stats v0.2.1 2026-01-16

+
+

概要(Summary)

+

このリリースでは Pyt4Stats の各モジュールに幾つかの関数の追加を行いました。

+
+
+

✨ 主な新機能 (New Features)

+
    +
  • plot_category() 関数の追加 +
      +
    • カテゴリ変数の回答分布を 100% 積み上げ横棒グラフとして描画する関数です。
    • +
  • +
  • plot_miss_var() 関数の追加 +
      +
    • データフレームの各変数について欠測値の量を横棒グラフとして可視化します。
    • +
  • +
  • relocate() 関数の追加 +
      +
    • データフレームの列を、削除することなく並べ替えます。
    • +
  • +
  • weighted_mean(), scale(), min_max() 関数の追加 +
      +
    • それぞれ Series オブジェクトの加重平均の計算と、標準化を行う関数です。
    • +
  • +
+
+
+

🛠 修正と改善(Fixes /Improvements)

+
    +
  • eda_tools の Pandas ベース実装 eda_tools/_pands.py に、FutureWarning を実装しました。
  • +
  • ユーザビリティ向上のため、freq_table() 関数に sort_by 引数を導入しました。 +
      +
    • sort_by = 'frequency' なら度数分布表を頻度に応じてソートし(従来の sort = True に相当)、sort_by = 'values' なら subset で指定した列の値に応じてソートします(従来の sort = False に相当)。
    • +
    • この変更に合わせて、sort 引数は非推奨扱いに変更されています。
    • +
  • +
  • Pareto_plot()aggfunc 引数に、np.mean など values 列を1次元配列として受け取って単一の数値を返す任意の関数を使用できるように改良を行いました。
  • +
  • その他、py4stats ライブラリ全体のエラーメッセージ改善
  • +
  • building_block.assert_* 系関数の改良を行い、与えられた引数の要素数に関するアサーションと、None やリストを拒否する機能を追加しました。
  • +
  • cmpare_ols() および cmpare_mfx() に stars 引数を追加し、有意性のアスタリスクの表示形式を変更できる機能を追加しました。また、その他エラーメッセージの改善を行なっています。
  • +
+
+
+

⚠️ 既知の制限・注意点(Notes)

+
    +
  • pyarrow.Table を使用する場合、plot_category() 関数の一部機能が制限されます。
  • +
+
+
+
+

Py4Stats v0.1.0 2026-01-11

+
+

概要(Summary)

+

このリリースでは EDA モジュールの narwhals ベース実装を統合し、パフォーマンスと互換性を大幅に改善しました。いくつかの既知の挙動も修正されています。

+
+
+

✨ 主な新機能 (New Features)

+
    +
  • py4stats.eda_tools が Pandas ベースの実装から narwhals ベース実装へ移行しました。 +
      +
    • この変更により、複数バックエンド(pandas / polars / pyarrow)をサポートしました。
    • +
  • +
  • Pandas ベースの実装は、当面 py4stats ライブラリのサブモジュール eda_tools._pandas として維持されますが、将来的に廃止される予定です。
  • +
+
+
+

🛠 修正と改善(Fixes /Improvements)

+
    +
  • bilding_block モジュールの名称を building_block に修正
  • +
  • Py4Stats.building_block モジュールの assert_* 系関数の出力を AssertionError から ValueError に変更しました。
  • +
  • Py4Stats.eda_tools モジュールの関数の bool 値の引数を中心に、型の不一致があった場合のエラーメッセージを改善しました。
  • +
+
+
+

⚠️ 既知の制限・注意点(Notes)

+
    +
  • バックエンドの変更に伴い、py4st.freq_table()py4st.diagnose()py4st.tabyl() など、従来はインデックス(Index)付きの pandas.DataFrame データフレームが出力されていた関数で、インデックスのない pandas.DataFrame が出力されるように変更されました。
  • +
  • polars / pyarrow のサポートは experimental であり、一部のエッジケースで動作に違いが出る可能性があります。詳細は Technical Notes および eda_tools開発状況 を参照してください。
  • +
+ + +
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/articles/scaling_up_regression.html b/docs/articles/scaling_up_regression.html new file mode 100644 index 0000000..6b3db75 --- /dev/null +++ b/docs/articles/scaling_up_regression.html @@ -0,0 +1,1232 @@ + + + + + + + + + +scaling up regression – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

scaling up regression

+
+ + + +
+ + + + +
+ + + +
+ + +

 ここでは実証分析の場面で便利な回帰分析の実装例を紹介します。

+
import py4stats as py4st
+import statsmodels.formula.api as smf
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+
+

複数の回帰式を比較する

+

 異なる説明変数の組合せを比較したい場合、リスと内包表記を使って実装するとコードが簡潔で扱いやすくなります。まずは smf.ols() をもとに回帰式を受け取って回帰分析の結果を返す関数 fit_ols と、回帰式のリストlist_fml を定義します。

+
# 回帰分析の推定
+def fit_ols(fml, data):
+  res = smf.ols(fml, data = data).fit()
+  return res
+
+list_fml = [
+    'body_mass_g ~ bill_length_mm + species',
+    'body_mass_g ~ bill_length_mm + bill_depth_mm + species',
+    'body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex'
+]
+

回帰分析の実行部分は次のように記述します。

+
# 回帰分析の実行
+list_fitted1 = [fit_ols(fml, penguins) for fml in list_fml]
+

このとき list_fitted1 は回帰分析の推定結果を要素に持つリストであるため、py4st.compare_ols() にそのまま代入することができます。

+
py4st.compare_ols(list_models = list_fitted1) # 表の作成
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termmodel 1model 2model 3
Intercept153.7397-1742.7202 ***843.9812 **
(268.9012)(313.7697)(403.5956)
species[T.Chinstrap]-885.8121 ***-539.6864 ***-245.1516 ***
(88.2502)(86.9425)(84.5952)
species[T.Gentoo]578.6292 ***1492.8283 ***1443.3525 ***
(75.3623)(118.4442)(107.7844)
bill_length_mm91.4358 ***55.6461 ***26.5366 ***
(6.8871)(7.2326)(7.2436)
bill_depth_mm179.0434 ***87.9328 ***
(19.0997)(20.2192)
sex[T.male]437.2007 ***
(49.1098)
rsquared_adj0.78100.82580.8613
nobs342342333
df345
+

この方法であれば、試したい回帰式のパターンが増えた場合でも、list_fml の要素を追加するだけで済むため、実行部分を変更する必要がありません。
+ また、回帰係数を視覚的に比較するには次のようなコードを使うと良いでしょう。

+
plt.rcParams["figure.autolayout"] = True
+
+fig, ax = plt.subplots(1, 3, figsize = (3.2 * 5, 5), dpi = 100)
+
+for k, mod in enumerate(list_fitted1):
+  py4st.coefplot(mod, ax = ax[k])
+  ax[k].set_xlim(-1200, 1800)
+  ax[k].set_title(f'model {k + 1}')
+  ax[k].set_xlabel(f'coefficient (n = {mod.nobs:,.0f})')
+

scaling_up_regression1 ## グループ別の回帰分析

+

 次に、データセットのグループ別に回帰分析を行う場合を考えます。この場合、データを受け取ると回帰分析の結果を返す関数 group_ols を定義し、回帰式は固定しておきます。

+
# グループ別の回帰分析の実行
+def group_ols(data):
+  res = smf.ols(
+      'body_mass_g ~ bill_length_mm + bill_depth_mm + sex', 
+      data = data).fit()
+  return res
+

次に pd.DataFrame.groupby() メソッドを使ってグループ分けを行い、続いて .apply() メソッドを使ってグループ別に回帰分析を実行します。ここでは、実行結果が回帰分析の結果を要素にもつ pd.Series になるので、.to_list() メソッドでリストに変換しています。

+
penguins2 = penguins.groupby('species')
+
+list_fitted2 = penguins2.apply(group_ols).to_list()
+

ここまでの準備ができれば、後は py4st.compare_ols() で分析結果を比較できます。

+
list_groups = list(penguins2.groups.keys())
+
+py4st.compare_ols(
+    list_models = list_fitted2,
+    model_name = list_groups
+    )
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termAdelieChinstrapGentoo
Intercept984.4166286.25401829.0302 ***
(601.1999)(980.5230)(638.6999)
sex[T.male]476.6000 ***102.9407536.5500 ***
(69.9994)(119.3246)(80.3899)
bill_length_mm26.8589 **18.421833.6324 ***
(11.4707)(16.0333)(11.2907)
bill_depth_mm78.5228 ***135.4873 **92.5900 **
(25.1993)(51.1571)(41.9318)
rsquared_adj0.58220.36870.6956
nobs14668119
df333
+
plt.rcParams["figure.autolayout"] = True
+
+fig, ax = plt.subplots(1, 3, figsize = (3.2 * 5, 5), dpi = 100)
+
+for k, mod in enumerate(list_fitted2):
+  py4st.coefplot(mod, ax = ax[k])
+  ax[k].set_xlim(-500, 1000)
+  ax[k].set_title(list_groups[k])
+  ax[k].set_xlabel(f'coefficient (n = {mod.nobs:,.0f})')
+
+
+

+
scaling_up_regression2
+
+
+
+
+

ブートストラップ回帰

+

 前節でグループ別の回帰分析を行なった方法を応用すると、ブートストラップ法を簡単に実装することができます。

+
def est_ols(data):
+  fitted = smf.ols(
+      'body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex',
+      data = data).fit()
+  return fitted
+

 次にブートストラップ法の実行部分を作成します。ここでは pandas の DataFrame.sample() メソッドを使い、引数に frac = 1, replace = True を指定することで復元抽出を行います。また、ここでは反復回数を Efron, Hastie(2016, p.161)などで推奨されている \(B = 1000\) を指定しています。

+
# ブートストラップ法の実装
+B = 1000 # ブートストラップ法の反復回数
+model_list = [
+    penguins.sample(frac = 1, replace = True, random_state = 123)\
+    .pipe(est_ols) 
+    for b in range(B)
+]
+
+boot_sample = pd.concat([py4st.tidy(mod) for mod in model_list])
+
+len(boot_sample)
+#> 6000
+

次にブートストラップ統計量を集計して結果を確認しますが、ここではごく簡単に py4st.mean_qi() を使って、説明変数別に回帰係数の平均値と分位点を求めています。

+
res = boot_sample.groupby(['term'])[['estimate']]\
+    .apply(py4st.mean_qi)
+
+print(res.round(4))
+#>                         variable       mean      lower      upper
+#> term                                                             
+#> Intercept            0  estimate   823.7098   823.7098   823.7098
+#> bill_depth_mm        0  estimate   109.9439   109.9439   109.9439
+#> bill_length_mm       0  estimate    17.8235    17.8235    17.8235
+#> sex[T.male]          0  estimate   474.2673   474.2673   474.2673
+#> species[T.Chinstrap] 0  estimate  -191.4717  -191.4717  -191.4717
+#> species[T.Gentoo]    0  estimate  1487.5680  1487.5680  1487.5680
+

ブートストラップ法を使うと、次のような回帰係数の分布のグラフを描くこともできます。

+
import ptitprince as pt
+
+fig, ax = plt.subplots(figsize = (np.sqrt(2) * 3, 3), dpi = 150)
+
+pt.RainCloud(
+    data = boot_sample.sort_index().reset_index()\
+      .query('~term.str.contains("Intercept")'),
+    x = 'term',
+    y = 'estimate',
+    orient = 'h',
+    ax = ax
+);
+
+ax.axvline(0, ls = "--", color = '#969696');
+
+
+

+
scaling_up_regression3
+
+
+
+

補足

+
    +
  • データセットが大きい場合、ブートストラップ法の実行には時間がかかるので boot_sample.to_csv('output/boot_sample.csv') を追加して保存しておいた方が、事後的な分析がしやすいと思います。
  • +
  • 今回のような通常の回帰分析であれば、回帰係数の標準誤差は簡単に計算できるためブートストラップ法を使う必要性を感じにくいですが、傾向スコアを用いたIPW推定量など、標準誤差の推定にブートストラップ法が必要になる場合もあります。
  • +
  • 今回は DataFrame.sample() メソッドを使ったごく簡単な方法でブートストラップ法を実装していますが、もう少し効率的な方法もあるのではないかと思います。
  • +
+
+
+
+

参考文献

+
    +
  • Efron, Bradley, and Trevor Hastie. (2016). Computer age statistical inference. Cambridge University Press.
  • +
  • 末石直也(2015)『計量経済学:ミクロデータ分析へのいざない』 日本評論社.
  • +
+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..4c85065 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,1036 @@ + + + + + + + + + + +Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Py4Stats

+
+ + + +
+ + +
+
Published
+
+

2026-01-24

+
+
+ + +
+ + + +
+ + +
+

Readme

+

Py4Stats は、主に実証研究で用いられる、探索的データ分析および回帰結果レポート用のユーティリティライブラリです。回帰分析を中心とする分析でよく使われるR言語の機能を Python で実装しています。

+ +

本ライブラリの主な機能は Get Started を、実装されている関数の一覧は Function reference を参照してください。

+
+

Installation

+

uv をお使いの場合、次のコードで py4stats をインストールできます。

+
! uv add git+https://github.com/Hirototensho/py4stats.git
+

一方で、pip をお使いの場合には、次のコードで py4stats をインストールできます。

+
! pip install git+https://github.com/Hirototensho/py4stats.git
+
+
+

使用例

+
import py4stats as py4st
+

py4stats.diagnose() 関数はデータの全般的な状態についての要約を提供します。

+
import pandas as pd
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+
+print(py4st.diagnose(penguins).round(4))
+#>              columns    dtype  missing_count  missing_percent  unique_count  unique_rate
+#> 0            species   object              0           0.0000             3       0.8721
+#> 1             island   object              0           0.0000             3       0.8721
+#> 2     bill_length_mm  float64              2           0.5814           165      47.9651
+#> 3      bill_depth_mm  float64              2           0.5814            81      23.5465
+#> 4  flipper_length_mm  float64              2           0.5814            56      16.2791
+#> 5        body_mass_g  float64              2           0.5814            95      27.6163
+#> 6                sex   object             11           3.1977             3       0.8721
+#> 7               year    int64              0           0.0000             3       0.8721
+

py4stats.compare_ols() 関数は、計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。

+
import statsmodels.formula.api as smf
+
+# 回帰分析の実行
+fit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()
+fit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit()
+fit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()
+
+compare_tab1 = py4st.compare_ols(list_models = [fit1, fit2, fit3]) # 表の作成
+compare_tab1
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termmodel 1model 2model 3
Intercept153.7397-1,742.7202 ***843.9812 **
(268.9012)(313.7697)(403.5956)
species[T.Chinstrap]-885.8121 ***-539.6864 ***-245.1516 ***
(88.2502)(86.9425)(84.5952)
species[T.Gentoo]578.6292 ***1,492.8283 ***1,443.3525 ***
(75.3623)(118.4442)(107.7844)
bill_length_mm91.4358 ***55.6461 ***26.5366 ***
(6.8871)(7.2326)(7.2436)
bill_depth_mm179.0434 ***87.9328 ***
(19.0997)(20.2192)
sex[T.male]437.2007 ***
(49.1098)
rsquared_adj0.78100.82580.8613
nobs342342333
df345
+

詳細は、py4stats.compare_ols() を参照してください。 

+
+

Jump to Get Started.
+Jump to Function reference.

+ + +
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/introduction.html b/docs/introduction.html new file mode 100644 index 0000000..e932ef6 --- /dev/null +++ b/docs/introduction.html @@ -0,0 +1,1331 @@ + + + + + + + + + +Introduction to Py4Stats – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Introduction to Py4Stats

+
+ + + +
+ + + + +
+ + + +
+ + +
import py4stats as py4st
+

ここでは Py4Stats の主な機能を紹介します。実装されている関数の一覧は Function reference を参照してください。

+
+

py4stats.eda_tools

+

 探索的データ解析と前処理に関する機能を提供するモジュールです。このモジュールは、複数の DataFrame バックエンドに対して共通の API を提供することを目的として、narwhals ライブラリを用いて実装されています。詳細は Technical Notes: py4stats.eda_tools における narwhals ベースの実装 を参照してください。

+

 py4stats.diagnose():R言語のdlookr::diagnose()を再現した関数で、データの全般的な状態についての要約を提供します。

+
import pandas as pd
+import numpy as np
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+
+print(py4st.diagnose(penguins).round(4))
+#>                      dtype  missing_count  missing_percent  unique_count  unique_rate
+#> species             object              0           0.0000             3       0.8721
+#> island              object              0           0.0000             3       0.8721
+#> bill_length_mm     float64              2           0.5814           164      47.6744
+#> bill_depth_mm      float64              2           0.5814            80      23.2558
+#> flipper_length_mm  float64              2           0.5814            55      15.9884
+#> body_mass_g        float64              2           0.5814            94      27.3256
+#> sex                 object             11           3.1977             2       0.5814
+#> year                 int64              0           0.0000             3       0.8721
+

py4stats.tabyl():R言語の janitor::tabyl()を参考にした、クロス集計表を作成する関数です。

+
print(py4st.tabyl(penguins, 'island', 'species'))
+#> species         Adelie   Chinstrap       Gentoo  All
+#> island                                              
+#> Biscoe      44 (26.2%)    0 (0.0%)  124 (73.8%)  168
+#> Dream       56 (45.2%)  68 (54.8%)     0 (0.0%)  124
+#> Torgersen  52 (100.0%)    0 (0.0%)     0 (0.0%)   52
+#> All        152 (44.2%)  68 (19.8%)  124 (36.0%)  344
+

 py4stats.freq_table():R言語のDescTools::Freq()をオマージュした、1変数の度数分布表を計算する関数。度数 freq と相対度数 perc に加えて、それぞれの累積値を計算します。

+
print(py4st.freq_table(penguins, 'species'))
+#>            freq      perc  cumfreq   cumperc
+#> species                                     
+#> Adelie      152  0.441860      152  0.441860
+#> Gentoo      124  0.360465      276  0.802326
+#> Chinstrap    68  0.197674      344  1.000000
+

引数 group を指定すると、グループ別の度数分布表を計算できます。

+
penguins2 = penguins.assign(bill_length_mm2 = pd.cut(penguins['bill_length_mm'], 6))
+
+print(
+    py4st.freq_table(penguins2, ['species', 'bill_length_mm2'], sort = False)
+    )
+#>                             freq      perc  cumfreq   cumperc
+#> species   bill_length_mm2
+#> Adelie    (32.072, 38.975]    79  0.523179       79  0.523179
+#>           (38.975, 45.85]     71  0.470199      150  0.993377
+#>           (45.85, 52.725]      1  0.006623      151  1.000000
+#>           (52.725, 59.6]       0  0.000000      151  1.000000
+#> Chinstrap (32.072, 38.975]     0  0.000000        0  0.000000
+#>           (38.975, 45.85]     13  0.191176       13  0.191176
+#>           (45.85, 52.725]     50  0.735294       63  0.926471
+#>           (52.725, 59.6]       5  0.073529       68  1.000000
+#> Gentoo    (32.072, 38.975]     0  0.000000        0  0.000000
+#>           (38.975, 45.85]     40  0.325203       40  0.325203
+#>           (45.85, 52.725]     78  0.634146      118  0.959350
+#>           (52.725, 59.6]       5  0.040650      123  1.000000
+

 py4stats.remove_empty():完全に空白な列や行の削除する関数。R言語の janitor::remove_empty() をオマージュした関数で、全ての要素が NaN である列や行をデータフレームから除外します。

+
penguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy()
+penguins2.loc[:, 'empty'] = np.nan
+penguins2.loc[344, :] = np.nan
+
+print(penguins2.tail(3))
+#>        species  body_mass_g  empty
+#> 342  Chinstrap       4100.0    NaN
+#> 343  Chinstrap       3775.0    NaN
+#> 344        NaN          NaN    NaN
+
+# 完全に空白な行と列を削除。
+print(py4st.remove_empty(penguins2, quiet = False).tail(3))
+#> Removing 1 empty column(s) out of 3 columns(Removed: empty).
+#> Removing 1 empty row(s) out of 345 rows(Removed: 344). 
+#>        species  body_mass_g
+#> 341  Chinstrap       3775.0
+#> 342  Chinstrap       4100.0
+#> 343  Chinstrap       3775.0
+
+# 完全に空白な列のみ削除。
+print(py4st.remove_empty(penguins2, rows = False, quiet = False).tail(3))
+#> Removing 1 empty column(s) out of 3 columns(Removed: empty).
+#>        species  body_mass_g
+#> 342  Chinstrap       4100.0
+#> 343  Chinstrap       3775.0
+#> 344        NaN          NaN
+
+# 完全に空白な行のみ削除。
+print(py4st.remove_empty(penguins2, cols = False, quiet = False).tail(3))
+#> Removing 1 empty row(s) out of 345 rows(Removed: 344). 
+#>        species  body_mass_g  empty
+#> 341  Chinstrap       3775.0    NaN
+#> 342  Chinstrap       4100.0    NaN
+#> 343  Chinstrap       3775.0    NaN
+

 py4stats.remove_constant():定数列の削除。R言語の janitor::remove_constant() をオマージュした関数で、1種類だけの要素からなる列をデータフレームから除外します。

+
penguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy()
+penguins2.loc[:, 'constant'] = 'c'
+
+print(penguins2.head(3))
+#>   species  body_mass_g constant
+#> 0  Adelie       3750.0        c
+#> 1  Adelie       3800.0        c
+#> 2  Adelie       3250.0        c
+
+print(py4st.remove_constant(penguins2, quiet = False).head(3))
+#> Removing 1 constant column(s) out of 3 column(s)(Removed: constant). 
+#>   species  body_mass_g
+#> 0  Adelie       3750.0
+#> 1  Adelie       3800.0
+#> 2  Adelie       3250.0
+

 py4stats.filtering_out()pandasDataFrame.filter() メソッドでは引数 like に文字列を指定することで、列名に特定の文字列を含む列を選択できますが、反対に py4stats.filtering_out() では列名に特定の文字列を含む列を除外します。実装の一部はR言語の dplyr::select() を参考にしました。

+
# 列名に 'length' を含む列を除外
+print(py4st.filtering_out(penguins, contains = 'length').head(3))
+#>   species     island  bill_depth_mm  body_mass_g     sex  year  female
+#> 0  Adelie  Torgersen           18.7       3750.0    male  2007       0
+#> 1  Adelie  Torgersen           17.4       3800.0  female  2007       1
+#> 2  Adelie  Torgersen           18.0       3250.0  female  2007       1
+
+# 列名が 'bill' から始まる列を除外
+print(py4st.filtering_out(penguins, starts_with = 'bill').head(3))
+#>   species     island  flipper_length_mm  body_mass_g     sex  year  female
+#> 0  Adelie  Torgersen              181.0       3750.0    male  2007       0
+#> 1  Adelie  Torgersen              186.0       3800.0  female  2007       1
+#> 2  Adelie  Torgersen              195.0       3250.0  female  2007       1
+
+# 列名が '_mm' で終わる列を除外
+print(py4st.filtering_out(penguins, ends_with = '_mm').head(3))
+#>   species     island  body_mass_g     sex  year  female
+#> 0  Adelie  Torgersen       3750.0    male  2007       0
+#> 1  Adelie  Torgersen       3800.0  female  2007       1
+#> 2  Adelie  Torgersen       3250.0  female  2007       1
+
+
+

py4stats.regression_tools

+

 py4stats.regression_toolsstatsmodelsライブラリで作成された回帰分析の結果についての表作成と可視化を補助する機能を提供するモジュールです。

+

 py4stats.compare_ols() :計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。表のフォーマットについてはR言語のtexreg::screenreg()modelsummary::modelsummary()を参考にしています。同種の機能を提供する Python ライブラリーとしては、R言語の stargazer パッケージをもとにした stargazer ライブラリがあります。

+
import statsmodels.formula.api as smf
+
+# 回帰分析の実行
+fit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()
+fit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit()
+fit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()
+
+compare_tab1 = py4st.compare_ols(list_models = [fit1, fit2, fit3]) # 表の作成
+compare_tab1
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termmodel 1model 2model 3
Intercept153.7397-1,742.7202 ***843.9812 **
(268.9012)(313.7697)(403.5956)
species[T.Chinstrap]-885.8121 ***-539.6864 ***-245.1516 ***
(88.2502)(86.9425)(84.5952)
species[T.Gentoo]578.6292 ***1,492.8283 ***1,443.3525 ***
(75.3623)(118.4442)(107.7844)
bill_length_mm91.4358 ***55.6461 ***26.5366 ***
(6.8871)(7.2326)(7.2436)
bill_depth_mm179.0434 ***87.9328 ***
(19.0997)(20.2192)
sex[T.male]437.2007 ***
(49.1098)
rsquared_adj0.78100.82580.8613
nobs342342333
df345
+

py4stats.compare_ols() の実行結果は PandasDataFrame として出力されるため、.xlsx. ファイルなどに変換することができます。また、用途に応じて表の体裁を調整できるようにしています。詳細については 「回帰分析の比較」 を参照してください。

+
compare_tab2 = py4st.compare_ols(
+    list_models = [fit1, fit2, fit3],
+    model_name = ['基本モデル', '嘴の高さ追加', '性別追加'], # モデル名を変更
+    stats = 'p_value',        # () 内の値をP-値に変更する
+    add_stars = False,        # 有意性のアスタリスクなし
+    table_style = 'one_line', # 表スタイルを1行表示に設定 'one' でも可能
+    digits = 3                # 小数点以下の桁数を3に設定
+    )
+compare_tab2
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
term基本モデル嘴の高さ追加性別追加
Intercept153.740(0.568)-1,742.720(0.000)843.981(0.037)
species[T.Chinstrap]-885.812(0.000)-539.686(0.000)-245.152(0.004)
species[T.Gentoo]578.629(0.000)1,492.828(0.000)1,443.353(0.000)
bill_length_mm91.436(0.000)55.646(0.000)26.537(0.000)
bill_depth_mm179.043(0.000)87.933(0.000)
sex[T.male]437.201(0.000)
rsquared_adj0.7810.8260.861
nobs342342333
df345
+

py4stats.coefplot():回帰係数の可視化。R言語の coefplot::coefplot() を参考にしました。

+
import matplotlib.pyplot as plt
+py4st.coefplot(fit3)
+
+
+

+
coefplot1
+
+
+
plt.rcParams["figure.autolayout"] = True
+
+fig, ax = plt.subplots(1, 2, figsize = (2.2 * 5, 5), dpi = 100)
+
+py4st.coefplot(fit2, ax = ax[0])
+ax[0].set_xlim(-900, 1800)
+
+py4st.coefplot(fit3, ax = ax[1], palette = ['#FF6F91', '#F2E5EB'])
+ax[1].set_xlim(-900, 1800);
+
+
+

+
coefplot2
+
+
+

 py4stats.compare_mfx()py4stats.mfxplot() は、それぞれ py4stats.compare_ols()py4stats.coefplot() の一般化線型モデルバージョンです。statsmodels ライブラリの.get_margeff() メソッドから得られた限界効果の推定値を表示します。

+
penguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)
+
+# ロジスティック回帰の実行
+fit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()
+fit_logit2 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm + species', data = penguins).fit()
+
+py4st.compare_mfx([fit_logit1, fit_logit2])
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termmodel 1model 2
body_mass_g-0.0004 ***-0.0003 ***
(0.0000)(0.0000)
bill_length_mm-0.0053-0.0357 ***
(0.0036)(0.0070)
bill_depth_mm-0.1490 ***-0.1098 ***
(0.0051)(0.0175)
species[T.Chinstrap]0.4172 ***
(0.0848)
species[T.Gentoo]0.3527 ***
(0.1308)
prsquared0.56470.6187
nobs342342
df35
+
plt.rcParams["figure.autolayout"] = True
+
+fig, ax = plt.subplots(1, 2, figsize = (2.2 * 5, 5), dpi = 100)
+
+py4st.mfxplot(fit_logit1, ax = ax[0])
+ax[0].set_xlim(-0.2, 0.85)
+
+py4st.mfxplot(fit_logit2, ax = ax[1], palette = ['#FF6F91', '#F2E5EB'])
+ax[1].set_xlim(-0.2, 0.85);
+
+
+

+
coefplot3
+
+
+
+

Jump to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/Blinder_Oaxaca.html b/docs/man/Blinder_Oaxaca.html new file mode 100644 index 0000000..a5e29e0 --- /dev/null +++ b/docs/man/Blinder_Oaxaca.html @@ -0,0 +1,1114 @@ + + + + + + + + + +Blinder_Oaxaca, plot_Blinder_Oaxaca – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Blinder_Oaxaca, plot_Blinder_Oaxaca

+
+ + + +
+ + + + +
+ + + +
+ + +
+

概要

+

 2つのサブサンプルを用いた回帰分析の推定結果に対して、Blinder-Oaxaca分解を行います。

+
Blinder_Oaxaca(model1, model2)
+
+plot_Blinder_Oaxaca(
+    model1, model2,
+    diff_type = ['observed_diff', 'unobserved_diff'],
+    ax = None, 
+)
+

 いま、ある変数 \(s\) を用いて \(s = m\)\(s = f\) の2つのサブグループからなるデータセットがあるとし、次のような回帰式を仮定します。

+

\[ +\begin{aligned} +Y_{i}^s = \boldsymbol{X}_i^s\boldsymbol{\beta}^s + \epsilon_i^s, && +s = m, f +\end{aligned} +\tag{1} +\]

+

 ここで、\(\boldsymbol{X}_i^s\) サブグループ \(s\) に属する個人 \(i\) についての説明変数からなる行列で、\(\boldsymbol{\beta}^s\) はサブグループ \(s\) のについての回帰係数、\(\epsilon_i^s\) は誤差項です。  さらに、サブグループ \(s\) の被説明変数の平均値を \(\bar{Y}^s\) とし、説明変数の平均値を \(\bar{\boldsymbol{X}}^s\) とするとき、Blinder-Oaxaca分解は2つのグループにおける被説明変数の平均値の差 \(\bar{Y}^m - \bar{Y}^f\) を次のように分解します。

+

\[ +\begin{aligned} +\bar{Y}^m - \bar{Y}^f = (\bar{\boldsymbol{X}}^m - \bar{\boldsymbol{X}}^f)\boldsymbol{\beta}^m + \bar{\boldsymbol{X}}^f(\boldsymbol{\beta}^m - \boldsymbol{\beta}^f) +\end{aligned} +\tag{2} +\]

+

このとき、式(2)右辺の各項は、それぞれ次のような意味を持ちます。

+
    +
  • \((\bar{\boldsymbol{X}}^m - \bar{\boldsymbol{X}}^f)\boldsymbol{\beta}^m\):2つのグループの観測可能な属性の差に起因する被説明変数の差 observed_diff
  • +
  • \(\bar{\boldsymbol{X}}^f(\boldsymbol{\beta}^m - \boldsymbol{\beta}^f)\):2つのグループの観測できない要因の違いに起因する被説明変数の差 unobserved_diff
  • +
+

 式(1)および式(2)については朝井(2014, p.9)を参照しました。

+
+
+

引数 Argument

+
    +
  • model1statsmodels で作成した回帰分析の結果(必須)。
  • +
  • model2statsmodels で作成した回帰分析の結果(必須)。
  • +
  • diff_typeplot_Blinder_Oaxaca()のみ)list of str or str
     グラフの描画に使用する要約統計量の種類。初期設定では observed_diffunobserved_diff の両方を表示します。
  • +
  • ax:matplotlib の ax オブジェクト。複数のグラフを並べる場合などに使用します。   ## 使用例 Examples
  • +
+
import pandas as pd
+import statsmodels.formula.api as smf
+import py4stats as py4st
+
+wage1 = wooldridge.data('wage1')
+
+fit_female = smf.ols(
+    'lwage ~ educ + exper + expersq + tenure + tenursq + married', 
+    data = wage1.query('female == 1')
+    ).fit()
+
+fit_male = smf.ols(
+    'lwage ~ educ + exper + expersq + tenure + tenursq + married', 
+    data = wage1.query('female == 0')
+    ).fit()
+
py4st.compare_ols(
+    list_models = [fit_female, fit_male],
+    model_name = ['female', 'male']
+    )
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termfemalemale
Intercept0.3159 **
(0.1401)
0.2255 *
(0.1302)
educ0.0737 ***
(0.0104)
0.0830 ***
(0.0089)
exper0.0200 ***
(0.0072)
0.0329 ***
(0.0076)
expersq-0.0004 ***
(0.0002)
-0.0006 ***
(0.0002)
tenure0.0391 ***
(0.0117)
0.0301 ***
(0.0089)
tenursq-0.0014 ***
(0.0005)
-0.0005 *
(0.0003)
married-0.0548
(0.0539)
0.1718 ***
(0.0595)
rsquared_adj0.24460.4509
nobs252274
df66
+
wage_decomp = py4st.Blinder_Oaxaca(
+    model1 = fit_female,
+    model2 = fit_male
+)
+wage_decomp
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termsobserved_diffunobserved_diff
Intercept0-0.0903337
educ0.03906610.114713
exper0.03715770.211177
expersq-0.0216026-0.0962631
tenure0.0859831-0.0327949
tenursq-0.03427270.0378497
married0.02788060.118657
+
py4st.plot_Blinder_Oaxaca(
+    model1 = fit_female,
+    model2 = fit_male
+)
+
+
+

+
plot_Blinder_Oaxaca1
+
+
+

diff_type を指定することで、一方の統計量だけを表示することもできます。

+
py4st.plot_Blinder_Oaxaca(
+    model1 = fit_female,
+    model2 = fit_male,
+    diff_type = 'unobserved_diff'
+)
+
+
+

+
plot_Blinder_Oaxaca2
+
+
+

グラフのサイズや解像度を指定するには、次のように行います。

+
fig, ax = plt.subplots(1, 2, figsize = (1.1 * 2 * 4, 4), sharey = True, dpi = 200)
+
+py4st.plot_Blinder_Oaxaca(
+    model1 = fit_female,
+    model2 = fit_male,
+    ax = ax
+)
+fig.tight_layout()
+
+
+

参考文献

+
    +
  • 朝井 友紀子 (2014) 「労働市場における男女差の30年― 就業のサンプルセレクションと男女間賃金格差」『日本労働研究雑誌』, No.648, pp.6–16
  • +
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/Heckit_from_formula.html b/docs/man/Heckit_from_formula.html new file mode 100644 index 0000000..65a79b1 --- /dev/null +++ b/docs/man/Heckit_from_formula.html @@ -0,0 +1,974 @@ + + + + + + + + + +heckit_helper.Heckit_from_formula – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

heckit_helper.Heckit_from_formula

+
+ + + +
+ + + + +
+ + + +
+ + +
+

概要

+
Heckit_from_formula(
+  selection, 
+  outcome, 
+  data, 
+  **kwargs
+  )
+
+
+

引数 Argument

+
    +
  • selectionstr(必須)
     Type2トービットモデルのうち第1段階の selection equation(選択関数, 就業決定関数)の回帰式
  • +
  • outcomestr(必須)
     Type2トービットモデルのうち第2段階の regression equation(賃金関数)の回帰式
  • +
  • datapandas.DataFrame(必須)
  • +
  • **kwargs
    py4etrics.heckit.Heckit() に渡すその他の引数
  • +
+
+
+

返り値 Value

+

 3つの要素を持つ tuple。左から順に次の3つのオブジェクトが出力されます。

+
    +
  1. py4etrics.heckit.Heckit() から出力されたモデルの推定結果
  2. +
  3. 第2段階の regression equation(賃金関数)の説明変数からなる pd.DataFrame
  4. +
  5. 第1段階のselection equation(選択関数, 就業決定関数)の説明変数からなる pd.DataFrame
  6. +
+
+
+

使用例 Examples

+

 heckit_helper モジュールはヘックマンの2段階推定(Heckit)を実行を Py4Etrics モジュールの py4etrics.heckit.Heckit() に依存しているため、事前のインストールをお願いします。

+
pip install git+https://github.com/Py4Etrics/py4etrics.git
+

ここでは春山(2023, Chap.24)のモデルを再現するため、wooldridge モジュールから mroz データを読み込みます。

+
import pandas as pd
+import wooldridge
+from py4stats import heckit_helper
+
+mroz = wooldridge.data('mroz') # サンプルデータの読み込み
+

Heckit_from_formula() 関数を使い、モデルを推定します。なお、Type2トービットモデルを推定する場合、第2段階の回帰式 outcome で使用される説明変数は全て第1段階の回帰式 selection に含まれ、なおかつ selection に含まれるものの、outcome には含まれない説明変数が少なくとも1つは必要であることに注意してください(末石, 2015, p.117)。

+
mod_heckit, exog_outcome, exog_select = \
+ heckit_helper.Heckit_from_formula(
+    selection = 'lwage ~ educ + exper + expersq + nwifeinc + age + kidslt6 + kidsge6',
+    outcome = 'lwage ~ educ + exper + expersq',
+    data = mroz
+)
+
+res_heckit = mod_heckit.fit(cov_type_2 = 'HC1')
+
+print(res_heckit.summary())
+#>                            Heckit Regression Results                            
+#> ================================================================================
+#> Dep. Variable:                    lwage   R-squared:                       0.156
+#> Model:                           Heckit   Adj. R-squared:                  0.150
+#> Method:                Heckman Two-Step   F-statistics:                   26.148
+#> Date:                  Mon, 11 Mar 2024   Prob (F-statistic):              0.000
+#> Time:                          08:40:39   Cov in 1st Stage:            nonrobust
+#> No. Total Obs.:                     753   Cov in 2nd Stage:                  HC1
+#> No. Censored Obs.:                  325                                         
+#> No. Uncensored Obs.:                428                                         
+#> ==============================================================================
+#>                  coef    std err          z      P>|z|      [0.025      0.975]
+#> ------------------------------------------------------------------------------
+#> Intercept     -0.5781      0.305     -1.895      0.058      -1.176       0.020
+#> educ           0.1091      0.016      7.026      0.000       0.079       0.139
+#> exper          0.0439      0.016      2.699      0.007       0.012       0.076
+#> expersq       -0.0009      0.000     -1.957      0.050      -0.002    1.15e-06
+#> ==============================================================================
+#>                  coef    std err          z      P>|z|      [0.025      0.975]
+#> ------------------------------------------------------------------------------
+#> Intercept      0.2701      0.509      0.531      0.595      -0.727       1.267
+#> educ           0.1309      0.025      5.183      0.000       0.081       0.180
+#> exper          0.1233      0.019      6.590      0.000       0.087       0.160
+#> expersq       -0.0019      0.001     -3.145      0.002      -0.003      -0.001
+#> nwifeinc      -0.0120      0.005     -2.484      0.013      -0.022      -0.003
+#> age           -0.0529      0.008     -6.235      0.000      -0.069      -0.036
+#> kidslt6       -0.8683      0.119     -7.326      0.000      -1.101      -0.636
+#> kidsge6        0.0360      0.043      0.828      0.408      -0.049       0.121
+#> ================================================================================
+#>                    coef    std err          z      P>|z|      [0.025      0.975]
+#> --------------------------------------------------------------------------------
+#> IMR (Lambda)     0.0323      0.134      0.241      0.809      -0.230       0.294
+#> =====================================
+#> rho:                            0.049
+#> sigma:                          0.664
+#> =====================================
+#> 
+#> First table are the estimates for the regression (response) equation.
+#> Second table are the estimates for the selection equation.
+#> Third table is the estimate for the coef of the inverse Mills ratio (Heckman's Lambda).
+
+
+

参考文献

+
    +
  • 末石直也(2015)『計量経済学:ミクロデータ分析へのいざない』 日本評論社.
  • +
  • 春山鉄源(2023) 『Pythonで学ぶ入門計量経済学』 https://py4etrics.github.io/index.html
  • +
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/Pareto_plot.html b/docs/man/Pareto_plot.html new file mode 100644 index 0000000..7fb4052 --- /dev/null +++ b/docs/man/Pareto_plot.html @@ -0,0 +1,944 @@ + + + + + + + + + +Pareto_plot – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Pareto_plot

+
+ + + +
+ + + + +
+ + + +
+ + +

パレート図の作成

+
+

概要

+

データフレームからパレート図を作図する関数です。

+
Pareto_plot(
+    data: IntoFrameT,
+    group: str,
+    values: Optional[str] = None,
+    top_n: Optional[int] = None,
+    aggfunc: Callable[..., Any] = np.mean,
+    ax: Optional[Axes] = None,
+    fontsize: int = 12,
+    xlab_rotation: Union[int, float] = 0,
+    palette: Sequence[str] = ("#478FCE", "#252525"),
+    )
+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • groupstr
     集計に使用するデータフレームの列名(必須)。
  • +
  • valuesstr
     集計に使用するデータフレームの列名。values = None(初期設定)の場合、group 別の度数が表示され、values が指定された場合、group 別に valuesaggfuncで集計した値がグラフに表示されます。
  • +
  • top_nint
     棒グラフを表示するカテゴリーの件数。top_n = None(初期設定)の場合、すべてのカテゴリーを表示し、整数値が指定された場合、上位 top_n 件が表示されます。
  • +
  • aggfunccallable
    values が指定された際に、集計に使用する集計関数。np.mean など values 列を1次元配列として受け取って単一の数値を返す任意の関数が使用できるほか、nw.mean など narwhals.functions モジュールで実装された関数を使用できます。
  • +
  • ax
    描画先となる matplotlib の Axes。複数のグラフを並べる場合などに使用します。デフォルトの None の場合は、新しい Figure と Axes が作成されます。
  • +
  • fontsizeint
     軸ラベルなどのフォントサイズ。
  • +
  • xlab_rotationint or float
    横軸ラベルの角度。matplotlib の ax.xaxis.set_tick_params() に引数 rotation として渡されます。
  • +
  • palettelist of str
    グラフの描画に使用する色コード。1つ目の要素が棒グラフの色に、2つ目の累積値を表す折線グラフの色に対応します。
  • +
+
+
+

使用例

+
import py4stats as py4st
+import pandas as pd
+import numpy as np
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込
+
+penguins['group'] = penguins['species'] + '\n' + penguins['island']
+
+py4st.Pareto_plot(penguins, group = 'group')
+
+
+

+
Pareto_plot1
+
+
+
py4st.Pareto_plot(
+    penguins, group = 'group', 
+    values = 'bill_length_mm',
+    aggfunc = np.mean,
+    palette = ['#FF6F91', '#252525']
+    )
+
+
+

+
Pareto_plot2
+
+
+
py4st.Pareto_plot(
+    penguins, 
+    values = 'bill_length_mm',
+    group = 'group',
+    aggfunc = lambda x: x.std()
+    )
+
+
+

+
Pareto_plot3
+
+
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/arg_match.html b/docs/man/arg_match.html new file mode 100644 index 0000000..15cfc70 --- /dev/null +++ b/docs/man/arg_match.html @@ -0,0 +1,959 @@ + + + + + + + + + +building_block.arg_match – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

building_block.arg_match

+
+ + + +
+ + + + +
+ + + +
+ + +

引数のアサーション

+
+

概要

+

 R言語の rlang::arg_match() をオマージュした関数で、文字列で与えられた引数のアサーションを行います。

+
arg_match(
+    arg: Union[str, Sequence[str], pd.Series, np.ndarray],
+    values: Sequence[str],
+    arg_name: Optional[str] = None,
+    multiple: bool = False,
+    any_missing: bool = False,
+    all_missing: bool = False,
+    nullable: bool = False
+    )
+
+
+

引数 Argument

+
    +
  • arg(必須)str or list of str
     適正かどうかを判断したい引数の値
  • +
  • values(必須):list of str
     引数 arg の適正な値のリスト
  • +
  • arg_namestr
     エラーメッセージに表示する引数の名前。指定されなかった場合(初期設定)、引数 arg に代入されたオブジェクトの名称を表示します。なお、この機能は varname.argname()関数を使って実装されています。
  • +
  • multiplebool
     引数の値として複数の値を許容するかどうかを示すブール値。arg にリストが代入された場合、multiple = False(初期設定)であれば最初の値のみを出力し、multiple = True であればリストの値を全て出力します。
  • +
  • any_missing:bool
    True の場合、欠測値(例:NoneNaNpd.NA など)が引数 arg一部に含まれていても許容されます。
  • +
  • all_missing: bool
    True の場合、すべての要素が欠測値であることを許容します。
  • +
  • nullable: bool
    True の場合、引数そのものが None であることを許容します。
  • +
+
+
+

返り値 Value

+

 引数 arg に代入された値が、values に代入されたリストに含まれていればその値を返し、そうでなければエラーメッセージを出力します。エラーメッセージでは values に代入されたリストの値を arg の適正な値の候補として提示します。

+
+
+

使用例 Examples

+
from py4stats import building_block as build
+
+def my_faivarit(fruits):
+  fruits = build.arg_match(
+      fruits, arg_name = 'fruits',
+      values = ['apple', 'orange', 'grape'], 
+      multiple = False
+      )
+  return fruits
+
+my_faivarit('apple')
+#> 'apple'
+
+my_faivarit('orang')
+#> ValueError: `fruits` must be one of 'apple', 'orange' or 'grape', not 'orang'.
+#>              Did you mean 'orange'?
+
+my_faivarit('ap')
+#> ValueError: `fruits` must be one of 'apple', 'orange' or 'grape', not 'ap'.
+#>              Did you mean 'apple' or 'grape'?
+
# arg に list を指定した場合
+# 初期設定では1つ目の要素だけ使用されます。
+my_faivarit(['apple', 'orange'])
+#> 'apple'
+
+# multiple = True として再度関数を定義
+def my_faivarit2(fruits):
+  fruits = build.arg_match(
+      fruits, arg_name = 'fruits',
+      values = ['apple', 'orange', 'grape'], 
+      multiple = True
+      )
+  return fruits
+
+my_faivarit2(['apple', 'orange'])
+#> ['apple', 'orange']
+
+my_faivarit2(['apple', 'orang'])
+#> ValueError: `fruits` must be one of 'apple', 'orange' or 'grape', not 'orang'.
+#>              Did you mean 'orange'?
+

 Py4Stats では eda_tools.tabyl()regression_tools.compare_ols() など、文字列で指定する引数をもつ関数で、引数のアサーションに build.arg_match() を使用しています。

+
import py4stats as py4st
+import pandas as pd
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込
+
+py4st.tabyl(penguins, 'island', 'species', normalize = 'ind')
+#> ValueError: `normalize` must be one of 'index', 'columns' or 'all', not 'ind'.
+#>              Did you mean 'index'?
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/assert_dtype.html b/docs/man/assert_dtype.html new file mode 100644 index 0000000..e3f45a1 --- /dev/null +++ b/docs/man/assert_dtype.html @@ -0,0 +1,1034 @@ + + + + + + + + + +building_block.assert_dtypes – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

building_block.assert_dtypes

+
+ + + +
+ + + + +
+ + + +
+ + +

データ型による引数のアサーション

+
+

概要

+

 R言語の checkmate パッケージの関数群をオマージュした、引数に代入された値が想定されたデータ型ではないときにエラーを出力する関数です。

+
assert_character(
+    arg: Any, 
+    arg_name: Optional[str] = None,
+    len_arg: Optional[int] = None,
+    len_min: int = 1,
+    len_max: Optional[int] = None,
+    any_missing: bool = False,
+    all_missing: bool = False,
+    nullable: bool = False,
+    scalar_only: bool = False
+    )
+
+assert_logical(
+    arg: Any, 
+    arg_name: Optional[str] = None,
+    len_arg: Optional[int] = None,
+    len_min: int = 1,
+    len_max: Optional[int] = None,
+    any_missing: bool = False,
+    all_missing: bool = False,
+    nullable: bool = False,
+    scalar_only: bool = False
+    )
+
+assert_numeric(
+    arg: Any,
+    arg_name: Optional[str] = None,
+    lower = -float('inf'), 
+    upper = float('inf'), 
+    inclusive: Literal["both", "neither", "left", "right"] = "both",
+    len_arg: Optional[int] = None,
+    len_min: int = 1,
+    len_max: Optional[int] = None,
+    any_missing: bool = False,
+    all_missing: bool = False,
+    nullable: bool = False,
+    scalar_only: bool = False
+    )
+
+assert_integer(
+    arg: Any,
+    arg_name: Optional[str] = None,
+    lower = -float('inf'), 
+    upper = float('inf'), 
+    inclusive: Literal["both", "neither", "left", "right"] = "both",
+    len_arg: Optional[int] = None,
+    len_min: int = 1,
+    len_max: Optional[int] = None,
+    any_missing: bool = False,
+    all_missing: bool = False,
+    nullable: bool = False,
+    scalar_only: bool = False
+    )
+
+assert_count(
+    arg: Any,
+    arg_name: Optional[str] = None,
+    lower = 0, 
+    upper = float('inf'), 
+    inclusive: Literal["both", "neither", "left", "right"] = "both",
+    len_arg: Optional[int] = None,
+    len_min: int = 1,
+    len_max: Optional[int] = None,
+    any_missing: bool = False,
+    all_missing: bool = False,
+    nullable: bool = False,
+    scalar_only: bool = False
+    )
+
+assert_float(
+    arg: Any,
+    arg_name: Optional[str] = None,
+    lower = -float('inf'), 
+    upper = float('inf'), 
+    inclusive: Literal["both", "neither", "left", "right"] = "both",
+    len_arg: Optional[int] = None,
+    len_min: int = 1,
+    len_max: Optional[int] = None,
+    any_missing: bool = False,
+    all_missing: bool = False,
+    nullable: bool = False,
+    scalar_only: bool = False
+    )
+

 それぞれの関数は第一引数 arg に代入された array-like オブジェクトの要素が、次の型ではない場合にエラーを出力します。

+
    +
  • assert_character()str
  • +
  • assert_numeric()int or float
  • +
  • assert_integer()int
  • +
  • assert_count()int
  • +
  • assert_float()float
  • +
+
+
+

引数 Argument

+
    +
  • arg(必須)array-like
     適正かどうかを判断したい引数。検証対象となる引数。スカラー値、または array-like オブジェクト(例:list、NumPy 配列、pandas Series)を指定できます。
  • +
  • arg_namestr
     エラーメッセージに表示する引数の名前。None の場合、可能であれば arg に渡された変数名が自動的に推定されます。なお、この機能は varname.argname()関数を使って実装されています。
  • +
  • lower, upperint or float
     arg に代入されたオブジェクトの要素が取るべき値の最大値と最小値。
  • +
  • inclusive:str
     値の範囲チェックにおいて、境界値を含めるかどうかを表す文字列。
    'both', 'neither', 'left', 'right' から選択できます。
    +
      +
    • 'both'lower <= x <= upper
    • +
    • 'neither'lower < x < upper
    • +
    • 'left'lower <= x < upper
    • +
    • 'right'lower < x <= upper
    • +
  • +
  • len_arg: int 引数の要素数を表す自然数:要素数をこの値と正確に一致させたい場合に指定します。len_arg を指定した場合、引数はちょうどこの個数の要素をもつ必要があります。
     引数の長さは、Nonenp.nan などの欠測値を含む要素数をもとに判定されます。例えば引数の要素が arg = [1, None, 3] のとき、len_arg = 3なら正常として判定され、len_arg = 2 ならエラーが出されます。
  • +
  • len_min, len_max:: int
    許容される最小の要素数と最大の要素数。len_max = None の場合、上限は設けられません。
  • +
  • any_missing:bool
    True の場合、欠測値(例:NoneNaNpd.NA など)が引数 arg一部に含まれていても許容されます。
  • +
  • all_missing: bool
    True の場合、すべての要素が欠測値であることを許容します。
  • +
  • nullable: bool
    True の場合、引数そのものが None であることを許容します。
  • +
  • scalar_only: bool
    True の場合、スカラー値のみを許容します。この場合、1要素であっても、list や配列などの array-like オブジェクトは受け付けません。
  • +
+
+
+

返り値 Value

+

引数 arg に代入されたオブジェクトの全ての要素が、アサーションの条件を満たしていれば何も返さず、そうでなければエラーメッセージを出力します。

+
+
+

使用例 Examples

+
from py4stats import building_block as build
+x = [1, 2, 3]
+y = ['A', 'B', 'C']
+
+build.assert_character(x, arg_name = 'x')
+#> TypeError: Argument `x` must be of type 'str'.
+
+build.assert_character(y, arg_name = 'y')
+
build.assert_numeric(x, arg_name = 'x')
+
+build.assert_numeric(y, arg_name = 'y')
+#> TypeError: Argument `y` must be of type 'int' or 'float' with value(s) -inf <= x <= inf.
+
+z = [0.1, 0.3, 0.6]
+build.assert_numeric(z, arg_name = 'z', lower = 0, upper = 1)
+
+z.extend([2, 3])
+build.assert_numeric(z, arg_name = 'z', lower = 0, upper = 1)
+#> ValueError: Argument `z` must have value 0 <= x <= 1
+#> element '3' and '4' of 'z' not sutisfy the condtion.
+
+z = 1
+build.assert_numeric(
+    z, arg_name = 'z', 
+    lower = 0, upper = 1, 
+    inclusive = 'left'
+    )
+#> ValueError: Argument `z` must have value 0 <= x < 1.
+
+
+

参照

+

 データ型の判定にはこちらの関数を使用しています。

+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/coefplot.html b/docs/man/coefplot.html new file mode 100644 index 0000000..f3ffcb9 --- /dev/null +++ b/docs/man/coefplot.html @@ -0,0 +1,985 @@ + + + + + + + + + +coefplot, mfxplot – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

coefplot, mfxplot

+
+ + + +
+ + + + +
+ + + +
+ + +

回帰分析による推定値の視覚化

+
+

概要

+

グラフ上の縦軸が説明変数、横軸回帰係数の値です。点が回帰係数の推定値を、エラーバー(横棒)が信頼区間を表します。

+
coefplot(
+    mod, 
+    subset = None, 
+    conf_level = [0.95, 0.99], 
+    palette = ['#1b69af', '#629CE7'], 
+    show_Intercept = False,
+    show_vline = True,
+    ax = None,
+    **kwargs
+)
+
+mfxplot(
+    mod, 
+    subset = None, 
+    conf_level = [0.95, 0.99], 
+    at = 'overall',
+    method = 'dydx',
+    dummy = False,
+    palette = ['#1b69af', '#629CE7'], 
+    show_Intercept = False,
+    show_vline = True,
+    ax = None,
+    **kwargs
+)
+
+
+

引数 Argument

+
    +
  • modstatsmodels で作成した回帰分析の結果(必須)。

  • +
  • subset:グラフに回帰係数を表示する説明変数のリスト。指定しなければモデルに含まれる全ての説明変数を使用します。また subset に指定された順番に合わせてグラフ内での回帰係数の並び順が変更されます。

  • +
  • conf.level:信頼区間の計算に用いる信頼係数。1つ目の要素が太い方のエラーバーの幅に、2つ目の要素が細い方のエラーバーの幅に対応します。初期設定は [0.95, 0.99] です。

  • +
  • palette:グラフの描画に使用する色コード。1つ目の要素が太い方のエラーバーの色に、2つ目の要素が細い方のエラーバーの色に対応します。

  • +
  • show_Intercept:切片の係数を表示するかどうか。True だと切片の係数を表示し、False(初期設定)だと表示しません。

  • +
  • show_vline:回帰係数 = 0 の垂直線を表示するかどうか。True (初期設定)を指定すると垂直線を表示し、False を指定すると表示されません。

  • +
  • ax:matplotlib の ax オブジェクト。複数のグラフを並べる場合などに使用します。

  • +
  • at:限界効果の集計方法(mfxplot() のみ)。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 at として渡されます。method = 'coef' を指定した場合、この引数は無視されます。

    +
      +
    • 'overall':各観測値の限界効果の平均値を表示(初期設定)
    • +
    • 'mean':各説明変数の平均値における限界効果を表示
    • +
    • 'median':各説明変数の中央値における限界効果を表示
    • +
    • 'zero':各説明変数の値がゼロであるときの限界効果を表示
    • +
  • +
  • method:推定する限界効果の種類(mfxplot() のみ)。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 method として渡されます。ただし、method = 'coef' を指定した場合には限界効果を推定せずに回帰係数をそのまま表示します。

    +
      +
    • 'coef':回帰係数の推定値を表示
    • +
    • 'dydx':限界効果の値を変換なしでそのまま表。(初期設定)
    • +
    • 'eyex':弾力性 d(lny)/d(lnx) の推定値を表示
    • +
    • 'dyex':準弾力性 dy /d(lnx) の推定値を表示
    • +
    • 'eydx':準弾力性 d(lny)/dx の推定値を表示
    • +
  • +
  • dummy:ダミー変数の限界効果の推定方法(mfxplot() のみ)。もし False (初期設定)であれば、ダミー変数を連続な数値変数として扱います。もし、True であればダミー変数が0から1へと変化したときの予測値の変化を推定します。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 dummy として渡されます。

  • +
+
+
+

使用例

+
import py4stats as py4st
+import statsmodels.formula.api as smf
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+
+
+# 回帰分析の実行
+fit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit()
+fit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()
+
+py4st.coefplot(fit3)
+
+
+

+
coefplot1
+
+
+
plt.rcParams["figure.autolayout"] = True
+
+fig, ax = plt.subplots(1, 2, figsize = (2.2 * 5, 5), dpi = 100)
+
+py4st.coefplot(fit2, ax = ax[0])
+ax[0].set_xlim(-900, 1800)
+
+py4st.coefplot(fit3, ax = ax[1], palette = ['#FF6F91', '#F2E5EB'])
+ax[1].set_xlim(-900, 1800);
+
+
+

+
coefplot2
+
+
+
penguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)
+
+# ロジスティック回帰の実行
+fit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()
+fit_logit2 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm + species', data = penguins).fit()
+
plt.rcParams["figure.autolayout"] = True
+
+fig, ax = plt.subplots(1, 2, figsize = (2.2 * 5, 5), dpi = 100)
+
+py4st.mfxplot(fit_logit1, ax = ax[0])
+ax[0].set_xlim(-0.2, 0.85)
+
+py4st.mfxplot(fit_logit2, ax = ax[1], palette = ['#FF6F91', '#F2E5EB'])
+ax[1].set_xlim(-0.2, 0.85);
+

coefplot3 *** Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/compare_df_cols.html b/docs/man/compare_df_cols.html new file mode 100644 index 0000000..9ea629e --- /dev/null +++ b/docs/man/compare_df_cols.html @@ -0,0 +1,951 @@ + + + + + + + + + +compare_df_cols, compare_df_stats – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

compare_df_cols, compare_df_stats

+
+ + + +
+ + + + +
+ + + +
+ + +

データ型と統計値によるデータフレームの比較

+
+

概要

+

R言語の janitor::compare_df_cols() をオマージュした関数で、compare_df_cols() は複数の pandas.DataFrame に含まれる同じ名前を持つ列同士のデータ型 dtype を比較し、compare_df_stats() は同じ名前を持つ列同士の記述統計量を比較します。

+
compare_df_cols(
+    df_list: Union[List[IntoFrameT], Mapping[str, IntoFrameT]],
+    df_name: Optional[List[str]] = None,
+    return_match: Literal["all", "match", "mismatch"] = 'all',
+    dropna:bool = False,
+    to_native: bool = True
+)
+
+compare_df_stats(
+    df_list: List[IntoFrameT],
+    df_name: Optional[List[str]] = None,
+    return_match: Literal["all", "match", "mismatch"] = "all",
+    stats: Callable[..., Any] = np.mean,
+    rtol: float = 1e-05,
+    atol: float = 1e-08,
+    to_native: bool = True,
+    **kwargs: Any,
+)
+
+
+

引数 Argument

+
    +
  • df_list(必須) A list or dict of IntoFrameT
     列を比較するデータフレームのリストもしくは辞書オブジェクト。辞書が df_name が未指定の場合、辞書の keys を df_name として使用します。
  • +
  • df_name list of str
     表頭に表示するデータフレームの名前。['df1', 'df2'] のように文字列のリストを指定してください。初期設定では、自動的に df1, df2, df3 … と連番が割り当てられます。
  • +
  • return_match str
     出力に反映する変数の範囲を表す文字列。次の値から選択できます。 +
      +
    • 'all'(初期設定): 全ての列を表示。
    • +
    • 'match':全てのデータフレームで dtype が一致している列のみを表示。
    • +
    • 'mismatch':少なくとも1つのデータフレームで dtype が一致していない列のみを表示。
    • +
  • +
  • dropna bool (compare_df_cols() のみ)
     データ型 dtype の一致判定に当たり、NaN を無視するかどうか。初期設定 False の場合、すべてのデータフレームが同名かつ同じデータ型の列を持たない限り、ミスマッチが発生したと判定されます。
  • +
  • stats str or function
     比較に用いる記述統計量を定義する関数。np.mean など values 列を1次元配列として受け取って単一の数値を返す任意の関数が使用できるほか、nw.mean など narwhals.functions モジュールで実装された関数を使用できます。初期設定は np.mean です。
  • +
+
+
+

使用例 Examples

+
import pandas as pd
+import py4stats as py4st
+
+df1 = pd.DataFrame({'x':[1, 2, 3], 'y':[5,   4, 2], 'z':[True, False, True]})
+df2 = pd.DataFrame({'x':[1, 2, 3], 'y':[5.0, 4, 2], 'z':['True', 'False', 'True']})
+
+print(py4st.compare_df_cols([df1, df2]))
+#>   term    df1      df2  match_dtype
+#> 0    x  int64    int64         True
+#> 1    y  int64  float64        False
+#> 2    z   bool   object        False
+

return_match = 'mismatch' を指定すると、データフレームの中で、dtype が一致していないものがある列を返します。

+
print(py4st.compare_df_cols(
+    [df1, df2], return_match = 'mismatch'
+    ))
+#>   term    df1      df2  match_dtype
+#> 1    y  int64  float64        False
+#> 2    z   bool   object        False
+

 py4st.compare_df_stats() は数値変数の記述統計量を比較するため、異なる経路で行われたデータ処理の結果が一致しているかを検証する場合に便利です。

+
from palmerpenguins import load_penguins
+penguins = load_penguins()
+penguins2 = penguins.copy()
+vars = ['flipper_length_mm', 'body_mass_g']
+penguins2.loc[:, vars] = py4st.scale(penguins2.loc[:, vars])
+
+print(
+    py4st.compare_df_stats([penguins, penguins2]).round(2)
+)
+#>                 term      df1      df2  match_stats
+#> 0      bill_depth_mm    17.15    17.15         True
+#> 1     bill_length_mm    43.92    43.92         True
+#> 2        body_mass_g  4201.75     0.00        False
+#> 3  flipper_length_mm   200.92    -0.00        False
+#> 4               year  2008.03  2008.03         True
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/compare_group_stats.html b/docs/man/compare_group_stats.html new file mode 100644 index 0000000..9e4a7cd --- /dev/null +++ b/docs/man/compare_group_stats.html @@ -0,0 +1,1037 @@ + + + + + + + + + +compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff

+
+ + + +
+ + + + +
+ + + +
+ + +

統計量に基づく2グループの比較と差分の可視化

+
+

概要

+

これら関数は、入力された2つのデータフレームについて、各数値変数の統計量に基づいた比較を提供します。

+
compare_group_means(
+    group1: IntoFrameT,
+    group2: IntoFrameT,
+    group_names: Sequence[str] = ('group1', 'group2'),
+    columns: Literal['common', 'all'] = 'all',
+    to_native: bool = True
+    )
+
+compare_group_median(
+    group1: IntoFrameT,
+    group2: IntoFrameT,
+    group_names: Sequence[str] = ('group1', 'group2'),
+    columns: Literal['common', 'all'] = 'all',
+    to_native: bool = True
+    )
+
+plot_mean_diff(
+    group1: IntoFrameT,
+    group2: IntoFrameT,
+    stats_diff: Literal["norm_diff", "abs_diff", "rel_diff"] = "norm_diff",
+    ax: Optional[Axes] = None,
+    )
+
+plot_median_diff(
+    group1: IntoFrameT,
+    group2: IntoFrameT,
+    stats_diff: Literal["abs_diff", "rel_diff"] = "rel_diff",
+    ax: Optional[Axes] = None,
+    )
+
+
+

引数 Argument

+
    +
  • group1(必須)a pandas.DataFrame
     数値変数を含む pandas.DataFrame で group2 との比較対象となるもの
  • +
  • group2(必須)a pandas.DataFrame
     数値変数を含む pandas.DataFrame で group1 との比較対象となるもの
  • +
  • group_names list of str
     表頭に表示するグループの名前。['group1', 'group2'] のように、2つの要素をもつ文字列のリストとして指定してください。
  • +
  • columns str
    2つのグループの結果を結合する際に含める変数を指定します。 +
      +
    • "common": 両方のグループに存在する変数のみが含まれます。
    • +
    • "all": いずれかのグループに存在する全ての変数が含まれます。この場合、一方のグループにのみ存在する変数についての差分統計量は、欠損値(例:NaN または None)となります。
    • +
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
  • stats_diff: strplot_mean_diff() および plot_median_diff() のみ)
     グラフの描画に使用する差分統計量。'norm_diff'plot_mean_diff() のみ)、'abs_diff', 'rel_diff' のいずれかから選ぶことができます。
  • +
+
+
+

返り値 Value

+

 compare_group_means()関数および, compare_group_median() 関数では、次の値をもつ pandas.DataFrame が出力されます。

+
    +
  • group1, group2(初期設定の場合)
     各グループにおける記述統計統計量の値
  • +
  • norm_diffcompare_group_means() のみ)
     標準化された平均値の差で、2つのグループの平均値を \(\bar{X}_1\), \(\bar{X}_2\)、分散を \(s^2_1, s^2_2\) とし、サンプルサイズを \(n_1, n_2\) とするとき、次式のように定義されます。
  • +
+

\[ +\delta = \frac{\bar{X}_1 - \bar{X}_2}{s},~~~~~ s^2 = \frac{(n_1-1)s_1^2 + (n_2-1)s_2^2}{n_1 + n_2 - 2} +\]

+
    +
  • abs_diff
    2つのグループの記述統計量の絶対差
  • +
  • rel_diff
    2つのグループの記述統計量の相対差。2つのグループの記述統計量を \(\bar{X}_1\), \(\bar{X}_2\) とするとき、次式のように定義されます。
  • +
+

\[ +\delta = \cfrac{\bar{X}_1 - \bar{X}_2}{\cfrac{\bar{X}_1 + \bar{X}_2}{2}} += 2 \cdot \frac{\bar{X}_1 - \bar{X}_2}{\bar{X}_1 + \bar{X}_2} +\]

+

plot_mean_diff() 関数および, plot_median_diff() 関数では、グループ別の記述統計両の差をグラフとして可視化します。詳細は使用例を参照して下さい。

+
+
+

使用例 Examples

+
import pandas as pd
+import py4stats as py4st
+from palmerpenguins import load_penguins
+
+penguins = load_penguins().drop('year', axis = 1) # サンプルデータの読み込み
+
res1 = py4st.compare_group_means(
+    penguins.query('species == "Gentoo"'),
+    penguins.query('species == "Adelie"')
+)
+print(res1.round(3))
+#>             variable    group1    group2  norm_diff  abs_diff  rel_diff
+#> 0      bill_depth_mm    14.982    18.346     -3.012     3.364    -0.202
+#> 1     bill_length_mm    47.505    38.791      3.048     8.713     0.202
+#> 2        body_mass_g  5076.016  3700.662      2.868  1375.354     0.313
+#> 3  flipper_length_mm   217.187   189.954      4.180    27.233     0.134
+
res2 = py4st.compare_group_median(
+    penguins.query('species == "Gentoo"'),
+    penguins.query('species == "Adelie"'),
+    group_names = ['Gentoo', 'Adelie']
+)
+print(res2.round(3))
+#>             variable    Gentoo    Adelie  abs_diff  rel_diff
+#> 0      bill_depth_mm    14.982    18.346     3.364    -0.202
+#> 1     bill_length_mm    47.505    38.791     8.713     0.202
+#> 2        body_mass_g  5076.016  3700.662  1375.354     0.313
+#> 3  flipper_length_mm   217.187   189.954    27.233     0.134
+
py4st.plot_mean_diff(
+    penguins.query('species == "Gentoo"'),
+    penguins.query('species == "Adelie"'),
+    stats_diff = 'norm_diff'
+)
+
+
+

+
plot_mean_diff1
+
+
+
py4st.plot_mean_diff(
+    penguins.query('species == "Gentoo"'),
+    penguins.query('species == "Adelie"'),
+    stats_diff = 'abs_diff'
+)
+
+
+

+
plot_mean_diff2
+
+
+
py4st.plot_median_diff(
+    penguins.query('species == "Gentoo"'),
+    penguins.query('species == "Adelie"'),
+    stats_diff = 'rel_diff'
+)
+
+
+

+
plot_median_diff1
+
+
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/compare_mfx.html b/docs/man/compare_mfx.html new file mode 100644 index 0000000..be8e2c2 --- /dev/null +++ b/docs/man/compare_mfx.html @@ -0,0 +1,1067 @@ + + + + + + + + + +compare_mfx – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

compare_mfx

+
+ + + +
+ + + + +
+ + + +
+ + +

限界効果の比較

+
+

概要

+

 sm.glm()の推定結果を計量経済学の実証論文でよく用いられる、回帰分析の結果を縦方向に並べて比較する表を作成します。表のフォーマットについてはR言語の texreg::screenreg()modelsummary::modelsummary()を参考にしています。

+
compare_mfx(
+    list_models, 
+    model_name = None,
+    subset = None,
+    stats = 'std_err',
+    add_stars = True,
+    stats_glance = ['prsquared', 'nobs', 'df'],
+    at = 'overall',
+    method = 'dydx',
+    dummy = False,
+    digits = 4, 
+    table_style = 'two_line',
+    line_break = '\n',
+    **kwargs
+)
+
+
+

引数 Argument

+
    +
  • list_models
    推定結果を表示する分析結果のリスト(必須)。sm.glm()で作成された一般化線形モデルの結果を list_models = [fit1, fit2] のようにリストとして指定してください。

  • +
  • model_namelist of str
    表頭に表示するモデルの名前。['モデル1', 'モデル2'] のように文字列のリストを指定してください。初期設定では、自動的に model 1, model 2, model 3 … と連番が割り当てられます。

  • +
  • subsetlist of str
    表示する回帰係数のリスト。指定しない場合(初期設定)、モデルに含まれる全ての回帰係数が表示されます。内部ではpandas.DataFrame.locメソッドを用いて処理を行っているため、['変数1', '変数2', ...] のような文字列のリスト、[True, False, True, ...] のようなブール値のリストに対応しています。文字列のリストが指定された場合、リストの並び順に合わせて回帰係数が表示されます。

  • +
  • statsstr
    表中の丸括弧 ( ) 内に表示する統計値の設定。次の値が指定できます。

    +
      +
    • 'std_err' 標準誤差(初期設定)
    • +
    • 'p_value' p-値
    • +
    • 'statistics' t統計量
    • +
  • +
  • add_starsbool
    回帰係数の統計的有意性を表すアスタリスク * を表示するかどうかを表すブール値。add_stars = True(初期-設定)なら表示、add_stars = Falseなら非表示となります。table_style'two_line' を指定した場合はアスタリスクは回帰係数の直後に表示され、'one_line' を指定した場合は stats で指定した統計値の後に表示されます。アスタリスクはp-値の値に応じて次のように表示されます。

  • +
  • starsdictp_stars() のみ)
     有意性を示す記号を key に、表示を切り替える閾値を値(value)にもつ辞書オブジェクト。初期設定の stars = None の場合、下記の方式で表示されます。

    +
  • +
  • stats_glance:list of str

  • +
  • 表の下部に追加する当てはまりの尺度の種類を表す文字列のリスト。リストの値には次の値を指定できます。なお、None もしくは空のリスト [ ] が指定された場合には非表示となります。

    +
      +
    • 'rsquared':決定係数
    • +
    • 'rsquared_adj':自由度調整済み決定係数
    • +
    • 'nobs':サインプルサイズ
    • +
    • 'df':モデルの自由度(説明変数の数)
    • +
    • 'sigma':回帰式の標準誤差
    • +
    • 'F_values':全ての回帰係数がゼロであることを帰無仮説とするF検定の統計量
    • +
    • 'p_values':F検定のP-値
    • +
    • 'AIC':赤池情報量基準
    • +
    • 'BIC':ベイズ情報量基準
    • +
  • +
  • digits: int
    回帰係数と統計値について表示する小数点以下の桁数。初期設定は4です。

  • +
  • table_style: str
    表の書式を表す文字列。次の値から選択できます(部分一致可)。

    +
      +
    • 'two_line'回帰係数と統計値を2行に分ける(初期設定)
    • +
    • 'one_line'回帰係数と統計値を1行で表示する
    • +
  • +
  • line_break: str
    table_style = 'two_line' とした場合に使用される改行記号。table_style = 'one_line' とした場合、この引数は無視されます。

  • +
  • at: str
    限界効果の集計方法。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 at として渡されます。method = 'coef' を指定した場合、この引数は無視されます。

    +
      +
    • 'overall':各観測値の限界効果の平均値を表示(初期設定)
    • +
    • 'mean':各説明変数の平均値における限界効果を表示
    • +
    • 'median':各説明変数の中央値における限界効果を表示
    • +
    • 'zero':各説明変数の値がゼロであるときの限界効果を表示
    • +
  • +
  • method: str
    推定する限界効果の種類。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 method として渡されます。ただし、method = 'coef' を指定した場合には限界効果を推定せずに回帰係数をそのまま表示します。

    +
      +
    • 'coef':回帰係数の推定値を表示
    • +
    • 'dydx':限界効果の値を変換なしでそのまま表。(初期設定)
    • +
    • 'eyex':弾力性 d(lny)/d(lnx) の推定値を表示
    • +
    • 'dyex':準弾力性 dy /d(lnx) の推定値を表示
    • +
    • 'eydx':準弾力性 d(lny)/dx の推定値を表示
    • +
  • +
  • dummy: bool
    ダミー変数の限界効果の推定方法を制御するブール値。もし False (初期設定)であれば、ダミー変数を連続な数値変数として扱います。もし、True であればダミー変数が0から1へと変化したときの予測値の変化を推定します。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 dummy として渡されます。

  • +
+
+
+

使用例

+
import py4stats as py4st
+import statsmodels.formula.api as smf
+
+import pandas as pd
+import numpy as np
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+

 py4st.compare_mfx()py4st.compare_ols() の一般化線型モデルバージョンで、初期設定では statsmodels ライブラリの.get_margeff() メソッドから得られた限界効果の推定値を表示します。

+
penguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)
+
+# ロジスティック回帰の実行
+fit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()
+fit_logit2 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm + species', data = penguins).fit()
+
+py4st.compare_mfx([fit_logit1, fit_logit2])
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termmodel 1model 2
body_mass_g-0.0004 ***-0.0003 ***
(0.0000)(0.0000)
bill_length_mm-0.0053-0.0357 ***
(0.0036)(0.0070)
bill_depth_mm-0.1490 ***-0.1098 ***
(0.0051)(0.0175)
species[T.Chinstrap]0.4172 ***
(0.0848)
species[T.Gentoo]0.3527 ***
(0.1308)
prsquared0.56470.6187
nobs342342
df35
+
from great_tables import GT, md, html
+compare_tab = py4st.compare_mfx(
+    [fit_logit1, fit_logit2],
+    model_name = ['ベースモデル', 'species 追加'], # モデル名を変更
+    line_break = '<br>'                         # 改行文字の変更
+)
+
+GT(compare_tab.reset_index())\
+  .tab_header(title = 'ロジットモデルの限界効果')\
+  .tab_source_note(
+      source_note= "Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’"
+      )\
+  .tab_source_note(source_note = '丸括弧 ( ) の値は標準誤差')
+

compare_tab_gt2

+
+
+

補足

+

  table_style = 'two_line' としたとき、初期設定ではの回帰係数とp-値の間に改行記号 '\n'が挿入されます。そのため、print() 関数や display() 関数を使った出力では、改行記号 '\n' がそのまま表示されます。この場合でも、pd.DataFrame.to_excel()pd.DataFrame.to_markdown() を使って Excel ファイルや markdown の表に変換していただくと、改行として反映されます。

+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/compare_ols.html b/docs/man/compare_ols.html new file mode 100644 index 0000000..c6316d2 --- /dev/null +++ b/docs/man/compare_ols.html @@ -0,0 +1,1387 @@ + + + + + + + + + +compare_ols – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

compare_ols

+
+ + + +
+ + + + +
+ + + +
+ + +

回帰係数の比較

+
+

概要

+

 sm.ols()smf.glm() で作成された回帰分析の結果から、推定結果を縦方向に並べて比較する表を作成します。表のフォーマットについてはR言語の texreg::screenreg()modelsummary::modelsummary()を参考にしています。

+
compare_ols(
+    list_models: Sequence[RegressionResultsWrapper],
+    model_name: Optional[Sequence[str]] = None,
+    subset: Optional[Sequence[str]] = None,
+    stats: Literal["std_err", "statistics", "p_value", "conf_int"] = "std_err",
+    add_stars: bool = True,
+    stars: Optional[Mapping[str, float]] = None,
+    stats_glance: Optional[Sequence[str]] = ("rsquared_adj", "nobs", "df"),
+    digits: int = 4,
+    table_style: Literal["two_line", "one_line"] = "two_line",
+    line_break: str = "\n",
+    **kwargs: Any
+)
+
+
+

引数 Argument

+
    +
  • list_modelsSequence[RegressionResultsWrapper]
    推定結果を表示する分析結果のリスト(必須)。sm.ols()smf.ols() で作成された回帰分析の結果を list_models = [fit1, fit2] のようにリストとして指定してください。

  • +
  • model_namelist of str
    表頭に表示するモデルの名前。['モデル1', 'モデル2'] のように文字列のリストを指定してください。初期設定では、自動的に model 1, model 2, model 3 … と連番が割り当てられます。

  • +
  • subsetlist of str
    表示する回帰係数のリスト。指定しない場合(初期設定)、モデルに含まれる全ての回帰係数が表示されます。内部ではpandas.DataFrame.locメソッドを用いて処理を行っているため、['変数1', '変数2', ...] のような文字列のリスト、[True, False, True, ...] のようなブール値のリストに対応しています。文字列のリストが指定された場合、リストの並び順に合わせて回帰係数が表示されます。

  • +
  • statsstr
    表中の丸括弧 ( ) 内に表示する統計値の設定。次の値が指定できます。

    +
      +
    • 'std_err' 標準誤差(初期設定)
    • +
    • 'p_value' p-値
    • +
    • 'statistics' t統計量
    • +
  • +
  • add_starsbool
    回帰係数の統計的有意性を表すアスタリスク * を表示するかどうかを表すブール値。add_stars = True(初期-設定)なら表示、add_stars = Falseなら非表示となります。table_style'two_line' を指定した場合はアスタリスクは回帰係数の直後に表示され、'one_line' を指定した場合は stats で指定した統計値の後に表示されます。アスタリスクはp-値の値に応じて次のように表示されます。

  • +
  • starsdictp_stars() のみ)
     有意性を示す記号を key に、表示を切り替える閾値を値(value)にもつ辞書オブジェクト。初期設定の stars = None の場合、下記の方式で表示されます。

    +
  • +
  • stats_glance:list of str

  • +
  • 表の下部に追加する当てはまりの尺度の種類を表す文字列のリスト。リストの値には次の値を指定できます。なお、None もしくは空のリスト [ ] が指定された場合には非表示となります。

    +
      +
    • 'rsquared':決定係数
    • +
    • 'rsquared_adj':自由度調整済み決定係数
    • +
    • 'nobs':サインプルサイズ
    • +
    • 'df':モデルの自由度(説明変数の数)
    • +
    • 'sigma':回帰式の標準誤差
    • +
    • 'F_values':全ての回帰係数がゼロであることを帰無仮説とするF検定の統計量
    • +
    • 'p_values':F検定のP-値
    • +
    • 'AIC':赤池情報量基準
    • +
    • 'BIC':ベイズ情報量基準
    • +
  • +
  • digits: int
    回帰係数と統計値について表示する小数点以下の桁数。初期設定は4です。

  • +
  • table_style: str
    表の書式を表す文字列。次の値から選択できます(部分一致可)。

    +
      +
    • 'two_line'回帰係数と統計値を2行に分ける(初期設定)
    • +
    • 'one_line'回帰係数と統計値を1行で表示する
    • +
  • +
  • line_break: str
    table_style = 'two_line' とした場合に使用される改行記号。table_style = 'one_line' とした場合、この引数は無視されます。

  • +
+
+
+

使用例 Examples

+
import py4stats as py4st
+import statsmodels.formula.api as smf
+
+import pandas as pd
+import numpy as np
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+
+# 回帰分析の実行
+fit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()
+fit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit()
+fit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()
+
+compare_tab1 = py4st.compare_ols(list_models = [fit1, fit2, fit3]) # 表の作成
+compare_tab1
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termmodel 1model 2model 3
Intercept153.7397-1,742.7202 ***843.9812 **
(268.9012)(313.7697)(403.5956)
species[T.Chinstrap]-885.8121 ***-539.6864 ***-245.1516 ***
(88.2502)(86.9425)(84.5952)
species[T.Gentoo]578.6292 ***1,492.8283 ***1,443.3525 ***
(75.3623)(118.4442)(107.7844)
bill_length_mm91.4358 ***55.6461 ***26.5366 ***
(6.8871)(7.2326)(7.2436)
bill_depth_mm179.0434 ***87.9328 ***
(19.0997)(20.2192)
sex[T.male]437.2007 ***
(49.1098)
rsquared_adj0.78100.82580.8613
nobs342342333
df345
+

py4st.compare_ols() の実行結果は PandasDataFrame として出力されるため、.xlsx. ファイルなどに変換することができます。また、用途に応じて表の体裁を調整できるようにしています。

+
compare_tab2 = py4st.compare_ols(
+    list_models = [fit1, fit2, fit3],
+    model_name = ['基本モデル', '嘴の高さ追加', '性別追加'], # モデル名を変更
+    stats = 'p_value',        # () 内の値をP-値に変更する
+    add_stars = False,        # 有意性のアスタリスクなし
+    table_style = 'one_line', # 表スタイルを1行表示に設定 'one' でも可能
+    digits = 3                # 小数点以下の桁数を3に設定
+    )
+compare_tab2
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
term基本モデル嘴の高さ追加性別追加
Intercept153.740(0.568)-1,742.720(0.000)843.981(0.037)
species[T.Chinstrap]-885.812(0.000)-539.686(0.000)-245.152(0.004)
species[T.Gentoo]578.629(0.000)1,492.828(0.000)1,443.353(0.000)
bill_length_mm91.436(0.000)55.646(0.000)26.537(0.000)
bill_depth_mm179.043(0.000)87.933(0.000)
sex[T.male]437.201(0.000)
rsquared_adj0.7810.8260.861
nobs342342333
df345
+

table_style = 'two_line' のときに使用される改行記号は line_break で指定できます。great_tables モジュールの GT() 関数と併用する場合など、html 形式で出力する場合には line_break = '<br>' を指定します。

+
from great_tables import GT, md, html
+
+compare_tab3 = py4st.compare_ols(
+    list_models = [fit1, fit2, fit3],
+    model_name = ['基本モデル', '嘴の高さ追加', '性別追加'], # モデル名を変更
+    line_break = '<br>'                              # 改行文字の変更
+    )
+
+GT(compare_tab3.reset_index())\
+  .tab_header(title = 'Palmer penguin データを使った回帰分析の結果')\
+  .tab_source_note(
+      source_note= "Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’"
+      )\
+  .tab_source_note(source_note = '( ) の値は標準誤差')
+

compare_tab_gt

+
+

有意性の表示規則の変更

+

py4statsv0.2.0 以降は、stars 引数で有意性の表示規則を変更できるようになりました。

+
stars_dict = {'★★★':0.001, '★★':0.01, '★': 0.05, '.':0.1}
+
+reg.compare_ols(
+    list_models = [fit3],
+    model_name = ['model 3'],
+    stars = stars_dict
+    )
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termmodel 3
Intercept843.9812 ★
(403.5956)
species[T.Chinstrap]-245.1516 ★★
(84.5952)
species[T.Gentoo]1,443.3525 ★★★
(107.7844)
sex[T.male]437.2007 ★★★
(49.1098)
bill_length_mm26.5366 ★★★
(7.2436)
bill_depth_mm87.9328 ★★★
(20.2192)
rsquared_adj0.8613
nobs333
df5
+
+
+

回帰係数の sbusetting

+

引数 subset を使って表示したい回帰係数を指定することで、一部の回帰係数を省略して表記することもできます。

+
# 説明変数に island を追加したモデルを推定
+fit4 = smf.ols(
+    'body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex + island',
+    data = penguins).fit()
+
+var_list = [
+    'species[T.Chinstrap]', 'species[T.Gentoo]',
+    'bill_length_mm', 'bill_depth_mm', 'sex[T.male]'
+    ]
+
+# 全ての回帰係数を表示すると表が長すぎるので、一部を省略します
+compare_tab4 = py4st.compare_ols(
+    list_models = [fit2, fit3, fit4],
+    subset = var_list
+    )
+
+compare_tab4.loc['島ダミー', :] = ['No', 'No', 'Yes']
+
+compare_tab4
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
termmodel 1model 2model 3
species[T.Chinstrap]-539.6864 ***-245.1516 ***-255.2732 ***
(86.9425)(84.5952)(92.4796)
species[T.Gentoo]1,492.8283 ***1,443.3525 ***1,446.1574 ***
(118.4442)(107.7844)(114.1676)
bill_length_mm55.6461 ***26.5366 ***26.6643 ***
(7.2326)(7.2436)(7.2792)
bill_depth_mm179.0434 ***87.9328 ***88.3284 ***
(19.0997)(20.2192)(20.3267)
sex[T.male]437.2007 ***436.0334 ***
(49.1098)(49.4227)
rsquared_adj0.82580.86130.8605
nobs342333333
df457
島ダミーNoNoYes
+

pandas の pandas.DataFrame.query メソッドを使って、次のように説明変数を除外することもできます。

+
compare_tab4 = py4st.compare_ols(
+    list_models = [fit2, fit3, fit4]
+    )
+
+compare_tab4 = compare_tab4\
+  .query('~term.str.contains("Intercept|island")').copy()
+
+compare_tab4.loc['島ダミー', :] = ['No', 'No', 'Yes']
+
+compare_tab4 # 上記のコードと同じ結果
+
+
+
+

補足

+

  table_style = 'two_line' としたとき、初期設定ではの回帰係数とp-値の間に改行記号 '\n'が挿入されます。そのため、print() 関数や display() 関数を使った出力では、改行記号 '\n' がそのまま表示されます。この場合でも、pd.DataFrame.to_excel()pd.DataFrame.to_markdown() を使って Excel ファイルや markdown の表に変換していただくと、改行として反映されます。

+
+
+

参照 see also

+

 一般化線形モデルの限界効果を比較する場合は py4stats.compare_mfx()をご利用ください。

+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/diagnose.html b/docs/man/diagnose.html new file mode 100644 index 0000000..d37e7ea --- /dev/null +++ b/docs/man/diagnose.html @@ -0,0 +1,917 @@ + + + + + + + + + +diagnose – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

diagnose

+
+ + + +
+ + + + +
+ + + +
+ + +

データフレームの概要

+
+

概要

+

R言語の dlookr::diagnose() を再現した関数で、データの全般的な状態についての要約を提供します。

+
diagnose(data: IntoFrameT, to_native: bool = True)
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

返り値

+
    +
  • dtype:該当する列のpandasにおけるデータの型。「〇〇の個数」や「〇〇の金額」といったデータの dtypeobjectString になっていたら、文字列として読み込まれているので要注意です。
  • +
  • missing_count:1列のなかで NaN などの欠測値になっている数
  • +
  • missing_percent:1列のなかで欠測値が占めている割合でmissing_percent = (missing_count / 行数) * 100 として計算されます。もし missing_percent = 100 なら、その列は完全に空白です。
  • +
  • unique_count:その列で重複を除外したユニークな値の数。例えばある列の中身が「a, a, b」であればユニークな値は ab の2つなので unique_count = 2 です。もし unique_count = 1 であれば、その行にはたった1種類の値しか含まれていないことが分かりますし、例えば都道府県を表す列の unique_count が47より多ければ、都道府県以外のものが混ざっていると考えられます。
  • +
  • unique_rate: サンプルに占めるユニークな値の割合。 unique_rate = unique_count / 行数 で計算されます。unique_rate = 1 であれば、全ての行に異なる値が入っています。一般的に、実数値の列は unique_rate が高くなりますが、年齢の「20代」や価格の「200円代」のように階級に分けられている場合には unique_rate が低くなります。
  • +
+
+
+

使用例 Examples

+
import py4stats as py4st
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+
+print(py4st.diagnose(penguins).round(4))
+#>              columns    dtype  missing_count  missing_percent  unique_count  unique_rate
+#> 0            species   object              0           0.0000             3       0.8721
+#> 1             island   object              0           0.0000             3       0.8721
+#> 2     bill_length_mm  float64              2           0.5814           165      47.9651
+#> 3      bill_depth_mm  float64              2           0.5814            81      23.5465
+#> 4  flipper_length_mm  float64              2           0.5814            56      16.2791
+#> 5        body_mass_g  float64              2           0.5814            95      27.6163
+#> 6                sex   object             11           3.1977             3       0.8721
+#> 7               year    int64              0           0.0000             3       0.8721
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/diagnose_category.html b/docs/man/diagnose_category.html new file mode 100644 index 0000000..83593c3 --- /dev/null +++ b/docs/man/diagnose_category.html @@ -0,0 +1,962 @@ + + + + + + + + + +diagnose_category – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

diagnose_category

+
+ + + +
+ + + + +
+ + + +
+ + +

カテゴリー変数の要約

+
+

概要

+

データフレームのカテゴリー変数を要約します。本関数は、カテゴリー情報を表す列(カテゴリ型・文字列型・ブール型)およびダミー変数(値が {0, 1} に制限された整数列)を対象として、欠損率、ユニーク値の数、最頻値、最頻値の頻度と割合、evenness などの指標を提供します。

+
diagnose_category(
+        data: IntoFrameT, 
+        dropna: bool = True, 
+        to_native: bool = True
+        )
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • dropnabool
     欠測値(NaN, None など)を統計値の計算から除外するかどうかを表すブール値。初期設定は True です。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

返り値 Value

+

freq_table()関数は、次の値をもつ DataFrame を出力します。

+
    +
  • variables: 変数(列)名
  • +
  • count: 非欠損値の個数
  • +
  • miss_pct: 欠損率(null_count / N * 100) (* ここで Ndata の行数)
  • +
  • unique: ユニーク値の個数
  • +
  • unique_pct: ユニーク値の割合(unique / N * 100)
  • +
  • mode: 最頻値
  • +
  • mode_freq: 最頻値の度数
  • +
  • mode_pct: 最頻値の割合(mode_freq / N * 100)
  • +
  • evenness: カテゴリー分布の均等度([0, 1] の範囲)
  • +
+
+
+

使用例 Examples

+
import pandas as pd
+import py4stats as py4st
+from palmerpenguins import load_penguins
+
+penguins = load_penguins().drop('year', axis = 1) # サンプルデータの読み込み
+
penguins2 = penguins.copy()
+s = penguins2['body_mass_g']
+penguins2['heavy'] = np.where(s >= s.quantile(0.75), True, False)
+
+print(py4st.diagnose_category(penguins2).round(4))
+#>   variables  count  miss_pct  unique  unique_pct    mode  mode_freq  mode_pct  evenness
+#> 0   species    344    0.0000       3      0.8721  Adelie        152   44.1860    0.9550
+#> 1    island    344    0.0000       3      0.8721  Biscoe        168   48.8372    0.9133
+#> 2       sex    333    3.1977       2      0.5814    male        168   50.4505    0.9999
+#> 3     heavy    344    0.0000       2      0.5814   False        254   73.8372    0.8292
+
+
+

Note

+

evenness は、各列ごとに情報エントロピーを \([0, 1]\) の範囲に正規化した指標です。本実装では、対数の底をカテゴリの個数(unique)に設定することで正規化を行っており、これは底を2とした情報エントロピーを log2(unique) で割ることと同値です。この指標は正規化エントロピー(normalized entropy)としても知られています。

+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/filtering_out.html b/docs/man/filtering_out.html new file mode 100644 index 0000000..fd856be --- /dev/null +++ b/docs/man/filtering_out.html @@ -0,0 +1,962 @@ + + + + + + + + + +filtering_out – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

filtering_out

+
+ + + +
+ + + + +
+ + + +
+ + +

データフレームの行と列の除外

+
+

概要

+

pandasDataFrame.filter() メソッドでは引数 like に文字列を指定することで、列名に特定の文字列を含む列を選択できます。py4st.filtering_out() では、反対に列名に特定の文字列を含む列を除外します。実装の一部はR言語の dplyr::select() を参考にしました。

+
filtering_out(
+    data: IntoFrameT,
+    contains: Optional[str] = None,
+    starts_with: Optional[str] = None,
+    ends_with: Optional[str] = None,
+    axis: Union[int, str] = 'columns',
+    to_native: bool = True,
+)
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • *argsstr / list[str] / narwhals.Expr / narwhals.Selector
    移動したい列を指定します。指定方法は次のとおりです。 +
      +
    • 列名(例:"x"
    • +
    • 列名のリスト(例:["x", "y"]
    • +
    • narwhals の式(Expr)(例:nw.col("x")) *axis = 'columns' の場合のみ
    • +
    • narwhals の Selector (例:ncs.numeric())*axis = 'columns' の場合のみ
    • +
  • +
  • containsstr
     列名(行名)の検索に使用する文字列。内部で使用している pandas.Series.str.contains に渡され、指定された文字列を列名(行名)に含む列(行)を除外します。
  • +
  • starts_withstr
     列名(行名)の検索に使用する文字列。内部で使用している pandas.Series.str.startswith に渡され、指定された文字列で列名(行名)が始まる列(行)を除外します。
  • +
  • ends_withstr
     列名(行名)の検索に使用する文字列。内部で使用している pandas.Series.str.endswith に渡され、指定された文字列で列名(行名)が終わる列(行)を除外します。
  • +
  • axis{0 or 'index', 1 or 'columns'}
    axis = 1 または axis = 'columns' なら列の削除を行い、axis = 0 または axis = 'index' なら行の削除を行います。 このオプションは、data がインデックス属性 (例: pandas.DataFrame) をもつ場合のみ有効です。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

使用例

+
import py4stats as py4st
+import pandas as pd
+import narwhals.selectors as ncs
+from palmerpenguins import load_penguins
+
+penguins = load_penguins().head(3) # サンプルデータの読み込み
+
+print(penguins)
+#>   species     island  bill_length_mm  bill_depth_mm  flipper_length_mm  body_mass_g     sex  year  female
+#> 0  Adelie  Torgersen            39.1           18.7              181.0       3750.0    male  2007       0
+#> 1  Adelie  Torgersen            39.5           17.4              186.0       3800.0  female  2007       1
+#> 2  Adelie  Torgersen            40.3           18.0              195.0       3250.0  female  2007       1
+
# *args で列名を直接指定
+print(py4st.filtering_out(penguins, 'year', 'island', 'sex'))
+#>   species  bill_length_mm  bill_depth_mm  flipper_length_mm  body_mass_g
+#> 0  Adelie            39.1           18.7              181.0       3750.0
+#> 1  Adelie            39.5           17.4              186.0       3800.0
+#> 2  Adelie            40.3           18.0              195.0       3250.0
+
+
+# narwhals.selector の使用例 文字列型の変数を除外
+print(py4st.filtering_out(penguins, ncs.string()))
+#>    bill_length_mm  bill_depth_mm  flipper_length_mm  body_mass_g  year
+#> 0            39.1           18.7              181.0       3750.0  2007
+#> 1            39.5           17.4              186.0       3800.0  2007
+#> 2            40.3           18.0              195.0       3250.0  2007
+
+# 列名に 'length' を含む列を除外
+print(py4st.filtering_out(penguins, contains = 'length'))
+#>   species     island  bill_depth_mm  body_mass_g     sex  year  female
+#> 0  Adelie  Torgersen           18.7       3750.0    male  2007       0
+#> 1  Adelie  Torgersen           17.4       3800.0  female  2007       1
+#> 2  Adelie  Torgersen           18.0       3250.0  female  2007       1
+
+# 列名が 'bill' から始まる列を除外
+print(py4st.filtering_out(penguins, starts_with = 'bill'))
+#>   species     island  flipper_length_mm  body_mass_g     sex  year  female
+#> 0  Adelie  Torgersen              181.0       3750.0    male  2007       0
+#> 1  Adelie  Torgersen              186.0       3800.0  female  2007       1
+#> 2  Adelie  Torgersen              195.0       3250.0  female  2007       1
+
+# 列名が '_mm' で終わる列を除外
+print(py4st.filtering_out(penguins, ends_with = '_mm'))
+#>   species     island  body_mass_g     sex  year  female
+#> 0  Adelie  Torgersen       3750.0    male  2007       0
+#> 1  Adelie  Torgersen       3800.0  female  2007       1
+#> 2  Adelie  Torgersen       3250.0  female  2007       1
+
+
+

Notes

+

axis='index' による行を対象とするフィルタリングは、インデックスの存在に依存します。したがって、pd.DataFrame 以外の行ラベルをもたない DataFrame バックエンドでは、このオプションは利用できません。

+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/freq_table.html b/docs/man/freq_table.html new file mode 100644 index 0000000..efb5706 --- /dev/null +++ b/docs/man/freq_table.html @@ -0,0 +1,958 @@ + + + + + + + + + +freq_table – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

freq_table

+
+ + + +
+ + + + +
+ + + +
+ + +

1変数の度数分布表

+
+

概要

+

R言語のDescTools::Freq()をオマージュした、1変数の度数分布表を計算する関数。度数 freq と相対度数 perc に加えて、それぞれの累積値を計算します。

+
freq_table(
+    data: IntoFrameT,
+    subset: Union[str, Sequence[str]],
+    sort_by: Literal['frequency', 'values'] = 'frequency',
+    descending: bool = False,
+    dropna: bool = False,
+    to_native: bool = True,
+    *,
+    sort: Optional[bool] = None
+)
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • subsetstr or list of str
     集計に使用するデータフレームの列名(必須)。
  • +
  • sort_bystr
     sort_by = 'frequency' なら度数分布表を頻度に応じてソートし、sort_by = 'values' なら subset で指定した列の値に応じてソートします。
  • +
  • descendingbool
     ソートの方式。True なら降順でソートし、False(初期設定)なら昇順でソートします。
  • +
  • dropnabool
     欠測値(NaN, None など)を集計から除外するかどうかを表すブール値。初期設定は False です。
  • +
  • sortDeprecated..
     sort_by の使用を推奨しています。この引数は後方互換性のために保持されおり、指定された場合は FutureWarningが発生します。デフォルトは None です。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

返り値 Value

+

 freq_table()関数は、次の値をもつ DataFrame を出力します。

+
    +
  • freq: 度数
  • +
  • perc: 相対度数
  • +
  • cumfreq: 累積度数
  • +
  • cumperc: 累積相対度数
  • +
+
+
+

使用例

+
import py4stats as py4st
+import pandas as pd
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込
+
+print(py4st.freq_table(penguins, 'species'))
+#>      species  freq      perc  cumfreq   cumperc
+#> 0  Chinstrap    68  0.197674       68  0.197674
+#> 1     Gentoo   124  0.360465      192  0.558140
+#> 2     Adelie   152  0.441860      344  1.000000
+
+print(py4st.freq_table(penguins, ['island', 'species']))
+#>       island    species  freq      perc  cumfreq   cumperc
+#> 0     Biscoe     Adelie    44  0.127907       44  0.127907
+#> 1  Torgersen     Adelie    52  0.151163       96  0.279070
+#> 2      Dream     Adelie    56  0.162791      152  0.441860
+#> 3      Dream  Chinstrap    68  0.197674      220  0.639535
+#> 4     Biscoe     Gentoo   124  0.360465      344  1.000000
+
penguins2 = penguins.assign(bill_length_mm2 = pd.cut(penguins['bill_length_mm'], 6))
+
+print(
+    py4st.freq_table(
+        penguins2, ['species', 'bill_length_mm2'], 
+        sort_by = 'values',  dropna = True
+        )
+    )
+#>       species   bill_length_mm2  freq      perc  cumfreq   cumperc
+#> 0      Adelie  (32.072, 36.683]    36  0.105263       36  0.105263
+#> 1      Adelie  (36.683, 41.267]    89  0.260234      125  0.365497
+#> 2      Adelie   (41.267, 45.85]    25  0.073099      150  0.438596
+#> 3      Adelie   (45.85, 50.433]     1  0.002924      151  0.441520
+#> 4   Chinstrap  (36.683, 41.267]     1  0.002924      152  0.444444
+#> 5   Chinstrap   (41.267, 45.85]    12  0.035088      164  0.479532
+#> 6   Chinstrap   (45.85, 50.433]    29  0.084795      193  0.564327
+#> 7   Chinstrap  (50.433, 55.017]    24  0.070175      217  0.634503
+#> 8   Chinstrap    (55.017, 59.6]     2  0.005848      219  0.640351
+#> 9      Gentoo  (36.683, 41.267]     1  0.002924      220  0.643275
+#> 10     Gentoo   (41.267, 45.85]    39  0.114035      259  0.757310
+#> 11     Gentoo   (45.85, 50.433]    65  0.190058      324  0.947368
+#> 12     Gentoo  (50.433, 55.017]    15  0.043860      339  0.991228
+#> 13     Gentoo    (55.017, 59.6]     3  0.008772      342  1.000000
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/glance.html b/docs/man/glance.html new file mode 100644 index 0000000..7aa8c57 --- /dev/null +++ b/docs/man/glance.html @@ -0,0 +1,923 @@ + + + + + + + + + +glance – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

glance

+
+ + + +
+ + + + +
+ + + +
+ + +

線形モデルの当てはまりの尺度

+
+

概要

+

 R言語の bloom::glance() をオマージュした関数で、sm.ols()smf.logit() などで推定されたモデルを pands.DataFrame に変換します。

+
glance(x)
+
+
+

引数 Argument

+
    +
  • x(必須)
     sm.ols() もしくは smf.logit() などで作成された分析結果のオブジェクト。
  • +
+
+
+

返り値 Value

+

 モデルの当てはまり(goodness of fit)の尺度を各列に持つ pands.DataFrame が出力されます。表示される指標はモデルの種類によって異なります。

+
+
+

使用例 Examples

+
import pandas as pd
+import numpy as np
+from palmerpenguins import load_penguins
+import statsmodels.formula.api as smf
+
+import py4stats as py4st
+penguins = load_penguins() # サンプルデータの読み込み
+
# 線形回帰の場合
+fit_lm1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()
+
+pd.set_option('display.expand_frame_repr', False)
+print(py4st.glance(fit_lm1).round(4))
+#>    rsquared  rsquared_adj  nobs  df     sigma  F_values  p_values        AIC        BIC
+#> 0    0.7829         0.781   342   3  375.3251  406.2735       0.0  5029.1406  5044.4798
+
# ロジスティック回帰の場合
+penguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)
+fit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()
+
+print(py4st.glance(fit_logit1).round(4))
+#>    prsquared   LL-Null  df_null    logLik       AIC      BIC  deviance  df_resid  df_model  nobs
+#> 0     0.5647 -236.8458      341 -103.1079  214.2157  229.555  206.2157       338         3   342
+
+
+

注意点

+

 参考にしたR言語の bloom::glance() は様々な種類のモデルに対応したジェネリック関数として定義されていますが、py4st.glance() は現段階では限られたモデルにしか対応していません。py4st.glance() のメソッドが定義されているオブジェクトのクラスを確認するには次のコードを実行して下さい。

+
list(py4st.glance.registry.keys())
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/heckitmfx_compute.html b/docs/man/heckitmfx_compute.html new file mode 100644 index 0000000..3eb95d1 --- /dev/null +++ b/docs/man/heckitmfx_compute.html @@ -0,0 +1,1002 @@ + + + + + + + + + +heckit_helper.heckitmfx_compute – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

heckit_helper.heckitmfx_compute

+
+ + + +
+ + + + +
+ + + +
+ + +
+

概要

+

 Type2トービットモデルの限界効果を推定します。推定方法についてはダハナ, 勝又(2023, p.136)および Hoffmann, Kassouf(2005)を参照し、関数の実装についてはR言語の heckitmfx::heckitmfx_log() 関数を参考にしています。

+
heckitmfx_compute(
+    model, 
+    exog_select, 
+    exog_outcome, 
+    exponentiate = False
+)
+
+
+

引数 Argument

+
    +
  • model(必須)
      Py4Etrics モジュールの py4etrics.heckit.Heckit() で作成された HeckitResults クラスのオブジェクト
  • +
  • exog_selectpd.DataFrame(必須)
     Type2トービットモデルのうち第1段階の selection equation(選択関数, 就業決定関数)の説明変数からなる pd.DataFrame
  • +
  • exog_outcomepd.DataFrame(必須)
     Type2トービットモデルのうち第2段階の regression equation(賃金関数)の説明変数からなる pd.DataFrame
  • +
+

これらの引数は heckit_helper.Heckit_from_formula() の出力を使用することを想定しています(使用例を参照)。

+
    +
  • exponentiatebool
     推定結果に指数関数を用いた変換を行うかどうかを表す論理値。もし False (初期設定)であれば限界効果と回帰係数の推定値をそのまま出力し、もし True であれば出力されるデータフレームのうち unconditionalconditionalselectionbeta の列について指数関数 \(100[\exp(x - 1)]\) を用いた変換を行います。例えば被説明変数は対数賃金であれば、変換後の限界効果はパーセンテージで表された賃金の変化率として解釈できます。
  • +
+
+
+

返り値 Value

+

 次の列を含む pands.DataFrame が出力されます。

+
    +
  • term(index)
     説明変数の名称
  • +
  • unconditional
     Hoffmann, Kassouf(2005, p.6)の(14)式および(15)式に基づく条件付なしの平均限界効果(unconditional marginal effect)
  • +
  • conditional
     Hoffmann, Kassouf(2005, pp.4-5)の(8)式および(9)式に基づく条件付平均限界効果(conditional marginal effect)
  • +
  • selection
     Hoffmann, Kassouf(2005, p.6)の(14)式および(15)式の第3項に当たる間接効果
  • +
  • beta
     第2段階の regression equation の回帰係数
  • +
  • gamma
     第1段階の selection equation の回帰係数
  • +
+
+
+

使用例 Examples

+

 heckit_helper モジュールはヘックマンの2段階推定(Heckit)を実行を Py4Etrics モジュールの py4etrics.heckit.Heckit() に依存しているため、事前のインストールをお願いします。

+
pip install git+https://github.com/Py4Etrics/py4etrics.git
+

ここでは wooldridge モジュールの mroz データを使い、春山(2023, Chap.24)のモデルを再現します。

+
import pandas as pd
+import wooldridge
+from py4stats import heckit_helper
+
+mroz = wooldridge.data('mroz') # サンプルデータの読み込み
+
+mod_heckit, exog_outcome, exog_select = \
+ heckit_helper.Heckit_from_formula(
+    selection = 'lwage ~ educ + exper + expersq + nwifeinc + age + kidslt6 + kidsge6',
+    outcome = 'lwage ~ educ + exper + expersq',
+    data = mroz
+)
+
+res_heckit = mod_heckit.fit(cov_type_2 = 'HC1')
+
print(heckit_helper.heckitmfx_compute(
+    res_heckit,
+    exog_select = exog_select,
+    exog_outcome = exog_outcome
+    ).round(4))
+#>           unconditional  conditional  selection    beta   gamma
+#> term                                                           
+#> age             -0.0385       0.0010    -0.0395  0.0000 -0.0529
+#> educ             0.2045       0.1067     0.0978  0.1091  0.1309
+#> exper            0.1338       0.0417     0.0922  0.0439  0.1233
+#> expersq         -0.0022      -0.0008    -0.0014 -0.0009 -0.0019
+#> kidsge6          0.0263      -0.0006     0.0269  0.0000  0.0360
+#> kidslt6         -0.6332       0.0157    -0.6489  0.0000 -0.8683
+#> nwifeinc        -0.0088       0.0002    -0.0090  0.0000 -0.0120
+

被説明変数の lwage は対数賃金であるため、exponentiate = True として指数関数 \(100[\exp(x - 1)]\) を使った変換を行うことで、限界効果を賃金の変化率として解釈できるようになります。

+
print(heckit_helper.heckitmfx_compute(
+    res_heckit,
+    exog_select = exog_select,
+    exog_outcome = exog_outcome,
+    exponentiate = True
+    ).round(4))
+#>           unconditional  conditional  selection     beta   gamma
+#> term                                                            
+#> age             -3.7809       0.0954    -3.8725   0.0000 -0.0529
+#> educ            22.6943      11.2606    10.2765  11.5235  0.1309
+#> exper           14.3206       4.2543     9.6555   4.4865  0.1233
+#> expersq         -0.2233      -0.0825    -0.1409  -0.0859 -0.0019
+#> kidsge6          2.6604      -0.0649     2.7271   0.0000  0.0360
+#> kidslt6        -46.9117       1.5782   -47.7365   0.0000 -0.8683
+#> nwifeinc        -0.8730       0.0217    -0.8945   0.0000 -0.0120
+
+
+

注意

+

 heckitmfx_compute() の実装は実験的なものであり、 Stata における margins コマンドなどの既存の手法とは計算結果が一致しない可能性があります。

+
+
+

参考文献

+
    +
  • ダハナ・ウィラワン ドニ, 勝又壮太郎(2023) 『Rによるマーケティング・データ分析: 基礎から応用まで (ライブラリ データ分析への招待 4)』新世社.
  • +
  • 春山鉄源 (2023) 『Pythonで学ぶ入門計量経済学』. https://py4etrics.github.io/index.html
  • +
  • Hoffmann, Rodolfo, and Ana Lucia Kassouf. (2005). Deriving conditional and unconditional marginal effects in log earnings equations estimated by heckman’s procedure. Applied Economics, 37(11), 1303–1311. *** Return to Function reference.
  • +
+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/image/Pareto_plot1.png b/docs/man/image/Pareto_plot1.png new file mode 100644 index 0000000..a3d9d1b Binary files /dev/null and b/docs/man/image/Pareto_plot1.png differ diff --git a/docs/man/image/Pareto_plot2.png b/docs/man/image/Pareto_plot2.png new file mode 100644 index 0000000..82f83fb Binary files /dev/null and b/docs/man/image/Pareto_plot2.png differ diff --git a/docs/man/image/Pareto_plot3.png b/docs/man/image/Pareto_plot3.png new file mode 100644 index 0000000..99c5826 Binary files /dev/null and b/docs/man/image/Pareto_plot3.png differ diff --git a/docs/man/image/coefplot1.png b/docs/man/image/coefplot1.png new file mode 100644 index 0000000..82a4975 Binary files /dev/null and b/docs/man/image/coefplot1.png differ diff --git a/docs/man/image/coefplot2.png b/docs/man/image/coefplot2.png new file mode 100644 index 0000000..7430971 Binary files /dev/null and b/docs/man/image/coefplot2.png differ diff --git a/docs/man/image/coefplot3.png b/docs/man/image/coefplot3.png new file mode 100644 index 0000000..ddcd281 Binary files /dev/null and b/docs/man/image/coefplot3.png differ diff --git a/docs/man/image/plot_Blinder_Oaxaca1.png b/docs/man/image/plot_Blinder_Oaxaca1.png new file mode 100644 index 0000000..8b3dda7 Binary files /dev/null and b/docs/man/image/plot_Blinder_Oaxaca1.png differ diff --git a/docs/man/image/plot_Blinder_Oaxaca2.png b/docs/man/image/plot_Blinder_Oaxaca2.png new file mode 100644 index 0000000..d268b4b Binary files /dev/null and b/docs/man/image/plot_Blinder_Oaxaca2.png differ diff --git a/docs/man/image/plot_category1.png b/docs/man/image/plot_category1.png new file mode 100644 index 0000000..00c95fb Binary files /dev/null and b/docs/man/image/plot_category1.png differ diff --git a/docs/man/image/plot_category2.png b/docs/man/image/plot_category2.png new file mode 100644 index 0000000..4b0b7b8 Binary files /dev/null and b/docs/man/image/plot_category2.png differ diff --git a/docs/man/image/plot_mean_diff1.png b/docs/man/image/plot_mean_diff1.png new file mode 100644 index 0000000..987f93f Binary files /dev/null and b/docs/man/image/plot_mean_diff1.png differ diff --git a/docs/man/image/plot_mean_diff2.png b/docs/man/image/plot_mean_diff2.png new file mode 100644 index 0000000..59cf8db Binary files /dev/null and b/docs/man/image/plot_mean_diff2.png differ diff --git a/docs/man/image/plot_median_diff1.png b/docs/man/image/plot_median_diff1.png new file mode 100644 index 0000000..2891587 Binary files /dev/null and b/docs/man/image/plot_median_diff1.png differ diff --git a/docs/man/image/plot_miss_var1.png b/docs/man/image/plot_miss_var1.png new file mode 100644 index 0000000..7d99d39 Binary files /dev/null and b/docs/man/image/plot_miss_var1.png differ diff --git a/docs/man/image/plot_miss_var2.png b/docs/man/image/plot_miss_var2.png new file mode 100644 index 0000000..125ab48 Binary files /dev/null and b/docs/man/image/plot_miss_var2.png differ diff --git a/docs/man/image/set_miss.png b/docs/man/image/set_miss.png new file mode 100644 index 0000000..38c441d Binary files /dev/null and b/docs/man/image/set_miss.png differ diff --git a/docs/man/is_dtype.html b/docs/man/is_dtype.html new file mode 100644 index 0000000..4c940cd --- /dev/null +++ b/docs/man/is_dtype.html @@ -0,0 +1,932 @@ + + + + + + + + + +building_block.is_dtypes – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

building_block.is_dtypes

+
+ + + +
+ + + + +
+ + + +
+ + +

データ型を判定する論理関数

+
+

概要

+

 代入された値、あるいはリストの要素が特定のデータ型であるかどうかを判定する関数です。基本的には pandas.api.types.is_*() 関数のラッパー関数で、命名規則はR言語の同種の関数に基づいています。

+
is_character(x)
+
+is_logical(x)
+
+is_numeric(x)
+
+is_integer(x)
+
+is_float(x)
+
+
+

引数 Argument

+
    +
  • x(必須)array, list, or pd.Series
  • +
+
+
+

返り値 Value

+

引数 x が次の型であるときに、True を返します。

+
    +
  • is_character()str
  • +
  • is_logical()bool
  • +
  • is_numeric()int, float or bool
  • +
  • is_integer()int or bool
  • +
  • is_float()float
  • +
+
+
+

使用例 Examples

+
from py4stats import building_block as build
+x_str = ['A', 'B']
+x_bool = [True, False, True]
+x_int = [1, 2, 3]
+x_float = [0, 1, 2.1, 0.5]
+x_list = [x_str, x_bool, x_int, x_float]
+
+print([build.is_character(x) for x in x_list])
+#> [True, False, False, False]
+
+print([build.is_logical(x) for x in x_list])
+#> [False, True, False, False]
+
+print([build.is_numeric(x) for x in x_list])
+#> [False, True, True, True]
+
+print([build.is_integer(x) for x in x_list])
+#> [False, False, True, False]
+
+print([build.is_float(x) for x in x_list])
+#> [False, False, False, True]
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/is_dummy.html b/docs/man/is_dummy.html new file mode 100644 index 0000000..1d16ce9 --- /dev/null +++ b/docs/man/is_dummy.html @@ -0,0 +1,946 @@ + + + + + + + + + +is_dummy – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

is_dummy

+
+ + + +
+ + + + +
+ + + +
+ + +

ダミー変数を判定する論理関数

+
+

概要

+

リストや Series の要素が、指定されたダミーコードのみで構成されたダミー変数かどうかを判定します。

+
is_dummy(
+    data: Union[IntoFrameT, IntoSeriesT],
+    cording: Sequence[Any] = (0, 1),
+    dropna: bool = True,
+    to_pd_series: bool = False,
+    **kwargs
+    )
+
+
+

引数 Argument

+
    +
  • data: list, IntoFrameT or IntoSeriesT
    入力データ。list あるいは、narwhals が受け入れ可能な DataFrame もしくは Series 互換オブジェクト
  • +
  • cording: list
    ダミーコードとして許容される値の集合。入力データに含まれる値の集合が、この集合と完全に一致する場合にダミー変数であると判定されます。デフォルトは (0, 1) です。
  • +
  • dropnabool
     欠測値(NaN)をコーディングの判定から除外するかどうかを表すブール値。初期設定は True です。
  • +
  • to_pd_series: bool
    data が DataFrame 場合の戻り値の形式を制御します。 +
      +
    • True の場合:列名をインデックスにもつ pandas.Series を返します
    • +
    • False の場合:各列の判定結果を要素とする list を返します
    • +
  • +
  • **kwargs: 将来の拡張のために予約されたキーワード引数です。
  • +
+
+
+

返り値 Value

+
    +
  • data が Series-like の場合
    +
      +
    • -指定されたダミーコードのみで構成されていれば True、それ以外の場合は False
    • +
  • +
  • data が DataFrame-like の場合
    +
      +
    • to_pd_Series = False のとき:各列ごとの判定結果を要素とする list[bool]
    • +
    • to_pd_Series = True のとき:列名をインデックスにもつ pd.Series
    • +
  • +
+
+
+

使用例 Examples

+
import py4stats as py4st
+import pandas as pd
+from palmerpenguins import load_penguins
+
+penguins = load_penguins() # サンプルデータの読み込み
+
+# ダミー変数の作成
+penguins2 = pd.get_dummies(
+    penguins.loc[:, 'species':'bill_length_mm'], 
+    columns = ['species']
+    )
+penguins2['Intercept'] = 1 # 定数列の作成
+penguins2['female'] = penguins['sex'] == 'female' # bool 型の変数を作成
+
+print(py4st.is_dummy(penguins2['species_Adelie']))
+#> True
+

なお、初期設定では bool 型の変数についても True が出力されます。

+
print(py4st.is_dummy(penguins2))
+#> island               False
+#> bill_length_mm       False
+#> species_Adelie        True
+#> species_Chinstrap     True
+#> species_Gentoo        True
+#> Intercept            False
+#> female                True
+#> Name: 0, dtype: bool
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/miscellaneous.html b/docs/man/miscellaneous.html new file mode 100644 index 0000000..d900f61 --- /dev/null +++ b/docs/man/miscellaneous.html @@ -0,0 +1,931 @@ + + + + + + + + + +building_block.style_number, style_percent, style_percent – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

building_block.style_number, style_percent, style_percent

+
+ + + +
+ + + + +
+ + + +
+ + +

数字のフォーマットを変更する関数

+
+

概要

+
style_number(x, digits = 2, big_mark = ',')
+
+style_currency(x, symbol = '$', digits = 0, big_mark = ',')
+
+style_percent(x, digits = 2, unit = 100, symbol = '%')
+
+
+

引数 Argument

+
    +
  • xscalar or array-like of int or float
  • +
  • p_valuescalar or array-like of int or float
  • +
  • digitsint
    小数点以下の桁数
  • +
  • big_markint
    3桁毎の桁区切りに使用する記号。カンマ ',', アンダーバー '_', もしくは 非表示 '' から選ぶことができます。
  • +
  • symbolstr
     貨幣記号を表す文字列
  • +
+
+
+

返り値 Value

+

 以下の値をもつ pd.Series を返します。

+
    +
  • building_block.style_number(): 任意の数値に対して、小数点以下を桁数 digits に丸め、3桁区切り記号を通過した値を文字列として返します。f-string によるフォーマット f'{x:{big_mark}.{digits}f}' を用いて実装されています。
  • +
  • building_block.style_currency()build.style_number() と同じく任意の数値に対して、小数点以下を桁数 digits に丸め、3桁区切り記号を通過した値を文字列として返しますが、さらに貨幣記号を追加します。f-string によるフォーマット f'{symbol}{x:{big_mark}.{digits}f}' を用いて実装されています。
  • +
  • building_block.style_percent(): 任意の数値をパーセンテージ表示に変換した値を文字列として返します。f-string によるフォーマット f'{x:,.{digits}%}' を用いて実装されています。
  • +
+
+
+

使用例 Examples

+
import numpy as np
+from py4stats import building_block as build
+
+x = [2000, 1000, 0.5, 0.11, 0.123]
+
+print(build.style_number(x).to_list())
+#> ['2,000.00', '1,000.00', '0.50', '0.11', '0.12']
+
+print(build.style_number(x, big_mark = '').to_list())
+#> ['2000.00', '1000.00', '0.50', '0.11', '0.12']
+
+print(build.style_currency(x).to_list())
+#> ['$2,000', '$1,000', '$0', '$0', '$0']
+
pct = [0.11, 0.06, 0.05, 0.01, 0.00234]
+
+print(build.style_percent(pct).to_list())
+#> ['11.00%', '6.00%', '5.00%', '1.00%', '0.23%']
+
+print(build.style_percent(pct, unit = 1).to_list())
+#> ['0.11%', '0.06%', '0.05%', '0.01%', '0.00%']
+
+print(build.style_percent(pct, unit = 1000, symbol = '‰').to_list())
+#> ['110.00‰', '60.00‰', '50.00‰', '10.00‰', '2.34‰']
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/oxford_comma.html b/docs/man/oxford_comma.html new file mode 100644 index 0000000..63218f5 --- /dev/null +++ b/docs/man/oxford_comma.html @@ -0,0 +1,915 @@ + + + + + + + + + +oxford_comma – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

oxford_comma

+
+ + + +
+ + + + +
+ + + +
+ + +

文字列のリストから並列文を作成

+
+

概要

+

文字列のリストを与えると、リストの要素を英文における並列文の形に変換する関数です。表記法については Wikipedia Serial comma を参照し、コードについては stack overflow:Grammatical List Join in Python [duplicate] を参照しました。

+
oxford_comma(x, sep_last = 'and', quotation = True)
+
+oxford_comma_and(x, quotation = True)
+
+oxford_comma_or(x, quotation = True)
+
+
+

引数

+
    +
  • xstr or list of str
  • +
  • quotation: bool
     リストの各要素にクオーテーションマーク ’’ を追加するかどうかを表す論理値。True(初期設定)であればクオーテーションマークを追加し、False であれば追加しません。
  • +
  • sep_last: str oxford_comma() のみ
     リストの最後の要素の直前に付加する単語を表す文字列。
  • +
+

なお、oxford_comma_and(x)oxford_comma(x, 'and') と、oxford_comma_or(x)oxford_comma(x, 'or') と同等です。

+
+
+

使用例

+
from py4stats import building_block as build
+x = ['A', 'B', 'C']
+
+print(build.oxford_comma_and(x))
+#> 'A', 'B' and 'C'
+
+print(build.oxford_comma_and(x, quotation = False))
+#> A, B and C
+
+print(build.oxford_comma_or(x))
+#> 'A', 'B' or 'C'
+

リストの要素が1つの場合、あるいは x に文字列が指定された場合はカンマなどを追加せずにそのまま出力します。

+
print(build.oxford_comma_or(['A']))
+#> 'A'
+
+print(build.oxford_comma_or('A'))
+#> 'A'
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/plot_category.html b/docs/man/plot_category.html new file mode 100644 index 0000000..357c49e --- /dev/null +++ b/docs/man/plot_category.html @@ -0,0 +1,965 @@ + + + + + + + + + +plot_category – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

plot_category

+
+ + + +
+ + + + +
+ + + +
+ + +

カテゴリ変数の回答分布を 100% 積み上げ横棒グラフとして描画します。

+
+

概要

+

本関数は、複数のカテゴリ変数について回答分布を集計し、各変数を1本の100%積み上げ横棒グラフとして可視化します。リッカート尺度による設問や、共通のカテゴリをもつ、アンケートの回答データの可視化を主な用途としています。

+
plot_category(
+    data: IntoFrameT,
+    palette: Optional[sns.palettes._ColorPalette] = None,
+    legend_type: Literal['horizontal', 'vertical', 'none'] = 'horizontal',
+    show_vline: bool = True,
+    ax: Optional[Axes] = None,
+):
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    カテゴリ変数を含む入力データフレーム(1列につき1変数)。 narwhals がサポートする任意のデータフレーム型(例:pandas.DataFramepolars.DataFrame)を指定できます。 すべての列は、同一のカテゴリ体系(共通のカテゴリラベル)を共有している必要があります。 注意pyarrow.Table については、その仕様による機能制限があります。詳細は「注意 Notes」セクションを参照してください。
  • +
  • sort_by: str
    回答カテゴリの並び順を決定する基準。'values':カテゴリの値(ラベル)でソートします。'frequency':出現頻度の高い順にソートします。デフォルトは 'values' です。
  • +
  • palette sns.palettes._ColorPalette:
    回答カテゴリに使用するカラーパレット。 None の場合は、内部でデフォルトの発散型パレットを生成します。 指定する場合は、カテゴリ数と同じ長さの配列である必要があります。 デフォルトは None です。
  • +
  • legend_typestr:
    凡例の配置方法。デフォルトは 'horizontal' です。 +
      +
    • 'horizontal':凡例をグラフ下部に横並びで表示します。
    • +
    • 'vertical':凡例をグラフ右側に縦並びで表示します。
    • +
    • 'none':凡例を表示しません。
    • +
  • +
  • show_vline:bool
    True の場合、x = 0.5(50%)の位置に基準となる垂直線を描画します。 割合の中点を視覚的に示す目的で使用できます。デフォルトは True です。
  • +
  • ax:
    描画先となる matplotlib の Axes。複数のグラフを並べる場合などに使用します。デフォルトの None の場合は、新しい Figure と Axes が作成されます。
  • +
+
+
+

使用例 Example

+
import py4stats as py4st
+import pandas as pd
+import itertools
+
+Q1 = [70 * ['Strongly agree'], 200 * ['Agree'], 235 * ['Disagree'], 149 * ['Strongly disagree']]
+Q2 = [74 * ['Strongly agree'], 209 * ['Agree'], 238 * ['Disagree'], 133 * ['Strongly disagree']]
+Q3 = [59 * ['Strongly agree'], 235 * ['Agree'], 220 * ['Disagree'], 140 * ['Strongly disagree']]
+Q4 = [40 * ['Strongly agree'], 72 * ['Agree'], 266 * ['Disagree'], 276 * ['Strongly disagree']]
+
+data = pd.DataFrame({
+    'I read only if I have to.':list(itertools.chain.from_iterable(Q1)),
+    'Reading is one of my favorite hobbies.':list(itertools.chain.from_iterable(Q2)),
+    'I like talking about books with other people.':list(itertools.chain.from_iterable(Q3)),
+    'For me, reading is a waste of time.':list(itertools.chain.from_iterable(Q4))
+})
+
categ_list = ['Strongly disagree', 'Disagree', 'Agree', 'Strongly agree']
+
+data_pd = data.apply(pd.Categorical, categories = categ_list)
+
+py4st.plot_category(data_pd)
+
+
+

+
plot_category1
+
+
+
import polars as pl
+import textwrap
+
+data_pl = pl.from_pandas(data)
+data_pl = data_pl.with_columns(
+        pl.all().cast(pl.Enum(categ_list))
+    )\
+    .rename(lambda x: textwrap.fill(x, width = 25))
+
+fig, ax = plt.subplots()
+
+py4st.plot_category(
+    data_pl, 
+    palette = sns.color_palette('RdBu', n_colors = 4),
+    ax = ax
+    )
+
+ax.set_title('Survey on attitudes toward reading');
+
+
+

+
plot_category2
+
+
+
+
+

注意 Notes

+
    +
  • sort_by="values" は、カテゴリの順序情報(例:pandasordered categoricalPolarsEnum で定義した順序)を前提に、カテゴリ順で描画します。
  • +
  • 推奨: sort_by=“values” を利用する場合は、入力として pandas.DataFrame(各列を pd.Categorical に設定)または polars.DataFrame(各列を Enum に設定)を推奨します。
  • +
  • polars.Categorical の列では、カテゴリ順が期待通りに保持されず、辞書順(例:Agree, Disagree, …)で描画される場合があります。
  • +
  • pyarrow.Table を入力した場合、sort_by = 'values’dictionary 型の制約によりエラーとなる場合があります。その場合は sort_by="frequency" を使用してください。
  • +
+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/plot_miss_var.html b/docs/man/plot_miss_var.html new file mode 100644 index 0000000..111e83a --- /dev/null +++ b/docs/man/plot_miss_var.html @@ -0,0 +1,930 @@ + + + + + + + + + +plot_miss_var – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

plot_miss_var

+
+ + + +
+ + + + +
+ + + +
+ + +
+

概要

+

R言語の naniar::gg_miss_var() をオマージュした関数で、データフレームの各変数について欠測値の量を横棒グラフとして可視化します。欠損値統計の計算には py4stats.diagnose() を使用しています。

+
plot_miss_var(
+    data: IntoFrameT,
+    values: Literal['missing_percent', 'missing_count'] = 'missing_percent', 
+    sort: bool = True, 
+    miss_only: bool = False, 
+    top_n: Optional[int] = None,
+    fontsize: int = 12,
+    ax: Optional[Axes] = None,
+    color: str = '#478FCE',
+    **kwargs: Any
+)
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • normalizestr
     グラフに表示する値の種類。 +
      +
    • missing_percent 列毎の欠測率をパーセンテージで表示します。
    • +
    • columns 列毎の欠測数を表示します。
    • +
  • +
  • sortbool
    プロット前に選択した指標で列をソートするかどうか。初期設定は True です。。
  • +
  • miss_onlybool
    欠測値を含まない列を除外するかどうか。True だと欠測値を含まない列を除外し、False(初期設定)だと省略せずに全ての列を表示します。
  • +
  • top_nint
    棒グラフを表示するグラフの個数。top_n = None(初期設定)の場合、すべての棒グラフを表示し、整数値が指定された場合、欠測率(数)の上位 top_n 件が表示されます。
  • +
  • ax
     matplotlib の ax オブジェクト。複数のグラフを並べる場合などに使用します。
  • +
  • fontsizeint
     軸ラベルなどのフォントサイズ。
  • +
  • palettelist of str
     グラフの描画に使用する色コード。棒グラフの色に対応します。
  • +
+
+
+

使用例 Example

+
import py4stats as py4st
+import pandas as pd
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込
+
+py4st.plot_miss_var(penguins)
+
+
+

+
plot_miss_var1
+
+
+
py4st.plot_miss_var(penguins, values = 'missing_count', miss_only = True)
+
+
+

+
plot_miss_var2
+
+
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/point_range.html b/docs/man/point_range.html new file mode 100644 index 0000000..97e956d --- /dev/null +++ b/docs/man/point_range.html @@ -0,0 +1,946 @@ + + + + + + + + + +mean_qi median_qi mean_ci – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

mean_qi median_qi mean_ci

+
+ + + +
+ + + + +
+ + + +
+ + +

数値変数の点推定と区間推定

+
+

概要

+

R言語の ggdist::mean_qi() をオマージュした数値変数の点推定と区間推定を行う関数です。

+
mean_qi(
+    data: Union[IntoFrameT, SeriesT],
+    width: float = 0.975,
+    interpolation: str = 'midpoint',
+    to_native: bool = True
+)
+mean_qi(
+    data: Union[IntoFrameT, SeriesT],
+    width: float = 0.975,
+    interpolation: str = 'midpoint',
+    to_native: bool = True
+)
+
+median_qi(
+    data: Union[IntoFrameT, IntoSeriesT],
+    width: float = 0.975,
+    interpolation: str = 'midpoint',
+    to_native: bool = True
+)
+
+mean_ci(
+    data: Union[IntoFrameT, IntoSeriesT],
+    width: float = 0.975,
+    to_native: bool = True
+)
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT or IntoSeriesT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame もしくは Series 互換オブジェクト (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • widthfloat
     分位点区間の幅、もしくは信頼区間の計算に用いる信頼係数。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

使用例 Examples

+
import py4stats as py4st
+import pandas as pd
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+
+print(py4st.mean_qi(penguins['bill_length_mm']).round(2))
+#>          variable   mean  lower  upper
+#> 0  bill_length_mm  43.92   34.8   53.1
+
+
+print(py4st.median_qi(penguins['bill_length_mm']).round(2))
+#>          variable  median  lower  upper
+#> 0  bill_length_mm   44.45   34.8   53.1
+
+print(py4st.mean_ci(penguins['bill_length_mm']).round(2))
+#>          variable   mean  lower  upper
+#> 0  bill_length_mm  43.92  43.26  44.58
+
+print(py4st.mean_ci(penguins[['bill_length_mm', 'bill_depth_mm']]).round(2))
+#>          variable   mean  lower  upper
+#> 0  bill_length_mm  43.92  43.26  44.58
+#> 1   bill_depth_mm  17.15  16.91  17.39
+
+print(penguins.groupby('species')[['bill_length_mm']].apply(py4st.median_qi).round(2))
+#>                    variable  median  lower  upper
+#> species                                          
+#> Adelie    0  bill_length_mm   38.80  34.05  44.10
+#> Chinstrap 0  bill_length_mm   49.55  42.45  55.00
+#> Gentoo    0  bill_length_mm   47.30  42.65  53.85
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/predicate_str.html b/docs/man/predicate_str.html new file mode 100644 index 0000000..7240dc9 --- /dev/null +++ b/docs/man/predicate_str.html @@ -0,0 +1,977 @@ + + + + + + + + + +is_number, is_ymd, is_ymd_like – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

is_number, is_ymd, is_ymd_like

+
+ + + +
+ + + + +
+ + + +
+ + +

文字列のフォーマットに判定する論理関数

+
+

概要

+

Series の要素が、特定のフォーマットにそった文字列かどうかを判定する関数です。

+
is_number(
+  data:IntoSeriesT, 
+  na_default:bool = True, 
+  to_native: bool = True
+  )
+
+is_ymd(
+  data:IntoSeriesT, 
+  na_default:bool = True, 
+  to_native: bool = True
+  )
+
+is_ymd_like(
+  data:IntoSeriesT, 
+  na_default:bool = True, 
+  to_native: bool = True
+  )
+
    +
  • py4stats.is_number():与えられた文字列が数字かどうかを判定します。
  • +
  • py4stats.is_ymd():与えられた文字列が yyyy-mm-dd フォーマットにそった値かどうかを判定します。
  • +
  • py4stats.is_ymd_like():与えられた文字列が’2024年3月3日’ のような yyyy-mm-dd に近いフォーマットの値かどうかを判定します。
  • +
+
+
+

引数 Argument

+
    +
  • dataIntoSeriesT(必須)
  • +
  • 入力データ。narwhals が受け入れ可能な Series 互換オブジェクト (例:pandas.Seriespolars.DataFramepyarrow.Table)を指定できます。
  • +
  • na_defaultbool
     NA値に対して関数が返す値。na_default = True (初期設定)であれば NoneNaN には True を返し、na_default = False であれば False が返します。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

使用例

+
import py4stats as py4st
+import pandas as pd
+import numpy as np
+
+s = pd.Series([
+    '123', "0.12", "1e+07", '-31', '2個', '1A',
+    "2024-03-03", "2024年3月3日", "24年3月3日", '令和6年3月3日',
+    '0120-123-456', "apple", "不明", None, np.nan
+    ])
+
+print(s[py4st.is_number(s)])
+#> 0       123
+#> 1      0.12
+#> 2     1e+07
+#> 3       -31
+#> 13     None
+#> 14      NaN
+#> dtype: object
+
+print(s[py4st.is_ymd(s)])
+#> 6     2024-03-03
+#> 13          None
+#> 14           NaN
+#> dtype: object
+
+print(s[py4st.is_ymd_like(s)])
+#> 6     2024-03-03
+#> 7      2024年3月3日
+#> 8        24年3月3日
+#> 9       令和6年3月3日
+#> 13          None
+#> 14           NaN
+#> dtype: object
+

 実践的な使用例として「厚生労働省 4.食中毒統計資料」のうち、2020年の食中毒事件一覧を考えます。東京都のデータを取り出て'摂食者数'の列を見ると、数字が並んでいるものの dtypeobject となっており、数字ではない値が含まれていることが疑われます。

+
# 厚生労働省:食中毒統計資料より
+data = pd.read_excel('https://www.mhlw.go.jp/content/R2itiran.xlsx', header = 1)\
+  .query('都道府県名等.str.contains("東京")')
+
+print(data['摂食者数'])
+#> 280    41
+#> 281    86
+#> 282     3
+#> 283    10
+#> 284     3
+#>        ..
+#> 381     2
+#> 382     2
+#> 383     4
+#> 384     6
+#> 385     4
+#> Name: 摂食者数, Length: 106, dtype: object
+

eda.is_number() を使うと数字以外にどのような値が含まれているかを確認できるため、これをもとに「不明」となっている部分は NaN に置き換えるなどの対処法が考えられます。

+
print(data.loc[~py4st.is_number(data['摂食者数']), '摂食者数'])
+#> 285    不明
+#> 315    不明
+#> 374    不明
+#> 375    不明
+#> 377    不明
+#> 378    不明
+#> 379    不明
+#> 380    不明
+#> Name: 摂食者数, dtype: object
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/relocate.html b/docs/man/relocate.html new file mode 100644 index 0000000..2e6994b --- /dev/null +++ b/docs/man/relocate.html @@ -0,0 +1,968 @@ + + + + + + + + + +relocate – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

relocate

+
+ + + +
+ + + + +
+ + + +
+ + +

データフレームの列を削除することなく並び替える関数

+
+

概要

+

relocate() 関数は、データフレームに含まれる列を削除することなく並び替えるための関数です。指定した列(1 列または複数列)を、先頭・特定の列の前・特定の列の後に移動させることができます。本関数は、R の dplyr:relocate() に近い操作感を Python で提供することを目的としています。列の指定には、列名(文字列)だけでなく、narwhals の式(Expr)や Selector を利用でき、柔軟な列選択

+
relocate(
+      data: IntoFrameT, 
+      *args: Union[str, List[str], narwhals.Expr, narwhals.selectors.Selector], 
+      before: Optional[str] = None,
+      after: Optional[str] = None,
+      place: Optional[Literal["first", "last"]] = None,
+      to_native: bool = True
+    ):
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。

  • +
  • *argsstr / list[str] / narwhals.Expr / narwhals.Selector
    移動したい列を指定します。指定方法は次のとおりです。

    +
      +
    • 列名(例:"x"
    • +
    • 列名のリスト(例:["x", "y"]
    • +
    • narwhals の式(Expr)(例:nw.col("x")
    • +
    • narwhals の Selector (例:ncs.numeric()
    • +
    +

    指定した順序は、移動後の列順にもそのまま反映されます。

  • +
  • beforestr, optional)
    args で指定された列を、この列の直前に移動します。
    after と同時に指定することはできません。デフォルトは None です。

  • +
  • afterstr, optional)
    args で指定された列を、この列の直後に移動します。
    before と同時に指定することはできません。デフォルトは None です。

  • +
  • placestr, optional)
    *args で指定された列の、配置場所を指定します。

    +
      +
    • "first": 選択した列をデータフレームの先頭(最も左)に配置します。
    • +
    • "last": 選択した列をデータフレームの末尾(最も右)に配置します。 place 引数は before または after と同時に指定することはできません。 未指定(None)の場合は "first" と同じ挙動になります。
    • +
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。

  • +
+
+

返り値

+
    +
  • IntoFrameT
    入力データフレームと同じ列を保持したまま、指定されたルールに従って並び替えられたデータフレームを返します。
  • +
+
+
+
+

使用例 Example

+
import py4stats as py4st
+import pandas as pd
+import narwhals.selectors as ncs
+from palmerpenguins import load_penguins
+
+penguins_mini = py4st.filtering_out(penguins, starts_with = 'bill').head(3)
+print(penguins_mini)
+#>   species     island  flipper_length_mm  body_mass_g     sex  year
+#> 0  Adelie  Torgersen              181.0       3750.0    male  2007
+#> 1  Adelie  Torgersen              186.0       3800.0  female  2007
+#> 2  Adelie  Torgersen              195.0       3250.0  female  2007
+
# *args に指定した列は最前列に移動します
+print(py4st.relocate(penguins_mini, 'year', 'sex'))
+#>    year     sex species     island  flipper_length_mm  body_mass_g
+#> 0  2007    male  Adelie  Torgersen              181.0       3750.0
+#> 1  2007  female  Adelie  Torgersen              186.0       3800.0
+#> 2  2007  female  Adelie  Torgersen              195.0       3250.0
+
+# ncs.numeric() を使うことで、数値変数を指定できます
+print(py4st.relocate(penguins_mini, ncs.numeric()))
+#>    flipper_length_mm  body_mass_g  year species     island     sex
+#> 0              181.0       3750.0  2007  Adelie  Torgersen    male
+#> 1              186.0       3800.0  2007  Adelie  Torgersen  female
+#> 2              195.0       3250.0  2007  Adelie  Torgersen  female
+
+# year 列を island 列の直前に移動
+print(py4st.relocate(penguins_mini, 'year', before = 'island'))
+#>   species  year     island  flipper_length_mm  body_mass_g     sex
+#> 0  Adelie  2007  Torgersen              181.0       3750.0    male
+#> 1  Adelie  2007  Torgersen              186.0       3800.0  female
+#> 2  Adelie  2007  Torgersen              195.0       3250.0  female
+
+# year 列を island 列の直後に移動
+print(py4st.relocate(penguins_mini, 'year', after = 'island'))
+#>   species     island  year  flipper_length_mm  body_mass_g     sex
+#> 0  Adelie  Torgersen  2007              181.0       3750.0    male
+#> 1  Adelie  Torgersen  2007              186.0       3800.0  female
+#> 2  Adelie  Torgersen  2007              195.0       3250.0  female
+
+#.  place = 'last' で最後列に移動
+print(py4st.relocate(penguins_mini, 'year', place = 'last'))
+#>   species     island  flipper_length_mm  body_mass_g     sex  year
+#> 0  Adelie  Torgersen              181.0       3750.0    male  2007
+#> 1  Adelie  Torgersen              186.0       3800.0  female  2007
+#> 2  Adelie  Torgersen              195.0       3250.0  female  2007
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/remove_empty_constant.html b/docs/man/remove_empty_constant.html new file mode 100644 index 0000000..7fff66e --- /dev/null +++ b/docs/man/remove_empty_constant.html @@ -0,0 +1,991 @@ + + + + + + + + + +remove_empty, remove_constant – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

remove_empty, remove_constant

+
+ + + +
+ + + + +
+ + + +
+ + +

データフレームの空白列および、定数列の削除

+
+

概要

+

py4stats.remove_empty()はR言語の janitor:remove_empty() をオマージュした関数で、全ての要素が NaN である列や行をデータフレームから除外します py4stats.remove_constant() はR言語の janitor:remove_constant() をオマージュした関数で、1種類だけの要素からなる列をデータフレームから除外します。

+
remove_empty(
+    data: IntoFrameT,
+    cols: bool = True,
+    rows: bool = True,
+    cutoff: float = 1.0,
+    quiet: bool = True,
+    to_native: bool = True,
+    **kwargs: Any
+) 
+
+remove_constant(
+    data: IntoFrameT,
+    quiet: bool = True,
+    to_native: bool = True,
+    dropna = False,
+    **kwargs: Any
+)
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • colsbool
     空白列を削除するかどうかを表すブール値(remove_empty() のみ)。True(初期設定) なら空白列を削除し、Falseなら全ての要素が NaN の列があっても削除しません。
  • +
  • rowsbool
     空白行を削除するかどうかを表すブール値(remove_empty() のみ)。True(初期設定) なら空白行を削除し、Falseなら全ての要素が NaN の行があっても削除しません。
  • +
  • cutofffloat
     列(行)の削除を行うかどうかを判定する欠測率の閾値(remove_empty() のみ)。ある列(行)における NaN の割合が >= cutoff のとき、その列(行)を削除します。初期設定は1で全ての要素が NaN の列(行)のみ削除しますが、例えば cutoff = 0.9 とすることで NaN の割合9が割以上の列(行)を削除できます。
  • +
  • quietbool
     削除した列(行)を報告するかどうかを表すブール値。quiet = True(初期設定) であれば何も報告せずに削除だけ行い、quiet = False なら、削除した列(行)の数と列名(行名)を報告します。
  • +
  • dropnabool
     ユニーク値の数を計算する際に、NaN を除外するかどうかを表すブール値(remove_constant() のみ)。dropna = True だと NaN を除外し、dropna = False(初期設定)だと NaN を除外しません。データフレームに NaN と、 NaN ではない1種類の値からなる列がある場合、dropna = False だと削除されず、dropna = True だと削除されます。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

使用例 Example

+

py4stats.remove_empty() の使用例。

+
import py4stats as py4st
+import pandas as pd
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込み
+
+penguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy()
+# 空白列を作成
+penguins2.loc[:, 'empty'] = np.nan
+# 空白行を作成
+penguins2.loc[344, :] = np.nan
+
+print(penguins2.tail(3))
+#>        species  body_mass_g  empty
+#> 342  Chinstrap       4100.0    NaN
+#> 343  Chinstrap       3775.0    NaN
+#> 344        NaN          NaN    NaN
+
# 完全に空白な行と列を削除。
+print(py4st.remove_empty(penguins2, quiet = False).tail(3))
+#> Removing 1 empty column(s) out of 3 columns(Removed: empty).
+#> Removing 1 empty row(s) out of 345 rows(Removed: 344).
+#>        species  body_mass_g
+#> 341  Chinstrap       3775.0
+#> 342  Chinstrap       4100.0
+#> 343  Chinstrap       3775.0
+
+# 完全に空白な列のみ削除。
+print(py4st.remove_empty(penguins2, rows = False, quiet = False).tail(3))
+#> Removing 1 empty column(s) out of 3 columns(Removed: empty).
+#>        species  body_mass_g
+#> 342  Chinstrap       4100.0
+#> 343  Chinstrap       3775.0
+#> 344        NaN          NaN
+
+# 完全に空白な行のみ削除。
+print(py4st.remove_empty(penguins2, cols = False, quiet = False).tail(3))
+#> Removing 1 empty row(s) out of 345 rows(Removed: 344).
+#>        species  body_mass_g  empty
+#> 341  Chinstrap       3775.0    NaN
+#> 342  Chinstrap       4100.0    NaN
+#> 343  Chinstrap       3775.0    NaN
+
# quiet = True の場合
+print(py4st.remove_empty(penguins2).tail(3))
+#>        species  body_mass_g
+#> 341  Chinstrap       3775.0
+#> 342  Chinstrap       4100.0
+#> 343  Chinstrap       3775.0
+

py4stats.remove_constant() の使用例。

+
penguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy()
+penguins2.loc[:, 'constant'] = 'c'
+
+print(penguins2.head(3))
+#>   species  body_mass_g constant
+#> 0  Adelie       3750.0        c
+#> 1  Adelie       3800.0        c
+#> 2  Adelie       3250.0        c
+
+print(py4st.remove_constant(penguins2, quiet = False).head(3))
+#> Removing 1 constant column(s) out of 3 column(s)(Removed: constant).
+#>   species  body_mass_g
+#> 0  Adelie       3750.0
+#> 1  Adelie       3800.0
+#> 2  Adelie       3250.0
+
penguins2.loc[:, 'almost_empty'] = pd.NA
+penguins2.loc[1, 'almost_empty'] = 'c'
+
+# dropna = False なら、almost_empty は削除されません。
+print(py4st.remove_constant(penguins2).head(3))
+#>   species  body_mass_g almost_empty
+#> 0  Adelie       3750.0         <NA>
+#> 1  Adelie       3800.0            c
+#> 2  Adelie       3250.0         <NA>
+
+print(py4st.remove_constant(penguins2, dropna = True).head(3))
+#>   species  body_mass_g
+#> 0  Adelie       3750.0
+#> 1  Adelie       3800.0
+#> 2  Adelie       3250.0
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/scale_wmean.html b/docs/man/scale_wmean.html new file mode 100644 index 0000000..56bac39 --- /dev/null +++ b/docs/man/scale_wmean.html @@ -0,0 +1,986 @@ + + + + + + + + + +weighted_mean, scale, min_max – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

weighted_mean, scale, min_max

+
+ + + +
+ + + + +
+ + + +
+ + +

加重平均と標準化・正規化ユーティリティ

+
+

概要

+

探索的データ解析(EDA)で頻繁に用いられる加重平均の計算および 数値データの正規化・標準化を行う関数群です。 内部では narwhals を利用することで、pandas・polars など複数のデータフレーム/シリーズ実装に対して共通の API を提供しています。

+
weighted_mean(
+    x: IntoSeriesT, 
+    w: IntoSeriesT, 
+    dropna:bool = False
+    ) -> float:
+
+scale(
+    x: Union[IntoSeriesT, pd.DataFrame], 
+    ddof: int = 1, to_native: bool = True
+    ) -> IntoSeriesT:
+
+min_max(
+    x: Union[IntoSeriesT, pd.DataFrame], 
+    to_native: bool = True
+    ) -> IntoSeriesT:
+

weighted_mean(): 数値系列 x と対応する重み w を用いて、加重平均を計算します。欠損値の扱いを制御するためのオプションを備えています。

+

scale(): 数値データを Z スコア標準化します。系列データを主な対象としますが、pandas.DataFrame に対しても専用実装により列単位での標準化をサポートしています。

+

min_max(): 数値データを Min-Max Normarization により \([0, 1]\) の範囲に変換します。scale() と同様に、Series を主対象としつつ pandas.DataFrame にも対応しています。

+
+
+

引数 Argument

+
    +
  • xIntoSeriesT or pd.DataFrame(必須)
    +
      +
    • narwhals が受け入れ可能な Series 互換オブジェクト(例:pandas.Seriespolars.Series)を指定できます。scale()関数と min_max()関数のみ pandas.DataFrame を指定することができ、この場合、各列ごとに変換が適用されます。
    • +
  • +
  • wIntoSeriesT(必須)
    x に対応する重みを表す数値系列。x と同じ長さである必要があります。narwhals が受け入れ可能な Series 互換オブジェクト(例:pandas.Seriespolars.Series)を指定できます。
  • +
  • ddofint, optional)scale(), min_max() のみ
    標準偏差の計算に用いる自由度調整量(delta degrees of freedom)。デフォルトは 1 です。
  • +
  • dropnabool, optional)scale(), min_max() のみ
    True の場合、x または w のいずれかが欠損値(NaN)である観測を計算前に除外します。デフォルトは False です。
  • +
  • to_nativebool, optional)scale(), min_max() のみ
    True の場合、入力と同じ型の Series(e.g. pandas / polars / pyarrow)を返します。
    False の場合、Series を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+
+

返り値 Value

+
    +
  • weighted_mean +
      +
    • float
    • +
    • 加重平均
    • +
  • +
  • scale +
      +
    • IntoSeriesT
    • +
    • 平均 0、標準偏差 1 に標準化された値を返します。
    • +
  • +
  • min_max +
      +
    • IntoSeriesT
    • +
    • 最小値が 0、最大値が 1 となるよう正規化された値を返します。
    • +
  • +
+
+
+

使用例 Example

+
import py4stats as py4st
+import pandas as pd
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込
+
+x1 = penguins.groupby('species')['bill_length_mm'].mean()
+w = penguins.groupby('species')['bill_length_mm'].count()
+
+print(
+    f"{py4st.weighted_mean(x1, w) :.2f}, "
+    f"{penguins['bill_length_mm'].mean() :.2f}"
+)
+#> 43.92, 43.92
+
+x2 = penguins['bill_length_mm']
+z1 = py4st.scale(x2)
+print(f"{z1.mean():.2f}, {z1.std():.2f}")
+#> 0.00, 1.00
+
+z2 = py4st.min_max(x2)
+print(f"{z2.min():.2f}, {z2.max():.2f}")
+#> 0.00, 1.00
+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/set_miss.html b/docs/man/set_miss.html new file mode 100644 index 0000000..14706d2 --- /dev/null +++ b/docs/man/set_miss.html @@ -0,0 +1,950 @@ + + + + + + + + + +set_miss – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

set_miss

+
+ + + +
+ + + + +
+ + + +
+ + +

Series オブジェクトに対する欠測値の挿入

+
+

概要

+

この関数は、Series の非欠測要素のうち、指定された個数または割合を欠測値に置き換えます。narwhals を利用することで、複数の Series バックエンドに対応しています。主にテストデータの作成や、欠測データのシミュレーションを目的とした関数です。

+
set_miss(
+    x: IntoSeriesT, 
+    n: Optional[int] = None,
+    prop: Optional[float] = None, 
+    method: Literal['random', 'first', 'last'] = 'random', 
+    random_state: Optional[int] = None, 
+    na_value: Any = None,
+    to_native: bool = True
+    )
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • nint
    処理後の Series に含まれる欠測値の目標個数。すでに n 個以上の欠測値が含まれている場合は、新たな欠測値は追加されず、警告が発せられます。
  • +
  • propfloat
    処理後の Series に含まれる欠測値の目標割合。0 から 1 の間で指定してください。すでに欠測値の割合が prop 以上である場合は、新たな欠測値は追加されず、警告が発せられます。
  • +
  • method: str: 欠測値に置き換える要素の選択方法。 +
      +
    • 'random': 非欠測要素の中からランダムに選択します。
    • +
    • 'first': Series の先頭から選択します。
    • +
    • 'last': Series の末尾から選択します。 デフォルトは 'random' です。
    • +
  • +
  • random_state (int, optional): method = 'random' の場合に使用する乱数シード。再現性のある結果を得るために指定できます。 method'random' 以外の場合、random_state は無視されます。
  • +
  • na_value: (Any)
    欠測値として使用する値。デフォルトは None です。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型の Series(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.Series を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

使用例 Example

+
import pandas as pd
+from py4stats import set_miss
+s = pd.Series([1, 2, 3, 4, 5])
+py4st.set_miss(s, n = 2, method='first')
+#> 0    NaN
+#> 1    NaN
+#> 2    3.0
+#> 3    4.0
+#> 4    5.0
+#> dtype: float64
+
+s_miss = py4st.set_miss(s, prop=0.4, method='random', random_state=0)
+#> 0    1.0
+#> 1    NaN
+#> 2    3.0
+#> 3    NaN
+#> 4    5.0
+#> dtype: float64
+

x に代入された Series オブジェクトに、既に指定された以上の欠測値が含まれていた場合、次のように欠測値を追加せず UserWarning を出します。

+
py4st.set_miss(s_miss, n = 2)
+#> UserWarning: Already contained 2(>= n) missing value(s) in `x`, 
+#> no additional missing values were added.
+#> 0    1.0
+#> 1    NaN
+#> 2    3.0
+#> 3    NaN
+#> 4    5.0
+#> dtype: float64
+
from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込
+
+penguins['island'] = py4st.set_miss(
+    penguins['island'], 
+    n = 100, method='first'
+    )
+py4st.plot_miss_var(penguins, values = 'missing_count')
+
+
+

+
set_miss
+
+
+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/style_pvalue.html b/docs/man/style_pvalue.html new file mode 100644 index 0000000..11ae672 --- /dev/null +++ b/docs/man/style_pvalue.html @@ -0,0 +1,938 @@ + + + + + + + + + +building_block.style_pvalue, ‘p_stars’ – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

building_block.style_pvalue, ‘p_stars’

+
+ + + +
+ + + + +
+ + + +
+ + +

p-値のフォーマットを変更する関数

+
+

概要

+

 R言語の style_pvalue()gtools::stars.pval() をオマージュした関数でp-値を見やすい形のフォーマットに変換します。

+
style_pvalue(
+    p_value: ArrayLike,
+    digits: int = 3,
+    prepend_p: bool = False,
+    p_min: float = 0.001,
+    p_max: float = 0.9
+    )
+
+p_stars(
+    p_value, 
+    stars = {'***':0.01, '**':0.05, '*':0.1}
+    )
+
+
+

引数 Argument

+
    +
  • p_valuescalar or array-like of int or float
  • +
  • digitsintstyle_pvalue() のみ)
     小数点以下の桁数
  • +
  • prepend_pboolstyle_pvalue() のみ)
     出区力に接頭辞 ’p’ を追加するかどうかを表す論理値。False であれば追加されず、True であれば追加されます。
  • +
  • p_minintstyle_pvalue() のみ)
     p-値を実数値で表示する最小値。p_value がこの値を下回る場合、’<p_min’ もしくは ’p<p_min’ の形で表示されます。
  • +
  • p_maxintstyle_pvalue() のみ)
     p-値を実数値で表示する最大値。p_value がこの値を下回る場合、’>p_max’ もしくは ’p>p_max’ の形で表示されます。
  • +
  • starsdictp_stars() のみ)
     有意性を示す記号を key に、表示を切り替える閾値を値(value)にもつ辞書オブジェクト。初期設定の stars = None の場合、{'***': 0.01, '**': 0.05, '*': 0.1} が使用されます。詳細は下記を参照して下さい。
  • +
+
+
+

返り値 Value

+

 フォーマットされたp-値を表す pd.Series を出力します。building_block.style_pvalue() では引数 p_value に与えられた数値を指定された桁数に丸めた値を表示し、指定された範囲を外れる値については ’<p_min’ や ’>p_max’の書式にへんかんします。  building_block.p_stars()では仮説検定の有意性を示すアスタリスク*` に変換します。初期設定ではアスタリスクはp-値の値に応じて次のように表示されます。

+
    +
  • p ≤ 0.1 *
  • +
  • p ≤ 0.05 **
  • +
  • p ≤ 0.01 ***
  • +
  • p > 0.1 表示なし
  • +
+
+
+

使用例 Examples

+

+from py4stats import building_block as build
+p_value = [
+    0.999, 0.5028, 0.2514, 0.197, 0.10, 
+    0.0999, 0.06, 0.03, 0.002, 0.0002
+    ]
+
+print(build.style_pvalue(p_value).to_list())
+#> ['>0.9', '0.503', '0.251', '0.197', '0.1', '0.1', '0.06', '0.03', '0.002', '<0.001']
+
+print(build.style_pvalue(p_value, prepend_p = True).to_list())
+#> ['p>0.9', 'p=0.503', 'p=0.251', 'p=0.197', 'p=0.1', 'p=0.1', 'p=0.06', 'p=0.03', 'p=0.002', 'p<0.001']
+
+print(build.p_stars(p_value).to_list())
+#> ['', '', '', '', '*', '*', '*', '**', '***', '***']
+
+# R言語の stats::summary.lm() や gtools::stars.pval() を再現する場合。
+stars_dict = {'***':0.001, '**':0.01, '*': 0.05, '.':0.1}
+print(build.p_stars(p_value, stars = stars_dict).to_list())
+#> ['', '', '', '', '.', '.', '.', '*', '**', '***']
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/tabyl.html b/docs/man/tabyl.html new file mode 100644 index 0000000..0ceaab5 --- /dev/null +++ b/docs/man/tabyl.html @@ -0,0 +1,945 @@ + + + + + + + + + +tabyl – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

tabyl

+
+ + + +
+ + + + +
+ + + +
+ + +

レポートティング向けのクロス集計表を作成

+
+

概要

+

データフレームのクロス集計表を作成します。R言語の janitor::tabyl()にいくつかの adorn_ 関数を追加した状態を再現した関数です。初期設定ではクロス集計表の各セルに度数と相対度数を 「度数(相対度数%)`」 の形式で表示します。

+
tabyl(
+    data: IntoFrameT,
+    index: str,
+    columns: str,
+    margins: bool = True,
+    margins_name: str = 'All',
+    normalize: Union[bool, Literal["index", "columns", "all"]] = "index",
+    dropna: bool = False,
+    digits: int = 1,
+    **kwargs: Any
+)
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
    入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • indexstr
     集計に使用するデータフレームの変数名(必須)。
  • +
  • columnsstr
     集計に使用するデータフレームの変数名(必須)。
  • +
  • marginsbool
     行または列の合計を追加するかどうかを表すブール値。初期設定は True です。
  • +
  • margins_namebool
     行や列の合計の名前。初期設定は 'All' です。
  • +
  • dropnabool
      欠測値(NaN)を集計から除外するかどうかを表すブール値。初期設定は False です。
  • +
  • normalizestr
     丸括弧( )に表示する相対度数の計算方式。 +
      +
    • index 各セルの度数を行の和で割り、横方向の相対度数の和が100%になるように計算します。
    • +
    • columns 各セルの度数を行の列で割り、縦方向の相対度数の和が100%になるように計算します。
    • +
    • all 各セルの度数を総度数で割り、全てのセルの相対度数の和が100%になるように計算します。
    • +
  • +
  • digitsint
     丸括弧( )に表示する相対度数の小数点以下の桁数。初期設定は1です。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
+
+
+

使用例

+
import py4stats as py4st
+import pandas as pd
+from palmerpenguins import load_penguins
+penguins = load_penguins() # サンプルデータの読み込
+
+# 横方向の和を100%として計算(初期設定)
+print(py4st.tabyl(penguins, 'island', 'species', normalize = 'index'))
+#> species         Adelie   Chinstrap       Gentoo  All
+#> island                                              
+#> Biscoe      44 (26.2%)    0 (0.0%)  124 (73.8%)  168
+#> Dream       56 (45.2%)  68 (54.8%)     0 (0.0%)  124
+#> Torgersen  52 (100.0%)    0 (0.0%)     0 (0.0%)   52
+#> All        152 (44.2%)  68 (19.8%)  124 (36.0%)  344
+
+# 縦方向の和を100%として計算
+print(py4st.tabyl(penguins, 'island', 'species', normalize = 'columns'))
+#> species        Adelie    Chinstrap        Gentoo          All
+#> island                                                       
+#> Biscoe     44 (28.9%)     0 (0.0%)  124 (100.0%)  168 (48.8%)
+#> Dream      56 (36.8%)  68 (100.0%)      0 (0.0%)  124 (36.0%)
+#> Torgersen  52 (34.2%)     0 (0.0%)      0 (0.0%)   52 (15.1%)
+#> All               152           68           124          344
+
+# 全体の和を100%として計算
+print(py4st.tabyl(penguins, 'island', 'species', normalize = 'all'))
+#> species         Adelie   Chinstrap       Gentoo           All
+#> island                                                       
+#> Biscoe      44 (12.8%)    0 (0.0%)  124 (36.0%)   168 (48.8%)
+#> Dream       56 (16.3%)  68 (19.8%)     0 (0.0%)   124 (36.0%)
+#> Torgersen   52 (15.1%)    0 (0.0%)     0 (0.0%)    52 (15.1%)
+#> All        152 (44.2%)  68 (19.8%)  124 (36.0%)  344 (100.0%)
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/tidy.html b/docs/man/tidy.html new file mode 100644 index 0000000..1b1e37b --- /dev/null +++ b/docs/man/tidy.html @@ -0,0 +1,1000 @@ + + + + + + + + + +tidy, tidy_mfx – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

tidy, tidy_mfx

+
+ + + +
+ + + + +
+ + + +
+ + +

線形モデルの推定結果を DataFrame に集約

+
+

概要

+

 R言語の broom::tidy() をオマージュした関数で、sm.ols()smf.logit() などの推定結果を pands.DataFrame に変換します。py4stats.tidy() は回帰係数と関連する検定結果を表示し、 py4stats.tidy_mfx() は限界効果と関連する検定結果を表示します。

+
tidy(
+  x, 
+  name_of_term = None,
+  conf_level = 0.95,
+  **kwargs
+  )
+
+tidy_mfx(
+  x, 
+  at = 'overall', 
+  method = 'dydx', 
+  dummy = False, 
+  conf_level = 0.95, 
+  **kwargs
+  )
+
+
+

引数 Argument

+
    +
  • x(必須)
     sm.ols()もしくは smf.logit() などで作成された分析結果のオブジェクト。

  • +
  • name_of_termlist of str
     term 列(index) として表示する説明変数の名前のリスト。指定しない場合(初期設定)、モデルの推定に使用された説明変数の名前がそのまま表示されます。

  • +
  • conf_levelfloat
     信頼区間の計算に用いる信頼係数。

  • +
  • at:限界効果の集計方法(tidy_mfx() のみ)。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 at として渡されます。method = 'coef' を指定した場合、この引数は無視されます。

    +
      +
    • 'overall':各観測値の限界効果の平均値を表示(初期設定)
    • +
    • 'mean':各説明変数の平均値における限界効果を表示
    • +
    • 'median':各説明変数の中央値における限界効果を表示
    • +
    • 'zero':各説明変数の値がゼロであるときの限界効果を表示
    • +
  • +
  • method:推定する限界効果の種類(tidy_mfx() のみ)。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 method として渡されます。ただし、method = 'coef' を指定した場合には限界効果を推定せずに回帰係数をそのまま表示します。

    +
      +
    • 'coef':回帰係数の推定値を表示
    • +
    • 'dydx':限界効果の値を変換なしでそのまま表。(初期設定)
    • +
    • 'eyex':弾力性 d(lny)/d(lnx) の推定値を表示
    • +
    • 'dyex':準弾力性 dy /d(lnx) の推定値を表示
    • +
    • 'eydx':準弾力性 d(lny)/dx の推定値を表示
    • +
  • +
  • dummy:ダミー変数の限界効果の推定方法(tidy_mfx() のみ)。もし False (初期設定)であれば、ダミー変数を連続な数値変数として扱います。もし、True であればダミー変数が0から1へと変化したときの予測値の変化を推定します。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 dummy として渡されます。

  • +
+
+
+

返り値 Value

+

 次の列を含む pands.DataFrame が出力されます。

+
    +
  • term(index)
     説明変数の名称
  • +
  • estimate
     回帰係数(tidy()の場合)、もしくは限界効果(tidy_mfx()の場合)の推定値
  • +
  • std_err
    推定値 estimate の標準誤差
  • +
  • statistics
    estimate = 0 を帰無仮説とする仮説検定の標本検定統計量。x に代入されたモデルが sm.ols() によって作成されたものであれば \(t\) 統計量が表示され、sm.glm() によって作成されたものであれば \(z\) 統計量が表示されます。
  • +
  • p_value
    estimate = 0 を帰無仮説とする両側検定の標本p-値
  • +
  • conf_lower
     信頼区間の下側信頼限界
  • +
  • conf_higher
     信頼区間の上側信頼限界
  • +
+
+
+

使用例 Examples

+
import pandas as pd
+import numpy as np
+from palmerpenguins import load_penguins
+import statsmodels.formula.api as smf
+
+from py4stats import regression_tools as reg # 回帰分析の要約
+penguins = load_penguins() # サンプルデータの読み込み
+
# 回帰分析の実行
+fit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()
+
+print(py4st.tidy(fit1).round(4))
+#>                       estimate   std_err  statistics  p_value  conf_lower  conf_higher
+#> term                                                                                  
+#> Intercept             153.7397  268.9012      0.5717   0.5679   -375.1910     682.6704
+#> species[T.Chinstrap] -885.8121   88.2502    -10.0375   0.0000  -1059.4008    -712.2234
+#> species[T.Gentoo]     578.6292   75.3623      7.6780   0.0000    430.3909     726.8674
+#> bill_length_mm         91.4358    6.8871     13.2764   0.0000     77.8888     104.9828
+
penguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)
+
+# ロジスティック回帰の実行
+fit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()
+
+print(py4st.tidy_mfx(fit_logit1).round(4))
+#>                 estimate  std_err  statistics  p_value  conf_lower  conf_higher
+#> body_mass_g      -0.0004   0.0000    -17.6561   0.0000     -0.0004      -0.0003
+#> bill_length_mm   -0.0053   0.0036     -1.4628   0.1435     -0.0123       0.0018
+#> bill_depth_mm    -0.1490   0.0051    -29.1681   0.0000     -0.1591      -0.1390
+
+
+

注意点

+

 参考にしたR言語の broom::tidy() は様々な種類のモデルに対応したジェネリック関数として定義されていますが、py4stats.tidy()py4stats.tidy_mfx() では対応しているモデルは限定的であることにご注意ださい。py4st.tidy() のメソッドが定義されているオブジェクトのクラスを確認するには次のコードを実行して下さい。

+
list(py4st.tidy.registry.keys())
+

py4stats.tidy()functools.singledispatch を用いたジェネリック関数として実装しています。 Py4Etrics モジュールの py4etrics.heckit.Heckit() で作成された HeckitResults クラスのオブジェクト用のメソッドについては heckit_helper.tidy_heckit() を参照してください。

+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/tidy_heckit.html b/docs/man/tidy_heckit.html new file mode 100644 index 0000000..2ef23ac --- /dev/null +++ b/docs/man/tidy_heckit.html @@ -0,0 +1,991 @@ + + + + + + + + + +heckit_helper.tidy_heckit – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

heckit_helper.tidy_heckit

+
+ + + +
+ + + + +
+ + + +
+ + +
+

概要

+

 R言語の broom::tidy() をオマージュした regression_tools.tidy() 関数の、py4etrics.heckit.HeckitResults クラス専用のメソッドです。regression_tools.tidy()はジェネリック関数として実装されているため、py4st.tidy(x) としてご利用いただけます。

+
tidy_heckit(
+    model, 
+    name_selection = None, 
+    name_outcome = None, 
+    conf_level = 0.95
+  )
+
+
+

引数 Argument

+
    +
  • x(必須)
      Py4Etrics モジュールの py4etrics.heckit.Heckit() で作成された HeckitResults クラスのオブジェクト
  • +
  • name_selectionlist of str
     term 列(index) のうち、第1段階の説明変数の名称として表示する文字列のリスト。指定しない場合(初期設定)、モデルの推定に使用された説明変数の名前がそのまま表示されます。
  • +
  • name_outcomelist of str
     term 列(index) のうち、第2段階の説明変数の名称として表示する文字列のリスト。指定しない場合(初期設定)、モデルの推定に使用された説明変数の名前がそのまま表示されます。
  • +
  • conf_levelfloat
     信頼区間の計算に用いる信頼係数。
  • +
+
+
+

返り値 Value

+

 次の列を含む pands.DataFrame が出力されます。

+
    +
  • term(index)
     説明変数の名称
  • +
  • estimate
     回帰係数の推定値
  • +
  • std_err
    推定値 estimate の標準誤差
  • +
  • statistics
    estimate = 0 を帰無仮説とする仮説検定の標本検定統計量。x に代入されたモデルが sm.ols() によって作成されたものであれば \(t\) 統計量が表示され、sm.glm() によって作成されたものであれば \(z\) 統計量が表示されます。
  • +
  • p_value
    estimate = 0 を帰無仮説とする両側検定の標本p-値
  • +
  • conf_lower
     信頼区間の下側信頼限界
  • +
  • conf_higher
     信頼区間の上側信頼限界
  • +
+
+
+

使用例 Examples

+

 heckit_helper モジュールはヘックマンの2段階推定(Heckit)を実行を Py4Etrics モジュールの py4etrics.heckit.Heckit() に依存しているため、事前のインストールをお願いします。

+
pip install git+https://github.com/Py4Etrics/py4etrics.git
+

ここでは wooldridge モジュールの mroz データを使い、春山(2023, Chap.24)のモデルを再現します。

+
import pandas as pd
+import wooldridge
+import py4stats as py4st
+from py4stats import heckit_helper
+
+mroz = wooldridge.data('mroz') # サンプルデータの読み込み
+
+mod_heckit, exog_outcome, exog_select = heckit_helper.Heckit_from_formula(
+    selection = 'lwage ~ educ + exper + expersq + nwifeinc + age + kidslt6 + kidsge6',
+    outcome = 'lwage ~ educ + exper + expersq',
+    data = mroz
+)
+
+res_heckit = mod_heckit.fit(cov_type_2 = 'HC1')
+

内部で functools.singledispatch を使用して定義しているため、heckit_helper モジュールの読み込み後は、py4st.tidy() 関数を呼び出すことで tidy_heckit() を実行することができます。

+
# 初期設定で使用した場合
+print(py4st.tidy(res_heckit).round(4))
+#>               estimate  std_err  statistics  p_value  conf_lower  conf_higher
+#> term                                                                         
+#> O: Intercept   -0.5781   0.3050     -1.8954   0.0580     -1.1759       0.0197
+#> O: educ         0.1091   0.0155      7.0261   0.0000      0.0786       0.1395
+#> O: exper        0.0439   0.0163      2.6989   0.0070      0.0120       0.0758
+#> O: expersq     -0.0009   0.0004     -1.9574   0.0503     -0.0017       0.0000
+#> S: const        0.2701   0.5086      0.5310   0.5954     -0.7267       1.2669
+#> S: x1           0.1309   0.0253      5.1835   0.0000      0.0814       0.1804
+#> S: x2           0.1233   0.0187      6.5903   0.0000      0.0867       0.1600
+#> S: x3          -0.0019   0.0006     -3.1452   0.0017     -0.0031      -0.0007
+#> S: x4          -0.0120   0.0048     -2.4843   0.0130     -0.0215      -0.0025
+#> S: x5          -0.0529   0.0085     -6.2347   0.0000     -0.0695      -0.0362
+#> S: x6          -0.8683   0.1185     -7.3263   0.0000     -1.1006      -0.6360
+#> S: x7           0.0360   0.0435      0.8281   0.4076     -0.0492       0.1212
+

 注意:内部で使用している statsmodels.iolib.summary.summary_params_frame() の仕様上、初期設定では第1段階の説明変数の名前が反映されません。説明変数の名前を反映するには name_selection 引数で指定してください。

+
print(py4st.tidy(res_heckit, name_selection = exog_select.columns).round(4))
+#>               estimate  std_err  statistics  p_value  conf_lower  conf_higher
+#> term                                                                         
+#> O: Intercept   -0.5781   0.3050     -1.8954   0.0580     -1.1759       0.0197
+#> O: educ         0.1091   0.0155      7.0261   0.0000      0.0786       0.1395
+#> O: exper        0.0439   0.0163      2.6989   0.0070      0.0120       0.0758
+#> O: expersq     -0.0009   0.0004     -1.9574   0.0503     -0.0017       0.0000
+#> S: Intercept    0.2701   0.5086      0.5310   0.5954     -0.7267       1.2669
+#> S: educ         0.1309   0.0253      5.1835   0.0000      0.0814       0.1804
+#> S: exper        0.1233   0.0187      6.5903   0.0000      0.0867       0.1600
+#> S: expersq     -0.0019   0.0006     -3.1452   0.0017     -0.0031      -0.0007
+#> S: nwifeinc    -0.0120   0.0048     -2.4843   0.0130     -0.0215      -0.0025
+#> S: age         -0.0529   0.0085     -6.2347   0.0000     -0.0695      -0.0362
+#> S: kidslt6     -0.8683   0.1185     -7.3263   0.0000     -1.1006      -0.6360
+#> S: kidsge6      0.0360   0.0435      0.8281   0.4076     -0.0492       0.1212
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/tidy_test.html b/docs/man/tidy_test.html new file mode 100644 index 0000000..e17795b --- /dev/null +++ b/docs/man/tidy_test.html @@ -0,0 +1,961 @@ + + + + + + + + + +tidy_test – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

tidy_test

+
+ + + +
+ + + + +
+ + + +
+ + +

\(t\) 検定、\(F\) 検定に対応した tidy メソッド

+
+

概要

+

 R言語の broom::tidy() をオマージュした py4stats.tidy() 関数のうち、statsmodels ライブラリのメソッド RegressionResults.t_test() もしくは RegressionResults.f_test() で作成された statsmodels.stats.contrast.ContrastResults クラスのオブジェクト専用のメソッドです。py4stats.tidy()はジェネリック関数として実装されているため、py4st.tidy(x) としてご利用いただけます。

+
tidy_test(x, conf_level = 0.95, **kwargs)
+
+
+

引数 Argument

+
    +
  • x(必須)
     statsmodels ライブラリのメソッド RegressionResults.t_test() もしくはRegressionResults.f_test() で作成された statsmodels.stats.contrast.ContrastResults クラスのオブジェクト。
  • +
  • conf_levelfloat
     信頼区間の計算に用いる信頼係数。ただし、x に代入されたオブジェクトが f_test() の結果である場合は、この引数は無視されます。
  • +
+
+
+

返り値 Value

+

 引数 x に代入されたオブジェクトが t_test() の結果である場合、次の列を含む pands.DataFrame が出力されます。

+
    +
  • estimate
     帰無仮説のもとでの回帰係数(の線型結合)の推定値
  • +
  • std_err
    推定値 estimate の標準誤差
  • +
  • statistics
     仮説検定の標本検定統計量。
  • +
  • p_value
    両側検定の標本p-値
  • +
  • conf_lower
     信頼区間の下側信頼限界
  • +
  • conf_higher
     信頼区間の上側信頼限界
  • +
+

 一方で引数 x に代入されたオブジェクトが f_test() の結果である場合、次の列を含む pands.DataFrame が出力されます。

+
    +
  • statistics
     仮説検定の標本検定統計量。
  • +
  • p_value
     F検定の標本p-値
  • +
  • df_denom
     モデルの残差自由度
  • +
  • df_denom
     帰無仮説のもとでの制約数
  • +
+
+
+

使用例 Examples

+
import py4stats as py4st
+
+import pandas as pd
+import numpy as np
+from palmerpenguins import load_penguins
+import statsmodels.formula.api as smf
+
+penguins = load_penguins() # サンプルデータの読み込み
+
+fit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()
+
hypotheses = 'bill_length_mm = 20'
+print(py4st.tidy(fit3.t_test(hypotheses)).round(4))
+#>       estimate  std_err  statistics  p_value  conf_lower  conf_higher
+#> term                                                                 
+#> c0     26.5366   7.2436      0.9024   0.3675     12.2867      40.7866
+
hypotheses = 'species[T.Chinstrap] = 0, species[T.Gentoo] = 0'
+print(py4st.tidy(fit3.f_test(hypotheses)).round(4))
+#>           statistics  p_value  df_denom  df_num
+#> term                                           
+#> contrast    210.9432      0.0       327       2
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/man/varidate.html b/docs/man/varidate.html new file mode 100644 index 0000000..c343c4e --- /dev/null +++ b/docs/man/varidate.html @@ -0,0 +1,1018 @@ + + + + + + + + + +check_that check_viorate – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

check_that check_viorate

+
+ + + +
+ + + + +
+ + + +
+ + +

簡易なルールベースのデータ検証ツール

+
+

概要

+

 R言語の varidateパッケージの check_that() 関数などをオマージュした、ごく簡易なデータ検証関数です。

+
check_that(
+    data: IntoFrameT,
+    rule_dict: Union[Mapping[str, str], pd.Series],
+    **kwargs: Any,
+)
+
+check_viorate(
+    data: IntoFrameT,
+    rule_dict: Union[Mapping[str, str], pd.Series],
+    **kwargs: Any,
+)
+
+
+

引数 Argument

+
    +
  • dataIntoFrameT(必須)
     ルールに基づくデータ検証を行うデータセット。narwhals が受け入れ可能な DataFrame 互換オブジェクト
    (例:pandas.DataFramepolars.DataFramepyarrow.Table)を指定できます。
  • +
  • rule_dictdict or pd.Series of str(必須)
     pandas.eval() メソッドで実行した結果が論理値となるような expression の文字列を値とする辞書オブジェクト。詳細は使用例も参照してください。
  • +
  • to_nativebool, optional)
    True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。
    False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。
  • +
  • **kwargs
     pandas.eval() に渡す追加の引数。
  • +
+
+
+

返り値 Value

+
+

check_that(): データセット単位の検証結果の集計

+

次の列を含む、引数 data に代入されたデータフレームと同じ型の DataFrame が出力されます。

+
    +
  • rule: 検証ルールの名前
  • +
  • item: ルールが検証対象とした項目の数。レコード(行)を検証単位とするルールの場合、itemdata の行数(rows)になります。一方、データセット全体を検証単位とするルール(例:集計量に基づく条件)の場合、item は 1 になります。
  • +
  • passes: 検証の結果、ルールを満たすと判定されたレコードの数。
  • +
  • fails: 検証の結果、ルールを満たさないと判定されたレコードの数。
  • +
  • countna: 欠測値によって、ルールの検証が行えなかったレコードの数。行(レコード)を検証単位とするルールでは、ルールの評価に使用された変数のいずれかに欠測値が含まれる場合、そのレコードは検証不能として NA 扱いされます。countna は、このように検証を正しく実施できなかったレコードの件数を表します。
  • +
  • expression: 検証ルールを表す文字列(expression)。
  • +
+
+
+

check_viorate(): レコード単位の検証結果

+

ルール名を列名として、レコード毎の違反を示す論理変数をもつ DataFrame が出力されます。

+

各列の要素の True は検証のルールへの違反、もしくは欠測値によって評価に失敗したことを表します。rule_dict で設定された各ルールに対応する列の他に、次の列が追加で出力されます。

+
    +
  • any: 行内のいずれかのルールが違反または評価に失敗した場合に True となるブール値。
  • +
  • all: 行内の全ルールが違反または評価に失敗した場合に True となるブール値。
  • +
+
+
+
+

使用例 Examples

+

 ここでは py4st.check_that() 関数を使って Loo, Jonge(2022, p. 136)の結果を再現します。まずはR言語の validate パッケージに付属する retailers データを利用します。retailers は60件の小売業者の経営状況についてのデータで、従業員数、売上高とその他の収入、人件費、総費用、および利益がユーロ導入前の通貨単位である1000ギルダー単位で収録されています。

+
import py4stats as py4st
+import pandas as pd
+
+URL = 'https://raw.githubusercontent.com/data-cleaning/validate/master/pkg/data/retailers.csv'
+retailers = pd.read_csv(URL, sep = ';')
+retailers.columns = retailers.columns.to_series().str.replace('.', '_', regex = False)
+

 py4st.check_that() 関数は、第1引数にデータセットを、第2引数に検証ルールの辞書オブジェクトを代入して使用します。
+ まずは、検証ルールの辞書オブジェクトを定義します。辞書オブジェクトの値には pandas.eval() メソッドで実行可能な expression の文字列を指定し、key に検証ルールの名前を指定します。検証ルールの名前は任意の値で構いませんが、 expression は結果が論理値となるものでなければなりません。

+
rule_dict =  {
+    'to':'turnover > 0',                                     # 売上高は厳密に正である
+    'sc':'staff_costs / staff < 50',                         # 従業員1人当たりの人件費は50,000ギルダー未満である
+    'cd1':'staff_costs > 0 | ~(staff > 0)',                    # 従業員がいる場合、人件費は厳密に正である
+    'cd2':py4st.implies_exper('staff > 0', 'staff_costs > 0'), # cd1 の別表現
+    'bs':'turnover + other_rev == total_rev',                # 売上高とその他の収入の合計は総収入に等しい
+    'mn':'profit.mean() > 0'                                 # セクター全体の平均的な利益はゼロよりも大きい
+    }
+pd.Series(rule_dict)
+#> to                          turnover > 0
+#> sc              staff_costs / staff < 50
+#> cd1       staff_costs > 0 | ~(staff > 0)
+#> cd2       staff_costs > 0 | ~(staff > 0)
+#> bs     turnover + other_rev == total_rev
+#> mn                     profit.mean() > 0
+#> dtype: object
+

retailersrule_dictpy4st.check_that() に代入すると、rule_dict に指定したルールに基づいた検証が実行されます。item 列はその検証ルールで生成された論理値の個数(通常はデータセットの列数と一致します)を表し、passes 列は検証結果が True となったレコードの数を、fails は False となったレコードの数を表します。また、coutna はルールの検証に使用した変数(データセットの列)のいずれかが欠測値であったレコードの数です。

+
print(py4st.check_that(retailers, rule_dict))
+#>   rule  item  passes  fails  coutna                         expression
+#> 0   to    60      56      0       4                       turnover > 0
+#> 1   sc    60      39      5      16           staff_costs / staff < 50
+#> 2  cd1    60      44      0      16     staff_costs > 0 | ~(staff > 0)
+#> 3  cd2    60      44      0      16     staff_costs > 0 | ~(staff > 0)
+#> 4   bs    60      19      4      37  turnover + other_rev == total_rev
+#> 5   mn     1       1      0       0                  profit.mean() > 0
+

前述の通り、py4st.check_that() 関数ではルール検証を pandas.eval() メソッドで実行しているため、検証ルールに自作関数や外部のモジュールからインポート関数を使うには、関数名の前に @ をつけて @func(…) と記述し、また **kwargs 引数に local_dict = locals() と指定してください。
+ 次のコードで定義している is_complete() 関数は、代入された pd.Series が全て欠測値ではなく、指定された変数に関して完全ケースであることを判定する関数です。turnover.notna() & total_rev.notna() & other_rev.notna() と記述しても同じ結果が得られますが、自作関数を使うことで若干簡潔に記述できます。

+
from pandas.api.types import is_numeric_dtype
+def is_complete(*arg): return pd.concat(arg, axis = 'columns').notna().all(axis = 'columns')
+
+pd.set_option('display.expand_frame_repr', False)
+
+rule_dict2 =  {
+    'to_num':'@is_numeric_dtype(turnover)',                      # 売上高は数値変数である
+    'rev_complete':'@is_complete(turnover, total_rev, other_rev)', # 売上高と収入が全て観測されている
+    }
+
+print(py4st.check_that(
+    retailers, rule_dict2, local_dict = locals()
+    ))
+#>            rule  item  passes  fails  coutna                                    expression
+#> 0        to_num     1       1      0       0                   @is_numeric_dtype(turnover)
+#> 1  rev_complete    60      23      0      37  @is_complete(turnover, total_rev, other_rev)
+

py4st.check_viorate() の使い方も py4st.check_that() と同様ですが、py4st.check_that() がデータセット全体での検証結果を出力するのに対し、py4st.check_viorate() ではレコード別の検証結果を表示します。py4st.check_viorate() から出力されるデータフレームでは、各列が検証ルールに、各行が元データの観測値に対応し、当該ルールが満たされていない場合、True と表示されます。また、any 列は複数あるルールのいずれか1つでも満たされていないことを、all 列は全てのルールが満たされていないことを示します。

+
rule_dict3 =  {
+    'to':'turnover > 0',                                     # 売上高は厳密に正である
+    'sc':'staff_costs / staff < 50',                         # 従業員1人当たりの人件費は50,000ギルダー未満である
+    'rev_complete':'@is_complete(turnover, total_rev, other_rev)',# 売上高と収入が全て観測されている
+    }
+  
+df_viorate = py4st.check_viorate(retailers, rule_dict3)
+print(df_viorate.head())
+#>       to     sc rev_complete   any    all
+#> 0   True   True         True  True   True
+#> 1  False  False         True  True  False
+#> 2  False   True        False  True  False
+#> 3  False   True        False  True  False
+#> 4   True   True         True  True   True
+

df_viorate データフレームの各列は論理値であるため、次のように検証ルールを満たさない観測値を抽出することができます。

+
print(retailers.loc[df_viorate['to'], 'size':'turnover'])
+#>   size  incl_prob  staff  turnover
+#> 0  sc0       0.02   75.0       NaN
+#> 4  sc3       0.14    NaN       NaN
+#> 6  sc3       0.14    5.0       NaN
+
+
+

Notes

+

本関数の内部実装は、 pd.DataFrame.eval() メソッドに依存しているため、実行時間の面で必ずしも最適化されていません。

+
+
+

参考文献

+
    +
  • Loo, Mark van der, and Edwin de Jonge. (2022). 『統計的データクリーニングの理論と実践: Rによるデータ編集/欠測補完システム』. 共立出版. 地道 正行, 髙橋 雅夫, 藤野 友和, 安川 武彦〔訳〕
  • +
+
+

Return to Function reference.

+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/py4stats/eda_tools/_nw.py b/docs/py4stats/eda_tools/_nw.py new file mode 100644 index 0000000..6a34525 --- /dev/null +++ b/docs/py4stats/eda_tools/_nw.py @@ -0,0 +1,4249 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[ ]: + + +from __future__ import annotations + + +# # `eda_tools`:データセットを要約する関数群 `narwhals` ライブラリを使った実装 + +# `eda_tools._nw` モジュールに実装された主要な関数の依存関係 +# +# ``` python +# ## 1. 基本診断(欠測・ユニーク数など) +# +# diagnose() # 各列の dtype / 欠測 / ユニーク数を要約 +# ├─ build.assert_logical() # 引数チェック +# ├─ get_dtypes() # 列ごとの dtype 抽出(backend非依存) +# └─ narwhals 集計処理 +# +# get_dtypes() # DataFrame の dtype を Series として取得 +# +# ## 2. 欠測値の可視化 +# +# plot_miss_var() # 変数別欠測率・欠測数の横棒グラフ +# ├─ build.arg_match() # values 引数の選択検証 +# ├─ build.assert_logical() +# ├─ diagnose() # 欠測統計の計算 +# └─ matplotlib barh 描画 +# +# ## 3. DataFrame 間の比較(構造・統計) +# +# ### 列構造(dtype)比較 +# +# compare_df_cols() # 複数DF間で列 dtype を比較 +# ├─ is_FrameT() # DataFrame 互換判定 +# ├─ build.arg_match() # return_match 指定 +# ├─ build.assert_logical() +# ├─ get_dtypes() +# └─ pandas.concat / nunique +# +# is_FrameT() # narwhals.from_native 可否判定 +# +# ### 統計量の近接性比較 +# +# compare_df_stats() # 平均などの統計量の近さで比較 +# ├─ is_FrameT() +# ├─ build.arg_match() +# ├─ _compute_stats() # 数値列の統計量計算 +# ├─ itertools.combinations() # DF ペア生成 +# └─ numpy.isclose() +# +# _compute_stats() # 数値列のみを選び stats を計算 +# +# ### レコード単位比較 +# +# compare_df_record() # 行×列レベルで df1 と df2 を比較 +# ├─ build.assert_logical() +# ├─ build.arg_match() # columns = 'all' / 'common' +# ├─ build.oxford_comma_and() # エラーメッセージ整形 +# ├─ numpy.isclose() # 数値列比較 +# └─ 等値比較(非数値) +# +# ## 4. グループ間比較(平均・中央値) +# +# compare_group_means() # グループ平均と差分指標 +# ├─ build.assert_character() +# ├─ remove_constant() # 定数列除去 +# ├─ narwhals.mean / var +# └─ 差分指標(norm / abs / rel) +# +# compare_group_median() # グループ中央値と差分 +# ├─ build.assert_character() +# ├─ remove_constant() +# └─ abs / rel 差分計算 +# +# plot_mean_diff() # 平均差のステムプロット +# ├─ build.arg_match() +# ├─ compare_group_means() +# └─ matplotlib stem +# +# plot_median_diff() # 中央値差のステムプロット +# ├─ build.arg_match() +# ├─ compare_group_median() +# └─ matplotlib stem +# +# +# ## 5. クロス集計・度数表 +# +# crosstab() # backend非依存クロス集計 +# ├─ build.assert_logical() +# ├─ build.arg_match() # normalize +# ├─ narwhals.pivot() +# └─ 周辺合計・正規化処理 +# +# freq_table() # 度数・割合・累積度数表 +# ├─ build.arg_match() # sort_by +# ├─ build.assert_logical() +# ├─ FutureWarning 処理(sort) +# └─ group_by + 集計 +# +# tabyl() # janitor::tabyl 風クロス集計 +# ├─ build.assert_*() +# ├─ crosstab() # 分割表 +# ├─ build.style_number() +# ├─ build.style_percent() +# └─ 文字列結合("count (xx%)") +# +# ## 6. カテゴリー変数の診断 +# +# diagnose_category() # カテゴリー変数専用サマリ +# ├─ build.assert_logical() +# ├─ is_dummy() # ダミー変数検出 +# ├─ freq_table() # モード算出 +# ├─ std_entropy() # 標準化エントロピー +# └─ narwhals 集計 +# +# is_dummy() # ダミー変数判定(汎用) +# ├─ is_dummy_series() # Series 用 +# └─ is_dummy_data_frame() # DataFrame 用 +# +# entropy() # Shannon エントロピー +# └─ scipy.stats.entropy +# +# std_entropy() # 正規化エントロピー +# └─ entropy() +# +# ## 7. 欠測・定数・不要列の除去 +# +# missing_percent() # 行・列ごとの欠測率 +# +# remove_empty() # 空白行・列の除去 +# ├─ missing_percent() +# ├─ build.assert_*() +# └─ 条件付きフィルタ +# +# remove_constant() # 定数列の除去 +# ├─ build.assert_logical() +# └─ n_unique 判定 +# +# filtering_out() # 列名・行名のパターン除外 +# ├─ build.arg_match() # axis +# ├─ build.assert_character() +# └─ pandas.str.contains 系 +# +# ## 8. 数値変換・スケーリング +# +# weighted_mean() # 重み付き平均 +# ├─ build.assert_numeric() +# └─ sum(x*w)/sum(w) +# +# scale() # Z-score 標準化 +# ├─ build.assert_count() +# ├─ build.assert_numeric() +# └─ mean / std +# +# min_max() # Min-Max 正規化 +# ├─ build.assert_numeric() +# └─ (x-min)/(max-min) +# +# ## 9. パレート図 +# Pareto_plot() # パレート図(頻度 or 集計) +# ├─ build.assert_*() +# ├─ freq_table() / make_rank_table() +# ├─ make_Pareto_plot() +# └─ matplotlib 描画 +# +# make_rank_table() # 集計→順位→累積比率 +# +# make_Pareto_plot() # パレート図描画専用 +# +# ## 10. カテゴリー積み上げ棒グラフ +# +# plot_category() # カテゴリー積み上げ棒 +# ├─ build.arg_match() +# ├─ make_table_to_plot() # 描画用テーブル作成 +# ├─ make_categ_barh() # 描画処理 +# └─ seaborn / matplotlib +# +# make_table_to_plot() # freq_table を縦結合 +# ├─ freq_table() +# ├─ relocate() +# └─ 累積比率計算 +# +# make_categ_barh() # 積み上げ棒描画 +# └─ matplotlib + seaborn +# +# ## 11. 区間推定(QI / CI) +# +# mean_qi() # 平均 + 分位区間 +# ├─ build.assert_numeric() +# ├─ build.arg_match() +# ├─ mean_qi_data_frame() +# └─ mean_qi_series() +# +# median_qi() # 中央値 + 分位区間 +# ├─ build.assert_numeric() +# ├─ build.arg_match() +# ├─ median_qi_data_frame() +# └─ median_qi_series() +# +# mean_ci() # 平均 + t信頼区間 +# ├─ build.assert_numeric() +# ├─ mean_ci_data_frame() +# └─ mean_ci_series() +# +# ## 12. ルールベース検証 +# +# check_that() # ルール評価の要約 +# └─ check_that_pandas() +# +# check_viorate() # 行ごとの違反判定 +# └─ check_viorate_pandas() +# +# is_complete() # 欠損のない行を判定 +# +# Sum(), Mean(), Max(), Min(), Median() # 行方向の合計・平均・中央値などを計算 +# └─ pd.concat(...).sum() など +# +# ## 13. 列操作ユーティリティ +# +# relocate() # 列順の再配置 +# ├─ arrange_colnames() +# ├─ build.assert_character() +# └─ narwhals.select() +# +# arrange_colnames() # 列名リストの並び替えロジック +# +# ``` + +# In[ ]: + + +from py4stats import building_block as build # py4stats のプログラミングを補助する関数群 +# from py4stats import eda_tools as eda # 基本統計量やデータの要約など +import matplotlib.pyplot as plt +import functools +from functools import singledispatch, reduce +import pandas_flavor as pf + +import pandas as pd +import numpy as np +import scipy as sp +import itertools +import narwhals +import narwhals as nw +import narwhals.selectors as ncs +from narwhals.typing import FrameT, IntoFrameT, SeriesT, IntoSeriesT + +import pandas_flavor as pf + +import warnings + + +# In[ ]: + + +from typing import ( + Any, + Callable, + Dict, + Iterable, + List, + Mapping, + Optional, + Sequence, + Tuple, + Union, + Literal, + overload, +) +from numpy.typing import ArrayLike + +# matplotlib の Axes は遅延インポート/前方参照でもOK +try: + from matplotlib.axes import Axes +except Exception: # notebook等で未importでも落ちないように + Axes = Any # type: ignore + +DataLike = Union[pd.Series, pd.DataFrame] + + +# # `diagnose()` + +# In[ ]: + + +def get_dtypes(data: IntoFrameT) -> pd.Series: + data_nw = nw.from_native(data) + implement = data_nw.implementation + + if isinstance(data, nw.DataFrame): + list_dtypes = list(data.schema.values()) + else: + match str(implement): + case 'pandas': + list_dtypes = data.dtypes.to_list() + case 'polars': + list_dtypes = list(data.schema.values()) + case 'pyarrow': + list_dtypes = data.schema.types + case _: # どのケースにも一致しない場合 + list_dtypes = list(data_nw.schema.values()) + + list_dtypes = pd.Series( + [str(v) for v in list_dtypes], + index = data_nw.columns + ) + + return list_dtypes + + +# In[ ]: + + +@pf.register_dataframe_method +def diagnose(data: IntoFrameT, to_native: bool = True) -> IntoFrameT: + """Summarize each column of a DataFrame for quick EDA. + + This method computes basic diagnostics for each column: + - dtype + - missing_count / missing_percent + - unique_count / unique_rate + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame type supported by narwhals + (e.g. pandas, polars, pyarrow) can be used. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + IntoFrameT: + A summary table with one row per variable and the following columns: + - columns: names of columns in original DataFrame + - dtype: pandas dtype of the column. + - missing_count: number of missing values. + - missing_percent: percentage of missing values (100 * missing_count / nrow). + - unique_count: number of unique values (excluding duplicates). + - unique_rate: percentage of unique values (100 * unique_count / nrow). + """ + build.assert_logical(to_native, arg_name = 'to_native') + data_nw = nw.from_native(data) + + n = data_nw.shape[0] + list_dtypes = get_dtypes(data).to_list() + + result = nw.from_dict({ + 'columns':data_nw.columns, + 'dtype':list_dtypes, + 'missing_count':data_nw.null_count().row(0), + 'unique_count':[s.n_unique() for s in data_nw.iter_columns()] + }, backend = data_nw.implementation)\ + .with_columns( + (100 * nw.col('missing_count') / n).alias('missing_percent'), + (100 * nw.col('unique_count') / n).alias('unique_rate') + )\ + .select('columns', 'dtype', 'missing_count', 'missing_percent', 'unique_count', 'unique_rate') + + if to_native: return result.to_native() + return result + + +# In[ ]: + + +@pf.register_dataframe_method +def plot_miss_var( + data: IntoFrameT, + values: Literal['missing_percent', 'missing_count'] = 'missing_percent', + sort: bool = True, + miss_only: bool = False, + top_n: Optional[int] = None, + fontsize: int = 12, + ax: Optional[Axes] = None, + color: str = '#478FCE', + **kwargs: Any + ) -> None: + """Plot missing-value diagnostics for each variable in a DataFrame. + + This function visualizes the amount of missing data for each column + as a horizontal bar chart. It supports multiple DataFrame backends + via narwhals and relies on ``diagnose()`` to compute missing-value + statistics. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame type supported by narwhals + (e.g. pandas, polars, pyarrow) can be used. + values (Literal['missing_percent', 'missing_count'], optional): + Metric to plot on the horizontal axis. + - ``'missing_percent'``: percentage of missing values per column. + - ``'missing_count'``: absolute number of missing values per column. + Defaults to ``'missing_percent'``. + sort (bool, optional): + Whether to sort columns by the selected metric before plotting. + Defaults to ``True``. + miss_only (bool, optional): + Whether to include only columns that contain at least one + missing value. If ``True``, columns with no missing values + are excluded from the plot. Defaults to ``False``. + top_n (int or None): + If specified, plot only top-n variables. + fontsize (int, optional): + Base font size used for axis labels. Defaults to ``12``. + ax (matplotlib.axes.Axes, optional): + Matplotlib Axes object to draw the plot on. If ``None``, + a new figure and axes are created. Defaults to ``None``. + color (str, optional): + Color of the bars in the plot. Defaults to ``'#478FCE'``. + **kwargs: + Additional keyword arguments passed to + ``matplotlib.axes.Axes.barh``. + + Returns: + None: + This function draws a plot and does not return a value. + + Raises: + ValueError: + If ``values`` is not one of the supported options + (``'missing_percent'`` or ``'missing_count'``). + + Notes: + This function is intended for exploratory data analysis. + The underlying missing-value statistics are computed by + ``diagnose``, and the resulting plot reflects its output. + """ + values = build.arg_match( + values, arg_name = 'values', + values = ['missing_percent', 'missing_count'] + ) + build.assert_logical(sort, arg_name = 'sort') + build.assert_logical(miss_only, arg_name = 'miss_only') + + diagnose_tab = diagnose(data, to_native = False) + + if miss_only: diagnose_tab = diagnose_tab.filter(nw.col('missing_percent') > 0) + if top_n is not None: + build.assert_count(top_n, lower = 1, arg_name = 'top_n') + diagnose_tab = diagnose_tab.top_k(top_n, by = values) + if sort: diagnose_tab = diagnose_tab.sort(values) + + # グラフの描画 + if ax is None: + fig, ax = plt.subplots() + + ax.barh( + y = diagnose_tab['columns'], + width = diagnose_tab[values], + color = color, + **kwargs + ) + if values == 'missing_percent': + ax.set_xlabel('percentage of missing recode(%)', fontsize = fontsize * 1.1); + if values == 'missing_count': + ax.set_xlabel('number of missing recode', fontsize = fontsize * 1.1); + + +# ### 異なるデータフレームの列を比較する関数 + +# In[ ]: + + +def is_FrameT(obj: object) -> bool: + try: + _ = nw.from_native(obj) + return True + except Exception: + return False + + +# In[ ]: + + +def _join_comparsion(result_list, on): + redundant_col = f"{on}_right" + result = reduce( + lambda df1, df2: ( + df1.join(df2, on = on, how = 'full') + .with_columns( + nw.when(nw.col(on).is_null()).then(redundant_col)\ + .otherwise(on).alias(on) + )), result_list + ) + result = filtering_out( + result, starts_with = redundant_col, + to_native = False + ) + return result + + +# In[ ]: + + +def compare_df_cols( + df_list: Union[List[IntoFrameT], Mapping[str, IntoFrameT]], + df_name: Optional[List[str]] = None, + return_match: Literal["all", "match", "mismatch"] = 'all', + dropna:bool = False, + to_native: bool = True +) -> IntoFrameT: + """ + Compare column dtypes across multiple DataFrames. + + This function compares the dtypes of columns with the same names across + multiple DataFrame-like objects and summarizes the results in a single + table. The function supports multiple backends via narwhals + (e.g., pandas, polars, pyarrow). + + Args: + df_list: + A list or mapping of input DataFrames. Any DataFrame-like object + supported by narwhals (e.g., ``pandas.DataFrame``, + ``polars.DataFrame``, ``pyarrow.Table``) can be used. + If a mapping is provided, its keys are used as DataFrame names. + df_name: + Names for each DataFrame, used as column names in the output. + Must have the same length as ``df_list``. + If None, names are automatically generated as + ``['df1', 'df2', ...]``. + return_match: + Specifies which rows to return based on dtype consistency. + + - ``"all"``: return all columns. + - ``"match"``: return only columns whose dtypes match across + all DataFrames. + - ``"mismatch"``: return only columns whose dtypes do not match. + dropna: + Passed to ``nunique(dropna=...)`` when checking dtype consistency. + Controls whether missing values are ignored when determining + whether dtypes match. + to_native: + If True, returns the result as a native DataFrame of the input + backend. If False, returns a ``narwhals.DataFrame``. + + Returns: + IntoFrameT: + A DataFrame where each row corresponds to a column name shared + across the input DataFrames. The result contains the following + columns: + + - ``term``: column (variable) name. + - one column per input DataFrame, containing the dtype of that + column in each DataFrame. + - ``match_dtype``: boolean flag indicating whether the dtypes + are identical across all DataFrames for that column. + + Notes: + - The column name ``term`` is included as a regular column in the + output table (not as the index). + - Internally, the function aligns results using a join operation + on ``term``. + - The function performs dtype comparison only; it does not compare + values. + """ + # df_name が指定されていなければ、自動で作成します。 + if df_name is None: + if isinstance(df_list, dict): + df_name = list(df_list.keys()) + df_list = list(df_list.values()) + else: + df_name = [f'df{i + 1}' for i in range(len(df_list))] + + # 引数のアサーション ---------------------- + assert isinstance(df_list, list) & \ + all([is_FrameT(v) for v in df_list]), \ + "argument 'df_list' is must be a list of DataFrame." + + return_match = build.arg_match( + return_match, values = ['all', 'match', 'mismatch'], + arg_name = 'return_match' + ) + + build.assert_logical(dropna, arg_name = 'dropna') + + build.assert_character( + df_name, arg_name = 'df_name', + nullable = True, len_arg = build.length(df_list) + ) + build.assert_logical(to_native, arg_name = 'to_native') + # -------------------------------------- + implement = nw.from_native(df_list[0]).implementation + + # dtype の集計 ============================================= + dtype_list = [ + enframe( + get_dtypes(dt), + name = 'term', value = val, + to_native = False, + backend = implement + ) + for val, dt in zip(df_name, df_list) + ] + + # 結果の結合 ============================================== + result = _join_comparsion(dtype_list, on = 'term') + + # dtype の一致性を確認 ====================================== + match_dtype = ( + result[:, 1:].to_pandas() + .nunique(axis = 'columns', dropna = dropna) == 1 + ) + + match_dtype = nw.Series.from_iterable( + name = 'match_dtype', + values = match_dtype.to_list(), + backend = implement + ) + result = result.with_columns(match_dtype) + + if(return_match == 'match'): + result = result.filter(nw.col('match_dtype') == True) + elif(return_match == 'mismatch'): + result = result.filter(nw.col('match_dtype') == False) + + if to_native: return result.to_native() + return result + + +# ### 平均値などの統計値の近接性で比較するバージョン + +# In[ ]: + + +def compare_df_stats( + df_list: Union[List[IntoFrameT], Mapping[str, IntoFrameT]], + df_name: Optional[List[str]] = None, + return_match: Literal["all", "match", "mismatch"] = "all", + stats: Callable[..., Any] = np.mean, + rtol: float = 1e-05, + atol: float = 1e-08, + to_native: bool = True, + **kwargs: Any, +) -> IntoFrameT: + """ + Compare summary statistics of numeric columns across multiple DataFrames. + + This function computes a summary statistic (e.g., mean or median) for each + numeric column in multiple DataFrame-like objects and compares those + statistics across DataFrames. The results are combined into a single table, + along with an indicator showing whether the statistics are numerically + close across all DataFrames. + + The function supports multiple DataFrame backends via narwhals + (e.g., pandas, polars, pyarrow). + + Args: + df_list: + A list or mapping of input DataFrames. Any DataFrame-like object + supported by narwhals (e.g., ``pandas.DataFrame``, + ``polars.DataFrame``, ``pyarrow.Table``) can be used. + If a mapping is provided, its keys are used as DataFrame names. + df_name: + Names for each DataFrame, used as column names in the output. + Must have the same length as ``df_list``. + If None, names are automatically generated as + ``['df1', 'df2', ...]``. + return_match: + Specifies which rows to return based on the comparison of + statistics across DataFrames. + + - ``"all"``: return all variables. + - ``"match"``: return only variables whose statistics are close + across all DataFrames. + - ``"mismatch"``: return only variables whose statistics are not + close. + stats: + Aggregation function used to compute a single summary value for each + numeric column. + + This argument accepts either a general callable (e.g., + ``numpy.mean`` or a user-defined function) that takes a + one-dimensional array-like object and returns a single scalar, or a + function from ``narwhals.functions`` (e.g., ``narwhals.mean``, + ``narwhals.sum``), which will be applied directly within the + narwhals expression workflow. Defaults to ``numpy.mean``. + rtol: + Relative tolerance parameter passed to ``numpy.isclose`` when + comparing statistics. + atol: + Absolute tolerance parameter passed to ``numpy.isclose`` when + comparing statistics. + to_native: + If True, returns the result as a native DataFrame of the input + backend. If False, returns a ``narwhals.DataFrame``. + **kwargs: + Additional keyword arguments passed to the aggregation function + when applicable. + + Returns: + IntoFrameT: + A DataFrame where each row corresponds to a numeric column and the + result contains the following columns: + + - ``term``: column (variable) name. + - one column per input DataFrame, containing the computed statistic + for that column. + - ``match_stats``: boolean flag indicating whether the statistics + are numerically close across all DataFrames according to + ``numpy.isclose``. + + Notes: + - Only numeric columns are included in the comparison. + - The column name ``term`` is included as a regular column in the + output table (not as the index). + - When ``stats`` is a function from ``narwhals.functions``, the + computation is performed using narwhals expressions. Otherwise, the + function is applied to non-missing values converted to native Python + objects. + - Statistical comparison is based on the minimum and maximum values + across DataFrames for each variable. + """ + # df_name が指定されていなければ、自動で作成します。 + if df_name is None: + if isinstance(df_list, dict): + df_name = list(df_list.keys()) + df_list = list(df_list.values()) + else: + df_name = [f'df{i + 1}' for i in range(len(df_list))] + # 引数のアサーション ---------------------- + assert isinstance(df_list, list) & \ + all([is_FrameT(v) for v in df_list]), \ + "argument 'df_list' is must be a list of DataFrame." + + return_match = build.arg_match( + return_match, arg_name = 'return_match', + values = ['all', 'match', 'mismatch'] + ) + build.assert_character( + df_name, arg_name = 'df_name', + nullable = True, len_arg = build.length(df_list) + ) + build.assert_logical(to_native, arg_name = 'to_native') + # -------------------------------------- + + df_list_nw = [nw.from_native(v) for v in df_list] + + # 統計値の計算 ============================================= + stats_list = [ + _compute_stats(df, stats, name) + for df, name in zip(df_list_nw, df_name) + ] + + # 計算結果の結合 ============================================== + result = _join_comparsion(stats_list, on = 'term') + + # 統計値が近いかどうかを比較 ============================================== + match_stats = [ + np.isclose(np.min(x), np.max(x), rtol = rtol, atol = atol) + for x in result[:, 1:].iter_rows() + ] + + implement = df_list_nw[0].implementation + match_stats = nw.Series.from_iterable( + name = 'match_stats', + values = match_stats, + backend = implement + ) + result = result.with_columns(match_stats) + + # 結果の出力 ================================================================= + + if(return_match == 'match'): + result = result.filter(nw.col('match_dtype') == True) + elif(return_match == 'mismatch'): + result = result.filter(nw.col('match_dtype') == False) + + if to_native: return result.to_native() + return result + +def _compute_stats(df, stats, name): + numeric_vars = df.select(ncs.numeric()).columns + + if stats.__module__ == 'narwhals.functions': + stats_val = df.select(stats(numeric_vars)) + else: + stats_val = { + col: stats(df[:, col].drop_nulls().to_list()) + for col in numeric_vars + } + + stats_df = enframe( + stats_val , name = 'term', value = name, + to_native = False, + backend = df.implementation + ) + + return stats_df + + +# ## 2つのデータフレームをレコード単位で比較する関数 + +# In[ ]: + + +# レコード毎の近接性(数値の場合)または一致性(数値以外)で評価する関数 +def compare_df_record( + df1: IntoFrameT, + df2: IntoFrameT, + rtol: float = 1e-05, + atol: float = 1e-08, + sikipna: bool = True, + columns: Literal['common', 'all'] = 'all', + to_native: bool = True +) -> IntoFrameT: + """Compare two DataFrames record-wise (element-wise). + + Each element is compared row by row: + - Numeric columns are compared using `numpy.isclose`. + - Non-numeric columns are compared using equality (`==`). + + The set of columns used for comparison is controlled by `columns`. + + Args: + df1 (IntoFrameT): + First DataFrame-like object. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + df2 (IntoFrameT): + Second DataFrame-like object. + rtol (float, optional): + Relative tolerance for numeric comparison via `numpy.isclose`. + atol (float, optional): + Absolute tolerance for numeric comparison via `numpy.isclose`. + skipna (bool, optional): + If True(default), Exclude NA/null values when computing the result. + columns (Literal["common", "all"], optional): + Policy that determines which columns are compared. + + - `"all"` (default): + Require `df1` and `df2` to have exactly the same set of columns. + If columns differ, an error is raised. + - `"common"`: + Compare only the intersection of columns present in both + `df1` and `df2`. Columns that exist in only one DataFrame + are ignored. + to_native (bool, optional): + If True, return the result as a native DataFrame class of 'df1'. + If False, return a `narwhals.DataFrame`. + + Returns: + IntoFrameT or narwhals.DataFrame: + A DataFrame of boolean values indicating, for each element, + whether the values in `df1` and `df2` match (or are close for + numeric columns). Column order follows `df1.columns` + (restricted by `columns` if `"common"` is used). + + Raises: + AssertionError: + If `df1` and `df2` do not have the same number of rows. + ValueError: + If `columns="all"` and `df1` and `df2` do not have identical + column sets. + + Examples: + >>> compare_df_record(df1, df2, columns="all") + >>> compare_df_record(df1, df2, rtol=1e-4, columns="common") + """ + df1 = nw.from_native(df1) + df2 = nw.from_native(df2) + all1 = df1.columns + all2 = df2.columns + + build.assert_logical(sikipna, arg_name = 'sikipna') + if sikipna: + df1 = df1.drop_nulls(all1) + df2 = df2.drop_nulls(all2) + + # 引数のアサーション ---------------------------------------------------------------------------------- + build.assert_logical(to_native, arg_name = 'to_native') + + columns = build.arg_match( + columns, arg_name = 'columns', + values = ['common', 'all'] + ) + + assert df1.shape[0] == df2.shape[0], ( + "df1 and df2 must have the same number of rows " + f"(got len(df1)={df1.shape[0]} and len(df2)={df2.shape[0]})." + ) + if columns == 'all': + only_in_df1 = sorted(set(all1) - set(all2)) + only_in_df2 = sorted(set(all2) - set(all1)) + + if only_in_df1 or only_in_df2: + messages = [ + "Column sets of df1 and df2 do not match while columns='all' is specified." + ] + if only_in_df1: + messages.append( + f"Columns only in df1: {build.oxford_comma_and(only_in_df1)}." + ) + if only_in_df2: + messages.append( + f"Columns only in df2: {build.oxford_comma_and(only_in_df2)}." + ) + messages.append( + "Use columns='common' to compare only shared columns." + ) + raise ValueError("\n".join(messages)) + # -------------------------------------------------------------------------------------------------- + + numeric1 = df1.select(ncs.numeric()).columns + nonnum1 = df1.select(~ncs.numeric()).columns + numeric2 = df2.select(ncs.numeric()).columns + nonnum2 = df2.select(~ncs.numeric()).columns + + # df1と df2 の列名の共通部分を抽出します。 + all_columns = [item for item in all1 if item in all2] + numeric_col = set(numeric1) & set(numeric2) + nonnum_col = set(nonnum1) & set(nonnum2) + + # 類似性の評価 ========================================================== + res_number_col = [ + np.isclose( + df1[v], df2[v], rtol = rtol, atol = atol + ) for v in numeric_col + ] + if res_number_col: + res_number_col_df = nw.from_numpy( + np.vstack(res_number_col).T, + backend = df1.implementation + ) + res_number_col_df = res_number_col_df.rename( + dict(zip(res_number_col_df.columns, numeric_col)) + ) + else: + res_number_col_df = None + # カテゴリ変数の類似性評価 ================================================ + res_nonnum_col = [(df1[v] == df2[v]).to_frame() for v in nonnum_col] + + if res_nonnum_col: + res_nonnum_col_df = nw.concat(res_nonnum_col, how = 'horizontal') + else: + res_nonnum_col_df = None + + # 結果の結合と出力 ======================================================= + res_list = [res_number_col_df, res_nonnum_col_df] + res_list = list(filter(None, res_list)) + + result = nw.concat( + res_list, + how = 'horizontal' + )\ + .select(all_columns) + + + if to_native: return result.to_native() + return result + + +# ## グループ別平均(中央値)の比較 + +# In[ ]: + + +def enframe( + data: Any, + row_id:int = 0, + name: str = 'name', + value: str = 'value', + backend: Optional[Union[str, nw.Implementation]] = None, + names: list[str] = None, + to_native: bool = True, + **keywarg: Any +) -> IntoFrameT: + """Convert a row of DataFrame or other iterable object into two-column DataFrame. + + This function transforms an object containing values (such as a Series, + list, dict, or a single-row DataFrame) into a DataFrame with two columns: + one for names (keys) and one for values. It is inspired by + ``tibble::enframe()`` in R and is useful for reshaping aggregation results + into a tidy, long format. + + The function supports multiple backends via narwhals and can return either + a native DataFrame or a ``narwhals.DataFrame``. + + Args: + data (Any): + Input object to be converted. Supported types include: + - ``narwhals.DataFrame`` (typically with a single row) + - ``narwhals.Series`` + - ``list`` or ``tuple`` + - ``dict`` + row_id (int, optional): + Row index to extract values from when ``data`` is a DataFrame. + Defaults to 0. + name (str, optional): + Column name for variable names (keys). Defaults to ``'name'``. + value (str, optional): + Column name for values. Defaults to ``'value'``. + backend (str or narwhals.Implementation, optional): + Backend used to construct the output DataFrame. + If None, the backend is inferred from the input data. + names (list of str, optional): + Names corresponding to the values. + If None, names are inferred from column names, index, + or keys of the input object. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + **keywarg: + Additional keyword arguments passed to the internal dispatch methods. + + Returns: + IntoFrameT or narwhals.DataFrame: + A two-column DataFrame with one column for names and one for values. + The return type depends on the value of ``to_native``. + + Raises: + NotImplementedError: + If the input object type is not supported. + + Examples: + Convert a single-row DataFrame produced by an aggregation: + + >>> df.select(ncs.numeric().mean()).pipe(enframe) + name value + 0 mpg 20.09 + 1 hp 146.69 + + Convert a Series: + + >>> enframe(pd.Series([10, 20], index=['a', 'b'])) + name value + 0 a 10 + 1 b 20 + + Convert a dictionary: + + >>> enframe({'x': 1, 'y': 2}) + name value + 0 x 1 + 1 y 2 + """ + # 引数のアサーション ======================================================= + build.assert_count(row_id, arg_name = 'row_id', len_arg = 1) + build.assert_character(name, arg_name = 'name', len_arg = 1) + build.assert_character(value, arg_name = 'value', len_arg = 1) + build.assert_character(names, arg_name = 'names', nullable = True) + build.assert_logical(to_native, arg_name = 'to_native') + # ======================================================================= + + try: + data = nw.from_native(data, allow_series = True) + finally: + args_dict = locals() + args_dict.pop('data') + return enframe_default(data, **args_dict) + +@singledispatch +def enframe_default(data, **keywarg: Any) -> None: + raise NotImplementedError(f'enframe mtethod for object {type(data)} is not implemented.') + + +# In[ ]: + + +@enframe_default.register(nw.DataFrame) +def enframe_table( + data: IntoFrameT, + row_id:int = 0, + name: str = 'name', + value: str = 'value', + names: Union[list[str]] = None, + backend: Optional[Union[str, nw.Implementation]] = None, + to_native: bool = True, + **keywarg: Any +) -> IntoFrameT: + + if backend is None: + backend = data.implementation + if names is None: + nemes = data.columns + + result = nw.from_dict({ + name: nemes, + value: data.row(row_id) + }, backend = backend) + + if to_native: return result.to_native() + return result + + +# In[ ]: + + +@enframe_default.register(nw.series.Series) +@enframe_default.register(list) +@enframe_default.register(tuple) +def enframe_series( + data: Union[nw.Series, list, tuple], + name: str = 'name', + value: str = 'value', + names: Union[list[str]] = None, + backend: Optional[Union[str, nw.Implementation]] = None, + to_native: bool = True, + **keywarg: Any +) -> IntoFrameT: + + if backend is None: + if hasattr(data, 'implementation'): + backend = data.implementation + else: + backend = 'pandas' + if names is None: + if hasattr(data, 'implementation') and (data.implementation.is_pandas()): + names = data.to_pandas().index.to_list() + else: + names = range(build.length(data)) + + result = nw.from_dict({ + name: names, + value: list(data) + }, backend = backend) + + if to_native: return result.to_native() + return result + + +# In[ ]: + + +@enframe_default.register(dict) +def enframe_dict( + data: dict, + name: str = 'name', + value: str = 'value', + names: Union[list[str]] = None, + backend: Optional[Union[str, nw.Implementation]] = None, + to_native: bool = True, + **keywarg: Any +) -> IntoFrameT: + + if backend is None: backend = 'pandas' + if names is None: names = data.keys() + + result = nw.from_dict({ + name: names, + value: data.values() + }, backend = backend) + + if to_native: return result.to_native() + return result + + +# In[ ]: + + +def compare_group_means( + group1: IntoFrameT, + group2: IntoFrameT, + group_names: Sequence[str] = ('group1', 'group2'), + columns: Literal['common', 'all'] = 'all', + to_native: bool = True +) -> pd.DataFrame: + """ + Compare variable-wise means between two groups. + + This function computes the mean of each numeric column for two input + data frames and combines the results into a single table. It also derives + simple difference metrics based on the group-wise means. + + The function supports multiple DataFrame backends via narwhals + (e.g., pandas, polars, pyarrow). + + Args: + group1 (IntoFrameT): + Data for the first group. Any DataFrame-like object supported by + narwhals (e.g., ``pandas.DataFrame``, ``polars.DataFrame``, + ``pyarrow.Table``) can be used. + group2 (IntoFrameT): + Data for the second group. + group_names (Sequence[str]): + Names used for the output columns corresponding to the two groups. + Must be a sequence of length 2. + columns (Literal['common', 'all']): + Specifies which variables to include when combining results from + the two groups. + + - ``"common"``: + Only variables that appear in *both* groups are included. + - ``"all"``: + All variables appearing in either group are included. In this + case, difference metrics may contain missing values (e.g., + ``NaN`` or ``None``) for variables that are present in only one + group. + to_native (bool, optional): + If True, return the result as a native DataFrame class of 'group1'. + If False, return a `narwhals.DataFrame`. + + Returns: + IntoFrameT: + A DataFrame with one row per variable and the following columns: + + - ``{group_names[0]}``: mean value in the first group + - ``{group_names[1]}``: mean value in the second group + - norm_diff: normalized difference using pooled variance + - ``abs_diff``: absolute difference between group means + - ``rel_diff``: relative difference defined as + ``2 * (A - B) / (A + B)`` + + Notes: + - Only numeric columns are used when computing means. + - Constant columns are removed from each group before comparison. + - When ``columns="all"``, variables that exist in only one group are + retained, and derived difference metrics may be missing. + - The function performs a join operation internally to align variables + across the two groups. + """ + # 引数のアサーション ============================================== + build.assert_character(group_names, arg_name = 'group_names', len_arg = 2) + columns = build.arg_match( + columns, arg_name = 'columns', + values = ['common', 'all'] + ) + if columns == "all": how_join = 'full' + else: how_join = 'inner' + + # ============================================================== + group1 = nw.from_native(group1) + group2 = nw.from_native(group2) + group1 = remove_constant(group1, to_native = False) + group2 = remove_constant(group2, to_native = False) + + # 平均値の計算 ========================================================= + stats_df1 = enframe( + group1.select(ncs.numeric().mean()), + name = 'variable', value = group_names[0], + row_id = 0, to_native = False + ) + + stats_df2 = enframe( + group2.select(ncs.numeric().mean()), + name = 'variable', value = group_names[1], + row_id = 0, to_native = False + ) + # return stats_df1, stats_df2 + # 分散の計算 ========================================================= + var_df1 = enframe( + group1.select(ncs.numeric().var()), + row_id = 0, name = 'variable', value = 's2A', + to_native = False + ) + + var_df2 = enframe( + group2.select(ncs.numeric().var()), + row_id = 0, name = 'variable', value = 's2B', + to_native = False + ) + nA = group1.shape[0] + nB = group2.shape[0] + + var_df = var_df1.join( + var_df2, + on = 'variable', + how = 'inner' + )\ + .with_columns( + _s2_pooled = ( + (nA - 1) * nw.col('s2A') + (nB - 1) * nw.col('s2B')) / + (nA + nB - 2) + ).select('variable', '_s2_pooled') + # データフレームの結合 =============================================================== + mean_sd2 = stats_df1\ + .join(stats_df2, on = 'variable', how = how_join) + + if columns == "all": + mean_sd2 = mean_sd2.with_columns( + nw.when(nw.col("variable").is_null()).then("variable_right")\ + .otherwise("variable").alias('variable') + ) + + mean_sd2 = mean_sd2.join(var_df, on = 'variable', how = 'left') + # 差分統計量の計算 ================================================================== + result = mean_sd2\ + .with_columns( + norm_diff = (nw.col(group_names[0]) - nw.col(group_names[1])) + / nw.col('_s2_pooled').sqrt(), + abs_diff = (nw.col(group_names[0]) - nw.col(group_names[1])).abs(), + rel_diff = 2 * (nw.col(group_names[0]) - nw.col(group_names[1])) / + (nw.col(group_names[0]) + nw.col(group_names[1])) + )\ + .select( + 'variable', nw.col(group_names), 'norm_diff', 'abs_diff', 'rel_diff' + ) + # ================================================================================ + if to_native: return result.to_native() + return result + + + +# In[ ]: + + +def compare_group_median( + group1: IntoFrameT, + group2: IntoFrameT, + group_names: Sequence[str] = ('group1', 'group2'), + columns: Literal['common', 'all'] = 'all', + to_native: bool = True +) -> IntoFrameT: + """ + Compare variable-wise medians between two groups. + + This function computes the median of each numeric column for two input + data frames and combines the results into a single table. It also derives + simple difference metrics based on the group-wise medians. + + The function supports multiple DataFrame backends via narwhals + (e.g., pandas, polars, pyarrow). + + Args: + group1 (IntoFrameT): + Data for the first group. Any DataFrame-like object supported by + narwhals (e.g., ``pandas.DataFrame``, ``polars.DataFrame``, + ``pyarrow.Table``) can be used. + group2 (IntoFrameT): + Data for the second group. + group_names (Sequence[str]): + Names used for the output columns corresponding to the two groups. + Must be a sequence of length 2. + columns (Literal['common', 'all']): + Specifies which variables to include when combining results from + the two groups. + + - ``"common"``: + Only variables that appear in *both* groups are included. + - ``"all"``: + All variables appearing in either group are included. In this + case, difference metrics may contain missing values (e.g., + ``NaN`` or ``None``) for variables that are present in only one + group. + to_native (bool, optional): + If True, return the result as a native DataFrame class of 'group1'. + If False, return a `narwhals.DataFrame`. + + Returns: + IntoFrameT: + A DataFrame with one row per variable and the following columns: + + - ``{group_names[0]}``: median value in the first group + - ``{group_names[1]}``: median value in the second group + - ``abs_diff``: absolute difference between group medians + - ``rel_diff``: relative difference defined as + ``2 * (A - B) / (A + B)`` + + Notes: + - Only numeric columns are used when computing medians. + - Constant columns are removed from each group before comparison. + - When ``columns="all"``, variables that exist in only one group are + retained, and derived difference metrics may be missing. + - The function performs a join operation internally to align variables + across the two groups. + """ + # 引数のアサーション ============================================== + build.assert_character(group_names, arg_name = 'group_names', len_arg = 2) + columns = build.arg_match( + columns, arg_name = 'columns', + values = ['common', 'all'] + ) + if columns == "all": how_join = 'full' + else: how_join = 'inner' + + # ============================================================== + group1 = nw.from_native(group1) + group2 = nw.from_native(group2) + group1 = remove_constant(group1, to_native = False) + group2 = remove_constant(group2, to_native = False) + + # 中央値の計算 ========================================================= + stats_df1 = enframe( + group1.select(ncs.numeric().mean()), + name = 'variable', value = group_names[0], + row_id = 0, to_native = False + ) + + stats_df2 = enframe( + group2.select(ncs.numeric().mean()), + name = 'variable', value = group_names[1], + row_id = 0, to_native = False + ) + # データフレームの結合 =============================================================== + stats_df = stats_df1\ + .join(stats_df2, on = 'variable', how = how_join) + + if columns == "all": + stats_df = stats_df.with_columns( + nw.when(nw.col("variable").is_null()).then("variable_right")\ + .otherwise("variable").alias('variable') + ) + + # 差分統計量の計算 ================================================================== + result = stats_df\ + .with_columns( + abs_diff = (nw.col(group_names[0]) - nw.col(group_names[1])).abs(), + rel_diff = 2 * (nw.col(group_names[0]) - nw.col(group_names[1])) / + (nw.col(group_names[0]) + nw.col(group_names[1])) + )\ + .select( + 'variable', nw.col(group_names), 'abs_diff', 'rel_diff' + ) + # ================================================================================ + if to_native: return result.to_native() + return result + + + +# In[ ]: + + +def plot_mean_diff( + group1: IntoFrameT, + group2: IntoFrameT, + stats_diff: Literal["norm_diff", "abs_diff", "rel_diff"] = "norm_diff", + ax: Optional[Axes] = None, +) -> None: + """Plot group mean differences for each variable as a stem plot. + + Args: + group1 (IntoFrameT): + Data for group 1.Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + group2 (IntoFrameT): + Data for group 2. + stats_diff (str): + Which difference metric to plot. + - 'norm_diff': normalized difference using pooled variance + - 'abs_diff': absolute difference + - 'rel_diff': relative difference + ax (matplotlib.axes.Axes or None): + Axes to draw on. If None, a new figure/axes is created. + + Returns: + None + """ + stats_diff = build.arg_match( + stats_diff, arg_name = 'stats_diff', + values = ['norm_diff', 'abs_diff', 'rel_diff'] + ) + group_means = compare_group_means( + group1, group2, + columns = 'common', + to_native = False + ).to_pandas().set_index('variable') + + if ax is None: + fig, ax = plt.subplots() + + ax.stem(group_means[stats_diff], orientation = 'horizontal', basefmt = 'C7--'); + + ax.set_yticks(range(len(group_means.index)), group_means.index) + + ax.invert_yaxis(); + + +# In[ ]: + + +def plot_median_diff( + group1: IntoFrameT, + group2: IntoFrameT, + stats_diff: Literal["abs_diff", "rel_diff"] = "rel_diff", + ax: Optional[Axes] = None, +) -> None: + """Plot group median differences for each variable as a stem plot. + + Args: + group1 (IntoFrameT): + Data for group 1.Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + group2 (IntoFrameT): + Data for group 2. + stats_diff (str): + Which difference metric to plot. + - 'norm_diff': normalized difference using pooled variance + - 'abs_diff': absolute difference + - 'rel_diff': relative difference + ax (matplotlib.axes.Axes or None): + Axes to draw on. If None, a new figure/axes is created. + + Returns: + None + """ + stats_diff = build.arg_match( + stats_diff, values = ['abs_diff', 'rel_diff'], + arg_name = 'stats_diff' + ) + + group_median = compare_group_median( + group1, group2, + columns = 'common', + to_native = False + ).to_pandas().set_index('variable') + + if ax is None: + fig, ax = plt.subplots() + + ax.stem(group_median[stats_diff], orientation = 'horizontal', basefmt = 'C7--') + ax.set_yticks(range(len(group_median.index)), group_median.index) + ax.invert_yaxis(); + + +# ## クロス集計表ほか + +# In[ ]: + + +def crosstab( + data: IntoFrameT, + index: str, columns: str, + margins: bool = False, + margins_name: str = 'All', + sort_index: bool = True, + normalize: Union[bool, Literal['all', 'index', 'columns']] = False, + to_native: bool = True, + dropna: bool = False, + **kwargs: Any + ) -> IntoFrameT: + # 引数のアサーション ------------------------------------- + build.assert_logical(to_native, arg_name = 'to_native') + build.assert_logical(margins, arg_name = 'margins') + build.assert_logical(dropna, arg_name = 'dropna') + + if not isinstance(normalize, bool): + normalize = build.arg_match( + normalize, + values = ['all', 'index', 'columns'], + arg_name = 'normalize' + ) + # ----------------------------------------------------- + data_nw = nw.from_native(data) + impl = data_nw.implementation + + if impl.is_pyarrow(): + # 2026年1月11日時点で バックエンドが pyarrow の場合 + # data_nw.pivot() メソッドが使用できないことへの対処です。 + data_nw = nw.from_native(data_nw.to_polars()) + + if dropna: data_nw = data_nw.drop_nulls([index, columns]) + + result = ( + data_nw.with_columns( + nw.col(index, columns).cast(nw.String), # nan によるエラー回避のため + __n=nw.lit(1), # 1を立てる + ) + .pivot( + on = columns, + index = index, + values = '__n', + aggregate_function = 'sum', # セル内の1を合計=件数 + sort_columns = True, + ) + # 欠損セルを0にしたい場合(バックエンド依存はあるが一般にOK) + .with_columns(ncs.numeric().fill_null(0)) + ) + + if sort_index: + result = result.sort(index) + # return result + if margins: + result = result.with_columns(nw.sum_horizontal(ncs.numeric()).alias(margins_name)) + + # row_sums の作成と結合 + row_sums = result.select(ncs.numeric().sum())\ + .with_columns(nw.lit(margins_name).alias(index)) + + if normalize == 'columns': + numeric_vars = result.select(ncs.numeric()).columns + for v in numeric_vars: + result = result.with_columns( + nw.col(v) / row_sums.item(0, v) + ) + else: + result = nw.concat([ + result, row_sums.select(index, ncs.numeric()) + ], + how = 'vertical' + ) + + if normalize == 'index': + result = result.with_columns( + ncs.numeric() / nw.col(margins_name) + ).drop(margins_name, strict = False) + + if normalize == 'all': + total_val = result[margins_name].tail(1).item(0) + result = result.with_columns(ncs.numeric()/total_val) + + if not normalize: + result = result.with_columns(ncs.numeric().cast(nw.Int64)) + + + if impl.is_pyarrow(): + result = nw.from_native(result.to_arrow()) + + if not to_native: return result + + if result.implementation.is_pandas_like(): + result = nw.to_native(result).set_index(index) + else: + result = result.to_native() + return result + + +# In[ ]: + + +@pf.register_dataframe_method +def freq_table( + data: IntoFrameT, + subset: Union[str, Sequence[str]], + sort_by: Literal['frequency', 'values'] = 'frequency', + descending: bool = False, + dropna: bool = False, + to_native: bool = True, + *, + sort: Optional[bool] = None +) -> IntoFrameT: + """Compute frequency table for one or multiple columns. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + subset (str or list[str]): + Column(s) to count by. Passed to `DataFrame.value_counts(subset=...)`. + sort_by (Literal['frequency', 'values']): + Sorting rule for the output table. + - 'frequency': sort by frequency. (default) + - 'values': sort by the category values. + descending (bool): + Sort order. Defaults to False. + dropna (bool): + Whether to drop NaN from counts. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + sort (bool): + **Deprecated.** Use `sort_by` instead. + This argument is kept for backward compatibility. If provided, a + `FutureWarning` is emitted. When both `sort` and `sort_by` + are provided, `sort_by` takes precedence and `sort` is ignored. + Defaults to None. + + Returns: + IntoFrameT: + Frequency table with columns: + - freq: counts + - perc: proportions + - cumfreq: cumulative counts + - cumperc: cumulative proportions + """ + # 引数のアサーション ======================================== + sort_by = build.arg_match( + sort_by, arg_name = 'sort_by', + values = ['frequency', 'values'] + ) + + build.assert_logical(descending, arg_name = 'descending') + build.assert_logical(dropna, arg_name = 'dropna') + build.assert_logical(to_native, arg_name = 'to_native') + # ========================================================= + + # sort の非推奨処理 ======================================== + if sort is not None: + build.assert_logical(sort, arg_name = 'sort') + warnings.warn( + "`sort` argument of `freq_table()` is deprecated and will be removed in a future release of Py4Stats. " + "Please use the `sort_by` argument instead (e.g., sort_by='frequency' or sort_by='values').", + category = FutureWarning, + stacklevel = 2, + ) + # ========================================================= + + data_nw = nw.from_native(data) + + if dropna: + data_nw = data_nw.drop_nulls(subset) + + result = data_nw.with_columns(__n=nw.lit(1))\ + .group_by(nw.col(subset))\ + .agg(nw.col('__n').sum().alias('freq')) + + # sort 引数を使った処理将来廃止予定 ============================ + if sort is not None: + if sort: + result = result.sort('freq', descending = descending) + else: + result = result.sort(subset, descending = descending) + # ========================================================= + + match sort_by: + case 'frequency': + result = result.sort('freq', descending = descending) + case 'values': + result = result.sort(subset, descending = descending) + + result = result.with_columns( + (nw.col('freq') / nw.col('freq').sum()).alias('perc'), + nw.col('freq').cum_sum().alias('cumfreq') + )\ + .with_columns( + (nw.col('cumfreq') / nw.col('freq').sum()).alias('cumperc'), + ) + + if to_native: + if result.implementation.is_pandas_like(): + return result.to_native().reset_index(drop=True) + return result.to_native() + return result + + +# + +# In[ ]: + + +@pf.register_dataframe_method +def tabyl( + data: IntoFrameT, + index: str, + columns: str, + margins: bool = True, + margins_name: str = 'All', + normalize: Union[bool, Literal["index", "columns", "all"]] = "index", + dropna: bool = False, + digits: int = 1, + to_native: bool = True, + **kwargs: Any +) -> IntoFrameT: + """Create a crosstab with counts and (optionally) percentages in parentheses. + + This function produces a table similar to `janitor::tabyl()` (R), where the + main cell is a count and percentages can be appended like: `count (xx.x%)`. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + index (str): + Column name used for row categories. + columns (str): + Column name used for column categories. + margins (bool): + Add margins (totals) if True. + margins_name (str): + Name of the margin row/column. + normalize (bool or {'index','columns','all'}): + If False, return counts only. + Otherwise, compute percentages normalized by the specified axis. + dropna (bool): + Whether to drop NaN from counts. + digits (int): + Number of decimal places for percentages. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + IntoFrameT: + Crosstab table. If `normalize` is not False, cells contain strings like + `"count (xx.x%)"`. Otherwise counts (as strings after formatting). + """ + # 引数のアサーション ============================================== + build.assert_logical(margins, arg_name = 'margins') + build.assert_character(margins_name, arg_name = 'margins_name') + build.assert_logical(dropna, arg_name = 'dropna') + build.assert_count(digits, arg_name = 'digits') + # build.assert_logical(to_native, arg_name = 'to_native') + # ============================================================== + + data_nw = nw.from_native(data) + + if(not isinstance(normalize, bool)): + normalize = build.arg_match( + normalize, arg_name = 'normalize', + values = ['index', 'columns', 'all'] + ) + + # index または columns に bool 値が指定されていると後続処理でエラーが生じるので、 + # 文字列型に cast します。 + data_nw = data_nw[[index, columns]].with_columns( + ncs.boolean().cast(nw.String) + ) + + # 度数クロス集計表(最終的な表では左側の数字) + args_dict = locals() + args_dict.pop('normalize') + args_dict.pop('data') + args_dict.pop('to_native') + + c_tab1 = crosstab( + data = data_nw, + normalize = False, + to_native = False, + **args_dict + ).to_pandas().set_index(index) + + c_tab1 = c_tab1.apply(build.style_number, digits = 0) # .astype('str') + + if(normalize != False): + # 回答率クロス集計表(最終的な表では括弧内の数字) + c_tab2 = crosstab( + data = data_nw, + normalize = normalize, + to_native = False, + **args_dict + ).to_pandas().set_index(index) + + # 2つめのクロス集計表の回答率をdigitsで指定した桁数のパーセントに換算し、文字列化します。 + c_tab2 = c_tab2.apply(build.style_percent, digits = digits) + + col = c_tab2.columns + idx = c_tab2.index + # 1つめのクロス集計表も文字列化して、↑で計算したパーセントに丸括弧と%記号を追加したものを文字列として結合します。 + c_tab1.loc[idx, col] = c_tab1.loc[idx, col] + ' (' + c_tab2 + ')' + + if to_native and data_nw.implementation.is_pandas(): + return c_tab1 + + c_tab1 = c_tab1.reset_index() + # バックエンドの書き換え ============================================== + # これは非推奨の実装なので、安易に使い回さないこと。 + dict_list = {col: c_tab1[col].to_list() for col in c_tab1.columns} + result = nw.from_dict(dict_list, backend = data_nw.implementation) + #================================================================== + if to_native: return result.to_native() + return result + + +# In[ ]: + + +@pf.register_dataframe_method +@pf.register_series_method +@singledispatch +def is_dummy( + data: Union[IntoFrameT, IntoSeriesT], + cording: Sequence[Any] = (0, 1), + dropna: bool = True, + to_pd_series: bool = False, + **kwargs +) -> Union[bool, IntoSeriesT, IntoFrameT]: + """ + Check whether values consist only of dummy codes. + + This function tests whether the input data contains *only* the specified + dummy codes. The behavior and return type depend on whether the input is + Series-like or DataFrame-like. + + The function supports multiple backends via narwhals and is implemented + using ``singledispatch``. + + Args: + data: + Input data to check. Can be a Series-like or DataFrame-like object + supported by narwhals (e.g., ``pandas.Series``, + ``pandas.DataFrame``, ``polars.Series``, ``polars.DataFrame``, + ``pyarrow.Table``). + cording: + Sequence of allowed dummy codes. The input is considered valid if + its unique values exactly match this set. + Defaults to ``(0, 1)``. + dropna (bool): + Whether to drop NaN from data before value check. + to_pd_series: + Controls the return type when ``data`` is DataFrame-like. + If True, returns a ``pandas.Series`` indexed by column names. + If False, returns a Python list of boolean values. + **kwargs: + Additional keyword arguments (reserved for future extensions). + + Returns: + bool or Series-like or list: + - If ``data`` is Series-like, returns a single boolean indicating + whether the Series consists only of the specified dummy codes. + - If ``data`` is DataFrame-like and ``to_pd_series`` is False, + returns a list of boolean values, one per column. + - If ``data`` is DataFrame-like and ``to_pd_series`` is True, + returns a ``pandas.Series`` with column names as the index. + + Notes: + - A Series is considered dummy-coded if the set of its values is + exactly equal to the set specified by ``cording``. + - The check is purely set-based; value frequency and ordering are + not considered. + - Missing values are not explicitly handled and will affect the + result according to the underlying data representation. + """ + build.assert_logical(to_pd_series, arg_name = 'to_pd_series') + build.assert_logical(dropna, arg_name = 'dropna') + + data_nw = nw.from_native(data, allow_series = True) + return is_dummy(data_nw, cording, dropna, to_pd_series) + + +# In[ ]: + + +@is_dummy.register(nw.Series) +def is_dummy_series( + data: IntoSeriesT, + cording: Sequence[Any] = (0, 1), + dropna: bool = True, + to_pd_series: bool = False, + **kwargs +) -> bool: + if dropna: data = data.drop_nulls() + return set(data) == set(cording) + + +# In[ ]: + + +@is_dummy.register(list) +def is_dummy_list( + data: list, + cording: Sequence[Any] = (0, 1), + dropna: bool = True, + to_pd_series: bool = False, + **kwargs +) -> bool: + return set(data) == set(cording) + + +# In[ ]: + + +@is_dummy.register(nw.DataFrame) +def is_dummy_data_frame( + data: IntoFrameT, + cording: Sequence[Any] = (0, 1), + dropna: bool = True, + to_pd_series: bool = False, + **kwargs + ) -> Union[IntoFrameT, pd.Series]: + + data_nw = nw.from_native(data) + + result = data_nw.select( + nw.all().map_batches( + lambda x: is_dummy_series(x, cording), + return_dtype = nw.Boolean, + returns_scalar = True + ) + ) + + if to_pd_series: + return result.to_pandas().loc[0, :] + return list(result.row(0)) + + +# In[ ]: + + +import scipy as sp + +def entropy(x: IntoSeriesT, base: float = 2.0, dropna: bool = True) -> float: + build.assert_numeric(base, arg_name = 'base', lower = 0, inclusive = 'right') + build.assert_logical(dropna, arg_name = 'dropna') + + x_nw = nw.from_native(x, series_only = True) + + if dropna: x_nw = x_nw.drop_nulls() + + prop = x_nw.value_counts(normalize = True, sort = False)['proportion'] + result = sp.stats.entropy(pk = prop, base = base, axis = 0) + return result + +def normalized_entropy(x: IntoSeriesT, dropna: bool = True) -> float: + build.assert_logical(dropna, arg_name = 'dropna') + + x_nw = nw.from_native(x, series_only = True) + if dropna: x_nw = x_nw.drop_nulls() + + K = x_nw.n_unique() + result = entropy(x_nw, base = K, dropna = dropna) if K > 1 else 0.0 + + return result + + +# In[ ]: + + +@pf.register_dataframe_method +def diagnose_category(data: IntoFrameT, dropna: bool = True, to_native: bool = True) -> IntoFrameT: + """Summarize categorical variables in a DataFrame. + + This function summarizes columns that represent categorical information, + including categorical/string/boolean columns and 0/1 dummy columns + (integer-valued columns restricted to {0, 1}). Dummy columns are cast to + string before summarization. + + The summary includes missing percentage, number/percentage of unique + values, mode and its frequency/share, and evenness. + + The implementation is backend-agnostic via narwhals. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame type supported by narwhals can be + used (e.g., pandas, polars, pyarrow). + dropna (bool): + Whether to drop NaN from data before computation. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + IntoFrameT: + A summary table with one row per selected variable and the + following columns: + + - variables: variable (column) name + - count: non-missing count + - miss_pct: missing percentage + - unique: number of unique values + - unique_pct: percentage of unique values (unique / N * 100) + - mode: most frequent value + - mode_freq: frequency of the mode value + - mode_pct: percentage of the mode value (mode_freq / N * 100) + - evenness: category evenness in [0,1], where 1 indicates a + uniform distribution and 0 indicates complete concentration + in a single category. + + Raises: + TypeError: + If ``data`` is not a DataFrame/Series type supported by narwhals. + ValueError: + If no columns are selected for summarization (i.e., ``data`` has + no categorical/string/boolean columns and no 0/1 dummy columns). + + Notes: + - ``N`` denotes the number of rows of the selected DataFrame. + - ``miss_pct`` is computed as ``null_count / N * 100``. + - ``unique_pct`` and ``mode_pct`` use ``N`` in the denominator (not + the non-missing count). + - ``evenness`` is a standardized measure of category dispersion, defined + as Shannon entropy normalized to the range [0,1]. It is computed by + setting the logarithm base to the number of unique categories (unique), + which is equivalent to dividing the entropy (with base 2) by ``log_2(unique)``. + This quantity is also known as *normalized entropy*. + + Examples: + Basic usage: + + >>> summary = diagnose_category(df) + >>> summary.head() + + Keep narwhals output (do not convert back to native): + + >>> summary_nw = diagnose_category(df, to_native=False) + + Dummy columns are included automatically if they are 0/1-valued + integer columns: + + >>> df = df.assign(dummy=(df["x"] > 0).astype(int)) + >>> diagnose_category(df) + """ + build.assert_logical(to_native, arg_name = 'to_native') + build.assert_logical(dropna, arg_name = 'dropna') + + data_nw = nw.from_native(data) + res_is_dummy = is_dummy(data_nw, to_pd_series = True) + dummy_col = res_is_dummy[res_is_dummy].index.to_list() + + df = ( + data_nw + .with_columns(nw.col(dummy_col).cast(nw.String))\ + .select( + ncs.categorical(), + ncs.by_dtype(nw.String), + ncs.boolean(), + )) + N = df.shape[0] + + var_name = df.columns + + if not var_name: + raise ValueError( + "`data` has no columns to summarize.\n" + "Expected at least one categorical, string, or boolean column,\n" + "or a 0/1 dummy column (integer values restricted to {0, 1})." + ) + + result = nw.from_dict({ + 'variables': var_name, + 'count':df.select(nw.all().count()).row(0), + 'miss_pct':df.select(nw.all().null_count() * nw.lit(100 / N)).row(0), + 'unique':df.select(nw.all().drop_nulls().n_unique()).row(0), + 'mode':[ + freq_table(df, v, descending = True, to_native = False, dropna = dropna)[v][0] + for v in var_name + ], + 'mode_freq':[ + freq_table(df, v, descending = True, to_native = False, dropna = dropna)['freq'][0] + for v in var_name + ], + 'mode_pct':[ + freq_table(df, v, descending = True, to_native = False, dropna = dropna)['perc'][0] + for v in var_name + ], + 'evenness':[normalized_entropy(s, dropna = dropna) for s in df.iter_columns()] + }, + backend = df.implementation + )\ + .with_columns( + unique_pct = 100 * nw.col('unique') / N, + mode_pct = 100 * nw.col('mode_pct') + )\ + .select( + nw.col([ + 'variables', 'count', 'miss_pct', + 'unique', 'unique_pct', + 'mode', 'mode_freq', 'mode_pct', + 'evenness' + ]) + ) + + if to_native: return result.to_native() + return result + + +# ## その他の補助関数 + +# In[ ]: + + +def weighted_mean(x: IntoSeriesT, w: IntoSeriesT, dropna:bool = False) -> float: + """Compute the weighted mean of a numeric series. + + This function computes the weighted mean of a numeric vector `x` + using weights `w`. Both inputs are converted internally to a + narwhals Series to support multiple backends. + + Args: + x (IntoSeriesT): + Numeric data for which the weighted mean is computed. + Any series-like object supported by narwhals can be used + (e.g., pandas.Series, polars.Series). + w (IntoSeriesT): + Numeric weights corresponding to `x`. + Must have the same length as `x`. + dropna (bool, optional): + If `True`, observations where either `x` or `w` is missing + (NaN) are removed before computing the weighted mean. + If `False`, missing values are not removed. + Defaults to `False`. + + Returns: + float: + The weighted mean, computed as + ``sum(x * w) / sum(w)``. + + Raises: + ValueError: + If `x` or `w` is not numeric. + """ + x = nw.from_native(x, series_only = True) + w = nw.from_native(w, series_only = True) + + if dropna: + non_nan = ~x.is_nan() & ~w.is_nan() + x = x.filter(non_nan) + w = w.filter(non_nan) + + build.assert_numeric(x, arg_name = 'x') + build.assert_numeric(w, arg_name = 'w') + + wmean = (x * w).sum() / w.sum() + return wmean + + +# In[ ]: + + +@singledispatch +def scale(x: Union[IntoSeriesT, pd.DataFrame], ddof: int = 1, to_native: bool = True) -> IntoSeriesT: + """Standardize a numeric series by Z-score scaling. + + This function standardizes numeric data by subtracting the mean + and dividing by the standard deviation: + + ``(x - mean(x)) / std(x)`` + + For non-pandas inputs, the computation is performed using a + narwhals Series to ensure backend-agnostic behavior. + + Args: + x (IntoSeriesT or pandas.DataFrame): + Numeric data to be standardized. Typically a series-like + object supported by narwhals (e.g., pandas.Series, + polars.Series). A pandas DataFrame is also supported via + a specialized implementation. + ddof (int, optional): + Delta degrees of freedom used in the calculation of the + standard deviation. Defaults to `1`. + to_native (bool, optional): + If `True`, return the result in the native type corresponding + to the input (e.g., pandas.Series or polars.Series). + If `False`, return a narwhals object. + Defaults to `True`. + + Returns: + IntoSeriesT: + Standardized values with mean 0 and standard deviation 1. + + Raises: + ValueError: + If `x` is not numeric. + ValueError: + If `ddof` is not a non-negative integer. + """ + build.assert_count(ddof, arg_name = 'ddof') + build.assert_logical(to_native, arg_name = 'to_native') + + x = nw.from_native(x, series_only = True) + + build.assert_numeric(x.drop_nulls(), arg_name = 'x') + + z = (x - x.mean()) / x.std(ddof = ddof) + if to_native: return z.to_native() + return z + +@scale.register(pd.DataFrame) +def scale_pandas(x: pd.DataFrame, ddof: int = 1, to_native: bool = True) -> IntoSeriesT: + build.assert_count(ddof, arg_name = 'ddof') + build.assert_logical(to_native, arg_name = 'to_native') + + z = (x - x.mean()) / x.std(ddof = ddof) + + if to_native: return z + return nw.from_native(z, allow_series = True) + + +# In[ ]: + + +@singledispatch +def min_max(x: Union[IntoSeriesT, pd.DataFrame], to_native: bool = True) -> IntoSeriesT: + """Normalize a numeric series using min-max scaling. + + This function rescales numeric data to the range [0, 1] using + min-max normalization: + + ``(x - min(x)) / (max(x) - min(x))`` + + For non-pandas inputs, the computation is performed using a + narwhals Series to ensure backend-agnostic behavior. + + Args: + x (IntoSeriesT or pandas.DataFrame): + Numeric data to be normalized. Typically a series-like + object supported by narwhals (e.g., pandas.Series, + polars.Series). A pandas DataFrame is also supported via + a specialized implementation. + to_native (bool, optional): + If `True`, return the result in the native type corresponding + to the input. + If `False`, return a narwhals object. + Defaults to `True`. + + Returns: + IntoSeriesT: + Min-max normalized values in the range [0, 1]. + + Raises: + ValueError: + If `x` is not numeric. + """ + build.assert_logical(to_native, arg_name = 'to_native') + + x = nw.from_native(x, series_only = True) + + build.assert_numeric(x.drop_nulls(), arg_name = 'x') + + z = (x - x.min()) / (x.max() - x.min()) + if to_native: return z.to_native() + return z + +@min_max.register(pd.DataFrame) +def min_max_pandas(x: pd.DataFrame, to_native: bool = True) -> IntoSeriesT: + build.assert_logical(to_native, arg_name = 'to_native') + + z = (x - x.min()) / (x.max() - x.min()) + + if to_native: return z + return nw.from_native(z, allow_series = True) + + +# ## 完全な空白列 and / or 行の除去 + +# In[ ]: + + +def missing_percent( + data: IntoFrameT, + axis: str = 'index', + pct: bool = True + ): + data_nw = nw.from_native(data) + n = data_nw.shape[0] + + if axis == 'index': + n = data_nw.shape[0] + miss_count = pd.Series(data_nw.null_count().row(0), index = data_nw.columns) + miss_pct = (100 ** pct) * miss_count / n + return miss_pct + else: + miss_count = data_nw.with_columns( + nw.all().is_null().cast(nw.Int32) + )\ + .select( + nw.sum_horizontal(nw.all()).alias('miss_count') + )['miss_count'] + + if data_nw.implementation.is_pandas_like(): + miss_count = pd.Series(miss_count, index = data.index) + else: + miss_count = pd.Series(miss_count) + + k = data_nw.shape[1] + miss_pct = (100 ** pct) * miss_count / k + return miss_pct + + +# In[ ]: + + +@pf.register_dataframe_method +def remove_empty( + data: IntoFrameT, + cols: bool = True, + rows: bool = True, + cutoff: float = 1.0, + quiet: bool = True, + to_native: bool = True, + **kwargs: Any +) -> IntoFrameT: + """Remove fully (or mostly) empty columns and/or rows. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + cols (bool): + If True, remove empty columns. + rows (bool): + If True, remove empty rows. + cutoff (float): + Threshold on missing proportion (0-1). A column/row is removed if + missing proportion is >= cutoff. + - cutoff=1 removes only completely empty columns/rows. + quiet (bool): + If False, print removal summary. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + pandas.DataFrame: + DataFrame after removing empty columns/rows. + """ + # 引数のアサーション ============================================== + build.assert_logical(cols, arg_name = 'cols') + build.assert_logical(rows, arg_name = 'rows') + build.assert_numeric(cutoff, lower = 0, upper = 1) + build.assert_logical(quiet, arg_name = 'quiet') + build.assert_logical(to_native, arg_name = 'to_native') + # ============================================================== + + df_shape = data.shape + data_nw = nw.from_native(data) + # 空白列の除去 ------------------------------ + if cols : + empty_col = missing_percent(data, axis = 'index', pct = False) >= cutoff + data_nw = data_nw[:, (~empty_col).to_list()] + + if not(quiet) : + ncol_removed = empty_col.sum() + col_removed = empty_col[empty_col].index.to_series().astype('str').to_list() + print( + f"Removing {ncol_removed} empty column(s) out of {df_shape[1]} columns" + + f"(Removed: {','.join(col_removed)}). " + ) + # 空白行の除去 ------------------------------ + if rows : + empty_rows = missing_percent(data, axis = 'columns', pct = False) >= cutoff + data_nw = data_nw.filter((~empty_rows).to_list()) + + if not(quiet) : + nrow_removed = empty_rows.sum() + row_removed = empty_rows[empty_rows].index.to_series().astype('str').to_list() + print( + f"Removing {nrow_removed} empty row(s) out of {df_shape[0]} rows" + + f"(Removed: {','.join(row_removed)}). " + ) + + if to_native: return data_nw.to_native() + return data_nw + + +# In[ ]: + + +@pf.register_dataframe_method +def remove_constant( + data: IntoFrameT, + quiet: bool = True, + to_native: bool = True, + dropna = False, + **kwargs: Any +) -> IntoFrameT: + """Remove constant columns (columns with only one unique value). + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + quiet (bool): + If False, print removal summary. + dropna (bool): + Passed to `nunique(dropna=...)`. If False, NaN is counted as a value. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + pandas.DataFrame: + DataFrame after removing constant columns. + """ + # 引数のアサーション ============================================== + build.assert_logical(quiet, arg_name = 'quiet') + build.assert_logical(to_native, arg_name = 'to_native') + # ============================================================== + data_nw = nw.from_native(data) + df_shape = data_nw.shape + col_name = data_nw.columns + + # データフレーム(data_nw) の行が定数かどうかを判定 + def foo (col, dropna): + if dropna: + return data_nw[col].drop_nulls().n_unique() + else: + return data_nw[col].n_unique() + # unique_count = pd.Series(data_nw.select(nw.all().n_unique()).row(0), index = data_nw.columns) + unique_count = pd.Series([foo(col, dropna) for col in col_name]) + constant_col = unique_count == 1 + data_nw = data_nw[:, (~constant_col).to_list()] + + if not(quiet) : + ncol_removed = constant_col.sum() + col_removed = constant_col[constant_col].index.to_series().astype('str').to_list() + + print( + f"Removing {ncol_removed} constant column(s) out of {df_shape[1]} columns" + + f"(Removed: {','.join(col_removed)}). " + ) + if to_native: return data_nw.to_native() + return data_nw + + +# ## 列名や行名に特定の文字列を含む列や行を除外する関数 + +# In[ ]: + + +def _assert_selectors(*args, arg_name = '*args', nullable = False): + if (not args and nullable) or (all(build.is_missing(args)) and nullable): + return None + + build.assert_missing(args, arg_name = arg_name) + + is_varid = [ + isinstance(v, str) or + (build.is_character(v) and isinstance(v, list)) or + isinstance(v, nw.expr.Expr) or + isinstance(v, nw.selectors.Selector) + for v in args + ] + + if not all(is_varid): + invalids = [v for i, v in enumerate(args) if not is_varid[i]] + message = f"Argument `{arg_name}` must be of type 'str', list of 'str', 'narwhals.Expr' or 'narwhals.Selector'\n"\ + + f" The value(s) of {build.oxford_comma_and(invalids)} cannot be accepted.\n"\ + + " Examples of valid inputs: 'x', ['x', 'y'], ncs.numeric(), nw.col('x')" + + raise ValueError(message) + + +# In[ ]: + + +# 列名や行名に特定の文字列を含む列や行を除外する関数 +@pf.register_dataframe_method +def filtering_out( + data: IntoFrameT, + *args: Union[str, List[str], narwhals.Expr, narwhals.selectors.Selector], + contains: Optional[str] = None, + starts_with: Optional[str] = None, + ends_with: Optional[str] = None, + axis: Union[int, str] = 'columns', + to_native: bool = True, +) -> IntoFrameT: + """Filter out rows/columns whose labels match given string patterns. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + *args (Union[str, List[str], narwhals.Expr, narwhals.Selector]): + Columns to relocate. Each element may be: + - a column name (`str`) + - a list of column names + - a narwhals expression + - a narwhals selector + The order of columns specified here is preserved in the output. + contains (str or None): + Exclude labels that contain this substring. + starts_with (str or None): + Exclude labels that start with this substring. + ends_with (str or None): + Exclude labels that end with this substring. + axis (int or str): + Axis to filter. + - 1 or 'columns': filter columns by column labels. + Supported for all DataFrame backends handled by narwhals. + - 0 or 'index': filter rows by index (row labels). + This option is only supported when the input DataFrame has + an explicit index attribute (e.g. pandas.DataFrame). + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + IntoFrameT: + Filtered DataFrame. + + Raises: + AssertionError: + If `contains`/`starts_with`/`ends_with` is provided but not a string. + TypeError: + If axis is set to 'index' (or 0) but the input DataFrame + does not support row labels (i.e. has no 'index' attribute). + + Notes: + Row-wise filtering via axis='index' relies on the presence of an explicit index. + Therefore, this option is not available for DataFrame backends that do not expose + row labels (e.g. some Arrow-based tables). + + """ + # 引数のアサーション ============================================== + axis = str(axis) + axis = build.arg_match(axis, arg_name = 'axis', values = ['1', 'columns', '0', 'index']) + build.assert_logical(to_native, arg_name = 'to_native') + build.assert_character(contains, arg_name = 'contains', nullable = True) + build.assert_character(starts_with, arg_name = 'starts_with', nullable = True) + build.assert_character(ends_with, arg_name = 'ends_with', nullable = True) + _assert_selectors(*args, nullable = True) + # ============================================================== + data_nw = nw.from_native(data) + + # columns に基づく除外処理 ================================================================= + if axis in ("0", "index"): + drop_table = pd.DataFrame() + if not hasattr(data, "index"): + raise TypeError( + f"filtering_out(..., axis='{axis}') requires an input that has" + "an 'index' (row labels), e.g. pandas.DataFrame.\n" + f"Got: {type(data)}." + ) + if((axis == '1') | (axis == 'columns')): + drop_table = pd.DataFrame() + + if args: + drop_list = data_nw.select(args).columns + else: drop_list = [] + + s_columns = pd.Series(data_nw.columns) + if contains is not None: + drop_table['contains'] = s_columns.str.contains(contains) + + if starts_with is not None: + drop_table['starts_with'] = s_columns.str.startswith(starts_with) + + if ends_with is not None: + drop_table['ends_with'] = s_columns.str.endswith(ends_with) + + if contains is not None or starts_with is not None or ends_with is not None: + drop_list = drop_list + s_columns[drop_table.any(axis = 'columns')].to_list() + + data_nw = data_nw.drop(drop_list) + if to_native: return data_nw.to_native() + return data_nw + + # index に基づく除外処理 ================================================================= + elif isinstance(data, pd.DataFrame): + drop_table = pd.DataFrame(index = data.index) + if args: + if isinstance(args[0], Union[list, tuple]): + args = args[0] + drop_table['selected'] = data.index.isin(list(args)) + + if contains is not None: + drop_table['contains'] = data.index.to_series().str.contains(contains) + + if starts_with is not None: + # return data.index.to_series().str.startswith(starts_with) + drop_table.loc[:, 'starts_with'] = data.index.to_series().str.startswith(starts_with) + + if ends_with is not None: + drop_table['ends_with'] = data.index.to_series().str.endswith(ends_with) + + # return drop_table + if args or contains is not None or starts_with is not None or ends_with is not None: + keep_list = (~drop_table.any(axis = 'columns')).to_list() + data_nw = data_nw.filter(keep_list) + + if to_native: return data_nw.to_native() + return data_nw + + +# # パレート図を作図する関数 + +# In[ ]: + + +def Pareto_plot( + data: IntoFrameT, + group: str, + values: Optional[str] = None, + top_n: Optional[int] = None, + aggfunc: Callable[..., Any] = np.mean, + ax: Optional[Axes] = None, + fontsize: int = 12, + xlab_rotation: Union[int, float] = 0, + palette: Sequence[str] = ("#478FCE", "#252525"), +) -> None: + """Plot a Pareto chart. + + If `values` is None, the chart is built from frequency counts of `group`. + Otherwise, it aggregates `values` by `group` using `aggfunc`. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + group (str): + Grouping column (x-axis categories). + values (str or None): + Value column to aggregate. If None, uses counts. + top_n (int or None): + If specified, plot only top-N categories. + aggfunc (callable): + Aggregation function used to compute a single summary value for each group. + This argument accepts either a general callable (e.g., ``numpy.mean`` or a + user-defined function) that takes a one-dimensional array-like object + containing the values of a group and returns a single scalar, or a function + from ``narwhals.functions`` (e.g., ``narwhals.mean``, ``narwhals.sum``), + which will be applied directly within the narwhals + ``group_by().agg()`` workflow. + Defaults to ``numpy.mean``. + ax (matplotlib.axes.Axes or None): + Axes to draw the bar chart on. If None, a new figure/axes is created. + fontsize (int): + Base font size. + xlab_rotation (float or int): + Rotation angle for x tick labels. + palette (list[str]): + Colors for bar and line. (Note: this function explicitly uses colors.) + + Returns: + None + + Notes: + The aggregation function is expected to return a single scalar value for + each group. If the function returns an array-like object or multiple + values, the resulting output may be invalid or lead to unexpected + behavior. + """ + + # 引数のアサーション =================================================================== + build.assert_numeric(fontsize, arg_name = 'fontsize', lower = 0, inclusive = 'right') + build.assert_numeric(xlab_rotation, arg_name = 'xlab_rotation') + build.assert_character(palette, arg_name = 'palette') + # =================================================================================== + data_nw = nw.from_native(data) + # 指定された変数でのランクを表すデータフレームを作成 + if values is None: + shere_rank = freq_table( + data_nw, group, dropna = True, + sort_by = 'frequency', + descending = True, + to_native = False + ) + cumlative = 'cumfreq' + # None のままだと `.top_k()` メソッドの使用に問題が生じるため + values = 'freq' + else: + shere_rank = make_rank_table( + data_nw.to_pandas(), + group, + values, + aggfunc = aggfunc, + to_native = False + ) + cumlative = 'cumshare' + + if top_n is not None: + build.assert_count(top_n, lower = 1, arg_name = 'top_n') + shere_rank = shere_rank.top_k(k = top_n, by = values) + + shere_rank = shere_rank.to_pandas().set_index(group) + + # 作図 + args_dict = locals() + make_Pareto_plot(**args_dict) + + +# In[ ]: + + +def make_rank_table( + data: pd.DataFrame, + group: str, + values: str, + aggfunc: Callable[..., Any] = np.mean, + to_native: bool = True, +) -> pd.DataFrame: + data_nw = nw.from_native(data) + + # 引数のアサーション =================================================================== + col_names = data_nw.columns + build.assert_scalar(group, arg_name = 'group') + build.assert_scalar(values, arg_name = 'values') + group = build.arg_match(group, values = col_names, arg_name = 'group') + values = build.arg_match(values, values = col_names, arg_name = 'values') + # =================================================================================== + + if aggfunc.__module__ == 'narwhals.functions': + stat_table = data_nw.group_by(group)\ + .agg(aggfunc(values)) + else: + group_value = data_nw[group].unique() + + # stat_values = [ + # aggfunc(data_nw.filter(nw.col(group) == g)[values].drop_nulls().to_native()) + # for g in group_value + # ] + stat_values = [ + aggfunc( + data_nw.filter(nw.col(group) == g)[values] + .drop_nulls().to_native() + ) + for g in group_value + ] + + stat_table = nw.from_dict({ + group:group_value, values:stat_values + }, backend = data_nw.implementation + ) + + rank_table = stat_table.sort(values, descending = True)\ + .with_columns(share = nw.col(values) / nw.col(values).sum())\ + .with_columns(cumshare = nw.col('share').cum_sum()) + + if to_native: + return rank_table.to_native() + else: + return rank_table + + +# In[ ]: + + +def make_Pareto_plot( + shere_rank: pd.DataFrame, + group: str, + cumlative: str, + values: Optional[str] = None, + ax: Optional[Axes] = None, + fontsize: int = 12, + xlab_rotation: Union[int, float] = 0, + palette: Sequence[str] = ("#478FCE", "#252525"), + **kwargs: Any +): + # グラフの描画 + if ax is None: + fig, ax = plt.subplots() + + if values is None: + ax.bar(shere_rank.index, shere_rank['freq'], color = palette[0]) + ax.set_ylabel('freq', fontsize = fontsize * 1.1) + else: + # yで指定された変数の棒グラフ + ax.bar(shere_rank.index, shere_rank[values], color = palette[0]) + ax.set_ylabel(values, fontsize = fontsize * 1.1) + + ax.set_xlabel(group, fontsize = fontsize * 1.1) + + # 累積相対度数(シェア率)の線グラフ + ax2 = ax.twinx() + ax2.plot( + shere_rank.index, shere_rank[cumlative], + linestyle = 'dashed', color = palette[1], marker = 'o' + ) + + ax2.set_xlabel(group, fontsize = fontsize * 1.1) + ax2.set_ylabel(cumlative, fontsize = fontsize * 1.1) + + # x軸メモリの回転 + ax.xaxis.set_tick_params(rotation = xlab_rotation, labelsize = fontsize) + ax2.xaxis.set_tick_params(rotation = xlab_rotation, labelsize = fontsize); + ax.yaxis.set_tick_params(labelsize = fontsize * 0.9) + ax2.yaxis.set_tick_params(labelsize = fontsize * 0.9); + + +# ### 代表値 + 区間推定関数 +# +# ```python +# import pandas as pd +# from palmerpenguins import load_penguins +# penguins = load_penguins() # サンプルデータの読み込み +# +# from py4stats import eda_tools as eda +# +# print(penguins['bill_depth_mm'].mean_qi().round(2)) +# #> mean lower upper +# #> variable +# #> bill_depth_mm 17.15 13.9 20.0 +# +# print(penguins['bill_depth_mm'].median_qi().round(2)) +# #> median lower upper +# #> variable +# #> bill_depth_mm 17.3 13.9 20.0 +# +# print(penguins['bill_depth_mm'].mean_ci().round(2)) +# #> mean lower upper +# #> variable +# #> bill_depth_mm 17.15 16.94 17.36 +# ``` + +# In[ ]: + + +Interpolation = Literal[ + 'inverted_cdf', 'averaged_inverted_cdf', 'closest_observation', + 'interpolated_inverted_cdf', 'hazen', 'weibull', 'linear', + 'median_unbiased', 'normal_unbiased', 'lower', 'higher', + 'midpoint', 'nearest' + ] + +interpolation_values = [ + 'inverted_cdf', 'averaged_inverted_cdf', 'closest_observation', + 'interpolated_inverted_cdf', 'hazen', 'weibull', 'linear', + 'median_unbiased', 'normal_unbiased', 'lower', 'higher', + 'midpoint', 'nearest' + ] + + +# In[ ]: + + +@pf.register_dataframe_method +@pf.register_series_method +@singledispatch +def mean_qi( + data: Union[IntoFrameT, SeriesT], + width: float = 0.975, + interpolation: Interpolation = 'midpoint', + to_native: bool = True +) -> IntoFrameT: + """Compute mean and quantile interval (QI). + + Args: + data (IntoFrameT, IntoSeriesT): + Input data. Any DataFrame-like or Series-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + width (float): + Upper quantile to use (must be in (0, 1)). + Lower quantile is computed as `1 - width`. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + IntoFrameT: + Table indexed by variable names with columns: + - mean: mean value + - lower: quantile at `1 - width` + - upper: quantile at `width` + + Raises: + AssertionError: + If `width` is not in (0, 1). + """ + # 引数のアサーション ======================================================= + build.assert_numeric(width, lower = 0, upper = 1, inclusive = 'neither') + build.assert_logical(to_native, arg_name = 'to_native') + interpolation = build.arg_match( + interpolation, arg_name = 'interpolation', + values = interpolation_values + ) + # ======================================================================= + + data_nw = nw.from_native(data, allow_series = True) + return mean_qi( + data_nw, interpolation = interpolation, + width = width, to_native = to_native + ) + +@mean_qi.register(nw.DataFrame) +def mean_qi_data_frame( + data: IntoFrameT, + width: float = 0.975, + interpolation: Interpolation = 'midpoint', + to_native: bool = True + ) -> pd.DataFrame: + + df_numeric = nw.from_native(data).select(ncs.numeric()) + + result = nw.from_dict({ + 'variable': df_numeric.columns, + 'mean': df_numeric.select(ncs.numeric().mean()).row(0), + 'lower': df_numeric.select( + ncs.numeric().quantile(1 - width, interpolation = interpolation) + ).row(0), + 'upper': df_numeric.select( + ncs.numeric().quantile(width, interpolation = interpolation) + ).row(0) + }, backend = df_numeric.implementation + ) + if to_native: return result.to_native() + return result + +@mean_qi.register(nw.Series) +def mean_qi_series( + data: SeriesT, + width: float = 0.975, + interpolation: Interpolation = 'midpoint', + to_native: bool = True + ): + + data_nw = nw.from_native(data, allow_series=True) + + result = nw.from_dict({ + 'variable': [data_nw.name], + 'mean': [data_nw.mean()], + 'lower': [data_nw.quantile(1 - width, interpolation = interpolation)], + 'upper': [data_nw.quantile(width, interpolation = interpolation)] + }, backend = data_nw.implementation + ) + if to_native: return result.to_native() + return result + + +# In[ ]: + + +@pf.register_dataframe_method +@pf.register_series_method +@singledispatch +def median_qi( + data: Union[IntoFrameT, IntoSeriesT], + width: float = 0.975, + interpolation: Interpolation = 'midpoint', + to_native: bool = True +) -> IntoFrameT: + """Compute median and quantile interval (QI). + + Args: + data (IntoFrameT, IntoSeriesT): + Input data. Any DataFrame-like or Series-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + width (float): + Upper quantile to use (must be in (0, 1)). + Lower quantile is computed as `1 - width`. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + IntoFrameT: + Table indexed by variable names with columns: + - median: median value + - lower: quantile at `1 - width` + - upper: quantile at `width` + + Raises: + AssertionError: + If `width` is not in (0, 1). + """ + # 引数のアサーション ======================================================= + build.assert_numeric(width, lower = 0, upper = 1, inclusive = 'neither') + build.assert_logical(to_native, arg_name = 'to_native') + interpolation = build.arg_match( + interpolation, arg_name = 'interpolation', + values = interpolation_values + ) + # ======================================================================= + + data_nw = nw.from_native(data, allow_series = True) + return median_qi( + data_nw, interpolation = interpolation, + width = width, to_native = to_native + ) + +@median_qi.register(nw.DataFrame) +def median_qi_data_frame( + data: IntoFrameT, + width: float = 0.975, + interpolation: Interpolation = 'midpoint', + to_native: bool = True +) -> IntoFrameT: + + df_numeric = nw.from_native(data).select(ncs.numeric()) + + result = nw.from_dict({ + 'variable': df_numeric.columns, + 'median': df_numeric.select(ncs.numeric().median()).row(0), + 'lower': df_numeric.select( + ncs.numeric().quantile(1 - width, interpolation = interpolation) + ).row(0), + 'upper': df_numeric.select( + ncs.numeric().quantile(width, interpolation = interpolation) + ).row(0) + }, backend = df_numeric.implementation + ) + if to_native: return result.to_native() + return result + +@median_qi.register(nw.Series) +def median_qi_series( + data: IntoSeriesT, + width: float = 0.975, + interpolation: Interpolation = 'midpoint', + to_native: bool = True +) -> IntoFrameT: + data_nw = nw.from_native(data, allow_series=True) + + result = nw.from_dict({ + 'variable': [data_nw.name], + 'median': [data_nw.median()], + 'lower': [data_nw.quantile(1 - width, interpolation = interpolation)], + 'upper': [data_nw.quantile(width, interpolation = interpolation)] + }, backend = data_nw.implementation + ) + if to_native: return result.to_native() + return result + + +# In[ ]: + + +from scipy.stats import t +@pf.register_dataframe_method +@pf.register_series_method +@singledispatch +def mean_ci( + data: Union[IntoFrameT, IntoSeriesT], + width: float = 0.975, + to_native: bool = True +) -> IntoFrameT: + """Compute mean and t-based confidence interval (CI). + + Args: + data (IntoFrameT, IntoSeriesT): + Input data. Any DataFrame-like or Series-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + width (float): + Confidence level in (0, 1) (e.g., 0.95). + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + + Returns: + IntoFrameT: + Table indexed by variable names with columns: + - mean: sample mean + - lower: lower bound of CI + - upper: upper bound of CI + + Raises: + AssertionError: + If `width` is not in (0, 1). + + Notes: + Uses t critical value with df = n - 1: + `t.isf((1 - width) / 2, df=n-1)`. + """ + # 引数のアサーション ======================================================= + build.assert_numeric(width, lower = 0, upper = 1, inclusive = 'neither') + build.assert_logical(to_native, arg_name = 'to_native') + # ======================================================================= + + data_nw = nw.from_native(data, allow_series = True) + + return mean_ci( + data_nw, width = width, to_native = to_native + ) + +@mean_ci.register(nw.DataFrame) +def mean_ci_data_frame( + data: IntoFrameT, + width: float = 0.975, + to_native: bool = True +) -> IntoFrameT: + df_numeric = nw.from_native(data).select(ncs.numeric()) + n = len(df_numeric) + t_alpha = t.isf((1 - width) / 2, df = n - 1) + x_mean = df_numeric.select(ncs.numeric().mean())\ + .to_numpy()[0, :] + x_std = df_numeric.select(ncs.numeric().std())\ + .to_numpy()[0, :] + + result = nw.from_dict({ + 'variable': df_numeric.columns, + 'mean':x_mean, + 'lower':x_mean - t_alpha * x_std / np.sqrt(n), + 'upper':x_mean + t_alpha * x_std / np.sqrt(n), + }, backend = df_numeric.implementation + ) + if to_native: return result.to_native() + return result + +@mean_ci.register(nw.Series) +def mean_ci_series( + data: SeriesT, + width: float = 0.975, + to_native: bool = True +) -> IntoFrameT: + data_nw = nw.from_native(data, allow_series=True) + n = len(data_nw) + t_alpha = t.isf((1 - width) / 2, df = n - 1) + x_mean = data_nw.mean() + x_std = data_nw.std() + + result = nw.from_dict({ + 'variable': [data_nw.name], + 'mean':[x_mean], + 'lower':[x_mean - t_alpha * x_std / np.sqrt(n)], + 'upper':[x_mean + t_alpha * x_std / np.sqrt(n)], + }, backend = data_nw.implementation + ) + if to_native: return result.to_native() + return result + + +# ## 正規表現と文字列関連の論理関数 + +# In[ ]: + + +@pf.register_series_method +def is_kanzi(data:IntoSeriesT, na_default:bool = True, to_native: bool = True) -> IntoSeriesT: + """ + Check whether each element contains Kanji characters. + + This method returns a boolean Series indicating whether each string + element contains at least one Kanji character (Unicode range U+4E00–U+9FFF). + + Args: + data: + Input Series containing string-like values. + na_default: + Boolean value to use for missing values (e.g., ``None``, ``NaN``). + to_native (bool, optional): + If True, convert the result to the native Series type of the + selected backend. If False, return a narwhals Series. + Defaults to True. + + Returns: + Series of boolean values indicating whether each element contains + Kanji characters. + + Notes: + - The check is performed using a regular expression. + - Missing values are filled with ``na_default`` before returning + the result. + """ + build.assert_logical(to_native, arg_name = 'to_native') + build.assert_logical(na_default, arg_name = 'na_default') + + data_nw = nw.from_native(data, allow_series = True) + + result = data_nw.str.contains('[\u4E00-\u9FFF]+').fill_null(na_default) + + if to_native: return result.to_native() + return result + + + +# In[ ]: + + +@pf.register_series_method +def is_ymd(data:IntoSeriesT, na_default:bool = True, to_native: bool = True) -> IntoSeriesT: + """ + Check whether each element matches a YYYY-MM-DD date format. + + This method tests whether each string matches the pattern + ``YYYY-M-D`` or ``YYYY-MM-DD`` using a regular expression. + No validation of actual calendar dates is performed. + + Args: + data: + Input Series containing string-like values. + na_default: + Boolean value to use for missing values (e.g., ``None``, ``NaN``). + to_native (bool, optional): + If True, convert the result to the native Series type of the + selected backend. If False, return a narwhals Series. + Defaults to True. + + Returns: + Series of boolean values indicating whether each element matches + the YYYY-MM-DD pattern. + + Notes: + - This function checks only the string pattern, not date validity. + - Missing values are filled with ``na_default`` before returning + the result. + """ + build.assert_logical(to_native, arg_name = 'to_native') + build.assert_logical(na_default, arg_name = 'na_default') + + rex_ymd = '[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}' + + data_nw = nw.from_native(data, allow_series = True) + + result = data_nw.str.contains(rex_ymd) + + result = result.fill_null(na_default) + if to_native: return result.to_native() + return result + + +# In[ ]: + + +@pf.register_series_method +def is_ymd_like(data:IntoSeriesT, na_default:bool = True, to_native: bool = True) -> IntoSeriesT: + """ + Check whether each element resembles a date in year-month-day order. + + This method detects strings that resemble date-like expressions such as + ``2023-1-5``, ``2023年1月5日``, or similar variants using a regular + expression. + + Args: + data: + Input Series containing string-like values. + na_default: + Boolean value to use for missing values. + to_native (bool, optional): + If True, convert the result to the native Series type of the + selected backend. If False, return a narwhals Series. + Defaults to True. + + Returns: + Series of boolean values indicating whether each element resembles + a year-month-day style date. + + Notes: + - The check is based on a regular expression and does not validate + whether the date actually exists. + - Missing values are filled with ``na_default`` before returning + the result. + """ + build.assert_logical(to_native, arg_name = 'to_native') + build.assert_logical(na_default, arg_name = 'na_default') + + rex_ymd_like = '[Script=Han]{0,2}[0-9]{1,4}(?:年|-)[0-9]{1,2}(?:月|-)[0-9]{1,2}(?:日)?' + + data_nw = nw.from_native(data, allow_series = True) + + result = data_nw.str.contains(rex_ymd_like) + + result = result.fill_null(na_default) + if to_native: return result.to_native() + return result + + +# In[ ]: + + +@pf.register_series_method +def is_number(data:IntoSeriesT, na_default:bool = True, to_native: bool = True) -> IntoSeriesT: + """ + Check whether each element represents a numeric value. + + This method evaluates whether each string element can be interpreted + as a number, including integers and scientific notation, while excluding + alphabetic characters, kana, kanji, phone-number-like patterns, and + other non-numeric forms. + + Args: + data: + Input Series containing string-like values. + na_default: + Boolean value to use for missing values. + to_native (bool, optional): + If True, convert the result to the native Series type of the + selected backend. If False, return a narwhals Series. + Defaults to True. + + Returns: + Series of boolean values indicating whether each element represents + a numeric value. + + Notes: + - This function uses multiple regular-expression-based heuristics + rather than numeric type casting. + - Scientific notation (e.g., ``1e-3``) is treated as numeric. + - Missing values are filled with ``na_default`` before returning + the result. + """ + build.assert_logical(to_native, arg_name = 'to_native') + build.assert_logical(na_default, arg_name = 'na_default') + + data_nw = nw.from_native(data, allow_series = True) + + rex_dict = { + 'exponent': r'[0-9]+[Ee][+-][0-9]+', + 'numeric':'[0-9]+', + 'phone':'[0-9]{0,4}(?: |-)[0-9]{0,4}(?: |-)[0-9]{0,4}', + 'alpha':'[A-z]+', + 'ひらがな': '[\u3041-\u309F]+', + 'カタカナ':'[\u30A1-\u30FF]+', + '半角カタカナ':'[\uFF61-\uFF9F]+', + '漢字':'[\u4E00-\u9FFF]+', + 'ymd_like':'[Script=Han]{0,2}[0-9]{1,4}(?:年|-)[0-9]{1,2}(?:月|-)[0-9]{1,2}(?:日)?' + } + + result_dict = { + key:~(data_nw.str.contains(rex_val).fill_null(na_default).cast(nw.Boolean)) + for rex_val, key in zip(rex_dict.values(), rex_dict.keys()) + } + + result_dict['numeric'] = ~result_dict['numeric'] + result_dict['exponent'] = ~result_dict['exponent'] + result_table = nw.from_dict(result_dict) + selected_col = list(rex_dict.keys())[1:] + + result = result_table\ + .with_columns( + res1 = nw.all_horizontal(nw.col(selected_col), ignore_nulls = True), + )\ + .with_columns( + result = nw.col('res1') | nw.col('exponent') + )['result'] + result + + if to_native: return result.to_native() + return result + + +# ## 簡易なデータバリデーションツール + +# In[ ]: + + +@pf.register_dataframe_method +def check_that( + data: IntoFrameT, + rule_dict: Union[Mapping[str, str], pd.Series], + to_native: bool = True, + **kwargs: Any, +) -> IntoFrameT: + """Evaluate validation rules and summarize pass/fail counts. + + Each rule is an expression evaluated by `pd.DataFrame.eval(...)` and must return + a boolean array-like of length equal to the number of rows, or a scalar bool. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + rule_dict (dict or pandas.Series): + Mapping from rule name to expression string (for `DataFrame.eval`). + If a Series is given, it is converted to dict. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + **kwargs: + Keyword arguments forwarded to `DataFrame.eval(...)` (e.g., engine, parser). + + Returns: + IntoFrameT: + Summary with columns: + - rule: name of rules which taken from keys of `rule_dict` + - item: number of evaluated items. + For rules evaluated per record, this corresponds to the number of rows + in the input data. For rules evaluated at the dataset level (e.g., rules + based on aggregated values), this value is 1. + - passes: number of records that were evaluated and determined to satisfy the rule. + - fails: number of records that were evaluated and determined not to satisfy the rule. + - countna: number of records for which the rule could not be evaluated due to missing values. + For record-level rules, if any variable used in the rule contains a missing + value for a given record, the result is treated as NA, and that record is + counted here. + - expression: the rule expression string + + Raises: + ValueError: + If a rule expression does not evaluate to a boolean result. + """ + # 引数のアサーション =============================================================== + if hasattr(rule_dict, 'to_dict'): rule_dict = rule_dict.to_dict() + build.assert_character(rule_dict.values(), arg_name = 'rule_dict') + build.assert_logical(to_native, arg_name = 'to_native') + # =============================================================================== + data_nw = nw.from_native(data) + data_pd = data_nw.to_pandas() + col_names = data_nw.columns + N = data_nw.shape[0] + + result_list = [] + for name, rule in zip(rule_dict.keys(), rule_dict.values()): + + passes = pd.Series(data_pd.eval(rule, **kwargs)) + + # `rule` 評価結果がブール値ではない場合、エラーを出す。 + if not build.is_logical(passes): + raise ValueError( + "Result of rule evaluation must be boolean. " + f"But the result of rule '{name}' has dtype '{passes.dtype}'. " + "Each rule must evaluate to a boolean expression." + ) + + # 欠測値の代入処理 ============================================================== + # passes の長さがデータの行数と等しく rule の計算に使用した変数に欠測値が含まれる場合、 + # そのレコードの passes は欠測値として扱います。これはそのレコードでは、 + # rule の検証ができなかったものとして扱うためです。 + if build.length(passes) == N: + use_in_rule = [col for col in col_names if col in rule] + + any_na = data_pd.loc[:, use_in_rule].isna().any(axis = 'columns') + + passes = passes.astype('boolean').mask(any_na, pd.NA) + # ============================================================================= + res_dict = { + 'rule':name, + 'item':len(passes), + 'passes':passes.sum(skipna = True), + 'fails':(~passes).sum(skipna = True), + 'countna':passes.isna().sum(), + 'expression':rule + } + + result_list.append(res_dict) + + result = nw.from_dicts(result_list, backend = data_nw.implementation) + + if to_native: return result.to_native() + return result + + +# In[ ]: + + +@pf.register_dataframe_method +def check_viorate( + data: IntoFrameT, + rule_dict: Union[Mapping[str, str], pd.Series], + to_native: bool = True, + **kwargs: Any, +) -> IntoFrameT: + """Return row-wise rule violation indicators for each rule. + + Args: + data (IntoFrameT): + Input DataFrame. Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + rule_dict (dict or pandas.Series): + Mapping from rule name to expression string (for `DataFrame.eval`). + If a Series is given, it is converted to dict. + to_native (bool, optional): + If True, convert the result to the native DataFrame type of the + selected backend. If False, return a narwhals DataFrame. + Defaults to True. + **kwargs: + Keyword arguments forwarded to `DataFrame.eval(...)`. + + Returns: + IntoFrameT: + Boolean DataFrame with one column per rule indicating violations + (True means violation) or rule evaluation failed due to a missing value. + Additional columns: + - any: True if any rule is violated or failed to evaluation in the row. + - all: True if all rules are violated or failed to evaluation in the row. + + Raises: + ValueError: + If a rule expression does not evaluate to a boolean result. + """ + # 引数のアサーション =============================================================== + if hasattr(rule_dict, 'to_dict'): rule_dict = rule_dict.to_dict() + build.assert_character(rule_dict.values(), arg_name = 'rule_dict') + build.assert_logical(to_native, arg_name = 'to_native') + # =============================================================================== + data_nw = nw.from_native(data) + data_pd = data_nw.to_pandas() + value_impl = data_nw.implementation + N = data_nw.shape[0] + col_names = data_nw.columns + + result_dict = dict() + + for name, rule in zip(rule_dict.keys(), rule_dict.values()): + violation = ~data_pd.eval(rule, **kwargs) + + # `rule` 評価結果がブール値ではない場合、エラーを出す。 + if not build.is_logical(violation): + raise ValueError( + "Result of rule evaluation must be boolean. " + f"But the result of rule '{name}' has dtype '{violation.dtype}'. " + "Each rule must evaluate to a boolean expression." + ) + + # 恐らく起きないと思いますが、violation が長さ N(データのレコード数)のSeries か、 + # スカラー値でなければ、nw.from_dict() でエラーが生じるので、 + # 当てはまらない場合は補正します。 + if isinstance(violation, pd.Series) and build.length(violation) != N: + violation = violation.iloc[0] + + if not isinstance(violation, pd.Series) and build.length(violation) == 1: + violation = pd.Series(N * [violation]) + + result_dict.update({name: violation}) + + # any と all 列の追加 ============================================================= + result_pd = pd.DataFrame(result_dict) + result_dict.update({ + 'any': result_pd.any(axis = 'columns'), + 'all': result_pd.all(axis = 'columns') + }) + # =============================================================================== + # return result_dict + result = nw.from_dict( + result_dict, + backend = value_impl + ).select( + nw.col(list(rule_dict.keys())), + nw.col('any', 'all') + ) + # 列の並びを key の並びと一致させるため + + # return result + if to_native: return result.to_native() + return result + + +# ### helper function for pandas `DataFrame.eval()` + +# In[ ]: + + +def implies_exper(P, Q): + return f"{Q} | ~({P})" + +@singledispatch +def is_complete(data: pd.DataFrame) -> pd.Series: + return data.notna().all(axis = 'columns') + +@is_complete.register(pd.Series) +def _(*arg: pd.Series) -> pd.Series: + return pd.concat(arg, axis = 'columns').notna().all(axis = 'columns') + + +# In[ ]: + + +def Sum(*arg: List[pd.Series]): + return pd.concat(arg, axis = 'columns').sum(axis = 'columns') +def Mean(*arg: List[pd.Series]): + return pd.concat(arg, axis = 'columns').mean(axis = 'columns') +def Max(*arg: List[pd.Series]): + return pd.concat(arg, axis = 'columns').max(axis = 'columns') +def Min(*arg: List[pd.Series]): + return pd.concat(arg, axis = 'columns').min(axis = 'columns') +def Median(*arg: List[pd.Series]): + return pd.concat(arg, axis = 'columns').median(axis = 'columns') + + +# ## set missing values in Series + +# In[ ]: + + +@pf.register_series_method +def set_miss( + x: IntoSeriesT, + n: Optional[int] = None, + prop: Optional[float] = None, + method: Literal['random', 'first', 'last'] = 'random', + random_state: Optional[int] = None, + na_value: Any = None, + to_native: bool = True + ): + """Insert missing values into a Series. + + This function replaces a specified number or proportion of non-missing + elements in a Series with missing values. It supports multiple Series + backends via narwhals and is primarily intended for generating test data + or simulating missingness. + + Exactly one of `n` or `prop` must be specified. + + Args: + x (IntoSeriesT): + Input Series. Any Series-like object supported by narwhals + (e.g., pandas.Series, polars.Series, pyarrow.ChunkedArray) + can be used. + n (int, optional): + Target number of missing values in the Series after processing. + If the Series already contains `n` or more missing values, + no additional missing values are added and a warning is issued. + prop (float, optional): + Target proportion of missing values in the Series after processing. + Must be between 0 and 1. If the current proportion of missing + values is greater than or equal to `prop`, no additional missing + values are added and a warning is issued. + method ({'random', 'first', 'last'}, optional): + Strategy for selecting elements to be replaced with missing values. + - ``'random'``: randomly select non-missing elements. + - ``'first'``: select from the beginning of the Series. + - ``'last'``: select from the end of the Series. + Defaults to ``'random'``. + random_state (int, optional): + Random seed used when ``method='random'`` to ensure reproducibility. + na_value (Any, optional): + Value used to represent missing data. Defaults to ``None``. + to_native (bool, optional): + If True, return the result as a native Series class of 'x'. + If False, return a `narwhals.Series`. + + Returns: + IntoSeriesT or narwhals.Series: + Series with additional missing values inserted. The return type + depends on the value of ``to_native``. + + Raises: + ValueError: + If neither or both of `n` and `prop` are specified. + + Warns: + UserWarning: + If the input Series already contains the specified number or + proportion of missing values and no additional missing values + are added. + + Examples: + >>> import pandas as pd + >>> import py4stats as py4st + >>> s = pd.Series([1, 2, 3, 4, 5]) + >>> py4st.set_miss(s, n=2, method='first') + 0 NaN + 1 NaN + 2 3.0 + 3 4.0 + 4 5.0 + dtype: float64 + + >>> py4st.set_miss(s, prop=0.4, method='random', random_state=0) + 0 1.0 + 1 NaN + 2 3.0 + 3 NaN + 4 5.0 + dtype: float64 + """ + x_nw = nw.from_native(x, series_only = True) + + # 引数のアサーション ================================================================== + if not((n is not None) ^ (prop is not None)): + raise ValueError("Exactly one of `n` and `prop` must be specified.") + + build.assert_logical(to_native, arg_name = 'to_native') + + n_miss = x_nw.null_count() + p_miss = n_miss / x_nw.shape[0] + + method = build.arg_match( + method, arg_name = 'method', + values = ['random', 'first', 'last'] + ) + build.assert_count( + n, arg_name = 'n', + lower = 0, upper = len(x), + nullable = True, scalar_only = True + ) + build.assert_numeric( + prop, arg_name = 'prop', + lower = 0, upper = 1, + nullable = True, scalar_only = True + ) + + # 欠測値代入個数の計算 ================================================================= + idx = pd.Series(np.arange(len(x_nw))) + non_miss = idx[~build.is_missing(x_nw)] + + if n is not None: + n_to_miss = np.max([n - n_miss, 0]) + + if n_to_miss <=0: + warnings.warn( + f"Already contained {n_miss}(>= n) missing value(s) in `x`, " + "no additional missing values were added.", + category = UserWarning, + stacklevel = 2 + ) + if to_native: return x_nw.to_native() + return x_nw + + elif prop is not None: + n_non_miss = non_miss.shape[0] + + n_to_miss = int(np.max([ + np.ceil(n_non_miss * (prop - p_miss)), 0 + ])) + + if prop <= p_miss: + warnings.warn( + f"Already contained {p_miss:.3f}(>= prop) missing value(s) in `x`, " + "no additional missing values were added.", + category = UserWarning, + stacklevel = 2 + ) + if to_native: return x_nw.to_native() + return x_nw + + # 欠測値代入位置の決定 ===================================================================== + + match method: + case 'random': + index_to_na = non_miss.sample(n = n_to_miss, random_state = random_state) + case 'first': + index_to_na = non_miss.head(n_to_miss) + case 'last': + index_to_na = non_miss.tail(n_to_miss) + + # 欠測値の代入と結果の出力 =================================================================== + x_with_na = [na_value if i in index_to_na else v + for i, v in enumerate(x_nw)] + + result = nw.Series.from_iterable( + name = x_nw.name, + values = x_with_na, + backend = x_nw.implementation + ) + + if to_native: return result.to_native() + return result + + +# # `relocate()` + +# In[ ]: + + +def arrange_colnames( + colnames: list[str], + selected: list[str], + before: Optional[str] = None, + after: Optional[str] = None, + place: Optional[Literal['first', 'last']] = None, + ): + unselected = [i for i in colnames if i not in selected] + if before is None and after is None: + if place is None: place = 'first' + + if place == 'first': + return selected + unselected + else: + return unselected + selected + + if before is not None: + idx = unselected.index(before) + col_pre = unselected[:idx] + col_behind = unselected[idx:] + return col_pre + selected + col_behind + + elif after is not None: + idx = unselected.index(after) + 1 + col_pre = unselected[:idx] + col_behind = unselected[idx:] + return col_pre + selected + col_behind + + +# In[ ]: + + +def _is_before_after_selected(selected: list[str], value:Optional[str] = None): + result = isinstance(value, str) and value in selected \ + and build.length(selected) == 1 \ + and selected[0] == value + return result + + +# In[ ]: + + +@pf.register_dataframe_method +def relocate( + data: IntoFrameT, + *args: Union[str, List[str], narwhals.Expr, narwhals.selectors.Selector], + before: Optional[str] = None, + after: Optional[str] = None, + place: Optional[Literal["first", "last"]] = None, + to_native: bool = True + ) -> IntoFrameT: + """Reorder columns in a DataFrame without dropping any columns. + + This function reorders columns in a DataFrame by relocating selected + columns to a new position, while keeping all other columns intact. + Selected columns can be specified by column names, lists of names, + or narwhals expressions/selectors. + + By default, the selected columns are moved to the front of the DataFrame. + Alternatively, they can be placed immediately before or after a specified + reference column. + + Internally, the input is converted to a narwhals DataFrame to support + multiple backends (e.g., pandas, polars, pyarrow), and the reordered + DataFrame is returned in its native type by default. + + Args: + data (IntoFrameT): + Input DataFrame whose columns are to be reordered. + Any DataFrame-like object supported by narwhals + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table) can be used. + *args (Union[str, List[str], narwhals.Expr, narwhals.Selector]): + Columns to relocate. Each element may be: + - a column name (`str`) + - a list of column names + - a narwhals expression + - a narwhals selector + The order of columns specified here is preserved in the output. + before (Optional[str], optional): + Name of a column before which the selected columns should be placed. + Cannot be specified together with `after`. Defaults to `None`. + after (Optional[str], optional): + Name of a column after which the selected columns should be placed. + Cannot be specified together with `before`. Defaults to `None`. + place (Optional[Literal["first", "last"]], optional): + Destination where the selected columns are placed when neither + `before` nor `after` is specified. + - `"first"`: place the selected columns at the beginning of the DataFrame. + - `"last"`: place the selected columns at the end of the DataFrame. + Cannot be used together with `before` or `after`. + Defaults to `None` (equivalent to `"first"`). + to_native (bool, optional): + If `True`, return the result as the native DataFrame type + corresponding to the input (e.g., pandas or polars). + If `False`, return a narwhals DataFrame. Defaults to `True`. + Returns: + IntoFrameT: + A DataFrame with the same columns as `data`, reordered according + to the specified rules. + + Raises: + ValueError: + If `*args` contains unsupported types. + ValueError: + If both `before` and `after` are specified. + ValueError: + If `before` or `after` is not a valid column name. + ValueError: + If `place` is specified together with `before` or `after`. + ValueError: + If `before`/`after` is the same as the only relocated column. + + + Notes: + - This function only changes the order of columns; no columns are added + or removed. + - If neither `before` nor `after` is specified, selected columns are placed + according to `place` (default: `"first"`). + - When `before`/`after` is specified and it is also included in the selected + columns (e.g., via a selector), the reference column is excluded from the + relocation target to avoid an undefined ordering. + - Column order among the selected columns follows the order specified in + `*args`. + + Examples: + >>> import py4stats as py4st + >>> import narwhals.selectors as ncs + >>> from palmerpenguins import load_penguins + >>> penguins = load_penguins() + + Move columns to the front (default behavior): + >>> py4st.relocate(penguins, "year", "sex") + + Move selected columns to the end: + >>> py4st.relocate(penguins, "year", "sex", place="last") + + Relocate columns using a selector: + >>> py4st.relocate(penguins, ncs.numeric()) + + Place columns before a specific column: + >>> py4st.relocate(penguins, "year", before="island") + + Place selected columns after a reference column (and exclude the reference + column from relocation if it was selected via a selector): + >>> py4st.relocate(penguins, ncs.numeric(), after="year") + """ + # 引数のアサーション ====================================== + build.assert_logical(to_native, arg_name = 'to_native') + _assert_selectors(*args, nullable = True) + + # is_varid = [ + # isinstance(v, str) or + # (build.is_character(v) and isinstance(v, list)) or + # isinstance(v, nw.expr.Expr) or + # isinstance(v, nw.selectors.Selector) + # for v in args + # ] + + # if not all(is_varid): + # invalids = [v for i, v in enumerate(args) if not is_varid[i]] + # message = "Argument `*args` must be of type 'str', list of 'str', 'narwhals.Expr' or 'narwhals.Selector'\n"\ + # + f" The value(s) of {build.oxford_comma_and(invalids)} cannot be accepted.\n"\ + # + " Examples of valid inputs: 'x', ['x', 'y'], ncs.numeric(), nw.col('x')" + + # raise ValueError(message) + + build.assert_character(before, arg_name = 'before', nullable = True, scalar_only = True) + build.assert_character(after, arg_name = 'after', nullable = True, scalar_only = True) + + if (before is not None) and (after is not None): + raise ValueError("Please specify either `before` or `after`, not both.") + + place = build.arg_match( + place, arg_name= 'place', + values = ['first', 'last'], + nullable = True + ) + if (place is not None) and ((before is not None) or (after is not None)): + raise ValueError("Please specify either `place` or `before`/`after`, not both.") + # ====================================================== + + data_nw = nw.from_native(data) + colnames = data_nw.columns + selected = data_nw.select(args).columns + + # before/after に指定された列が arg に含まれている場合への対処 ============================= + # selected の要素が1つで、befor/after と等しいなならエラー(並べ替え方が定義できないので) + if _is_before_after_selected(selected, before): + raise ValueError("`before` cannot be the same as the relocated column.") + if _is_before_after_selected(selected, after): + raise ValueError("`after` cannot be the same as the relocated column.") + + # selected が複数の要素を持ち、befor/after 含まれるなら除外 ================================== + if after is not None: + selected = [c for c in selected if c != after] + if before is not None: + selected = [c for c in selected if c != before] + + # selected が空のリストになった場合の安全処置 + # selected = [] なら arrange_colnames() は colnames をそのまま返すと思いますが念のため。 + if not selected: + return data_nw.to_native() if to_native else data_nw + + # 列を並べ替えて出力 ===================================================================== + arranged = arrange_colnames(colnames, selected, before, after, place) + result = data_nw.select(nw.col(arranged)) + + if to_native: return result.to_native() + return result + + +# # カテゴリー変数の積み上げ棒グラフ + +# In[ ]: + + +def make_table_to_plot( + data: IntoFrameT, + sort_by: Literal['values', 'frequency'] = 'values', + to_native: bool = True + ) -> None: + data_nw = nw.from_native(data) + + variables = data_nw.columns + def foo(v): + res_ft = freq_table( + data_nw, v, + dropna = True, + sort_by = sort_by, + descending = sort_by == 'frequency', + to_native = False + ).rename({v:'value'})\ + .with_columns( + bottom = nw.col('cumperc').shift(n = 1).fill_null(0) + ) + + res_ft = res_ft.with_columns(nw.lit(v).alias('variable')) + + return res_ft + + table_to_plot = nw.concat( + [foo(v) for v in variables], + how = 'vertical' + ) + table_to_plot = relocate(table_to_plot, nw.col('variable'), to_native = False) + if to_native: return table_to_plot.to_native() + return table_to_plot + + +# In[ ]: + + +import seaborn as sns +from matplotlib import patches as mpatches +from matplotlib.ticker import FuncFormatter + +def make_categ_barh( + table_to_plot, + list_values, + palette: Optional[Sequence] = None, + legend_type: Literal['horizontal', 'vertical', 'none'] = 'horizontal', + show_vline: bool = True, + ax: Optional[Axes] = None + ): + table_to_plot = table_to_plot.to_pandas() # seaborn が Pandas のみ対応しているため + k_categ = len(list_values) + ## カラーパレットの生成 ========================== + if palette is None: + palette = sns.diverging_palette( + h_neg = 183, h_pos = 64, + s = 70, l = 75, + n = k_categ, + as_cmap = False + ) + + value = list_values[0] + patch_list = [] + + if ax is None: + fig, ax = plt.subplots() + ## 積み上げ棒グラフの作成 ========================= + for i, value in enumerate(list_values): + + ax.barh( + y = table_to_plot.query('value == @value')['variable'], + width = table_to_plot.query('value == @value')['perc'], + left = table_to_plot.query('value == @value')['bottom'], + color = palette[i] + ) + + patch = mpatches.Patch(color = palette[i], label = value) + patch_list.append(patch) + + ## 軸ラベルと垂直線の設定 ========================= + ax.xaxis.set_major_formatter( + FuncFormatter(lambda x, pos: f"{abs(100 * x):.0f}%") + ) + + ax.set_xlim(0, 1) + ax.set_ylabel('') + ax.set_xlabel('Percentage') + ax.invert_yaxis() + + if show_vline: + ax.axvline(0.5, color = "gray", linewidth = 1, linestyle = "--") + + ## 凡例の設定 =============================== + if legend_type != 'none': + if legend_type == 'horizontal': + arg_dict = { + 'loc': 'upper center', + 'bbox_to_anchor': (0.5, -0.1), + 'ncol':k_categ, + 'reverse': True + } + else: + arg_dict = { + 'loc': 'upper left', + 'bbox_to_anchor': (1, 1), + 'ncol': 1 + } + plt.legend(handles = patch_list, frameon = False, **arg_dict); + + +# In[ ]: + + +@pf.register_dataframe_method +def plot_category( + data: IntoFrameT, + sort_by: Literal['values', 'frequency'] = 'values', + palette: Optional[sns.palettes._ColorPalette] = None, + legend_type: Literal["horizontal", "vertical", "none"] = "horizontal", + show_vline: bool = True, + ax: Optional[Axes] = None, +) -> None: + """Plot 100% stacked horizontal bar charts for categorical variables. + + This function summarizes multiple categorical variables and visualizes + their response distributions as 100% stacked horizontal bar charts + (one bar per variable). It is suitable for Likert-style survey items and + other categorical response data where all variables share a common + coding scheme. + + Internally, the function aggregates the input data into a plotting table + using `make_table_to_plot()`, then renders the stacked bars via + `make_categ_barh()` with matplotlib. + + Args: + data (IntoFrameT): + Input DataFrame containing categorical variables (one column per item). + Any DataFrame type supported by narwhals can be used + (e.g., pandas.DataFrame, polars.DataFrame, pyarrow.Table). + All columns must share the same set of category labels. + sort_by (Literal["frequency", "values"], optional): + Rule used to order response categories before plotting. + - `"values"`: sort by the category values themselves. + - `"frequency"`: sort by response frequency (descending). + Defaults to `"values"`. + palette (Optional[sns.palettes._ColorPalette], optional): + Color palette used for the response categories. + If `None`, a default diverging palette is generated internally. + The length of the palette must match the number of categories. + Defaults to `None`. + legend_type (Literal["horizontal", "vertical", "none"], optional): + Placement and layout of the legend. + - `"horizontal"`: place the legend below the plot in a single row. + - `"vertical"`: place the legend to the right of the plot. + - `"none"`: do not draw a legend. + Defaults to `"horizontal"`. + show_vline (bool, optional): + If `True`, draw a vertical reference line at 0.5 (50%), + which can serve as a visual midpoint for proportions. + Defaults to `True`. + ax (Optional[matplotlib.axes.Axes], optional): + Matplotlib axes to draw the plot on. If `None`, a new figure + and axes are created. Defaults to `None`. + + Returns: + None: + The function draws the plot on the provided or newly created + matplotlib axes and returns `None`. + + Raises: + ValueError: + If the categorical variables in `data` do not share a common + coding scheme (i.e., their category labels are not identical). + + Notes: + - When `sort_by="values"` is specified, the function relies on the presence of + explicit category order information (e.g., ordered categoricals in pandas + or Enum categories in polars) to determine the plotting order. + - **Recommended:** When using `sort_by="values"`, it is recommended to provide + the input as a `pandas.DataFrame` with columns of type `pd.Categorical` + (with an explicit order), or as a `polars.DataFrame` with columns defined + as `Enum` categories. + - For `polars.Categorical` columns, category order may not be preserved as + expected, and categories can be displayed in lexicographical order + (e.g., "Agree", "Disagree", "Strongly agree", "Strongly disagree"). + - When a `pyarrow.Table` is provided as input, `sort_by="values"` may raise + an error due to limitations of dictionary-encoded types in pyarrow. + In such cases, use `sort_by="frequency"` instead. + - Missing values are dropped when computing category frequencies. + - Category order is determined by `sort_by` and then reversed before + plotting so that the first category appears at the bottom of the bar. + - The x-axis represents proportions in the range [0, 1], formatted + as percentages. + - This function assumes that `make_table_to_plot()` produces the + columns `"variable"`, `"value"`, `"perc"`, and `"bottom"`. + + Examples: + >>> import py4stats as py4st + >>> import pandas as pd + >>> df = pd.DataFrame({ + ... "Q1": ["Agree", "Disagree", "Agree", "Strongly agree"], + ... "Q2": ["Disagree", "Disagree", "Agree", "Agree"], + ... }) + >>> py4st.plot_category(df, sort_by="values", legend_type="horizontal") + """ + data_nw = nw.from_native(data) + variables = data_nw.columns + # 引数のアサーション ============================================== + legend_type = build.arg_match( + legend_type, values = ['horizontal', 'vertical', 'none'], + arg_name = 'legend_type' + ) + build.assert_logical(show_vline, arg_name = 'sort') + + if data_nw.implementation.is_pyarrow() and sort_by == "values": + raise ValueError( + "`sort_by = 'values` is not supported in pyarrow.Table." + "Please try one of the following:\n"\ + " - Specify `sort_by = 'frequency`'\n"\ + " - Use a `pandas.DataFrame` and set the `pd.Categorical` column as an ordered category\n"\ + " - Use a `polars.DataFrame` and set the `Enum-type` column as an ordered category"\ + ) + + # カテゴリー変数のコーディング確認 ================================== + cording = data_nw[variables[0]].unique().to_list() + is_common_cording = all([ + s.unique().is_in(cording).all() + for s in data_nw.iter_columns() + ]) + + if not is_common_cording: + messages = "This function assumes that all columns contained in `data` share a common coding scheme." + raise ValueError(messages) + + # データの集計 ================================================== + + table_to_plot = make_table_to_plot( + data_nw, sort_by = sort_by, + to_native = False + ) + + list_values = table_to_plot['value'].unique().to_list() + # if nw.is_ordered_categorical(table_to_plot['value']): + # list_values = table_to_plot['value'].cat.get_categories().to_list() + # else: + # list_values = table_to_plot['value'].unique().to_list() + + list_values = list_values[::-1] + + # グラフの作図 ================================================== + make_categ_barh( + table_to_plot, + list_values = list_values, + palette = palette, + legend_type = legend_type, + show_vline = show_vline, + ax = ax + ) + diff --git a/docs/reference.html b/docs/reference.html new file mode 100644 index 0000000..1127a03 --- /dev/null +++ b/docs/reference.html @@ -0,0 +1,971 @@ + + + + + + + + + +Function reference – Py4Stats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Function reference

+
+ + + +
+ + + + +
+ + + +
+ + +
+

Main Module

+
+

py4stats.eda_tools

+

py4stats.eda_tools モジュールは、探索的データ解析と前処理に関する機能を提供します。複数の DataFrame バックエンドに対して共通の API を提供することを目的として、narwhals ライブラリを用いて実装されています。詳細は Technical Notes を参照してください。

+
+

データフレームの概要

+

py4stats.diagnose()

+

py4stats.diagnose_category()

+
+
+

クロス集計

+

py4stats.tabyl()

+

py4stats.freq_table()

+

py4stats.Pareto_plot()

+

py4stats.plot_category()

+
+
+
+

数値変数の点推定と区間推定

+

py4stats.mean_qi() py4stats.median_qi() py4stats.mean_ci()

+
+

データフレームの列や行の削除

+

py4stats.remove_empty()
+py4stats.remove_constant()

+

py4stats.filtering_out()

+
+
+

データフレームの列の並べ替え

+

py4stats.relocate()

+
+
+

複数のデータフレームの比較

+

py4stats.compare_df_cols() py4stats.compare_df_stats()

+
+
+

簡易なグループ別統計量の比較

+

py4stats.compare_group_means() py4stats.compare_group_median()

+

py4stats.plot_mean_diff() py4stats.plot_median_diff()

+
+
+

簡易な欠測値の可視化

+

py4stats.plot_miss_var()

+

py4stats.set_miss()

+
+
+

数値変数の集計と標準化

+

py4stats.weighted_mean() py4stats.scale() py4stats.min_max()

+
+
+

論理関数

+

py4stats.is_number() py4stats.is_ymd() py4stats.is_ymd_like()

+

py4stats.is_dummy()

+
+
+

簡易なルールベースのデータ検証ツール

+

py4stats.check_that() py4stats.check_viorate()

+
+
+
+
+

py4stats.regression_tools

+

py4stats.regression_toolsstatsmodels ライブラリで作成された回帰分析の結果についての可視化と表作成を補助する機能を提供するモジュールです。

+
+

線形モデルの比較

+

py4stats.compare_ols()

+

py4stats.compare_mfx()

+
+
+

線形モデルの可視化

+

py4stats.coefplot() py4stats.mfxplot()

+
+
+

線形モデルを作表するためのバックエンド関数

+

py4stats.tidy()py4stats.tidy_mfx()

+

py4stats.tidy_test()

+

py4stats.glance()

+
+
+

Blinder-Oaxaca分解

+

py4stats.Blinder_Oaxaca() py4stats.plot_Blinder_Oaxaca()

+
+
+
+
+

Sub Module

+
+

py4stats.heckit_helper

+

py4stats.regression_tools の関数を py4etrics.heckit ライブラリで実装された Heckit モデルに対応させるためのメソッドを提供します。

+

heckit_helper.Heckit_from_formula()

+

heckit_helper.tidy_heckit()

+

heckit_helper.heckitmfx_compute()

+
+
+
+

py4stats.building_block

+

py4stats ライブラリの実装に使用するアサーション関数やユーティリティ関数を提供します。 building_block モジュール自体は外部から呼び出すことなく内部実装に使用することを想定しています。

+
+
+

引数のアサーション関数

+

building_block.arg_match()

+

building_block.assert_character() building_block.assert_logical() building_block.assert_numeric() building_block.assert_integer() building_block.assert_count() building_block.assert_float()

+
+
+

データ型を判定する論理関数

+

building_block.is_character() building_block.is_logical() building_block.is_numeric() building_block.is_integer() building_block.is_float()

+
+
+

数字のフォーマット

+

building_block.style_number() building_block.style_currency() building_block.style_percent()

+

building_block.style_pvalue() building_block.p_stars()

+
+
+

並列文の作成

+

building_block.oxford_comma() building_block.oxford_comma_and() building_block.oxford_comma_or()

+
+

Jump to Get started.
+Jump to Readme.

+ + +
+
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/docs/robots.txt b/docs/robots.txt new file mode 100644 index 0000000..a6ff2eb --- /dev/null +++ b/docs/robots.txt @@ -0,0 +1 @@ +Sitemap: https://github.com/Hirototensho/Py4Stats/sitemap.xml diff --git a/docs/search.json b/docs/search.json new file mode 100644 index 0000000..35917c2 --- /dev/null +++ b/docs/search.json @@ -0,0 +1,2160 @@ +[ + { + "objectID": "index.html", + "href": "index.html", + "title": "Py4Stats", + "section": "", + "text": "Readme\nPy4Stats は、主に実証研究で用いられる、探索的データ分析および回帰結果レポート用のユーティリティライブラリです。回帰分析を中心とする分析でよく使われるR言語の機能を Python で実装しています。\n本ライブラリの主な機能は Get Started を、実装されている関数の一覧は Function reference を参照してください。", + "crumbs": [ + "1  Readme" + ] + }, + { + "objectID": "index.html#installation", + "href": "index.html#installation", + "title": "Py4Stats", + "section": "Installation", + "text": "Installation\nuv をお使いの場合、次のコードで py4stats をインストールできます。\n! uv add git+https://github.com/Hirototensho/py4stats.git\n一方で、pip をお使いの場合には、次のコードで py4stats をインストールできます。\n! pip install git+https://github.com/Hirototensho/py4stats.git", + "crumbs": [ + "1  Readme" + ] + }, + { + "objectID": "index.html#使用例", + "href": "index.html#使用例", + "title": "Py4Stats", + "section": "使用例", + "text": "使用例\nimport py4stats as py4st\npy4stats.diagnose() 関数はデータの全般的な状態についての要約を提供します。\nimport pandas as pd\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込み\n\nprint(py4st.diagnose(penguins).round(4))\n#> columns dtype missing_count missing_percent unique_count unique_rate\n#> 0 species object 0 0.0000 3 0.8721\n#> 1 island object 0 0.0000 3 0.8721\n#> 2 bill_length_mm float64 2 0.5814 165 47.9651\n#> 3 bill_depth_mm float64 2 0.5814 81 23.5465\n#> 4 flipper_length_mm float64 2 0.5814 56 16.2791\n#> 5 body_mass_g float64 2 0.5814 95 27.6163\n#> 6 sex object 11 3.1977 3 0.8721\n#> 7 year int64 0 0.0000 3 0.8721\npy4stats.compare_ols() 関数は、計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。\nimport statsmodels.formula.api as smf\n\n# 回帰分析の実行\nfit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()\nfit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit()\nfit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()\n\ncompare_tab1 = py4st.compare_ols(list_models = [fit1, fit2, fit3]) # 表の作成\ncompare_tab1\n\n\n\n\n\n\n\n\n\nterm\nmodel 1\nmodel 2\nmodel 3\n\n\n\n\nIntercept\n153.7397\n-1,742.7202 ***\n843.9812 **\n\n\n\n(268.9012)\n(313.7697)\n(403.5956)\n\n\nspecies[T.Chinstrap]\n-885.8121 ***\n-539.6864 ***\n-245.1516 ***\n\n\n\n(88.2502)\n(86.9425)\n(84.5952)\n\n\nspecies[T.Gentoo]\n578.6292 ***\n1,492.8283 ***\n1,443.3525 ***\n\n\n\n(75.3623)\n(118.4442)\n(107.7844)\n\n\nbill_length_mm\n91.4358 ***\n55.6461 ***\n26.5366 ***\n\n\n\n(6.8871)\n(7.2326)\n(7.2436)\n\n\nbill_depth_mm\n\n179.0434 ***\n87.9328 ***\n\n\n\n\n(19.0997)\n(20.2192)\n\n\nsex[T.male]\n\n\n437.2007 ***\n\n\n\n\n\n(49.1098)\n\n\nrsquared_adj\n0.7810\n0.8258\n0.8613\n\n\nnobs\n342\n342\n333\n\n\ndf\n3\n4\n5\n\n\n\n詳細は、py4stats.compare_ols() を参照してください。 \n\nJump to Get Started.\nJump to Function reference.", + "crumbs": [ + "1  Readme" + ] + }, + { + "objectID": "introduction.html", + "href": "introduction.html", + "title": "Introduction to Py4Stats", + "section": "", + "text": "py4stats.eda_tools\nここでは Py4Stats の主な機能を紹介します。実装されている関数の一覧は Function reference を参照してください。\n探索的データ解析と前処理に関する機能を提供するモジュールです。このモジュールは、複数の DataFrame バックエンドに対して共通の API を提供することを目的として、narwhals ライブラリを用いて実装されています。詳細は Technical Notes: py4stats.eda_tools における narwhals ベースの実装 を参照してください。\npy4stats.diagnose():R言語のdlookr::diagnose()を再現した関数で、データの全般的な状態についての要約を提供します。\npy4stats.tabyl():R言語の janitor::tabyl()を参考にした、クロス集計表を作成する関数です。\npy4stats.freq_table():R言語のDescTools::Freq()をオマージュした、1変数の度数分布表を計算する関数。度数 freq と相対度数 perc に加えて、それぞれの累積値を計算します。\n引数 group を指定すると、グループ別の度数分布表を計算できます。\npy4stats.remove_empty():完全に空白な列や行の削除する関数。R言語の janitor::remove_empty() をオマージュした関数で、全ての要素が NaN である列や行をデータフレームから除外します。\npy4stats.remove_constant():定数列の削除。R言語の janitor::remove_constant() をオマージュした関数で、1種類だけの要素からなる列をデータフレームから除外します。\npy4stats.filtering_out():pandas の DataFrame.filter() メソッドでは引数 like に文字列を指定することで、列名に特定の文字列を含む列を選択できますが、反対に py4stats.filtering_out() では列名に特定の文字列を含む列を除外します。実装の一部はR言語の dplyr::select() を参考にしました。", + "crumbs": [ + "2  Introduction to Py4Stats" + ] + }, + { + "objectID": "introduction.html#py4stats.eda_tools", + "href": "introduction.html#py4stats.eda_tools", + "title": "Introduction to Py4Stats", + "section": "", + "text": "import pandas as pd\nimport numpy as np\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込み\n\nprint(py4st.diagnose(penguins).round(4))\n#> dtype missing_count missing_percent unique_count unique_rate\n#> species object 0 0.0000 3 0.8721\n#> island object 0 0.0000 3 0.8721\n#> bill_length_mm float64 2 0.5814 164 47.6744\n#> bill_depth_mm float64 2 0.5814 80 23.2558\n#> flipper_length_mm float64 2 0.5814 55 15.9884\n#> body_mass_g float64 2 0.5814 94 27.3256\n#> sex object 11 3.1977 2 0.5814\n#> year int64 0 0.0000 3 0.8721\n\nprint(py4st.tabyl(penguins, 'island', 'species'))\n#> species Adelie Chinstrap Gentoo All\n#> island \n#> Biscoe 44 (26.2%) 0 (0.0%) 124 (73.8%) 168\n#> Dream 56 (45.2%) 68 (54.8%) 0 (0.0%) 124\n#> Torgersen 52 (100.0%) 0 (0.0%) 0 (0.0%) 52\n#> All 152 (44.2%) 68 (19.8%) 124 (36.0%) 344\n\nprint(py4st.freq_table(penguins, 'species'))\n#> freq perc cumfreq cumperc\n#> species \n#> Adelie 152 0.441860 152 0.441860\n#> Gentoo 124 0.360465 276 0.802326\n#> Chinstrap 68 0.197674 344 1.000000\n\npenguins2 = penguins.assign(bill_length_mm2 = pd.cut(penguins['bill_length_mm'], 6))\n\nprint(\n py4st.freq_table(penguins2, ['species', 'bill_length_mm2'], sort = False)\n )\n#> freq perc cumfreq cumperc\n#> species bill_length_mm2\n#> Adelie (32.072, 38.975] 79 0.523179 79 0.523179\n#> (38.975, 45.85] 71 0.470199 150 0.993377\n#> (45.85, 52.725] 1 0.006623 151 1.000000\n#> (52.725, 59.6] 0 0.000000 151 1.000000\n#> Chinstrap (32.072, 38.975] 0 0.000000 0 0.000000\n#> (38.975, 45.85] 13 0.191176 13 0.191176\n#> (45.85, 52.725] 50 0.735294 63 0.926471\n#> (52.725, 59.6] 5 0.073529 68 1.000000\n#> Gentoo (32.072, 38.975] 0 0.000000 0 0.000000\n#> (38.975, 45.85] 40 0.325203 40 0.325203\n#> (45.85, 52.725] 78 0.634146 118 0.959350\n#> (52.725, 59.6] 5 0.040650 123 1.000000\n\npenguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy()\npenguins2.loc[:, 'empty'] = np.nan\npenguins2.loc[344, :] = np.nan\n\nprint(penguins2.tail(3))\n#> species body_mass_g empty\n#> 342 Chinstrap 4100.0 NaN\n#> 343 Chinstrap 3775.0 NaN\n#> 344 NaN NaN NaN\n\n# 完全に空白な行と列を削除。\nprint(py4st.remove_empty(penguins2, quiet = False).tail(3))\n#> Removing 1 empty column(s) out of 3 columns(Removed: empty).\n#> Removing 1 empty row(s) out of 345 rows(Removed: 344). \n#> species body_mass_g\n#> 341 Chinstrap 3775.0\n#> 342 Chinstrap 4100.0\n#> 343 Chinstrap 3775.0\n\n# 完全に空白な列のみ削除。\nprint(py4st.remove_empty(penguins2, rows = False, quiet = False).tail(3))\n#> Removing 1 empty column(s) out of 3 columns(Removed: empty).\n#> species body_mass_g\n#> 342 Chinstrap 4100.0\n#> 343 Chinstrap 3775.0\n#> 344 NaN NaN\n\n# 完全に空白な行のみ削除。\nprint(py4st.remove_empty(penguins2, cols = False, quiet = False).tail(3))\n#> Removing 1 empty row(s) out of 345 rows(Removed: 344). \n#> species body_mass_g empty\n#> 341 Chinstrap 3775.0 NaN\n#> 342 Chinstrap 4100.0 NaN\n#> 343 Chinstrap 3775.0 NaN\n\npenguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy()\npenguins2.loc[:, 'constant'] = 'c'\n\nprint(penguins2.head(3))\n#> species body_mass_g constant\n#> 0 Adelie 3750.0 c\n#> 1 Adelie 3800.0 c\n#> 2 Adelie 3250.0 c\n\nprint(py4st.remove_constant(penguins2, quiet = False).head(3))\n#> Removing 1 constant column(s) out of 3 column(s)(Removed: constant). \n#> species body_mass_g\n#> 0 Adelie 3750.0\n#> 1 Adelie 3800.0\n#> 2 Adelie 3250.0\n\n# 列名に 'length' を含む列を除外\nprint(py4st.filtering_out(penguins, contains = 'length').head(3))\n#> species island bill_depth_mm body_mass_g sex year female\n#> 0 Adelie Torgersen 18.7 3750.0 male 2007 0\n#> 1 Adelie Torgersen 17.4 3800.0 female 2007 1\n#> 2 Adelie Torgersen 18.0 3250.0 female 2007 1\n\n# 列名が 'bill' から始まる列を除外\nprint(py4st.filtering_out(penguins, starts_with = 'bill').head(3))\n#> species island flipper_length_mm body_mass_g sex year female\n#> 0 Adelie Torgersen 181.0 3750.0 male 2007 0\n#> 1 Adelie Torgersen 186.0 3800.0 female 2007 1\n#> 2 Adelie Torgersen 195.0 3250.0 female 2007 1\n\n# 列名が '_mm' で終わる列を除外\nprint(py4st.filtering_out(penguins, ends_with = '_mm').head(3))\n#> species island body_mass_g sex year female\n#> 0 Adelie Torgersen 3750.0 male 2007 0\n#> 1 Adelie Torgersen 3800.0 female 2007 1\n#> 2 Adelie Torgersen 3250.0 female 2007 1", + "crumbs": [ + "2  Introduction to Py4Stats" + ] + }, + { + "objectID": "introduction.html#py4stats.regression_tools", + "href": "introduction.html#py4stats.regression_tools", + "title": "Introduction to Py4Stats", + "section": "py4stats.regression_tools", + "text": "py4stats.regression_tools\n py4stats.regression_tools は statsmodelsライブラリで作成された回帰分析の結果についての表作成と可視化を補助する機能を提供するモジュールです。\n py4stats.compare_ols() :計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。表のフォーマットについてはR言語のtexreg::screenreg()やmodelsummary::modelsummary()を参考にしています。同種の機能を提供する Python ライブラリーとしては、R言語の stargazer パッケージをもとにした stargazer ライブラリがあります。\nimport statsmodels.formula.api as smf\n\n# 回帰分析の実行\nfit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()\nfit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit()\nfit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()\n\ncompare_tab1 = py4st.compare_ols(list_models = [fit1, fit2, fit3]) # 表の作成\ncompare_tab1\n\n\n\n\n\n\n\n\n\nterm\nmodel 1\nmodel 2\nmodel 3\n\n\n\n\nIntercept\n153.7397\n-1,742.7202 ***\n843.9812 **\n\n\n\n(268.9012)\n(313.7697)\n(403.5956)\n\n\nspecies[T.Chinstrap]\n-885.8121 ***\n-539.6864 ***\n-245.1516 ***\n\n\n\n(88.2502)\n(86.9425)\n(84.5952)\n\n\nspecies[T.Gentoo]\n578.6292 ***\n1,492.8283 ***\n1,443.3525 ***\n\n\n\n(75.3623)\n(118.4442)\n(107.7844)\n\n\nbill_length_mm\n91.4358 ***\n55.6461 ***\n26.5366 ***\n\n\n\n(6.8871)\n(7.2326)\n(7.2436)\n\n\nbill_depth_mm\n\n179.0434 ***\n87.9328 ***\n\n\n\n\n(19.0997)\n(20.2192)\n\n\nsex[T.male]\n\n\n437.2007 ***\n\n\n\n\n\n(49.1098)\n\n\nrsquared_adj\n0.7810\n0.8258\n0.8613\n\n\nnobs\n342\n342\n333\n\n\ndf\n3\n4\n5\n\n\n\npy4stats.compare_ols() の実行結果は Pandas の DataFrame として出力されるため、.xlsx. ファイルなどに変換することができます。また、用途に応じて表の体裁を調整できるようにしています。詳細については 「回帰分析の比較」 を参照してください。\ncompare_tab2 = py4st.compare_ols(\n list_models = [fit1, fit2, fit3],\n model_name = ['基本モデル', '嘴の高さ追加', '性別追加'], # モデル名を変更\n stats = 'p_value', # () 内の値をP-値に変更する\n add_stars = False, # 有意性のアスタリスクなし\n table_style = 'one_line', # 表スタイルを1行表示に設定 'one' でも可能\n digits = 3 # 小数点以下の桁数を3に設定\n )\ncompare_tab2\n\n\n\n\n\n\n\n\n\nterm\n基本モデル\n嘴の高さ追加\n性別追加\n\n\n\n\nIntercept\n153.740(0.568)\n-1,742.720(0.000)\n843.981(0.037)\n\n\nspecies[T.Chinstrap]\n-885.812(0.000)\n-539.686(0.000)\n-245.152(0.004)\n\n\nspecies[T.Gentoo]\n578.629(0.000)\n1,492.828(0.000)\n1,443.353(0.000)\n\n\nbill_length_mm\n91.436(0.000)\n55.646(0.000)\n26.537(0.000)\n\n\nbill_depth_mm\n\n179.043(0.000)\n87.933(0.000)\n\n\nsex[T.male]\n\n\n437.201(0.000)\n\n\nrsquared_adj\n0.781\n0.826\n0.861\n\n\nnobs\n342\n342\n333\n\n\ndf\n3\n4\n5\n\n\n\npy4stats.coefplot():回帰係数の可視化。R言語の coefplot::coefplot() を参考にしました。\nimport matplotlib.pyplot as plt\npy4st.coefplot(fit3)\n\n\n\ncoefplot1\n\n\nplt.rcParams[\"figure.autolayout\"] = True\n\nfig, ax = plt.subplots(1, 2, figsize = (2.2 * 5, 5), dpi = 100)\n\npy4st.coefplot(fit2, ax = ax[0])\nax[0].set_xlim(-900, 1800)\n\npy4st.coefplot(fit3, ax = ax[1], palette = ['#FF6F91', '#F2E5EB'])\nax[1].set_xlim(-900, 1800);\n\n\n\ncoefplot2\n\n\n py4stats.compare_mfx() と py4stats.mfxplot() は、それぞれ py4stats.compare_ols() と py4stats.coefplot() の一般化線型モデルバージョンです。statsmodels ライブラリの.get_margeff() メソッドから得られた限界効果の推定値を表示します。\npenguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)\n\n# ロジスティック回帰の実行\nfit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()\nfit_logit2 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm + species', data = penguins).fit()\n\npy4st.compare_mfx([fit_logit1, fit_logit2])\n\n\n\nterm\nmodel 1\nmodel 2\n\n\n\n\nbody_mass_g\n-0.0004 ***\n-0.0003 ***\n\n\n\n(0.0000)\n(0.0000)\n\n\nbill_length_mm\n-0.0053\n-0.0357 ***\n\n\n\n(0.0036)\n(0.0070)\n\n\nbill_depth_mm\n-0.1490 ***\n-0.1098 ***\n\n\n\n(0.0051)\n(0.0175)\n\n\nspecies[T.Chinstrap]\n\n0.4172 ***\n\n\n\n\n(0.0848)\n\n\nspecies[T.Gentoo]\n\n0.3527 ***\n\n\n\n\n(0.1308)\n\n\nprsquared\n0.5647\n0.6187\n\n\nnobs\n342\n342\n\n\ndf\n3\n5\n\n\n\nplt.rcParams[\"figure.autolayout\"] = True\n\nfig, ax = plt.subplots(1, 2, figsize = (2.2 * 5, 5), dpi = 100)\n\npy4st.mfxplot(fit_logit1, ax = ax[0])\nax[0].set_xlim(-0.2, 0.85)\n\npy4st.mfxplot(fit_logit2, ax = ax[1], palette = ['#FF6F91', '#F2E5EB'])\nax[1].set_xlim(-0.2, 0.85);\n\n\n\ncoefplot3\n\n\n\nJump to Function reference.", + "crumbs": [ + "2  Introduction to Py4Stats" + ] + }, + { + "objectID": "reference.html", + "href": "reference.html", + "title": "Function reference", + "section": "", + "text": "Main Module", + "crumbs": [ + "3  Function reference" + ] + }, + { + "objectID": "reference.html#main-module", + "href": "reference.html#main-module", + "title": "Function reference", + "section": "", + "text": "py4stats.eda_tools\npy4stats.eda_tools モジュールは、探索的データ解析と前処理に関する機能を提供します。複数の DataFrame バックエンドに対して共通の API を提供することを目的として、narwhals ライブラリを用いて実装されています。詳細は Technical Notes を参照してください。\n\nデータフレームの概要\npy4stats.diagnose()\npy4stats.diagnose_category()\n\n\nクロス集計\npy4stats.tabyl()\npy4stats.freq_table()\npy4stats.Pareto_plot()\npy4stats.plot_category()\n\n\n\n数値変数の点推定と区間推定\npy4stats.mean_qi() py4stats.median_qi() py4stats.mean_ci()\n\nデータフレームの列や行の削除\npy4stats.remove_empty()\npy4stats.remove_constant()\npy4stats.filtering_out()\n\n\nデータフレームの列の並べ替え\npy4stats.relocate()\n\n\n複数のデータフレームの比較\npy4stats.compare_df_cols() py4stats.compare_df_stats()\n\n\n簡易なグループ別統計量の比較\npy4stats.compare_group_means() py4stats.compare_group_median()\npy4stats.plot_mean_diff() py4stats.plot_median_diff()\n\n\n簡易な欠測値の可視化\npy4stats.plot_miss_var()\npy4stats.set_miss()\n\n\n数値変数の集計と標準化\npy4stats.weighted_mean() py4stats.scale() py4stats.min_max()\n\n\n論理関数\npy4stats.is_number() py4stats.is_ymd() py4stats.is_ymd_like()\npy4stats.is_dummy()\n\n\n簡易なルールベースのデータ検証ツール\npy4stats.check_that() py4stats.check_viorate()\n\n\n\n\npy4stats.regression_tools\npy4stats.regression_tools は statsmodels ライブラリで作成された回帰分析の結果についての可視化と表作成を補助する機能を提供するモジュールです。\n\n線形モデルの比較\npy4stats.compare_ols()\npy4stats.compare_mfx()\n\n\n線形モデルの可視化\npy4stats.coefplot() py4stats.mfxplot()\n\n\n線形モデルを作表するためのバックエンド関数\npy4stats.tidy()py4stats.tidy_mfx()\npy4stats.tidy_test()\npy4stats.glance()\n\n\nBlinder-Oaxaca分解\npy4stats.Blinder_Oaxaca() py4stats.plot_Blinder_Oaxaca()", + "crumbs": [ + "3  Function reference" + ] + }, + { + "objectID": "reference.html#sub-module", + "href": "reference.html#sub-module", + "title": "Function reference", + "section": "Sub Module", + "text": "Sub Module\n\npy4stats.heckit_helper\npy4stats.regression_tools の関数を py4etrics.heckit ライブラリで実装された Heckit モデルに対応させるためのメソッドを提供します。\nheckit_helper.Heckit_from_formula()\nheckit_helper.tidy_heckit()\nheckit_helper.heckitmfx_compute()\n\n\n\npy4stats.building_block\npy4stats ライブラリの実装に使用するアサーション関数やユーティリティ関数を提供します。 building_block モジュール自体は外部から呼び出すことなく内部実装に使用することを想定しています。\n\n\n引数のアサーション関数\nbuilding_block.arg_match()\nbuilding_block.assert_character() building_block.assert_logical() building_block.assert_numeric() building_block.assert_integer() building_block.assert_count() building_block.assert_float()\n\n\nデータ型を判定する論理関数\nbuilding_block.is_character() building_block.is_logical() building_block.is_numeric() building_block.is_integer() building_block.is_float()\n\n\n数字のフォーマット\nbuilding_block.style_number() building_block.style_currency() building_block.style_percent()\nbuilding_block.style_pvalue() building_block.p_stars()\n\n\n並列文の作成\nbuilding_block.oxford_comma() building_block.oxford_comma_and() building_block.oxford_comma_or()\n\nJump to Get started.\nJump to Readme.", + "crumbs": [ + "3  Function reference" + ] + }, + { + "objectID": "man/diagnose.html", + "href": "man/diagnose.html", + "title": "diagnose", + "section": "", + "text": "概要\nデータフレームの概要\nR言語の dlookr::diagnose() を再現した関数で、データの全般的な状態についての要約を提供します。", + "crumbs": [ + "**EDA**", + "4  diagnose" + ] + }, + { + "objectID": "man/diagnose.html#概要", + "href": "man/diagnose.html#概要", + "title": "diagnose", + "section": "", + "text": "diagnose(data: IntoFrameT, to_native: bool = True)", + "crumbs": [ + "**EDA**", + "4  diagnose" + ] + }, + { + "objectID": "man/diagnose.html#引数-argument", + "href": "man/diagnose.html#引数-argument", + "title": "diagnose", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "4  diagnose" + ] + }, + { + "objectID": "man/diagnose.html#返り値", + "href": "man/diagnose.html#返り値", + "title": "diagnose", + "section": "返り値", + "text": "返り値\n\ndtype:該当する列のpandasにおけるデータの型。「〇〇の個数」や「〇〇の金額」といったデータの dtype が object や String になっていたら、文字列として読み込まれているので要注意です。\nmissing_count:1列のなかで NaN などの欠測値になっている数\nmissing_percent:1列のなかで欠測値が占めている割合でmissing_percent = (missing_count / 行数) * 100 として計算されます。もし missing_percent = 100 なら、その列は完全に空白です。\nunique_count:その列で重複を除外したユニークな値の数。例えばある列の中身が「a, a, b」であればユニークな値は a と b の2つなので unique_count = 2 です。もし unique_count = 1 であれば、その行にはたった1種類の値しか含まれていないことが分かりますし、例えば都道府県を表す列の unique_count が47より多ければ、都道府県以外のものが混ざっていると考えられます。\nunique_rate: サンプルに占めるユニークな値の割合。 unique_rate = unique_count / 行数 で計算されます。unique_rate = 1 であれば、全ての行に異なる値が入っています。一般的に、実数値の列は unique_rate が高くなりますが、年齢の「20代」や価格の「200円代」のように階級に分けられている場合には unique_rate が低くなります。", + "crumbs": [ + "**EDA**", + "4  diagnose" + ] + }, + { + "objectID": "man/diagnose.html#使用例-examples", + "href": "man/diagnose.html#使用例-examples", + "title": "diagnose", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport py4stats as py4st\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込み\n\nprint(py4st.diagnose(penguins).round(4))\n#> columns dtype missing_count missing_percent unique_count unique_rate\n#> 0 species object 0 0.0000 3 0.8721\n#> 1 island object 0 0.0000 3 0.8721\n#> 2 bill_length_mm float64 2 0.5814 165 47.9651\n#> 3 bill_depth_mm float64 2 0.5814 81 23.5465\n#> 4 flipper_length_mm float64 2 0.5814 56 16.2791\n#> 5 body_mass_g float64 2 0.5814 95 27.6163\n#> 6 sex object 11 3.1977 3 0.8721\n#> 7 year int64 0 0.0000 3 0.8721\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "4  diagnose" + ] + }, + { + "objectID": "man/tabyl.html", + "href": "man/tabyl.html", + "title": "tabyl", + "section": "", + "text": "概要\nレポートティング向けのクロス集計表を作成\nデータフレームのクロス集計表を作成します。R言語の janitor::tabyl()にいくつかの adorn_ 関数を追加した状態を再現した関数です。初期設定ではクロス集計表の各セルに度数と相対度数を 「度数(相対度数%)`」 の形式で表示します。", + "crumbs": [ + "**EDA**", + "5  tabyl" + ] + }, + { + "objectID": "man/tabyl.html#概要", + "href": "man/tabyl.html#概要", + "title": "tabyl", + "section": "", + "text": "tabyl(\n data: IntoFrameT,\n index: str,\n columns: str,\n margins: bool = True,\n margins_name: str = 'All',\n normalize: Union[bool, Literal[\"index\", \"columns\", \"all\"]] = \"index\",\n dropna: bool = False,\n digits: int = 1,\n **kwargs: Any\n)", + "crumbs": [ + "**EDA**", + "5  tabyl" + ] + }, + { + "objectID": "man/tabyl.html#引数-argument", + "href": "man/tabyl.html#引数-argument", + "title": "tabyl", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\nindex:str  集計に使用するデータフレームの変数名(必須)。\ncolumns:str  集計に使用するデータフレームの変数名(必須)。\nmargins:bool  行または列の合計を追加するかどうかを表すブール値。初期設定は True です。\nmargins_name:bool  行や列の合計の名前。初期設定は 'All' です。\ndropna:bool   欠測値(NaN)を集計から除外するかどうかを表すブール値。初期設定は False です。\nnormalize:str  丸括弧( )に表示する相対度数の計算方式。\n\nindex 各セルの度数を行の和で割り、横方向の相対度数の和が100%になるように計算します。\ncolumns 各セルの度数を行の列で割り、縦方向の相対度数の和が100%になるように計算します。\nall 各セルの度数を総度数で割り、全てのセルの相対度数の和が100%になるように計算します。\n\ndigits:int  丸括弧( )に表示する相対度数の小数点以下の桁数。初期設定は1です。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "5  tabyl" + ] + }, + { + "objectID": "man/tabyl.html#使用例", + "href": "man/tabyl.html#使用例", + "title": "tabyl", + "section": "使用例", + "text": "使用例\nimport py4stats as py4st\nimport pandas as pd\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込\n\n# 横方向の和を100%として計算(初期設定)\nprint(py4st.tabyl(penguins, 'island', 'species', normalize = 'index'))\n#> species Adelie Chinstrap Gentoo All\n#> island \n#> Biscoe 44 (26.2%) 0 (0.0%) 124 (73.8%) 168\n#> Dream 56 (45.2%) 68 (54.8%) 0 (0.0%) 124\n#> Torgersen 52 (100.0%) 0 (0.0%) 0 (0.0%) 52\n#> All 152 (44.2%) 68 (19.8%) 124 (36.0%) 344\n\n# 縦方向の和を100%として計算\nprint(py4st.tabyl(penguins, 'island', 'species', normalize = 'columns'))\n#> species Adelie Chinstrap Gentoo All\n#> island \n#> Biscoe 44 (28.9%) 0 (0.0%) 124 (100.0%) 168 (48.8%)\n#> Dream 56 (36.8%) 68 (100.0%) 0 (0.0%) 124 (36.0%)\n#> Torgersen 52 (34.2%) 0 (0.0%) 0 (0.0%) 52 (15.1%)\n#> All 152 68 124 344\n\n# 全体の和を100%として計算\nprint(py4st.tabyl(penguins, 'island', 'species', normalize = 'all'))\n#> species Adelie Chinstrap Gentoo All\n#> island \n#> Biscoe 44 (12.8%) 0 (0.0%) 124 (36.0%) 168 (48.8%)\n#> Dream 56 (16.3%) 68 (19.8%) 0 (0.0%) 124 (36.0%)\n#> Torgersen 52 (15.1%) 0 (0.0%) 0 (0.0%) 52 (15.1%)\n#> All 152 (44.2%) 68 (19.8%) 124 (36.0%) 344 (100.0%)\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "5  tabyl" + ] + }, + { + "objectID": "man/freq_table.html", + "href": "man/freq_table.html", + "title": "freq_table", + "section": "", + "text": "概要\n1変数の度数分布表\nR言語のDescTools::Freq()をオマージュした、1変数の度数分布表を計算する関数。度数 freq と相対度数 perc に加えて、それぞれの累積値を計算します。", + "crumbs": [ + "**EDA**", + "6  freq_table" + ] + }, + { + "objectID": "man/freq_table.html#概要", + "href": "man/freq_table.html#概要", + "title": "freq_table", + "section": "", + "text": "freq_table(\n data: IntoFrameT,\n subset: Union[str, Sequence[str]],\n sort_by: Literal['frequency', 'values'] = 'frequency',\n descending: bool = False,\n dropna: bool = False,\n to_native: bool = True,\n *,\n sort: Optional[bool] = None\n)", + "crumbs": [ + "**EDA**", + "6  freq_table" + ] + }, + { + "objectID": "man/freq_table.html#引数-argument", + "href": "man/freq_table.html#引数-argument", + "title": "freq_table", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\nsubset:str or list of str  集計に使用するデータフレームの列名(必須)。\nsort_by:str  sort_by = 'frequency' なら度数分布表を頻度に応じてソートし、sort_by = 'values' なら subset で指定した列の値に応じてソートします。\ndescending:bool  ソートの方式。True なら降順でソートし、False(初期設定)なら昇順でソートします。\ndropna:bool  欠測値(NaN, None など)を集計から除外するかどうかを表すブール値。初期設定は False です。\nsort:Deprecated..  sort_by の使用を推奨しています。この引数は後方互換性のために保持されおり、指定された場合は FutureWarningが発生します。デフォルトは None です。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "6  freq_table" + ] + }, + { + "objectID": "man/freq_table.html#返り値-value", + "href": "man/freq_table.html#返り値-value", + "title": "freq_table", + "section": "返り値 Value", + "text": "返り値 Value\n freq_table()関数は、次の値をもつ DataFrame を出力します。\n\nfreq: 度数\nperc: 相対度数\ncumfreq: 累積度数\ncumperc: 累積相対度数", + "crumbs": [ + "**EDA**", + "6  freq_table" + ] + }, + { + "objectID": "man/freq_table.html#使用例", + "href": "man/freq_table.html#使用例", + "title": "freq_table", + "section": "使用例", + "text": "使用例\nimport py4stats as py4st\nimport pandas as pd\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込\n\nprint(py4st.freq_table(penguins, 'species'))\n#> species freq perc cumfreq cumperc\n#> 0 Chinstrap 68 0.197674 68 0.197674\n#> 1 Gentoo 124 0.360465 192 0.558140\n#> 2 Adelie 152 0.441860 344 1.000000\n\nprint(py4st.freq_table(penguins, ['island', 'species']))\n#> island species freq perc cumfreq cumperc\n#> 0 Biscoe Adelie 44 0.127907 44 0.127907\n#> 1 Torgersen Adelie 52 0.151163 96 0.279070\n#> 2 Dream Adelie 56 0.162791 152 0.441860\n#> 3 Dream Chinstrap 68 0.197674 220 0.639535\n#> 4 Biscoe Gentoo 124 0.360465 344 1.000000\npenguins2 = penguins.assign(bill_length_mm2 = pd.cut(penguins['bill_length_mm'], 6))\n\nprint(\n py4st.freq_table(\n penguins2, ['species', 'bill_length_mm2'], \n sort_by = 'values', dropna = True\n )\n )\n#> species bill_length_mm2 freq perc cumfreq cumperc\n#> 0 Adelie (32.072, 36.683] 36 0.105263 36 0.105263\n#> 1 Adelie (36.683, 41.267] 89 0.260234 125 0.365497\n#> 2 Adelie (41.267, 45.85] 25 0.073099 150 0.438596\n#> 3 Adelie (45.85, 50.433] 1 0.002924 151 0.441520\n#> 4 Chinstrap (36.683, 41.267] 1 0.002924 152 0.444444\n#> 5 Chinstrap (41.267, 45.85] 12 0.035088 164 0.479532\n#> 6 Chinstrap (45.85, 50.433] 29 0.084795 193 0.564327\n#> 7 Chinstrap (50.433, 55.017] 24 0.070175 217 0.634503\n#> 8 Chinstrap (55.017, 59.6] 2 0.005848 219 0.640351\n#> 9 Gentoo (36.683, 41.267] 1 0.002924 220 0.643275\n#> 10 Gentoo (41.267, 45.85] 39 0.114035 259 0.757310\n#> 11 Gentoo (45.85, 50.433] 65 0.190058 324 0.947368\n#> 12 Gentoo (50.433, 55.017] 15 0.043860 339 0.991228\n#> 13 Gentoo (55.017, 59.6] 3 0.008772 342 1.000000\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "6  freq_table" + ] + }, + { + "objectID": "man/Pareto_plot.html", + "href": "man/Pareto_plot.html", + "title": "Pareto_plot", + "section": "", + "text": "概要\nパレート図の作成\nデータフレームからパレート図を作図する関数です。", + "crumbs": [ + "**EDA**", + "7  Pareto_plot" + ] + }, + { + "objectID": "man/Pareto_plot.html#概要", + "href": "man/Pareto_plot.html#概要", + "title": "Pareto_plot", + "section": "", + "text": "Pareto_plot(\n data: IntoFrameT,\n group: str,\n values: Optional[str] = None,\n top_n: Optional[int] = None,\n aggfunc: Callable[..., Any] = np.mean,\n ax: Optional[Axes] = None,\n fontsize: int = 12,\n xlab_rotation: Union[int, float] = 0,\n palette: Sequence[str] = (\"#478FCE\", \"#252525\"),\n )\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\ngroup:str  集計に使用するデータフレームの列名(必須)。\nvalues:str  集計に使用するデータフレームの列名。values = None(初期設定)の場合、group 別の度数が表示され、values が指定された場合、group 別に values を aggfuncで集計した値がグラフに表示されます。\ntop_n:int  棒グラフを表示するカテゴリーの件数。top_n = None(初期設定)の場合、すべてのカテゴリーを表示し、整数値が指定された場合、上位 top_n 件が表示されます。\naggfunc:callable values が指定された際に、集計に使用する集計関数。np.mean など values 列を1次元配列として受け取って単一の数値を返す任意の関数が使用できるほか、nw.mean など narwhals.functions モジュールで実装された関数を使用できます。\nax 描画先となる matplotlib の Axes。複数のグラフを並べる場合などに使用します。デフォルトの None の場合は、新しい Figure と Axes が作成されます。\nfontsize:int  軸ラベルなどのフォントサイズ。\nxlab_rotation:int or float 横軸ラベルの角度。matplotlib の ax.xaxis.set_tick_params() に引数 rotation として渡されます。\npalette:list of str グラフの描画に使用する色コード。1つ目の要素が棒グラフの色に、2つ目の累積値を表す折線グラフの色に対応します。", + "crumbs": [ + "**EDA**", + "7  Pareto_plot" + ] + }, + { + "objectID": "man/Pareto_plot.html#使用例", + "href": "man/Pareto_plot.html#使用例", + "title": "Pareto_plot", + "section": "使用例", + "text": "使用例\nimport py4stats as py4st\nimport pandas as pd\nimport numpy as np\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込\n\npenguins['group'] = penguins['species'] + '\\n' + penguins['island']\n\npy4st.Pareto_plot(penguins, group = 'group')\n\n\n\nPareto_plot1\n\n\npy4st.Pareto_plot(\n penguins, group = 'group', \n values = 'bill_length_mm',\n aggfunc = np.mean,\n palette = ['#FF6F91', '#252525']\n )\n\n\n\nPareto_plot2\n\n\npy4st.Pareto_plot(\n penguins, \n values = 'bill_length_mm',\n group = 'group',\n aggfunc = lambda x: x.std()\n )\n\n\n\nPareto_plot3\n\n\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "7  Pareto_plot" + ] + }, + { + "objectID": "man/plot_category.html", + "href": "man/plot_category.html", + "title": "plot_category", + "section": "", + "text": "概要\nカテゴリ変数の回答分布を 100% 積み上げ横棒グラフとして描画します。\n本関数は、複数のカテゴリ変数について回答分布を集計し、各変数を1本の100%積み上げ横棒グラフとして可視化します。リッカート尺度による設問や、共通のカテゴリをもつ、アンケートの回答データの可視化を主な用途としています。", + "crumbs": [ + "**EDA**", + "8  plot_category" + ] + }, + { + "objectID": "man/plot_category.html#概要", + "href": "man/plot_category.html#概要", + "title": "plot_category", + "section": "", + "text": "plot_category(\n data: IntoFrameT,\n palette: Optional[sns.palettes._ColorPalette] = None,\n legend_type: Literal['horizontal', 'vertical', 'none'] = 'horizontal',\n show_vline: bool = True,\n ax: Optional[Axes] = None,\n):", + "crumbs": [ + "**EDA**", + "8  plot_category" + ] + }, + { + "objectID": "man/plot_category.html#引数-argument", + "href": "man/plot_category.html#引数-argument", + "title": "plot_category", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) カテゴリ変数を含む入力データフレーム(1列につき1変数)。 narwhals がサポートする任意のデータフレーム型(例:pandas.DataFrame、polars.DataFrame)を指定できます。 すべての列は、同一のカテゴリ体系(共通のカテゴリラベル)を共有している必要があります。 注意:pyarrow.Table については、その仕様による機能制限があります。詳細は「注意 Notes」セクションを参照してください。\nsort_by: str 回答カテゴリの並び順を決定する基準。'values':カテゴリの値(ラベル)でソートします。'frequency':出現頻度の高い順にソートします。デフォルトは 'values' です。\npalette sns.palettes._ColorPalette: 回答カテゴリに使用するカラーパレット。 None の場合は、内部でデフォルトの発散型パレットを生成します。 指定する場合は、カテゴリ数と同じ長さの配列である必要があります。 デフォルトは None です。\nlegend_typestr: 凡例の配置方法。デフォルトは 'horizontal' です。\n\n'horizontal':凡例をグラフ下部に横並びで表示します。\n'vertical':凡例をグラフ右側に縦並びで表示します。\n'none':凡例を表示しません。\n\nshow_vline:bool True の場合、x = 0.5(50%)の位置に基準となる垂直線を描画します。 割合の中点を視覚的に示す目的で使用できます。デフォルトは True です。\nax: 描画先となる matplotlib の Axes。複数のグラフを並べる場合などに使用します。デフォルトの None の場合は、新しい Figure と Axes が作成されます。", + "crumbs": [ + "**EDA**", + "8  plot_category" + ] + }, + { + "objectID": "man/plot_category.html#使用例-example", + "href": "man/plot_category.html#使用例-example", + "title": "plot_category", + "section": "使用例 Example", + "text": "使用例 Example\nimport py4stats as py4st\nimport pandas as pd\nimport itertools\n\nQ1 = [70 * ['Strongly agree'], 200 * ['Agree'], 235 * ['Disagree'], 149 * ['Strongly disagree']]\nQ2 = [74 * ['Strongly agree'], 209 * ['Agree'], 238 * ['Disagree'], 133 * ['Strongly disagree']]\nQ3 = [59 * ['Strongly agree'], 235 * ['Agree'], 220 * ['Disagree'], 140 * ['Strongly disagree']]\nQ4 = [40 * ['Strongly agree'], 72 * ['Agree'], 266 * ['Disagree'], 276 * ['Strongly disagree']]\n\ndata = pd.DataFrame({\n 'I read only if I have to.':list(itertools.chain.from_iterable(Q1)),\n 'Reading is one of my favorite hobbies.':list(itertools.chain.from_iterable(Q2)),\n 'I like talking about books with other people.':list(itertools.chain.from_iterable(Q3)),\n 'For me, reading is a waste of time.':list(itertools.chain.from_iterable(Q4))\n})\ncateg_list = ['Strongly disagree', 'Disagree', 'Agree', 'Strongly agree']\n\ndata_pd = data.apply(pd.Categorical, categories = categ_list)\n\npy4st.plot_category(data_pd)\n\n\n\nplot_category1\n\n\nimport polars as pl\nimport textwrap\n\ndata_pl = pl.from_pandas(data)\ndata_pl = data_pl.with_columns(\n pl.all().cast(pl.Enum(categ_list))\n )\\\n .rename(lambda x: textwrap.fill(x, width = 25))\n\nfig, ax = plt.subplots()\n\npy4st.plot_category(\n data_pl, \n palette = sns.color_palette('RdBu', n_colors = 4),\n ax = ax\n )\n\nax.set_title('Survey on attitudes toward reading');\n\n\n\nplot_category2", + "crumbs": [ + "**EDA**", + "8  plot_category" + ] + }, + { + "objectID": "man/plot_category.html#注意-notes", + "href": "man/plot_category.html#注意-notes", + "title": "plot_category", + "section": "注意 Notes", + "text": "注意 Notes\n\nsort_by=\"values\" は、カテゴリの順序情報(例:pandas の ordered categorical、Polars の Enum で定義した順序)を前提に、カテゴリ順で描画します。\n推奨: sort_by=“values” を利用する場合は、入力として pandas.DataFrame(各列を pd.Categorical に設定)または polars.DataFrame(各列を Enum に設定)を推奨します。\npolars.Categorical の列では、カテゴリ順が期待通りに保持されず、辞書順(例:Agree, Disagree, …)で描画される場合があります。\npyarrow.Table を入力した場合、sort_by = 'values’ は dictionary 型の制約によりエラーとなる場合があります。その場合は sort_by=\"frequency\" を使用してください。", + "crumbs": [ + "**EDA**", + "8  plot_category" + ] + }, + { + "objectID": "man/diagnose_category.html", + "href": "man/diagnose_category.html", + "title": "diagnose_category", + "section": "", + "text": "概要\nカテゴリー変数の要約\nデータフレームのカテゴリー変数を要約します。本関数は、カテゴリー情報を表す列(カテゴリ型・文字列型・ブール型)およびダミー変数(値が {0, 1} に制限された整数列)を対象として、欠損率、ユニーク値の数、最頻値、最頻値の頻度と割合、evenness などの指標を提供します。", + "crumbs": [ + "**EDA**", + "9  diagnose_category" + ] + }, + { + "objectID": "man/diagnose_category.html#概要", + "href": "man/diagnose_category.html#概要", + "title": "diagnose_category", + "section": "", + "text": "diagnose_category(\n data: IntoFrameT, \n dropna: bool = True, \n to_native: bool = True\n )", + "crumbs": [ + "**EDA**", + "9  diagnose_category" + ] + }, + { + "objectID": "man/diagnose_category.html#引数-argument", + "href": "man/diagnose_category.html#引数-argument", + "title": "diagnose_category", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\ndropna:bool  欠測値(NaN, None など)を統計値の計算から除外するかどうかを表すブール値。初期設定は True です。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "9  diagnose_category" + ] + }, + { + "objectID": "man/diagnose_category.html#返り値-value", + "href": "man/diagnose_category.html#返り値-value", + "title": "diagnose_category", + "section": "返り値 Value", + "text": "返り値 Value\nfreq_table()関数は、次の値をもつ DataFrame を出力します。\n\nvariables: 変数(列)名\ncount: 非欠損値の個数\nmiss_pct: 欠損率(null_count / N * 100) (* ここで N は data の行数)\nunique: ユニーク値の個数\nunique_pct: ユニーク値の割合(unique / N * 100)\nmode: 最頻値\nmode_freq: 最頻値の度数\nmode_pct: 最頻値の割合(mode_freq / N * 100)\nevenness: カテゴリー分布の均等度([0, 1] の範囲)", + "crumbs": [ + "**EDA**", + "9  diagnose_category" + ] + }, + { + "objectID": "man/diagnose_category.html#使用例-examples", + "href": "man/diagnose_category.html#使用例-examples", + "title": "diagnose_category", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport pandas as pd\nimport py4stats as py4st\nfrom palmerpenguins import load_penguins\n\npenguins = load_penguins().drop('year', axis = 1) # サンプルデータの読み込み\npenguins2 = penguins.copy()\ns = penguins2['body_mass_g']\npenguins2['heavy'] = np.where(s >= s.quantile(0.75), True, False)\n\nprint(py4st.diagnose_category(penguins2).round(4))\n#> variables count miss_pct unique unique_pct mode mode_freq mode_pct evenness\n#> 0 species 344 0.0000 3 0.8721 Adelie 152 44.1860 0.9550\n#> 1 island 344 0.0000 3 0.8721 Biscoe 168 48.8372 0.9133\n#> 2 sex 333 3.1977 2 0.5814 male 168 50.4505 0.9999\n#> 3 heavy 344 0.0000 2 0.5814 False 254 73.8372 0.8292", + "crumbs": [ + "**EDA**", + "9  diagnose_category" + ] + }, + { + "objectID": "man/diagnose_category.html#note", + "href": "man/diagnose_category.html#note", + "title": "diagnose_category", + "section": "Note", + "text": "Note\nevenness は、各列ごとに情報エントロピーを \\([0, 1]\\) の範囲に正規化した指標です。本実装では、対数の底をカテゴリの個数(unique)に設定することで正規化を行っており、これは底を2とした情報エントロピーを log2(unique) で割ることと同値です。この指標は正規化エントロピー(normalized entropy)としても知られています。\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "9  diagnose_category" + ] + }, + { + "objectID": "man/point_range.html", + "href": "man/point_range.html", + "title": "mean_qi median_qi mean_ci", + "section": "", + "text": "概要\n数値変数の点推定と区間推定\nR言語の ggdist::mean_qi() をオマージュした数値変数の点推定と区間推定を行う関数です。", + "crumbs": [ + "**EDA**", + "10  mean_qi median_qi mean_ci" + ] + }, + { + "objectID": "man/point_range.html#概要", + "href": "man/point_range.html#概要", + "title": "mean_qi median_qi mean_ci", + "section": "", + "text": "mean_qi(\n data: Union[IntoFrameT, SeriesT],\n width: float = 0.975,\n interpolation: str = 'midpoint',\n to_native: bool = True\n)\nmean_qi(\n data: Union[IntoFrameT, SeriesT],\n width: float = 0.975,\n interpolation: str = 'midpoint',\n to_native: bool = True\n)\n\nmedian_qi(\n data: Union[IntoFrameT, IntoSeriesT],\n width: float = 0.975,\n interpolation: str = 'midpoint',\n to_native: bool = True\n)\n\nmean_ci(\n data: Union[IntoFrameT, IntoSeriesT],\n width: float = 0.975,\n to_native: bool = True\n)", + "crumbs": [ + "**EDA**", + "10  mean_qi median_qi mean_ci" + ] + }, + { + "objectID": "man/point_range.html#引数-argument", + "href": "man/point_range.html#引数-argument", + "title": "mean_qi median_qi mean_ci", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT or IntoSeriesT(必須) 入力データ。narwhals が受け入れ可能な DataFrame もしくは Series 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\nwidth:float  分位点区間の幅、もしくは信頼区間の計算に用いる信頼係数。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "10  mean_qi median_qi mean_ci" + ] + }, + { + "objectID": "man/point_range.html#使用例-examples", + "href": "man/point_range.html#使用例-examples", + "title": "mean_qi median_qi mean_ci", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport py4stats as py4st\nimport pandas as pd\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込み\n\nprint(py4st.mean_qi(penguins['bill_length_mm']).round(2))\n#> variable mean lower upper\n#> 0 bill_length_mm 43.92 34.8 53.1\n\n\nprint(py4st.median_qi(penguins['bill_length_mm']).round(2))\n#> variable median lower upper\n#> 0 bill_length_mm 44.45 34.8 53.1\n\nprint(py4st.mean_ci(penguins['bill_length_mm']).round(2))\n#> variable mean lower upper\n#> 0 bill_length_mm 43.92 43.26 44.58\n\nprint(py4st.mean_ci(penguins[['bill_length_mm', 'bill_depth_mm']]).round(2))\n#> variable mean lower upper\n#> 0 bill_length_mm 43.92 43.26 44.58\n#> 1 bill_depth_mm 17.15 16.91 17.39\n\nprint(penguins.groupby('species')[['bill_length_mm']].apply(py4st.median_qi).round(2))\n#> variable median lower upper\n#> species \n#> Adelie 0 bill_length_mm 38.80 34.05 44.10\n#> Chinstrap 0 bill_length_mm 49.55 42.45 55.00\n#> Gentoo 0 bill_length_mm 47.30 42.65 53.85\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "10  mean_qi median_qi mean_ci" + ] + }, + { + "objectID": "man/remove_empty_constant.html", + "href": "man/remove_empty_constant.html", + "title": "remove_empty, remove_constant", + "section": "", + "text": "概要\nデータフレームの空白列および、定数列の削除\npy4stats.remove_empty()はR言語の janitor:remove_empty() をオマージュした関数で、全ての要素が NaN である列や行をデータフレームから除外します py4stats.remove_constant() はR言語の janitor:remove_constant() をオマージュした関数で、1種類だけの要素からなる列をデータフレームから除外します。", + "crumbs": [ + "**EDA**", + "11  remove_empty, remove_constant" + ] + }, + { + "objectID": "man/remove_empty_constant.html#概要", + "href": "man/remove_empty_constant.html#概要", + "title": "remove_empty, remove_constant", + "section": "", + "text": "remove_empty(\n data: IntoFrameT,\n cols: bool = True,\n rows: bool = True,\n cutoff: float = 1.0,\n quiet: bool = True,\n to_native: bool = True,\n **kwargs: Any\n) \n\nremove_constant(\n data: IntoFrameT,\n quiet: bool = True,\n to_native: bool = True,\n dropna = False,\n **kwargs: Any\n)", + "crumbs": [ + "**EDA**", + "11  remove_empty, remove_constant" + ] + }, + { + "objectID": "man/remove_empty_constant.html#引数-argument", + "href": "man/remove_empty_constant.html#引数-argument", + "title": "remove_empty, remove_constant", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\ncols:bool  空白列を削除するかどうかを表すブール値(remove_empty() のみ)。True(初期設定) なら空白列を削除し、Falseなら全ての要素が NaN の列があっても削除しません。\nrows:bool  空白行を削除するかどうかを表すブール値(remove_empty() のみ)。True(初期設定) なら空白行を削除し、Falseなら全ての要素が NaN の行があっても削除しません。\ncutoff:float  列(行)の削除を行うかどうかを判定する欠測率の閾値(remove_empty() のみ)。ある列(行)における NaN の割合が >= cutoff のとき、その列(行)を削除します。初期設定は1で全ての要素が NaN の列(行)のみ削除しますが、例えば cutoff = 0.9 とすることで NaN の割合9が割以上の列(行)を削除できます。\nquiet:bool  削除した列(行)を報告するかどうかを表すブール値。quiet = True(初期設定) であれば何も報告せずに削除だけ行い、quiet = False なら、削除した列(行)の数と列名(行名)を報告します。\ndropna:bool  ユニーク値の数を計算する際に、NaN を除外するかどうかを表すブール値(remove_constant() のみ)。dropna = True だと NaN を除外し、dropna = False(初期設定)だと NaN を除外しません。データフレームに NaN と、 NaN ではない1種類の値からなる列がある場合、dropna = False だと削除されず、dropna = True だと削除されます。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "11  remove_empty, remove_constant" + ] + }, + { + "objectID": "man/remove_empty_constant.html#使用例-example", + "href": "man/remove_empty_constant.html#使用例-example", + "title": "remove_empty, remove_constant", + "section": "使用例 Example", + "text": "使用例 Example\npy4stats.remove_empty() の使用例。\nimport py4stats as py4st\nimport pandas as pd\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込み\n\npenguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy()\n# 空白列を作成\npenguins2.loc[:, 'empty'] = np.nan\n# 空白行を作成\npenguins2.loc[344, :] = np.nan\n\nprint(penguins2.tail(3))\n#> species body_mass_g empty\n#> 342 Chinstrap 4100.0 NaN\n#> 343 Chinstrap 3775.0 NaN\n#> 344 NaN NaN NaN\n# 完全に空白な行と列を削除。\nprint(py4st.remove_empty(penguins2, quiet = False).tail(3))\n#> Removing 1 empty column(s) out of 3 columns(Removed: empty).\n#> Removing 1 empty row(s) out of 345 rows(Removed: 344).\n#> species body_mass_g\n#> 341 Chinstrap 3775.0\n#> 342 Chinstrap 4100.0\n#> 343 Chinstrap 3775.0\n\n# 完全に空白な列のみ削除。\nprint(py4st.remove_empty(penguins2, rows = False, quiet = False).tail(3))\n#> Removing 1 empty column(s) out of 3 columns(Removed: empty).\n#> species body_mass_g\n#> 342 Chinstrap 4100.0\n#> 343 Chinstrap 3775.0\n#> 344 NaN NaN\n\n# 完全に空白な行のみ削除。\nprint(py4st.remove_empty(penguins2, cols = False, quiet = False).tail(3))\n#> Removing 1 empty row(s) out of 345 rows(Removed: 344).\n#> species body_mass_g empty\n#> 341 Chinstrap 3775.0 NaN\n#> 342 Chinstrap 4100.0 NaN\n#> 343 Chinstrap 3775.0 NaN\n# quiet = True の場合\nprint(py4st.remove_empty(penguins2).tail(3))\n#> species body_mass_g\n#> 341 Chinstrap 3775.0\n#> 342 Chinstrap 4100.0\n#> 343 Chinstrap 3775.0\npy4stats.remove_constant() の使用例。\npenguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy()\npenguins2.loc[:, 'constant'] = 'c'\n\nprint(penguins2.head(3))\n#> species body_mass_g constant\n#> 0 Adelie 3750.0 c\n#> 1 Adelie 3800.0 c\n#> 2 Adelie 3250.0 c\n\nprint(py4st.remove_constant(penguins2, quiet = False).head(3))\n#> Removing 1 constant column(s) out of 3 column(s)(Removed: constant).\n#> species body_mass_g\n#> 0 Adelie 3750.0\n#> 1 Adelie 3800.0\n#> 2 Adelie 3250.0\npenguins2.loc[:, 'almost_empty'] = pd.NA\npenguins2.loc[1, 'almost_empty'] = 'c'\n\n# dropna = False なら、almost_empty は削除されません。\nprint(py4st.remove_constant(penguins2).head(3))\n#> species body_mass_g almost_empty\n#> 0 Adelie 3750.0 <NA>\n#> 1 Adelie 3800.0 c\n#> 2 Adelie 3250.0 <NA>\n\nprint(py4st.remove_constant(penguins2, dropna = True).head(3))\n#> species body_mass_g\n#> 0 Adelie 3750.0\n#> 1 Adelie 3800.0\n#> 2 Adelie 3250.0\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "11  remove_empty, remove_constant" + ] + }, + { + "objectID": "man/filtering_out.html", + "href": "man/filtering_out.html", + "title": "filtering_out", + "section": "", + "text": "概要\nデータフレームの行と列の除外\npandas の DataFrame.filter() メソッドでは引数 like に文字列を指定することで、列名に特定の文字列を含む列を選択できます。py4st.filtering_out() では、反対に列名に特定の文字列を含む列を除外します。実装の一部はR言語の dplyr::select() を参考にしました。", + "crumbs": [ + "**EDA**", + "12  filtering_out" + ] + }, + { + "objectID": "man/filtering_out.html#概要", + "href": "man/filtering_out.html#概要", + "title": "filtering_out", + "section": "", + "text": "filtering_out(\n data: IntoFrameT,\n contains: Optional[str] = None,\n starts_with: Optional[str] = None,\n ends_with: Optional[str] = None,\n axis: Union[int, str] = 'columns',\n to_native: bool = True,\n)", + "crumbs": [ + "**EDA**", + "12  filtering_out" + ] + }, + { + "objectID": "man/filtering_out.html#引数-argument", + "href": "man/filtering_out.html#引数-argument", + "title": "filtering_out", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\n*args(str / list[str] / narwhals.Expr / narwhals.Selector) 移動したい列を指定します。指定方法は次のとおりです。\n\n列名(例:\"x\")\n列名のリスト(例:[\"x\", \"y\"])\nnarwhals の式(Expr)(例:nw.col(\"x\")) *axis = 'columns' の場合のみ\nnarwhals の Selector (例:ncs.numeric())*axis = 'columns' の場合のみ\n\ncontains:str  列名(行名)の検索に使用する文字列。内部で使用している pandas.Series.str.contains に渡され、指定された文字列を列名(行名)に含む列(行)を除外します。\nstarts_with:str  列名(行名)の検索に使用する文字列。内部で使用している pandas.Series.str.startswith に渡され、指定された文字列で列名(行名)が始まる列(行)を除外します。\nends_with:str  列名(行名)の検索に使用する文字列。内部で使用している pandas.Series.str.endswith に渡され、指定された文字列で列名(行名)が終わる列(行)を除外します。\naxis:{0 or 'index', 1 or 'columns'} axis = 1 または axis = 'columns' なら列の削除を行い、axis = 0 または axis = 'index' なら行の削除を行います。 このオプションは、data がインデックス属性 (例: pandas.DataFrame) をもつ場合のみ有効です。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "12  filtering_out" + ] + }, + { + "objectID": "man/filtering_out.html#使用例", + "href": "man/filtering_out.html#使用例", + "title": "filtering_out", + "section": "使用例", + "text": "使用例\nimport py4stats as py4st\nimport pandas as pd\nimport narwhals.selectors as ncs\nfrom palmerpenguins import load_penguins\n\npenguins = load_penguins().head(3) # サンプルデータの読み込み\n\nprint(penguins)\n#> species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year female\n#> 0 Adelie Torgersen 39.1 18.7 181.0 3750.0 male 2007 0\n#> 1 Adelie Torgersen 39.5 17.4 186.0 3800.0 female 2007 1\n#> 2 Adelie Torgersen 40.3 18.0 195.0 3250.0 female 2007 1\n# *args で列名を直接指定\nprint(py4st.filtering_out(penguins, 'year', 'island', 'sex'))\n#> species bill_length_mm bill_depth_mm flipper_length_mm body_mass_g\n#> 0 Adelie 39.1 18.7 181.0 3750.0\n#> 1 Adelie 39.5 17.4 186.0 3800.0\n#> 2 Adelie 40.3 18.0 195.0 3250.0\n\n\n# narwhals.selector の使用例 文字列型の変数を除外\nprint(py4st.filtering_out(penguins, ncs.string()))\n#> bill_length_mm bill_depth_mm flipper_length_mm body_mass_g year\n#> 0 39.1 18.7 181.0 3750.0 2007\n#> 1 39.5 17.4 186.0 3800.0 2007\n#> 2 40.3 18.0 195.0 3250.0 2007\n\n# 列名に 'length' を含む列を除外\nprint(py4st.filtering_out(penguins, contains = 'length'))\n#> species island bill_depth_mm body_mass_g sex year female\n#> 0 Adelie Torgersen 18.7 3750.0 male 2007 0\n#> 1 Adelie Torgersen 17.4 3800.0 female 2007 1\n#> 2 Adelie Torgersen 18.0 3250.0 female 2007 1\n\n# 列名が 'bill' から始まる列を除外\nprint(py4st.filtering_out(penguins, starts_with = 'bill'))\n#> species island flipper_length_mm body_mass_g sex year female\n#> 0 Adelie Torgersen 181.0 3750.0 male 2007 0\n#> 1 Adelie Torgersen 186.0 3800.0 female 2007 1\n#> 2 Adelie Torgersen 195.0 3250.0 female 2007 1\n\n# 列名が '_mm' で終わる列を除外\nprint(py4st.filtering_out(penguins, ends_with = '_mm'))\n#> species island body_mass_g sex year female\n#> 0 Adelie Torgersen 3750.0 male 2007 0\n#> 1 Adelie Torgersen 3800.0 female 2007 1\n#> 2 Adelie Torgersen 3250.0 female 2007 1", + "crumbs": [ + "**EDA**", + "12  filtering_out" + ] + }, + { + "objectID": "man/filtering_out.html#notes", + "href": "man/filtering_out.html#notes", + "title": "filtering_out", + "section": "Notes", + "text": "Notes\naxis='index' による行を対象とするフィルタリングは、インデックスの存在に依存します。したがって、pd.DataFrame 以外の行ラベルをもたない DataFrame バックエンドでは、このオプションは利用できません。\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "12  filtering_out" + ] + }, + { + "objectID": "man/relocate.html", + "href": "man/relocate.html", + "title": "relocate", + "section": "", + "text": "概要\nデータフレームの列を削除することなく並び替える関数\nrelocate() 関数は、データフレームに含まれる列を削除することなく並び替えるための関数です。指定した列(1 列または複数列)を、先頭・特定の列の前・特定の列の後に移動させることができます。本関数は、R の dplyr:relocate() に近い操作感を Python で提供することを目的としています。列の指定には、列名(文字列)だけでなく、narwhals の式(Expr)や Selector を利用でき、柔軟な列選択", + "crumbs": [ + "**EDA**", + "13  relocate" + ] + }, + { + "objectID": "man/relocate.html#概要", + "href": "man/relocate.html#概要", + "title": "relocate", + "section": "", + "text": "relocate(\n data: IntoFrameT, \n *args: Union[str, List[str], narwhals.Expr, narwhals.selectors.Selector], \n before: Optional[str] = None,\n after: Optional[str] = None,\n place: Optional[Literal[\"first\", \"last\"]] = None,\n to_native: bool = True\n ):", + "crumbs": [ + "**EDA**", + "13  relocate" + ] + }, + { + "objectID": "man/relocate.html#引数-argument", + "href": "man/relocate.html#引数-argument", + "title": "relocate", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\n*args(str / list[str] / narwhals.Expr / narwhals.Selector) 移動したい列を指定します。指定方法は次のとおりです。\n\n列名(例:\"x\")\n列名のリスト(例:[\"x\", \"y\"])\nnarwhals の式(Expr)(例:nw.col(\"x\"))\nnarwhals の Selector (例:ncs.numeric())\n\n指定した順序は、移動後の列順にもそのまま反映されます。\nbefore(str, optional) args で指定された列を、この列の直前に移動します。 after と同時に指定することはできません。デフォルトは None です。\nafter(str, optional) args で指定された列を、この列の直後に移動します。 before と同時に指定することはできません。デフォルトは None です。\nplace(str, optional) *args で指定された列の、配置場所を指定します。\n\n\"first\": 選択した列をデータフレームの先頭(最も左)に配置します。\n\"last\": 選択した列をデータフレームの末尾(最も右)に配置します。 place 引数は before または after と同時に指定することはできません。 未指定(None)の場合は \"first\" と同じ挙動になります。\n\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。\n\n\n返り値\n\nIntoFrameT 入力データフレームと同じ列を保持したまま、指定されたルールに従って並び替えられたデータフレームを返します。", + "crumbs": [ + "**EDA**", + "13  relocate" + ] + }, + { + "objectID": "man/relocate.html#使用例-example", + "href": "man/relocate.html#使用例-example", + "title": "relocate", + "section": "使用例 Example", + "text": "使用例 Example\nimport py4stats as py4st\nimport pandas as pd\nimport narwhals.selectors as ncs\nfrom palmerpenguins import load_penguins\n\npenguins_mini = py4st.filtering_out(penguins, starts_with = 'bill').head(3)\nprint(penguins_mini)\n#> species island flipper_length_mm body_mass_g sex year\n#> 0 Adelie Torgersen 181.0 3750.0 male 2007\n#> 1 Adelie Torgersen 186.0 3800.0 female 2007\n#> 2 Adelie Torgersen 195.0 3250.0 female 2007\n# *args に指定した列は最前列に移動します\nprint(py4st.relocate(penguins_mini, 'year', 'sex'))\n#> year sex species island flipper_length_mm body_mass_g\n#> 0 2007 male Adelie Torgersen 181.0 3750.0\n#> 1 2007 female Adelie Torgersen 186.0 3800.0\n#> 2 2007 female Adelie Torgersen 195.0 3250.0\n\n# ncs.numeric() を使うことで、数値変数を指定できます\nprint(py4st.relocate(penguins_mini, ncs.numeric()))\n#> flipper_length_mm body_mass_g year species island sex\n#> 0 181.0 3750.0 2007 Adelie Torgersen male\n#> 1 186.0 3800.0 2007 Adelie Torgersen female\n#> 2 195.0 3250.0 2007 Adelie Torgersen female\n\n# year 列を island 列の直前に移動\nprint(py4st.relocate(penguins_mini, 'year', before = 'island'))\n#> species year island flipper_length_mm body_mass_g sex\n#> 0 Adelie 2007 Torgersen 181.0 3750.0 male\n#> 1 Adelie 2007 Torgersen 186.0 3800.0 female\n#> 2 Adelie 2007 Torgersen 195.0 3250.0 female\n\n# year 列を island 列の直後に移動\nprint(py4st.relocate(penguins_mini, 'year', after = 'island'))\n#> species island year flipper_length_mm body_mass_g sex\n#> 0 Adelie Torgersen 2007 181.0 3750.0 male\n#> 1 Adelie Torgersen 2007 186.0 3800.0 female\n#> 2 Adelie Torgersen 2007 195.0 3250.0 female\n\n#. place = 'last' で最後列に移動\nprint(py4st.relocate(penguins_mini, 'year', place = 'last'))\n#> species island flipper_length_mm body_mass_g sex year\n#> 0 Adelie Torgersen 181.0 3750.0 male 2007\n#> 1 Adelie Torgersen 186.0 3800.0 female 2007\n#> 2 Adelie Torgersen 195.0 3250.0 female 2007\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "13  relocate" + ] + }, + { + "objectID": "man/compare_df_cols.html", + "href": "man/compare_df_cols.html", + "title": "compare_df_cols, compare_df_stats", + "section": "", + "text": "概要\nデータ型と統計値によるデータフレームの比較\nR言語の janitor::compare_df_cols() をオマージュした関数で、compare_df_cols() は複数の pandas.DataFrame に含まれる同じ名前を持つ列同士のデータ型 dtype を比較し、compare_df_stats() は同じ名前を持つ列同士の記述統計量を比較します。", + "crumbs": [ + "**EDA**", + "14  compare_df_cols, compare_df_stats" + ] + }, + { + "objectID": "man/compare_df_cols.html#概要", + "href": "man/compare_df_cols.html#概要", + "title": "compare_df_cols, compare_df_stats", + "section": "", + "text": "compare_df_cols(\n df_list: Union[List[IntoFrameT], Mapping[str, IntoFrameT]],\n df_name: Optional[List[str]] = None,\n return_match: Literal[\"all\", \"match\", \"mismatch\"] = 'all',\n dropna:bool = False,\n to_native: bool = True\n)\n\ncompare_df_stats(\n df_list: List[IntoFrameT],\n df_name: Optional[List[str]] = None,\n return_match: Literal[\"all\", \"match\", \"mismatch\"] = \"all\",\n stats: Callable[..., Any] = np.mean,\n rtol: float = 1e-05,\n atol: float = 1e-08,\n to_native: bool = True,\n **kwargs: Any,\n)", + "crumbs": [ + "**EDA**", + "14  compare_df_cols, compare_df_stats" + ] + }, + { + "objectID": "man/compare_df_cols.html#引数-argument", + "href": "man/compare_df_cols.html#引数-argument", + "title": "compare_df_cols, compare_df_stats", + "section": "引数 Argument", + "text": "引数 Argument\n\ndf_list(必須) A list or dict of IntoFrameT  列を比較するデータフレームのリストもしくは辞書オブジェクト。辞書が df_name が未指定の場合、辞書の keys を df_name として使用します。\ndf_name list of str  表頭に表示するデータフレームの名前。['df1', 'df2'] のように文字列のリストを指定してください。初期設定では、自動的に df1, df2, df3 … と連番が割り当てられます。\nreturn_match str  出力に反映する変数の範囲を表す文字列。次の値から選択できます。\n\n'all'(初期設定): 全ての列を表示。\n'match':全てのデータフレームで dtype が一致している列のみを表示。\n'mismatch':少なくとも1つのデータフレームで dtype が一致していない列のみを表示。\n\ndropna bool (compare_df_cols() のみ)  データ型 dtype の一致判定に当たり、NaN を無視するかどうか。初期設定 False の場合、すべてのデータフレームが同名かつ同じデータ型の列を持たない限り、ミスマッチが発生したと判定されます。\nstats str or function  比較に用いる記述統計量を定義する関数。np.mean など values 列を1次元配列として受け取って単一の数値を返す任意の関数が使用できるほか、nw.mean など narwhals.functions モジュールで実装された関数を使用できます。初期設定は np.mean です。", + "crumbs": [ + "**EDA**", + "14  compare_df_cols, compare_df_stats" + ] + }, + { + "objectID": "man/compare_df_cols.html#使用例-examples", + "href": "man/compare_df_cols.html#使用例-examples", + "title": "compare_df_cols, compare_df_stats", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport pandas as pd\nimport py4stats as py4st\n\ndf1 = pd.DataFrame({'x':[1, 2, 3], 'y':[5, 4, 2], 'z':[True, False, True]})\ndf2 = pd.DataFrame({'x':[1, 2, 3], 'y':[5.0, 4, 2], 'z':['True', 'False', 'True']})\n\nprint(py4st.compare_df_cols([df1, df2]))\n#> term df1 df2 match_dtype\n#> 0 x int64 int64 True\n#> 1 y int64 float64 False\n#> 2 z bool object False\nreturn_match = 'mismatch' を指定すると、データフレームの中で、dtype が一致していないものがある列を返します。\nprint(py4st.compare_df_cols(\n [df1, df2], return_match = 'mismatch'\n ))\n#> term df1 df2 match_dtype\n#> 1 y int64 float64 False\n#> 2 z bool object False\n py4st.compare_df_stats() は数値変数の記述統計量を比較するため、異なる経路で行われたデータ処理の結果が一致しているかを検証する場合に便利です。\nfrom palmerpenguins import load_penguins\npenguins = load_penguins()\npenguins2 = penguins.copy()\nvars = ['flipper_length_mm', 'body_mass_g']\npenguins2.loc[:, vars] = py4st.scale(penguins2.loc[:, vars])\n\nprint(\n py4st.compare_df_stats([penguins, penguins2]).round(2)\n)\n#> term df1 df2 match_stats\n#> 0 bill_depth_mm 17.15 17.15 True\n#> 1 bill_length_mm 43.92 43.92 True\n#> 2 body_mass_g 4201.75 0.00 False\n#> 3 flipper_length_mm 200.92 -0.00 False\n#> 4 year 2008.03 2008.03 True\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "14  compare_df_cols, compare_df_stats" + ] + }, + { + "objectID": "man/compare_group_stats.html", + "href": "man/compare_group_stats.html", + "title": "compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff", + "section": "", + "text": "概要\n統計量に基づく2グループの比較と差分の可視化\nこれら関数は、入力された2つのデータフレームについて、各数値変数の統計量に基づいた比較を提供します。", + "crumbs": [ + "**EDA**", + "15  compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff" + ] + }, + { + "objectID": "man/compare_group_stats.html#概要", + "href": "man/compare_group_stats.html#概要", + "title": "compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff", + "section": "", + "text": "compare_group_means(\n group1: IntoFrameT,\n group2: IntoFrameT,\n group_names: Sequence[str] = ('group1', 'group2'),\n columns: Literal['common', 'all'] = 'all',\n to_native: bool = True\n )\n\ncompare_group_median(\n group1: IntoFrameT,\n group2: IntoFrameT,\n group_names: Sequence[str] = ('group1', 'group2'),\n columns: Literal['common', 'all'] = 'all',\n to_native: bool = True\n )\n\nplot_mean_diff(\n group1: IntoFrameT,\n group2: IntoFrameT,\n stats_diff: Literal[\"norm_diff\", \"abs_diff\", \"rel_diff\"] = \"norm_diff\",\n ax: Optional[Axes] = None,\n )\n\nplot_median_diff(\n group1: IntoFrameT,\n group2: IntoFrameT,\n stats_diff: Literal[\"abs_diff\", \"rel_diff\"] = \"rel_diff\",\n ax: Optional[Axes] = None,\n )", + "crumbs": [ + "**EDA**", + "15  compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff" + ] + }, + { + "objectID": "man/compare_group_stats.html#引数-argument", + "href": "man/compare_group_stats.html#引数-argument", + "title": "compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff", + "section": "引数 Argument", + "text": "引数 Argument\n\ngroup1(必須)a pandas.DataFrame  数値変数を含む pandas.DataFrame で group2 との比較対象となるもの\ngroup2(必須)a pandas.DataFrame  数値変数を含む pandas.DataFrame で group1 との比較対象となるもの\ngroup_names list of str  表頭に表示するグループの名前。['group1', 'group2'] のように、2つの要素をもつ文字列のリストとして指定してください。\ncolumns str 2つのグループの結果を結合する際に含める変数を指定します。\n\n\"common\": 両方のグループに存在する変数のみが含まれます。\n\"all\": いずれかのグループに存在する全ての変数が含まれます。この場合、一方のグループにのみ存在する変数についての差分統計量は、欠損値(例:NaN または None)となります。\n\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。\nstats_diff: str (plot_mean_diff() および plot_median_diff() のみ)  グラフの描画に使用する差分統計量。'norm_diff'(plot_mean_diff() のみ)、'abs_diff', 'rel_diff' のいずれかから選ぶことができます。", + "crumbs": [ + "**EDA**", + "15  compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff" + ] + }, + { + "objectID": "man/compare_group_stats.html#返り値-value", + "href": "man/compare_group_stats.html#返り値-value", + "title": "compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff", + "section": "返り値 Value", + "text": "返り値 Value\n compare_group_means()関数および, compare_group_median() 関数では、次の値をもつ pandas.DataFrame が出力されます。\n\ngroup1, group2(初期設定の場合)  各グループにおける記述統計統計量の値\nnorm_diff(compare_group_means() のみ)  標準化された平均値の差で、2つのグループの平均値を \\(\\bar{X}_1\\), \\(\\bar{X}_2\\)、分散を \\(s^2_1, s^2_2\\) とし、サンプルサイズを \\(n_1, n_2\\) とするとき、次式のように定義されます。\n\n\\[\n\\delta = \\frac{\\bar{X}_1 - \\bar{X}_2}{s},~~~~~ s^2 = \\frac{(n_1-1)s_1^2 + (n_2-1)s_2^2}{n_1 + n_2 - 2}\n\\]\n\nabs_diff 2つのグループの記述統計量の絶対差\nrel_diff 2つのグループの記述統計量の相対差。2つのグループの記述統計量を \\(\\bar{X}_1\\), \\(\\bar{X}_2\\) とするとき、次式のように定義されます。\n\n\\[\n\\delta = \\cfrac{\\bar{X}_1 - \\bar{X}_2}{\\cfrac{\\bar{X}_1 + \\bar{X}_2}{2}}\n= 2 \\cdot \\frac{\\bar{X}_1 - \\bar{X}_2}{\\bar{X}_1 + \\bar{X}_2}\n\\]\nplot_mean_diff() 関数および, plot_median_diff() 関数では、グループ別の記述統計両の差をグラフとして可視化します。詳細は使用例を参照して下さい。", + "crumbs": [ + "**EDA**", + "15  compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff" + ] + }, + { + "objectID": "man/compare_group_stats.html#使用例-examples", + "href": "man/compare_group_stats.html#使用例-examples", + "title": "compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport pandas as pd\nimport py4stats as py4st\nfrom palmerpenguins import load_penguins\n\npenguins = load_penguins().drop('year', axis = 1) # サンプルデータの読み込み\nres1 = py4st.compare_group_means(\n penguins.query('species == \"Gentoo\"'),\n penguins.query('species == \"Adelie\"')\n)\nprint(res1.round(3))\n#> variable group1 group2 norm_diff abs_diff rel_diff\n#> 0 bill_depth_mm 14.982 18.346 -3.012 3.364 -0.202\n#> 1 bill_length_mm 47.505 38.791 3.048 8.713 0.202\n#> 2 body_mass_g 5076.016 3700.662 2.868 1375.354 0.313\n#> 3 flipper_length_mm 217.187 189.954 4.180 27.233 0.134\nres2 = py4st.compare_group_median(\n penguins.query('species == \"Gentoo\"'),\n penguins.query('species == \"Adelie\"'),\n group_names = ['Gentoo', 'Adelie']\n)\nprint(res2.round(3))\n#> variable Gentoo Adelie abs_diff rel_diff\n#> 0 bill_depth_mm 14.982 18.346 3.364 -0.202\n#> 1 bill_length_mm 47.505 38.791 8.713 0.202\n#> 2 body_mass_g 5076.016 3700.662 1375.354 0.313\n#> 3 flipper_length_mm 217.187 189.954 27.233 0.134\npy4st.plot_mean_diff(\n penguins.query('species == \"Gentoo\"'),\n penguins.query('species == \"Adelie\"'),\n stats_diff = 'norm_diff'\n)\n\n\n\nplot_mean_diff1\n\n\npy4st.plot_mean_diff(\n penguins.query('species == \"Gentoo\"'),\n penguins.query('species == \"Adelie\"'),\n stats_diff = 'abs_diff'\n)\n\n\n\nplot_mean_diff2\n\n\npy4st.plot_median_diff(\n penguins.query('species == \"Gentoo\"'),\n penguins.query('species == \"Adelie\"'),\n stats_diff = 'rel_diff'\n)\n\n\n\nplot_median_diff1\n\n\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "15  compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff" + ] + }, + { + "objectID": "man/plot_miss_var.html", + "href": "man/plot_miss_var.html", + "title": "plot_miss_var", + "section": "", + "text": "概要\nR言語の naniar::gg_miss_var() をオマージュした関数で、データフレームの各変数について欠測値の量を横棒グラフとして可視化します。欠損値統計の計算には py4stats.diagnose() を使用しています。", + "crumbs": [ + "**EDA**", + "16  plot_miss_var" + ] + }, + { + "objectID": "man/plot_miss_var.html#概要", + "href": "man/plot_miss_var.html#概要", + "title": "plot_miss_var", + "section": "", + "text": "plot_miss_var(\n data: IntoFrameT,\n values: Literal['missing_percent', 'missing_count'] = 'missing_percent', \n sort: bool = True, \n miss_only: bool = False, \n top_n: Optional[int] = None,\n fontsize: int = 12,\n ax: Optional[Axes] = None,\n color: str = '#478FCE',\n **kwargs: Any\n)", + "crumbs": [ + "**EDA**", + "16  plot_miss_var" + ] + }, + { + "objectID": "man/plot_miss_var.html#引数-argument", + "href": "man/plot_miss_var.html#引数-argument", + "title": "plot_miss_var", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\nnormalize:str  グラフに表示する値の種類。\n\nmissing_percent 列毎の欠測率をパーセンテージで表示します。\ncolumns 列毎の欠測数を表示します。\n\nsort:bool プロット前に選択した指標で列をソートするかどうか。初期設定は True です。。\nmiss_only:bool 欠測値を含まない列を除外するかどうか。True だと欠測値を含まない列を除外し、False(初期設定)だと省略せずに全ての列を表示します。\ntop_n:int 棒グラフを表示するグラフの個数。top_n = None(初期設定)の場合、すべての棒グラフを表示し、整数値が指定された場合、欠測率(数)の上位 top_n 件が表示されます。\nax  matplotlib の ax オブジェクト。複数のグラフを並べる場合などに使用します。\nfontsize:int  軸ラベルなどのフォントサイズ。\npalette:list of str  グラフの描画に使用する色コード。棒グラフの色に対応します。", + "crumbs": [ + "**EDA**", + "16  plot_miss_var" + ] + }, + { + "objectID": "man/plot_miss_var.html#使用例-example", + "href": "man/plot_miss_var.html#使用例-example", + "title": "plot_miss_var", + "section": "使用例 Example", + "text": "使用例 Example\nimport py4stats as py4st\nimport pandas as pd\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込\n\npy4st.plot_miss_var(penguins)\n\n\n\nplot_miss_var1\n\n\npy4st.plot_miss_var(penguins, values = 'missing_count', miss_only = True)\n\n\n\nplot_miss_var2\n\n\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "16  plot_miss_var" + ] + }, + { + "objectID": "man/set_miss.html", + "href": "man/set_miss.html", + "title": "set_miss", + "section": "", + "text": "概要\nSeries オブジェクトに対する欠測値の挿入\nこの関数は、Series の非欠測要素のうち、指定された個数または割合を欠測値に置き換えます。narwhals を利用することで、複数の Series バックエンドに対応しています。主にテストデータの作成や、欠測データのシミュレーションを目的とした関数です。", + "crumbs": [ + "**EDA**", + "17  set_miss" + ] + }, + { + "objectID": "man/set_miss.html#概要", + "href": "man/set_miss.html#概要", + "title": "set_miss", + "section": "", + "text": "set_miss(\n x: IntoSeriesT, \n n: Optional[int] = None,\n prop: Optional[float] = None, \n method: Literal['random', 'first', 'last'] = 'random', \n random_state: Optional[int] = None, \n na_value: Any = None,\n to_native: bool = True\n )", + "crumbs": [ + "**EDA**", + "17  set_miss" + ] + }, + { + "objectID": "man/set_miss.html#引数-argument", + "href": "man/set_miss.html#引数-argument", + "title": "set_miss", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須) 入力データ。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\nn:int 処理後の Series に含まれる欠測値の目標個数。すでに n 個以上の欠測値が含まれている場合は、新たな欠測値は追加されず、警告が発せられます。\nprop:float 処理後の Series に含まれる欠測値の目標割合。0 から 1 の間で指定してください。すでに欠測値の割合が prop 以上である場合は、新たな欠測値は追加されず、警告が発せられます。\nmethod: str: 欠測値に置き換える要素の選択方法。\n\n'random': 非欠測要素の中からランダムに選択します。\n'first': Series の先頭から選択します。\n'last': Series の末尾から選択します。 デフォルトは 'random' です。\n\nrandom_state (int, optional): method = 'random' の場合に使用する乱数シード。再現性のある結果を得るために指定できます。 method が 'random' 以外の場合、random_state は無視されます。\nna_value: (Any) 欠測値として使用する値。デフォルトは None です。\nto_native(bool, optional) True の場合、入力と同じ型の Series(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.Series を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "17  set_miss" + ] + }, + { + "objectID": "man/set_miss.html#使用例-example", + "href": "man/set_miss.html#使用例-example", + "title": "set_miss", + "section": "使用例 Example", + "text": "使用例 Example\nimport pandas as pd\nfrom py4stats import set_miss\ns = pd.Series([1, 2, 3, 4, 5])\npy4st.set_miss(s, n = 2, method='first')\n#> 0 NaN\n#> 1 NaN\n#> 2 3.0\n#> 3 4.0\n#> 4 5.0\n#> dtype: float64\n\ns_miss = py4st.set_miss(s, prop=0.4, method='random', random_state=0)\n#> 0 1.0\n#> 1 NaN\n#> 2 3.0\n#> 3 NaN\n#> 4 5.0\n#> dtype: float64\nx に代入された Series オブジェクトに、既に指定された以上の欠測値が含まれていた場合、次のように欠測値を追加せず UserWarning を出します。\npy4st.set_miss(s_miss, n = 2)\n#> UserWarning: Already contained 2(>= n) missing value(s) in `x`, \n#> no additional missing values were added.\n#> 0 1.0\n#> 1 NaN\n#> 2 3.0\n#> 3 NaN\n#> 4 5.0\n#> dtype: float64\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込\n\npenguins['island'] = py4st.set_miss(\n penguins['island'], \n n = 100, method='first'\n )\npy4st.plot_miss_var(penguins, values = 'missing_count')\n\n\n\nset_miss", + "crumbs": [ + "**EDA**", + "17  set_miss" + ] + }, + { + "objectID": "man/scale_wmean.html", + "href": "man/scale_wmean.html", + "title": "weighted_mean, scale, min_max", + "section": "", + "text": "概要\n加重平均と標準化・正規化ユーティリティ\n探索的データ解析(EDA)で頻繁に用いられる加重平均の計算および 数値データの正規化・標準化を行う関数群です。 内部では narwhals を利用することで、pandas・polars など複数のデータフレーム/シリーズ実装に対して共通の API を提供しています。\nweighted_mean(): 数値系列 x と対応する重み w を用いて、加重平均を計算します。欠損値の扱いを制御するためのオプションを備えています。\nscale(): 数値データを Z スコア標準化します。系列データを主な対象としますが、pandas.DataFrame に対しても専用実装により列単位での標準化をサポートしています。\nmin_max(): 数値データを Min-Max Normarization により \\([0, 1]\\) の範囲に変換します。scale() と同様に、Series を主対象としつつ pandas.DataFrame にも対応しています。", + "crumbs": [ + "**EDA**", + "18  weighted_mean, scale, min_max" + ] + }, + { + "objectID": "man/scale_wmean.html#概要", + "href": "man/scale_wmean.html#概要", + "title": "weighted_mean, scale, min_max", + "section": "", + "text": "weighted_mean(\n x: IntoSeriesT, \n w: IntoSeriesT, \n dropna:bool = False\n ) -> float:\n\nscale(\n x: Union[IntoSeriesT, pd.DataFrame], \n ddof: int = 1, to_native: bool = True\n ) -> IntoSeriesT:\n\nmin_max(\n x: Union[IntoSeriesT, pd.DataFrame], \n to_native: bool = True\n ) -> IntoSeriesT:", + "crumbs": [ + "**EDA**", + "18  weighted_mean, scale, min_max" + ] + }, + { + "objectID": "man/scale_wmean.html#引数-argument", + "href": "man/scale_wmean.html#引数-argument", + "title": "weighted_mean, scale, min_max", + "section": "引数 Argument", + "text": "引数 Argument\n\nx:IntoSeriesT or pd.DataFrame(必須)\n\nnarwhals が受け入れ可能な Series 互換オブジェクト(例:pandas.Series、polars.Series)を指定できます。scale()関数と min_max()関数のみ pandas.DataFrame を指定することができ、この場合、各列ごとに変換が適用されます。\n\nw:IntoSeriesT(必須) x に対応する重みを表す数値系列。x と同じ長さである必要があります。narwhals が受け入れ可能な Series 互換オブジェクト(例:pandas.Series、polars.Series)を指定できます。\nddof(int, optional)scale(), min_max() のみ 標準偏差の計算に用いる自由度調整量(delta degrees of freedom)。デフォルトは 1 です。\ndropna(bool, optional)scale(), min_max() のみ True の場合、x または w のいずれかが欠損値(NaN)である観測を計算前に除外します。デフォルトは False です。\nto_native(bool, optional)scale(), min_max() のみ True の場合、入力と同じ型の Series(e.g. pandas / polars / pyarrow)を返します。 False の場合、Series を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "18  weighted_mean, scale, min_max" + ] + }, + { + "objectID": "man/scale_wmean.html#返り値-value", + "href": "man/scale_wmean.html#返り値-value", + "title": "weighted_mean, scale, min_max", + "section": "返り値 Value", + "text": "返り値 Value\n\nweighted_mean\n\nfloat\n加重平均\n\nscale\n\nIntoSeriesT\n平均 0、標準偏差 1 に標準化された値を返します。\n\nmin_max\n\nIntoSeriesT\n最小値が 0、最大値が 1 となるよう正規化された値を返します。", + "crumbs": [ + "**EDA**", + "18  weighted_mean, scale, min_max" + ] + }, + { + "objectID": "man/scale_wmean.html#使用例-example", + "href": "man/scale_wmean.html#使用例-example", + "title": "weighted_mean, scale, min_max", + "section": "使用例 Example", + "text": "使用例 Example\nimport py4stats as py4st\nimport pandas as pd\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込\n\nx1 = penguins.groupby('species')['bill_length_mm'].mean()\nw = penguins.groupby('species')['bill_length_mm'].count()\n\nprint(\n f\"{py4st.weighted_mean(x1, w) :.2f}, \"\n f\"{penguins['bill_length_mm'].mean() :.2f}\"\n)\n#> 43.92, 43.92\n\nx2 = penguins['bill_length_mm']\nz1 = py4st.scale(x2)\nprint(f\"{z1.mean():.2f}, {z1.std():.2f}\")\n#> 0.00, 1.00\n\nz2 = py4st.min_max(x2)\nprint(f\"{z2.min():.2f}, {z2.max():.2f}\")\n#> 0.00, 1.00", + "crumbs": [ + "**EDA**", + "18  weighted_mean, scale, min_max" + ] + }, + { + "objectID": "man/predicate_str.html", + "href": "man/predicate_str.html", + "title": "is_number, is_ymd, is_ymd_like", + "section": "", + "text": "概要\n文字列のフォーマットに判定する論理関数\nSeries の要素が、特定のフォーマットにそった文字列かどうかを判定する関数です。", + "crumbs": [ + "**EDA**", + "19  is_number, is_ymd, is_ymd_like" + ] + }, + { + "objectID": "man/predicate_str.html#概要", + "href": "man/predicate_str.html#概要", + "title": "is_number, is_ymd, is_ymd_like", + "section": "", + "text": "is_number(\n data:IntoSeriesT, \n na_default:bool = True, \n to_native: bool = True\n )\n\nis_ymd(\n data:IntoSeriesT, \n na_default:bool = True, \n to_native: bool = True\n )\n\nis_ymd_like(\n data:IntoSeriesT, \n na_default:bool = True, \n to_native: bool = True\n )\n\npy4stats.is_number():与えられた文字列が数字かどうかを判定します。\npy4stats.is_ymd():与えられた文字列が yyyy-mm-dd フォーマットにそった値かどうかを判定します。\npy4stats.is_ymd_like():与えられた文字列が’2024年3月3日’ のような yyyy-mm-dd に近いフォーマットの値かどうかを判定します。", + "crumbs": [ + "**EDA**", + "19  is_number, is_ymd, is_ymd_like" + ] + }, + { + "objectID": "man/predicate_str.html#引数-argument", + "href": "man/predicate_str.html#引数-argument", + "title": "is_number, is_ymd, is_ymd_like", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoSeriesT(必須)\n入力データ。narwhals が受け入れ可能な Series 互換オブジェクト (例:pandas.Series、polars.DataFrame、pyarrow.Table)を指定できます。\nna_default:bool  NA値に対して関数が返す値。na_default = True (初期設定)であれば None や NaN には True を返し、na_default = False であれば False が返します。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。", + "crumbs": [ + "**EDA**", + "19  is_number, is_ymd, is_ymd_like" + ] + }, + { + "objectID": "man/predicate_str.html#使用例", + "href": "man/predicate_str.html#使用例", + "title": "is_number, is_ymd, is_ymd_like", + "section": "使用例", + "text": "使用例\nimport py4stats as py4st\nimport pandas as pd\nimport numpy as np\n\ns = pd.Series([\n '123', \"0.12\", \"1e+07\", '-31', '2個', '1A',\n \"2024-03-03\", \"2024年3月3日\", \"24年3月3日\", '令和6年3月3日',\n '0120-123-456', \"apple\", \"不明\", None, np.nan\n ])\n\nprint(s[py4st.is_number(s)])\n#> 0 123\n#> 1 0.12\n#> 2 1e+07\n#> 3 -31\n#> 13 None\n#> 14 NaN\n#> dtype: object\n\nprint(s[py4st.is_ymd(s)])\n#> 6 2024-03-03\n#> 13 None\n#> 14 NaN\n#> dtype: object\n\nprint(s[py4st.is_ymd_like(s)])\n#> 6 2024-03-03\n#> 7 2024年3月3日\n#> 8 24年3月3日\n#> 9 令和6年3月3日\n#> 13 None\n#> 14 NaN\n#> dtype: object\n 実践的な使用例として「厚生労働省 4.食中毒統計資料」のうち、2020年の食中毒事件一覧を考えます。東京都のデータを取り出て'摂食者数'の列を見ると、数字が並んでいるものの dtype は object となっており、数字ではない値が含まれていることが疑われます。\n# 厚生労働省:食中毒統計資料より\ndata = pd.read_excel('https://www.mhlw.go.jp/content/R2itiran.xlsx', header = 1)\\\n .query('都道府県名等.str.contains(\"東京\")')\n\nprint(data['摂食者数'])\n#> 280 41\n#> 281 86\n#> 282 3\n#> 283 10\n#> 284 3\n#> ..\n#> 381 2\n#> 382 2\n#> 383 4\n#> 384 6\n#> 385 4\n#> Name: 摂食者数, Length: 106, dtype: object\neda.is_number() を使うと数字以外にどのような値が含まれているかを確認できるため、これをもとに「不明」となっている部分は NaN に置き換えるなどの対処法が考えられます。\nprint(data.loc[~py4st.is_number(data['摂食者数']), '摂食者数'])\n#> 285 不明\n#> 315 不明\n#> 374 不明\n#> 375 不明\n#> 377 不明\n#> 378 不明\n#> 379 不明\n#> 380 不明\n#> Name: 摂食者数, dtype: object\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "19  is_number, is_ymd, is_ymd_like" + ] + }, + { + "objectID": "man/is_dummy.html", + "href": "man/is_dummy.html", + "title": "is_dummy", + "section": "", + "text": "概要\nダミー変数を判定する論理関数\nリストや Series の要素が、指定されたダミーコードのみで構成されたダミー変数かどうかを判定します。", + "crumbs": [ + "**EDA**", + "20  is_dummy" + ] + }, + { + "objectID": "man/is_dummy.html#概要", + "href": "man/is_dummy.html#概要", + "title": "is_dummy", + "section": "", + "text": "is_dummy(\n data: Union[IntoFrameT, IntoSeriesT],\n cording: Sequence[Any] = (0, 1),\n dropna: bool = True,\n to_pd_series: bool = False,\n **kwargs\n )", + "crumbs": [ + "**EDA**", + "20  is_dummy" + ] + }, + { + "objectID": "man/is_dummy.html#引数-argument", + "href": "man/is_dummy.html#引数-argument", + "title": "is_dummy", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata: list, IntoFrameT or IntoSeriesT 入力データ。list あるいは、narwhals が受け入れ可能な DataFrame もしくは Series 互換オブジェクト\ncording: list ダミーコードとして許容される値の集合。入力データに含まれる値の集合が、この集合と完全に一致する場合にダミー変数であると判定されます。デフォルトは (0, 1) です。\ndropna:bool  欠測値(NaN)をコーディングの判定から除外するかどうかを表すブール値。初期設定は True です。\nto_pd_series: bool data が DataFrame 場合の戻り値の形式を制御します。\n\nTrue の場合:列名をインデックスにもつ pandas.Series を返します\nFalse の場合:各列の判定結果を要素とする list を返します\n\n**kwargs: 将来の拡張のために予約されたキーワード引数です。", + "crumbs": [ + "**EDA**", + "20  is_dummy" + ] + }, + { + "objectID": "man/is_dummy.html#返り値-value", + "href": "man/is_dummy.html#返り値-value", + "title": "is_dummy", + "section": "返り値 Value", + "text": "返り値 Value\n\ndata が Series-like の場合\n\n-指定されたダミーコードのみで構成されていれば True、それ以外の場合は False\n\ndata が DataFrame-like の場合 \n\nto_pd_Series = False のとき:各列ごとの判定結果を要素とする list[bool]\nto_pd_Series = True のとき:列名をインデックスにもつ pd.Series", + "crumbs": [ + "**EDA**", + "20  is_dummy" + ] + }, + { + "objectID": "man/is_dummy.html#使用例-examples", + "href": "man/is_dummy.html#使用例-examples", + "title": "is_dummy", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport py4stats as py4st\nimport pandas as pd\nfrom palmerpenguins import load_penguins\n\npenguins = load_penguins() # サンプルデータの読み込み\n\n# ダミー変数の作成\npenguins2 = pd.get_dummies(\n penguins.loc[:, 'species':'bill_length_mm'], \n columns = ['species']\n )\npenguins2['Intercept'] = 1 # 定数列の作成\npenguins2['female'] = penguins['sex'] == 'female' # bool 型の変数を作成\n\nprint(py4st.is_dummy(penguins2['species_Adelie']))\n#> True\nなお、初期設定では bool 型の変数についても True が出力されます。\nprint(py4st.is_dummy(penguins2))\n#> island False\n#> bill_length_mm False\n#> species_Adelie True\n#> species_Chinstrap True\n#> species_Gentoo True\n#> Intercept False\n#> female True\n#> Name: 0, dtype: bool\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "20  is_dummy" + ] + }, + { + "objectID": "man/varidate.html", + "href": "man/varidate.html", + "title": "check_that check_viorate", + "section": "", + "text": "概要\n簡易なルールベースのデータ検証ツール\nR言語の varidateパッケージの check_that() 関数などをオマージュした、ごく簡易なデータ検証関数です。", + "crumbs": [ + "**EDA**", + "21  check_that check_viorate" + ] + }, + { + "objectID": "man/varidate.html#概要", + "href": "man/varidate.html#概要", + "title": "check_that check_viorate", + "section": "", + "text": "check_that(\n data: IntoFrameT,\n rule_dict: Union[Mapping[str, str], pd.Series],\n **kwargs: Any,\n)\n\ncheck_viorate(\n data: IntoFrameT,\n rule_dict: Union[Mapping[str, str], pd.Series],\n **kwargs: Any,\n)", + "crumbs": [ + "**EDA**", + "21  check_that check_viorate" + ] + }, + { + "objectID": "man/varidate.html#引数-argument", + "href": "man/varidate.html#引数-argument", + "title": "check_that check_viorate", + "section": "引数 Argument", + "text": "引数 Argument\n\ndata:IntoFrameT(必須)  ルールに基づくデータ検証を行うデータセット。narwhals が受け入れ可能な DataFrame 互換オブジェクト (例:pandas.DataFrame、polars.DataFrame、pyarrow.Table)を指定できます。\nrule_dictdict or pd.Series of str(必須)  pandas.eval() メソッドで実行した結果が論理値となるような expression の文字列を値とする辞書オブジェクト。詳細は使用例も参照してください。\nto_native(bool, optional) True の場合、入力と同じ型のデータフレーム(e.g. pandas / polars / pyarrow)を返します。 False の場合、narwhals.DataFrame を返します。デフォルトは True で、to_native = False は、主にライブラリ内部での利用や、backend に依存しない後続処理を行う場合を想定したオプションです。\n**kwargs  pandas.eval() に渡す追加の引数。", + "crumbs": [ + "**EDA**", + "21  check_that check_viorate" + ] + }, + { + "objectID": "man/varidate.html#返り値-value", + "href": "man/varidate.html#返り値-value", + "title": "check_that check_viorate", + "section": "返り値 Value", + "text": "返り値 Value\n\ncheck_that(): データセット単位の検証結果の集計\n次の列を含む、引数 data に代入されたデータフレームと同じ型の DataFrame が出力されます。\n\nrule: 検証ルールの名前\nitem: ルールが検証対象とした項目の数。レコード(行)を検証単位とするルールの場合、item は data の行数(rows)になります。一方、データセット全体を検証単位とするルール(例:集計量に基づく条件)の場合、item は 1 になります。\npasses: 検証の結果、ルールを満たすと判定されたレコードの数。\nfails: 検証の結果、ルールを満たさないと判定されたレコードの数。\ncountna: 欠測値によって、ルールの検証が行えなかったレコードの数。行(レコード)を検証単位とするルールでは、ルールの評価に使用された変数のいずれかに欠測値が含まれる場合、そのレコードは検証不能として NA 扱いされます。countna は、このように検証を正しく実施できなかったレコードの件数を表します。\nexpression: 検証ルールを表す文字列(expression)。\n\n\n\ncheck_viorate(): レコード単位の検証結果\nルール名を列名として、レコード毎の違反を示す論理変数をもつ DataFrame が出力されます。\n各列の要素の True は検証のルールへの違反、もしくは欠測値によって評価に失敗したことを表します。rule_dict で設定された各ルールに対応する列の他に、次の列が追加で出力されます。\n\nany: 行内のいずれかのルールが違反または評価に失敗した場合に True となるブール値。\nall: 行内の全ルールが違反または評価に失敗した場合に True となるブール値。", + "crumbs": [ + "**EDA**", + "21  check_that check_viorate" + ] + }, + { + "objectID": "man/varidate.html#使用例-examples", + "href": "man/varidate.html#使用例-examples", + "title": "check_that check_viorate", + "section": "使用例 Examples", + "text": "使用例 Examples\n ここでは py4st.check_that() 関数を使って Loo, Jonge(2022, p. 136)の結果を再現します。まずはR言語の validate パッケージに付属する retailers データを利用します。retailers は60件の小売業者の経営状況についてのデータで、従業員数、売上高とその他の収入、人件費、総費用、および利益がユーロ導入前の通貨単位である1000ギルダー単位で収録されています。\nimport py4stats as py4st\nimport pandas as pd\n\nURL = 'https://raw.githubusercontent.com/data-cleaning/validate/master/pkg/data/retailers.csv'\nretailers = pd.read_csv(URL, sep = ';')\nretailers.columns = retailers.columns.to_series().str.replace('.', '_', regex = False)\n py4st.check_that() 関数は、第1引数にデータセットを、第2引数に検証ルールの辞書オブジェクトを代入して使用します。\n まずは、検証ルールの辞書オブジェクトを定義します。辞書オブジェクトの値には pandas.eval() メソッドで実行可能な expression の文字列を指定し、key に検証ルールの名前を指定します。検証ルールの名前は任意の値で構いませんが、 expression は結果が論理値となるものでなければなりません。\nrule_dict = {\n 'to':'turnover > 0', # 売上高は厳密に正である\n 'sc':'staff_costs / staff < 50', # 従業員1人当たりの人件費は50,000ギルダー未満である\n 'cd1':'staff_costs > 0 | ~(staff > 0)', # 従業員がいる場合、人件費は厳密に正である\n 'cd2':py4st.implies_exper('staff > 0', 'staff_costs > 0'), # cd1 の別表現\n 'bs':'turnover + other_rev == total_rev', # 売上高とその他の収入の合計は総収入に等しい\n 'mn':'profit.mean() > 0' # セクター全体の平均的な利益はゼロよりも大きい\n }\npd.Series(rule_dict)\n#> to turnover > 0\n#> sc staff_costs / staff < 50\n#> cd1 staff_costs > 0 | ~(staff > 0)\n#> cd2 staff_costs > 0 | ~(staff > 0)\n#> bs turnover + other_rev == total_rev\n#> mn profit.mean() > 0\n#> dtype: object\nretailers と rule_dict を py4st.check_that() に代入すると、rule_dict に指定したルールに基づいた検証が実行されます。item 列はその検証ルールで生成された論理値の個数(通常はデータセットの列数と一致します)を表し、passes 列は検証結果が True となったレコードの数を、fails は False となったレコードの数を表します。また、coutna はルールの検証に使用した変数(データセットの列)のいずれかが欠測値であったレコードの数です。\nprint(py4st.check_that(retailers, rule_dict))\n#> rule item passes fails coutna expression\n#> 0 to 60 56 0 4 turnover > 0\n#> 1 sc 60 39 5 16 staff_costs / staff < 50\n#> 2 cd1 60 44 0 16 staff_costs > 0 | ~(staff > 0)\n#> 3 cd2 60 44 0 16 staff_costs > 0 | ~(staff > 0)\n#> 4 bs 60 19 4 37 turnover + other_rev == total_rev\n#> 5 mn 1 1 0 0 profit.mean() > 0\n前述の通り、py4st.check_that() 関数ではルール検証を pandas.eval() メソッドで実行しているため、検証ルールに自作関数や外部のモジュールからインポート関数を使うには、関数名の前に @ をつけて @func(…) と記述し、また **kwargs 引数に local_dict = locals() と指定してください。\n 次のコードで定義している is_complete() 関数は、代入された pd.Series が全て欠測値ではなく、指定された変数に関して完全ケースであることを判定する関数です。turnover.notna() & total_rev.notna() & other_rev.notna() と記述しても同じ結果が得られますが、自作関数を使うことで若干簡潔に記述できます。\nfrom pandas.api.types import is_numeric_dtype\ndef is_complete(*arg): return pd.concat(arg, axis = 'columns').notna().all(axis = 'columns')\n\npd.set_option('display.expand_frame_repr', False)\n\nrule_dict2 = {\n 'to_num':'@is_numeric_dtype(turnover)', # 売上高は数値変数である\n 'rev_complete':'@is_complete(turnover, total_rev, other_rev)', # 売上高と収入が全て観測されている\n }\n\nprint(py4st.check_that(\n retailers, rule_dict2, local_dict = locals()\n ))\n#> rule item passes fails coutna expression\n#> 0 to_num 1 1 0 0 @is_numeric_dtype(turnover)\n#> 1 rev_complete 60 23 0 37 @is_complete(turnover, total_rev, other_rev)\npy4st.check_viorate() の使い方も py4st.check_that() と同様ですが、py4st.check_that() がデータセット全体での検証結果を出力するのに対し、py4st.check_viorate() ではレコード別の検証結果を表示します。py4st.check_viorate() から出力されるデータフレームでは、各列が検証ルールに、各行が元データの観測値に対応し、当該ルールが満たされていない場合、True と表示されます。また、any 列は複数あるルールのいずれか1つでも満たされていないことを、all 列は全てのルールが満たされていないことを示します。\nrule_dict3 = {\n 'to':'turnover > 0', # 売上高は厳密に正である\n 'sc':'staff_costs / staff < 50', # 従業員1人当たりの人件費は50,000ギルダー未満である\n 'rev_complete':'@is_complete(turnover, total_rev, other_rev)',# 売上高と収入が全て観測されている\n }\n \ndf_viorate = py4st.check_viorate(retailers, rule_dict3)\nprint(df_viorate.head())\n#> to sc rev_complete any all\n#> 0 True True True True True\n#> 1 False False True True False\n#> 2 False True False True False\n#> 3 False True False True False\n#> 4 True True True True True\ndf_viorate データフレームの各列は論理値であるため、次のように検証ルールを満たさない観測値を抽出することができます。\nprint(retailers.loc[df_viorate['to'], 'size':'turnover'])\n#> size incl_prob staff turnover\n#> 0 sc0 0.02 75.0 NaN\n#> 4 sc3 0.14 NaN NaN\n#> 6 sc3 0.14 5.0 NaN", + "crumbs": [ + "**EDA**", + "21  check_that check_viorate" + ] + }, + { + "objectID": "man/varidate.html#notes", + "href": "man/varidate.html#notes", + "title": "check_that check_viorate", + "section": "Notes", + "text": "Notes\n本関数の内部実装は、 pd.DataFrame.eval() メソッドに依存しているため、実行時間の面で必ずしも最適化されていません。", + "crumbs": [ + "**EDA**", + "21  check_that check_viorate" + ] + }, + { + "objectID": "man/varidate.html#参考文献", + "href": "man/varidate.html#参考文献", + "title": "check_that check_viorate", + "section": "参考文献", + "text": "参考文献\n\nLoo, Mark van der, and Edwin de Jonge. (2022). 『統計的データクリーニングの理論と実践: Rによるデータ編集/欠測補完システム』. 共立出版. 地道 正行, 髙橋 雅夫, 藤野 友和, 安川 武彦〔訳〕\n\n\nReturn to Function reference.", + "crumbs": [ + "**EDA**", + "21  check_that check_viorate" + ] + }, + { + "objectID": "man/compare_ols.html", + "href": "man/compare_ols.html", + "title": "compare_ols", + "section": "", + "text": "概要\n回帰係数の比較\nsm.ols() や smf.glm() で作成された回帰分析の結果から、推定結果を縦方向に並べて比較する表を作成します。表のフォーマットについてはR言語の texreg::screenreg()やmodelsummary::modelsummary()を参考にしています。", + "crumbs": [ + "**Regression**", + "22  compare_ols" + ] + }, + { + "objectID": "man/compare_ols.html#概要", + "href": "man/compare_ols.html#概要", + "title": "compare_ols", + "section": "", + "text": "compare_ols(\n list_models: Sequence[RegressionResultsWrapper],\n model_name: Optional[Sequence[str]] = None,\n subset: Optional[Sequence[str]] = None,\n stats: Literal[\"std_err\", \"statistics\", \"p_value\", \"conf_int\"] = \"std_err\",\n add_stars: bool = True,\n stars: Optional[Mapping[str, float]] = None,\n stats_glance: Optional[Sequence[str]] = (\"rsquared_adj\", \"nobs\", \"df\"),\n digits: int = 4,\n table_style: Literal[\"two_line\", \"one_line\"] = \"two_line\",\n line_break: str = \"\\n\",\n **kwargs: Any\n)", + "crumbs": [ + "**Regression**", + "22  compare_ols" + ] + }, + { + "objectID": "man/compare_ols.html#引数-argument", + "href": "man/compare_ols.html#引数-argument", + "title": "compare_ols", + "section": "引数 Argument", + "text": "引数 Argument\n\nlist_models:Sequence[RegressionResultsWrapper] 推定結果を表示する分析結果のリスト(必須)。sm.ols() や smf.ols() で作成された回帰分析の結果を list_models = [fit1, fit2] のようにリストとして指定してください。\nmodel_name:list of str 表頭に表示するモデルの名前。['モデル1', 'モデル2'] のように文字列のリストを指定してください。初期設定では、自動的に model 1, model 2, model 3 … と連番が割り当てられます。\nsubset:list of str 表示する回帰係数のリスト。指定しない場合(初期設定)、モデルに含まれる全ての回帰係数が表示されます。内部ではpandas.DataFrame.locメソッドを用いて処理を行っているため、['変数1', '変数2', ...] のような文字列のリスト、[True, False, True, ...] のようなブール値のリストに対応しています。文字列のリストが指定された場合、リストの並び順に合わせて回帰係数が表示されます。\nstats:str 表中の丸括弧 ( ) 内に表示する統計値の設定。次の値が指定できます。\n\n'std_err' 標準誤差(初期設定)\n'p_value' p-値\n'statistics' t統計量\n\nadd_stars:bool 回帰係数の統計的有意性を表すアスタリスク * を表示するかどうかを表すブール値。add_stars = True(初期-設定)なら表示、add_stars = Falseなら非表示となります。table_style に 'two_line' を指定した場合はアスタリスクは回帰係数の直後に表示され、'one_line' を指定した場合は stats で指定した統計値の後に表示されます。アスタリスクはp-値の値に応じて次のように表示されます。\nstars:dict(p_stars() のみ)  有意性を示す記号を key に、表示を切り替える閾値を値(value)にもつ辞書オブジェクト。初期設定の stars = None の場合、下記の方式で表示されます。\n\np ≤ 0.1 *\np ≤ 0.05 **\np ≤ 0.01 ***\np > 0.1 表示なし 詳細はbuilding_block.style_pvalue() を参照してください。\n\nstats_glance:list of str\n表の下部に追加する当てはまりの尺度の種類を表す文字列のリスト。リストの値には次の値を指定できます。なお、None もしくは空のリスト [ ] が指定された場合には非表示となります。\n\n'rsquared':決定係数\n'rsquared_adj':自由度調整済み決定係数\n'nobs':サインプルサイズ\n'df':モデルの自由度(説明変数の数)\n'sigma':回帰式の標準誤差\n'F_values':全ての回帰係数がゼロであることを帰無仮説とするF検定の統計量\n'p_values':F検定のP-値\n'AIC':赤池情報量基準\n'BIC':ベイズ情報量基準\n\ndigits: int 回帰係数と統計値について表示する小数点以下の桁数。初期設定は4です。\ntable_style: str 表の書式を表す文字列。次の値から選択できます(部分一致可)。\n\n'two_line'回帰係数と統計値を2行に分ける(初期設定)\n'one_line'回帰係数と統計値を1行で表示する\n\nline_break: str table_style = 'two_line' とした場合に使用される改行記号。table_style = 'one_line' とした場合、この引数は無視されます。", + "crumbs": [ + "**Regression**", + "22  compare_ols" + ] + }, + { + "objectID": "man/compare_ols.html#使用例-examples", + "href": "man/compare_ols.html#使用例-examples", + "title": "compare_ols", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport py4stats as py4st\nimport statsmodels.formula.api as smf\n\nimport pandas as pd\nimport numpy as np\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込み\n\n# 回帰分析の実行\nfit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()\nfit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit()\nfit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()\n\ncompare_tab1 = py4st.compare_ols(list_models = [fit1, fit2, fit3]) # 表の作成\ncompare_tab1\n\n\n\n\n\n\n\n\n\nterm\nmodel 1\nmodel 2\nmodel 3\n\n\n\n\nIntercept\n153.7397\n-1,742.7202 ***\n843.9812 **\n\n\n\n(268.9012)\n(313.7697)\n(403.5956)\n\n\nspecies[T.Chinstrap]\n-885.8121 ***\n-539.6864 ***\n-245.1516 ***\n\n\n\n(88.2502)\n(86.9425)\n(84.5952)\n\n\nspecies[T.Gentoo]\n578.6292 ***\n1,492.8283 ***\n1,443.3525 ***\n\n\n\n(75.3623)\n(118.4442)\n(107.7844)\n\n\nbill_length_mm\n91.4358 ***\n55.6461 ***\n26.5366 ***\n\n\n\n(6.8871)\n(7.2326)\n(7.2436)\n\n\nbill_depth_mm\n\n179.0434 ***\n87.9328 ***\n\n\n\n\n(19.0997)\n(20.2192)\n\n\nsex[T.male]\n\n\n437.2007 ***\n\n\n\n\n\n(49.1098)\n\n\nrsquared_adj\n0.7810\n0.8258\n0.8613\n\n\nnobs\n342\n342\n333\n\n\ndf\n3\n4\n5\n\n\n\npy4st.compare_ols() の実行結果は Pandas の DataFrame として出力されるため、.xlsx. ファイルなどに変換することができます。また、用途に応じて表の体裁を調整できるようにしています。\ncompare_tab2 = py4st.compare_ols(\n list_models = [fit1, fit2, fit3],\n model_name = ['基本モデル', '嘴の高さ追加', '性別追加'], # モデル名を変更\n stats = 'p_value', # () 内の値をP-値に変更する\n add_stars = False, # 有意性のアスタリスクなし\n table_style = 'one_line', # 表スタイルを1行表示に設定 'one' でも可能\n digits = 3 # 小数点以下の桁数を3に設定\n )\ncompare_tab2\n\n\n\n\n\n\n\n\n\nterm\n基本モデル\n嘴の高さ追加\n性別追加\n\n\n\n\nIntercept\n153.740(0.568)\n-1,742.720(0.000)\n843.981(0.037)\n\n\nspecies[T.Chinstrap]\n-885.812(0.000)\n-539.686(0.000)\n-245.152(0.004)\n\n\nspecies[T.Gentoo]\n578.629(0.000)\n1,492.828(0.000)\n1,443.353(0.000)\n\n\nbill_length_mm\n91.436(0.000)\n55.646(0.000)\n26.537(0.000)\n\n\nbill_depth_mm\n\n179.043(0.000)\n87.933(0.000)\n\n\nsex[T.male]\n\n\n437.201(0.000)\n\n\nrsquared_adj\n0.781\n0.826\n0.861\n\n\nnobs\n342\n342\n333\n\n\ndf\n3\n4\n5\n\n\n\ntable_style = 'two_line' のときに使用される改行記号は line_break で指定できます。great_tables モジュールの GT() 関数と併用する場合など、html 形式で出力する場合には line_break = '<br>' を指定します。\nfrom great_tables import GT, md, html\n\ncompare_tab3 = py4st.compare_ols(\n list_models = [fit1, fit2, fit3],\n model_name = ['基本モデル', '嘴の高さ追加', '性別追加'], # モデル名を変更\n line_break = '<br>' # 改行文字の変更\n )\n\nGT(compare_tab3.reset_index())\\\n .tab_header(title = 'Palmer penguin データを使った回帰分析の結果')\\\n .tab_source_note(\n source_note= \"Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’\"\n )\\\n .tab_source_note(source_note = '( ) の値は標準誤差')\n\n\n有意性の表示規則の変更\npy4stats の v0.2.0 以降は、stars 引数で有意性の表示規則を変更できるようになりました。\nstars_dict = {'★★★':0.001, '★★':0.01, '★': 0.05, '.':0.1}\n\nreg.compare_ols(\n list_models = [fit3],\n model_name = ['model 3'],\n stars = stars_dict\n )\n\n\n\nterm\nmodel 3\n\n\n\n\nIntercept\n843.9812 ★\n\n\n\n(403.5956)\n\n\nspecies[T.Chinstrap]\n-245.1516 ★★\n\n\n\n(84.5952)\n\n\nspecies[T.Gentoo]\n1,443.3525 ★★★\n\n\n\n(107.7844)\n\n\nsex[T.male]\n437.2007 ★★★\n\n\n\n(49.1098)\n\n\nbill_length_mm\n26.5366 ★★★\n\n\n\n(7.2436)\n\n\nbill_depth_mm\n87.9328 ★★★\n\n\n\n(20.2192)\n\n\nrsquared_adj\n0.8613\n\n\nnobs\n333\n\n\ndf\n5\n\n\n\n\n\n回帰係数の sbusetting\n引数 subset を使って表示したい回帰係数を指定することで、一部の回帰係数を省略して表記することもできます。\n# 説明変数に island を追加したモデルを推定\nfit4 = smf.ols(\n 'body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex + island',\n data = penguins).fit()\n\nvar_list = [\n 'species[T.Chinstrap]', 'species[T.Gentoo]',\n 'bill_length_mm', 'bill_depth_mm', 'sex[T.male]'\n ]\n\n# 全ての回帰係数を表示すると表が長すぎるので、一部を省略します\ncompare_tab4 = py4st.compare_ols(\n list_models = [fit2, fit3, fit4],\n subset = var_list\n )\n\ncompare_tab4.loc['島ダミー', :] = ['No', 'No', 'Yes']\n\ncompare_tab4\n\n\n\n\n\n\n\n\n\nterm\nmodel 1\nmodel 2\nmodel 3\n\n\n\n\nspecies[T.Chinstrap]\n-539.6864 ***\n-245.1516 ***\n-255.2732 ***\n\n\n\n(86.9425)\n(84.5952)\n(92.4796)\n\n\nspecies[T.Gentoo]\n1,492.8283 ***\n1,443.3525 ***\n1,446.1574 ***\n\n\n\n(118.4442)\n(107.7844)\n(114.1676)\n\n\nbill_length_mm\n55.6461 ***\n26.5366 ***\n26.6643 ***\n\n\n\n(7.2326)\n(7.2436)\n(7.2792)\n\n\nbill_depth_mm\n179.0434 ***\n87.9328 ***\n88.3284 ***\n\n\n\n(19.0997)\n(20.2192)\n(20.3267)\n\n\nsex[T.male]\n\n437.2007 ***\n436.0334 ***\n\n\n\n\n(49.1098)\n(49.4227)\n\n\nrsquared_adj\n0.8258\n0.8613\n0.8605\n\n\nnobs\n342\n333\n333\n\n\ndf\n4\n5\n7\n\n\n島ダミー\nNo\nNo\nYes\n\n\n\npandas の pandas.DataFrame.query メソッドを使って、次のように説明変数を除外することもできます。\ncompare_tab4 = py4st.compare_ols(\n list_models = [fit2, fit3, fit4]\n )\n\ncompare_tab4 = compare_tab4\\\n .query('~term.str.contains(\"Intercept|island\")').copy()\n\ncompare_tab4.loc['島ダミー', :] = ['No', 'No', 'Yes']\n\ncompare_tab4 # 上記のコードと同じ結果", + "crumbs": [ + "**Regression**", + "22  compare_ols" + ] + }, + { + "objectID": "man/compare_ols.html#補足", + "href": "man/compare_ols.html#補足", + "title": "compare_ols", + "section": "補足", + "text": "補足\n  table_style = 'two_line' としたとき、初期設定ではの回帰係数とp-値の間に改行記号 '\\n'が挿入されます。そのため、print() 関数や display() 関数を使った出力では、改行記号 '\\n' がそのまま表示されます。この場合でも、pd.DataFrame.to_excel() や pd.DataFrame.to_markdown() を使って Excel ファイルや markdown の表に変換していただくと、改行として反映されます。", + "crumbs": [ + "**Regression**", + "22  compare_ols" + ] + }, + { + "objectID": "man/compare_ols.html#参照-see-also", + "href": "man/compare_ols.html#参照-see-also", + "title": "compare_ols", + "section": "参照 see also", + "text": "参照 see also\n 一般化線形モデルの限界効果を比較する場合は py4stats.compare_mfx()をご利用ください。\n\nReturn to Function reference.", + "crumbs": [ + "**Regression**", + "22  compare_ols" + ] + }, + { + "objectID": "man/compare_mfx.html", + "href": "man/compare_mfx.html", + "title": "compare_mfx", + "section": "", + "text": "概要\n限界効果の比較\nsm.glm()の推定結果を計量経済学の実証論文でよく用いられる、回帰分析の結果を縦方向に並べて比較する表を作成します。表のフォーマットについてはR言語の texreg::screenreg()やmodelsummary::modelsummary()を参考にしています。", + "crumbs": [ + "**Regression**", + "23  compare_mfx" + ] + }, + { + "objectID": "man/compare_mfx.html#概要", + "href": "man/compare_mfx.html#概要", + "title": "compare_mfx", + "section": "", + "text": "compare_mfx(\n list_models, \n model_name = None,\n subset = None,\n stats = 'std_err',\n add_stars = True,\n stats_glance = ['prsquared', 'nobs', 'df'],\n at = 'overall',\n method = 'dydx',\n dummy = False,\n digits = 4, \n table_style = 'two_line',\n line_break = '\\n',\n **kwargs\n)", + "crumbs": [ + "**Regression**", + "23  compare_mfx" + ] + }, + { + "objectID": "man/compare_mfx.html#引数-argument", + "href": "man/compare_mfx.html#引数-argument", + "title": "compare_mfx", + "section": "引数 Argument", + "text": "引数 Argument\n\nlist_models: 推定結果を表示する分析結果のリスト(必須)。sm.glm()で作成された一般化線形モデルの結果を list_models = [fit1, fit2] のようにリストとして指定してください。\nmodel_name:list of str 表頭に表示するモデルの名前。['モデル1', 'モデル2'] のように文字列のリストを指定してください。初期設定では、自動的に model 1, model 2, model 3 … と連番が割り当てられます。\nsubset:list of str 表示する回帰係数のリスト。指定しない場合(初期設定)、モデルに含まれる全ての回帰係数が表示されます。内部ではpandas.DataFrame.locメソッドを用いて処理を行っているため、['変数1', '変数2', ...] のような文字列のリスト、[True, False, True, ...] のようなブール値のリストに対応しています。文字列のリストが指定された場合、リストの並び順に合わせて回帰係数が表示されます。\nstats:str 表中の丸括弧 ( ) 内に表示する統計値の設定。次の値が指定できます。\n\n'std_err' 標準誤差(初期設定)\n'p_value' p-値\n'statistics' t統計量\n\nadd_stars:bool 回帰係数の統計的有意性を表すアスタリスク * を表示するかどうかを表すブール値。add_stars = True(初期-設定)なら表示、add_stars = Falseなら非表示となります。table_style に 'two_line' を指定した場合はアスタリスクは回帰係数の直後に表示され、'one_line' を指定した場合は stats で指定した統計値の後に表示されます。アスタリスクはp-値の値に応じて次のように表示されます。\nstars:dict(p_stars() のみ)  有意性を示す記号を key に、表示を切り替える閾値を値(value)にもつ辞書オブジェクト。初期設定の stars = None の場合、下記の方式で表示されます。\n\np ≤ 0.1 *\np ≤ 0.05 **\np ≤ 0.01 ***\np > 0.1 表示なし 詳細はbuilding_block.style_pvalue() を参照してください。\n\nstats_glance:list of str\n表の下部に追加する当てはまりの尺度の種類を表す文字列のリスト。リストの値には次の値を指定できます。なお、None もしくは空のリスト [ ] が指定された場合には非表示となります。\n\n'rsquared':決定係数\n'rsquared_adj':自由度調整済み決定係数\n'nobs':サインプルサイズ\n'df':モデルの自由度(説明変数の数)\n'sigma':回帰式の標準誤差\n'F_values':全ての回帰係数がゼロであることを帰無仮説とするF検定の統計量\n'p_values':F検定のP-値\n'AIC':赤池情報量基準\n'BIC':ベイズ情報量基準\n\ndigits: int 回帰係数と統計値について表示する小数点以下の桁数。初期設定は4です。\ntable_style: str 表の書式を表す文字列。次の値から選択できます(部分一致可)。\n\n'two_line'回帰係数と統計値を2行に分ける(初期設定)\n'one_line'回帰係数と統計値を1行で表示する\n\nline_break: str table_style = 'two_line' とした場合に使用される改行記号。table_style = 'one_line' とした場合、この引数は無視されます。\nat: str 限界効果の集計方法。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 at として渡されます。method = 'coef' を指定した場合、この引数は無視されます。\n\n'overall':各観測値の限界効果の平均値を表示(初期設定)\n'mean':各説明変数の平均値における限界効果を表示\n'median':各説明変数の中央値における限界効果を表示\n'zero':各説明変数の値がゼロであるときの限界効果を表示\n\nmethod: str 推定する限界効果の種類。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 method として渡されます。ただし、method = 'coef' を指定した場合には限界効果を推定せずに回帰係数をそのまま表示します。\n\n'coef':回帰係数の推定値を表示\n'dydx':限界効果の値を変換なしでそのまま表。(初期設定)\n'eyex':弾力性 d(lny)/d(lnx) の推定値を表示\n'dyex':準弾力性 dy /d(lnx) の推定値を表示\n'eydx':準弾力性 d(lny)/dx の推定値を表示\n\ndummy: bool ダミー変数の限界効果の推定方法を制御するブール値。もし False (初期設定)であれば、ダミー変数を連続な数値変数として扱います。もし、True であればダミー変数が0から1へと変化したときの予測値の変化を推定します。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 dummy として渡されます。", + "crumbs": [ + "**Regression**", + "23  compare_mfx" + ] + }, + { + "objectID": "man/compare_mfx.html#使用例", + "href": "man/compare_mfx.html#使用例", + "title": "compare_mfx", + "section": "使用例", + "text": "使用例\nimport py4stats as py4st\nimport statsmodels.formula.api as smf\n\nimport pandas as pd\nimport numpy as np\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込み\n py4st.compare_mfx() は py4st.compare_ols() の一般化線型モデルバージョンで、初期設定では statsmodels ライブラリの.get_margeff() メソッドから得られた限界効果の推定値を表示します。\npenguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)\n\n# ロジスティック回帰の実行\nfit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()\nfit_logit2 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm + species', data = penguins).fit()\n\npy4st.compare_mfx([fit_logit1, fit_logit2])\n\n\n\nterm\nmodel 1\nmodel 2\n\n\n\n\nbody_mass_g\n-0.0004 ***\n-0.0003 ***\n\n\n\n(0.0000)\n(0.0000)\n\n\nbill_length_mm\n-0.0053\n-0.0357 ***\n\n\n\n(0.0036)\n(0.0070)\n\n\nbill_depth_mm\n-0.1490 ***\n-0.1098 ***\n\n\n\n(0.0051)\n(0.0175)\n\n\nspecies[T.Chinstrap]\n\n0.4172 ***\n\n\n\n\n(0.0848)\n\n\nspecies[T.Gentoo]\n\n0.3527 ***\n\n\n\n\n(0.1308)\n\n\nprsquared\n0.5647\n0.6187\n\n\nnobs\n342\n342\n\n\ndf\n3\n5\n\n\n\nfrom great_tables import GT, md, html\ncompare_tab = py4st.compare_mfx(\n [fit_logit1, fit_logit2],\n model_name = ['ベースモデル', 'species 追加'], # モデル名を変更\n line_break = '<br>' # 改行文字の変更\n)\n\nGT(compare_tab.reset_index())\\\n .tab_header(title = 'ロジットモデルの限界効果')\\\n .tab_source_note(\n source_note= \"Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’\"\n )\\\n .tab_source_note(source_note = '丸括弧 ( ) の値は標準誤差')", + "crumbs": [ + "**Regression**", + "23  compare_mfx" + ] + }, + { + "objectID": "man/compare_mfx.html#補足", + "href": "man/compare_mfx.html#補足", + "title": "compare_mfx", + "section": "補足", + "text": "補足\n  table_style = 'two_line' としたとき、初期設定ではの回帰係数とp-値の間に改行記号 '\\n'が挿入されます。そのため、print() 関数や display() 関数を使った出力では、改行記号 '\\n' がそのまま表示されます。この場合でも、pd.DataFrame.to_excel() や pd.DataFrame.to_markdown() を使って Excel ファイルや markdown の表に変換していただくと、改行として反映されます。\n\nReturn to Function reference.", + "crumbs": [ + "**Regression**", + "23  compare_mfx" + ] + }, + { + "objectID": "man/coefplot.html", + "href": "man/coefplot.html", + "title": "coefplot, mfxplot", + "section": "", + "text": "概要\n回帰分析による推定値の視覚化\nグラフ上の縦軸が説明変数、横軸回帰係数の値です。点が回帰係数の推定値を、エラーバー(横棒)が信頼区間を表します。", + "crumbs": [ + "**Regression**", + "24  coefplot, mfxplot" + ] + }, + { + "objectID": "man/coefplot.html#概要", + "href": "man/coefplot.html#概要", + "title": "coefplot, mfxplot", + "section": "", + "text": "coefplot(\n mod, \n subset = None, \n conf_level = [0.95, 0.99], \n palette = ['#1b69af', '#629CE7'], \n show_Intercept = False,\n show_vline = True,\n ax = None,\n **kwargs\n)\n\nmfxplot(\n mod, \n subset = None, \n conf_level = [0.95, 0.99], \n at = 'overall',\n method = 'dydx',\n dummy = False,\n palette = ['#1b69af', '#629CE7'], \n show_Intercept = False,\n show_vline = True,\n ax = None,\n **kwargs\n)", + "crumbs": [ + "**Regression**", + "24  coefplot, mfxplot" + ] + }, + { + "objectID": "man/coefplot.html#引数-argument", + "href": "man/coefplot.html#引数-argument", + "title": "coefplot, mfxplot", + "section": "引数 Argument", + "text": "引数 Argument\n\nmod:statsmodels で作成した回帰分析の結果(必須)。\nsubset:グラフに回帰係数を表示する説明変数のリスト。指定しなければモデルに含まれる全ての説明変数を使用します。また subset に指定された順番に合わせてグラフ内での回帰係数の並び順が変更されます。\nconf.level:信頼区間の計算に用いる信頼係数。1つ目の要素が太い方のエラーバーの幅に、2つ目の要素が細い方のエラーバーの幅に対応します。初期設定は [0.95, 0.99] です。\npalette:グラフの描画に使用する色コード。1つ目の要素が太い方のエラーバーの色に、2つ目の要素が細い方のエラーバーの色に対応します。\nshow_Intercept:切片の係数を表示するかどうか。True だと切片の係数を表示し、False(初期設定)だと表示しません。\nshow_vline:回帰係数 = 0 の垂直線を表示するかどうか。True (初期設定)を指定すると垂直線を表示し、False を指定すると表示されません。\nax:matplotlib の ax オブジェクト。複数のグラフを並べる場合などに使用します。\nat:限界効果の集計方法(mfxplot() のみ)。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 at として渡されます。method = 'coef' を指定した場合、この引数は無視されます。\n\n'overall':各観測値の限界効果の平均値を表示(初期設定)\n'mean':各説明変数の平均値における限界効果を表示\n'median':各説明変数の中央値における限界効果を表示\n'zero':各説明変数の値がゼロであるときの限界効果を表示\n\nmethod:推定する限界効果の種類(mfxplot() のみ)。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 method として渡されます。ただし、method = 'coef' を指定した場合には限界効果を推定せずに回帰係数をそのまま表示します。\n\n'coef':回帰係数の推定値を表示\n'dydx':限界効果の値を変換なしでそのまま表。(初期設定)\n'eyex':弾力性 d(lny)/d(lnx) の推定値を表示\n'dyex':準弾力性 dy /d(lnx) の推定値を表示\n'eydx':準弾力性 d(lny)/dx の推定値を表示\n\ndummy:ダミー変数の限界効果の推定方法(mfxplot() のみ)。もし False (初期設定)であれば、ダミー変数を連続な数値変数として扱います。もし、True であればダミー変数が0から1へと変化したときの予測値の変化を推定します。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 dummy として渡されます。", + "crumbs": [ + "**Regression**", + "24  coefplot, mfxplot" + ] + }, + { + "objectID": "man/coefplot.html#使用例", + "href": "man/coefplot.html#使用例", + "title": "coefplot, mfxplot", + "section": "使用例", + "text": "使用例\nimport py4stats as py4st\nimport statsmodels.formula.api as smf\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込み\n\n\n# 回帰分析の実行\nfit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit()\nfit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()\n\npy4st.coefplot(fit3)\n\n\n\ncoefplot1\n\n\nplt.rcParams[\"figure.autolayout\"] = True\n\nfig, ax = plt.subplots(1, 2, figsize = (2.2 * 5, 5), dpi = 100)\n\npy4st.coefplot(fit2, ax = ax[0])\nax[0].set_xlim(-900, 1800)\n\npy4st.coefplot(fit3, ax = ax[1], palette = ['#FF6F91', '#F2E5EB'])\nax[1].set_xlim(-900, 1800);\n\n\n\ncoefplot2\n\n\npenguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)\n\n# ロジスティック回帰の実行\nfit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()\nfit_logit2 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm + species', data = penguins).fit()\nplt.rcParams[\"figure.autolayout\"] = True\n\nfig, ax = plt.subplots(1, 2, figsize = (2.2 * 5, 5), dpi = 100)\n\npy4st.mfxplot(fit_logit1, ax = ax[0])\nax[0].set_xlim(-0.2, 0.85)\n\npy4st.mfxplot(fit_logit2, ax = ax[1], palette = ['#FF6F91', '#F2E5EB'])\nax[1].set_xlim(-0.2, 0.85);\n *** Return to Function reference.", + "crumbs": [ + "**Regression**", + "24  coefplot, mfxplot" + ] + }, + { + "objectID": "man/tidy.html", + "href": "man/tidy.html", + "title": "tidy, tidy_mfx", + "section": "", + "text": "概要\n線形モデルの推定結果を DataFrame に集約\nR言語の broom::tidy() をオマージュした関数で、sm.ols() や smf.logit() などの推定結果を pands.DataFrame に変換します。py4stats.tidy() は回帰係数と関連する検定結果を表示し、 py4stats.tidy_mfx() は限界効果と関連する検定結果を表示します。", + "crumbs": [ + "**Regression**", + "25  tidy, tidy_mfx" + ] + }, + { + "objectID": "man/tidy.html#概要", + "href": "man/tidy.html#概要", + "title": "tidy, tidy_mfx", + "section": "", + "text": "tidy(\n x, \n name_of_term = None,\n conf_level = 0.95,\n **kwargs\n )\n\ntidy_mfx(\n x, \n at = 'overall', \n method = 'dydx', \n dummy = False, \n conf_level = 0.95, \n **kwargs\n )", + "crumbs": [ + "**Regression**", + "25  tidy, tidy_mfx" + ] + }, + { + "objectID": "man/tidy.html#引数-argument", + "href": "man/tidy.html#引数-argument", + "title": "tidy, tidy_mfx", + "section": "引数 Argument", + "text": "引数 Argument\n\nx(必須)  sm.ols()もしくは smf.logit() などで作成された分析結果のオブジェクト。\nname_of_term:list of str  term 列(index) として表示する説明変数の名前のリスト。指定しない場合(初期設定)、モデルの推定に使用された説明変数の名前がそのまま表示されます。\nconf_level:float  信頼区間の計算に用いる信頼係数。\nat:限界効果の集計方法(tidy_mfx() のみ)。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 at として渡されます。method = 'coef' を指定した場合、この引数は無視されます。\n\n'overall':各観測値の限界効果の平均値を表示(初期設定)\n'mean':各説明変数の平均値における限界効果を表示\n'median':各説明変数の中央値における限界効果を表示\n'zero':各説明変数の値がゼロであるときの限界効果を表示\n\nmethod:推定する限界効果の種類(tidy_mfx() のみ)。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 method として渡されます。ただし、method = 'coef' を指定した場合には限界効果を推定せずに回帰係数をそのまま表示します。\n\n'coef':回帰係数の推定値を表示\n'dydx':限界効果の値を変換なしでそのまま表。(初期設定)\n'eyex':弾力性 d(lny)/d(lnx) の推定値を表示\n'dyex':準弾力性 dy /d(lnx) の推定値を表示\n'eydx':準弾力性 d(lny)/dx の推定値を表示\n\ndummy:ダミー変数の限界効果の推定方法(tidy_mfx() のみ)。もし False (初期設定)であれば、ダミー変数を連続な数値変数として扱います。もし、True であればダミー変数が0から1へと変化したときの予測値の変化を推定します。内部で使用しているstatsmodels.discrete.discrete_model.DiscreteResults.get_margeff() メソッドに引数 dummy として渡されます。", + "crumbs": [ + "**Regression**", + "25  tidy, tidy_mfx" + ] + }, + { + "objectID": "man/tidy.html#返り値-value", + "href": "man/tidy.html#返り値-value", + "title": "tidy, tidy_mfx", + "section": "返り値 Value", + "text": "返り値 Value\n 次の列を含む pands.DataFrame が出力されます。\n\nterm(index)  説明変数の名称\nestimate  回帰係数(tidy()の場合)、もしくは限界効果(tidy_mfx()の場合)の推定値\nstd_err 推定値 estimate の標準誤差\nstatistics estimate = 0 を帰無仮説とする仮説検定の標本検定統計量。x に代入されたモデルが sm.ols() によって作成されたものであれば \\(t\\) 統計量が表示され、sm.glm() によって作成されたものであれば \\(z\\) 統計量が表示されます。\np_value estimate = 0 を帰無仮説とする両側検定の標本p-値\nconf_lower  信頼区間の下側信頼限界\nconf_higher  信頼区間の上側信頼限界", + "crumbs": [ + "**Regression**", + "25  tidy, tidy_mfx" + ] + }, + { + "objectID": "man/tidy.html#使用例-examples", + "href": "man/tidy.html#使用例-examples", + "title": "tidy, tidy_mfx", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport pandas as pd\nimport numpy as np\nfrom palmerpenguins import load_penguins\nimport statsmodels.formula.api as smf\n\nfrom py4stats import regression_tools as reg # 回帰分析の要約\npenguins = load_penguins() # サンプルデータの読み込み\n# 回帰分析の実行\nfit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()\n\nprint(py4st.tidy(fit1).round(4))\n#> estimate std_err statistics p_value conf_lower conf_higher\n#> term \n#> Intercept 153.7397 268.9012 0.5717 0.5679 -375.1910 682.6704\n#> species[T.Chinstrap] -885.8121 88.2502 -10.0375 0.0000 -1059.4008 -712.2234\n#> species[T.Gentoo] 578.6292 75.3623 7.6780 0.0000 430.3909 726.8674\n#> bill_length_mm 91.4358 6.8871 13.2764 0.0000 77.8888 104.9828\npenguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)\n\n# ロジスティック回帰の実行\nfit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()\n\nprint(py4st.tidy_mfx(fit_logit1).round(4))\n#> estimate std_err statistics p_value conf_lower conf_higher\n#> body_mass_g -0.0004 0.0000 -17.6561 0.0000 -0.0004 -0.0003\n#> bill_length_mm -0.0053 0.0036 -1.4628 0.1435 -0.0123 0.0018\n#> bill_depth_mm -0.1490 0.0051 -29.1681 0.0000 -0.1591 -0.1390", + "crumbs": [ + "**Regression**", + "25  tidy, tidy_mfx" + ] + }, + { + "objectID": "man/tidy.html#注意点", + "href": "man/tidy.html#注意点", + "title": "tidy, tidy_mfx", + "section": "注意点", + "text": "注意点\n 参考にしたR言語の broom::tidy() は様々な種類のモデルに対応したジェネリック関数として定義されていますが、py4stats.tidy() と py4stats.tidy_mfx() では対応しているモデルは限定的であることにご注意ださい。py4st.tidy() のメソッドが定義されているオブジェクトのクラスを確認するには次のコードを実行して下さい。\nlist(py4st.tidy.registry.keys())\npy4stats.tidy() は functools.singledispatch を用いたジェネリック関数として実装しています。 Py4Etrics モジュールの py4etrics.heckit.Heckit() で作成された HeckitResults クラスのオブジェクト用のメソッドについては heckit_helper.tidy_heckit() を参照してください。\n\nReturn to Function reference.", + "crumbs": [ + "**Regression**", + "25  tidy, tidy_mfx" + ] + }, + { + "objectID": "man/tidy_test.html", + "href": "man/tidy_test.html", + "title": "tidy_test", + "section": "", + "text": "概要\n\\(t\\) 検定、\\(F\\) 検定に対応した tidy メソッド\nR言語の broom::tidy() をオマージュした py4stats.tidy() 関数のうち、statsmodels ライブラリのメソッド RegressionResults.t_test() もしくは RegressionResults.f_test() で作成された statsmodels.stats.contrast.ContrastResults クラスのオブジェクト専用のメソッドです。py4stats.tidy()はジェネリック関数として実装されているため、py4st.tidy(x) としてご利用いただけます。", + "crumbs": [ + "**Regression**", + "26  tidy_test" + ] + }, + { + "objectID": "man/tidy_test.html#概要", + "href": "man/tidy_test.html#概要", + "title": "tidy_test", + "section": "", + "text": "tidy_test(x, conf_level = 0.95, **kwargs)", + "crumbs": [ + "**Regression**", + "26  tidy_test" + ] + }, + { + "objectID": "man/tidy_test.html#引数-argument", + "href": "man/tidy_test.html#引数-argument", + "title": "tidy_test", + "section": "引数 Argument", + "text": "引数 Argument\n\nx(必須)  statsmodels ライブラリのメソッド RegressionResults.t_test() もしくはRegressionResults.f_test() で作成された statsmodels.stats.contrast.ContrastResults クラスのオブジェクト。\nconf_level:float  信頼区間の計算に用いる信頼係数。ただし、x に代入されたオブジェクトが f_test() の結果である場合は、この引数は無視されます。", + "crumbs": [ + "**Regression**", + "26  tidy_test" + ] + }, + { + "objectID": "man/tidy_test.html#返り値-value", + "href": "man/tidy_test.html#返り値-value", + "title": "tidy_test", + "section": "返り値 Value", + "text": "返り値 Value\n 引数 x に代入されたオブジェクトが t_test() の結果である場合、次の列を含む pands.DataFrame が出力されます。\n\nestimate  帰無仮説のもとでの回帰係数(の線型結合)の推定値\nstd_err 推定値 estimate の標準誤差\nstatistics  仮説検定の標本検定統計量。\np_value 両側検定の標本p-値\nconf_lower  信頼区間の下側信頼限界\nconf_higher  信頼区間の上側信頼限界\n\n 一方で引数 x に代入されたオブジェクトが f_test() の結果である場合、次の列を含む pands.DataFrame が出力されます。\n\nstatistics  仮説検定の標本検定統計量。\np_value  F検定の標本p-値\ndf_denom  モデルの残差自由度\ndf_denom  帰無仮説のもとでの制約数", + "crumbs": [ + "**Regression**", + "26  tidy_test" + ] + }, + { + "objectID": "man/tidy_test.html#使用例-examples", + "href": "man/tidy_test.html#使用例-examples", + "title": "tidy_test", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport py4stats as py4st\n\nimport pandas as pd\nimport numpy as np\nfrom palmerpenguins import load_penguins\nimport statsmodels.formula.api as smf\n\npenguins = load_penguins() # サンプルデータの読み込み\n\nfit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit()\nhypotheses = 'bill_length_mm = 20'\nprint(py4st.tidy(fit3.t_test(hypotheses)).round(4))\n#> estimate std_err statistics p_value conf_lower conf_higher\n#> term \n#> c0 26.5366 7.2436 0.9024 0.3675 12.2867 40.7866\nhypotheses = 'species[T.Chinstrap] = 0, species[T.Gentoo] = 0'\nprint(py4st.tidy(fit3.f_test(hypotheses)).round(4))\n#> statistics p_value df_denom df_num\n#> term \n#> contrast 210.9432 0.0 327 2\n\nReturn to Function reference.", + "crumbs": [ + "**Regression**", + "26  tidy_test" + ] + }, + { + "objectID": "man/glance.html", + "href": "man/glance.html", + "title": "glance", + "section": "", + "text": "概要\n線形モデルの当てはまりの尺度\nR言語の bloom::glance() をオマージュした関数で、sm.ols() や smf.logit() などで推定されたモデルを pands.DataFrame に変換します。", + "crumbs": [ + "**Regression**", + "27  glance" + ] + }, + { + "objectID": "man/glance.html#概要", + "href": "man/glance.html#概要", + "title": "glance", + "section": "", + "text": "glance(x)", + "crumbs": [ + "**Regression**", + "27  glance" + ] + }, + { + "objectID": "man/glance.html#引数-argument", + "href": "man/glance.html#引数-argument", + "title": "glance", + "section": "引数 Argument", + "text": "引数 Argument\n\nx(必須)  sm.ols() もしくは smf.logit() などで作成された分析結果のオブジェクト。", + "crumbs": [ + "**Regression**", + "27  glance" + ] + }, + { + "objectID": "man/glance.html#返り値-value", + "href": "man/glance.html#返り値-value", + "title": "glance", + "section": "返り値 Value", + "text": "返り値 Value\n モデルの当てはまり(goodness of fit)の尺度を各列に持つ pands.DataFrame が出力されます。表示される指標はモデルの種類によって異なります。", + "crumbs": [ + "**Regression**", + "27  glance" + ] + }, + { + "objectID": "man/glance.html#使用例-examples", + "href": "man/glance.html#使用例-examples", + "title": "glance", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport pandas as pd\nimport numpy as np\nfrom palmerpenguins import load_penguins\nimport statsmodels.formula.api as smf\n\nimport py4stats as py4st\npenguins = load_penguins() # サンプルデータの読み込み\n# 線形回帰の場合\nfit_lm1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit()\n\npd.set_option('display.expand_frame_repr', False)\nprint(py4st.glance(fit_lm1).round(4))\n#> rsquared rsquared_adj nobs df sigma F_values p_values AIC BIC\n#> 0 0.7829 0.781 342 3 375.3251 406.2735 0.0 5029.1406 5044.4798\n# ロジスティック回帰の場合\npenguins['female'] = np.where(penguins['sex'] == 'female', 1, 0)\nfit_logit1 = smf.logit('female ~ body_mass_g + bill_length_mm + bill_depth_mm', data = penguins).fit()\n\nprint(py4st.glance(fit_logit1).round(4))\n#> prsquared LL-Null df_null logLik AIC BIC deviance df_resid df_model nobs\n#> 0 0.5647 -236.8458 341 -103.1079 214.2157 229.555 206.2157 338 3 342", + "crumbs": [ + "**Regression**", + "27  glance" + ] + }, + { + "objectID": "man/glance.html#注意点", + "href": "man/glance.html#注意点", + "title": "glance", + "section": "注意点", + "text": "注意点\n 参考にしたR言語の bloom::glance() は様々な種類のモデルに対応したジェネリック関数として定義されていますが、py4st.glance() は現段階では限られたモデルにしか対応していません。py4st.glance() のメソッドが定義されているオブジェクトのクラスを確認するには次のコードを実行して下さい。\nlist(py4st.glance.registry.keys())\n\nReturn to Function reference.", + "crumbs": [ + "**Regression**", + "27  glance" + ] + }, + { + "objectID": "man/Blinder_Oaxaca.html", + "href": "man/Blinder_Oaxaca.html", + "title": "Blinder_Oaxaca, plot_Blinder_Oaxaca", + "section": "", + "text": "概要\n2つのサブサンプルを用いた回帰分析の推定結果に対して、Blinder-Oaxaca分解を行います。\nいま、ある変数 \\(s\\) を用いて \\(s = m\\) と \\(s = f\\) の2つのサブグループからなるデータセットがあるとし、次のような回帰式を仮定します。\n\\[\n\\begin{aligned}\nY_{i}^s = \\boldsymbol{X}_i^s\\boldsymbol{\\beta}^s + \\epsilon_i^s, &&\ns = m, f\n\\end{aligned}\n\\tag{1}\n\\]\nここで、\\(\\boldsymbol{X}_i^s\\) サブグループ \\(s\\) に属する個人 \\(i\\) についての説明変数からなる行列で、\\(\\boldsymbol{\\beta}^s\\) はサブグループ \\(s\\) のについての回帰係数、\\(\\epsilon_i^s\\) は誤差項です。  さらに、サブグループ \\(s\\) の被説明変数の平均値を \\(\\bar{Y}^s\\) とし、説明変数の平均値を \\(\\bar{\\boldsymbol{X}}^s\\) とするとき、Blinder-Oaxaca分解は2つのグループにおける被説明変数の平均値の差 \\(\\bar{Y}^m - \\bar{Y}^f\\) を次のように分解します。\n\\[\n\\begin{aligned}\n\\bar{Y}^m - \\bar{Y}^f = (\\bar{\\boldsymbol{X}}^m - \\bar{\\boldsymbol{X}}^f)\\boldsymbol{\\beta}^m + \\bar{\\boldsymbol{X}}^f(\\boldsymbol{\\beta}^m - \\boldsymbol{\\beta}^f)\n\\end{aligned}\n\\tag{2}\n\\]\nこのとき、式(2)右辺の各項は、それぞれ次のような意味を持ちます。\n式(1)および式(2)については朝井(2014, p.9)を参照しました。", + "crumbs": [ + "**Regression**", + "28  Blinder_Oaxaca, plot_Blinder_Oaxaca" + ] + }, + { + "objectID": "man/Blinder_Oaxaca.html#概要", + "href": "man/Blinder_Oaxaca.html#概要", + "title": "Blinder_Oaxaca, plot_Blinder_Oaxaca", + "section": "", + "text": "Blinder_Oaxaca(model1, model2)\n\nplot_Blinder_Oaxaca(\n model1, model2,\n diff_type = ['observed_diff', 'unobserved_diff'],\n ax = None, \n)\n\n\n\n\n\n\n\\((\\bar{\\boldsymbol{X}}^m - \\bar{\\boldsymbol{X}}^f)\\boldsymbol{\\beta}^m\\):2つのグループの観測可能な属性の差に起因する被説明変数の差 observed_diff\n\\(\\bar{\\boldsymbol{X}}^f(\\boldsymbol{\\beta}^m - \\boldsymbol{\\beta}^f)\\):2つのグループの観測できない要因の違いに起因する被説明変数の差 unobserved_diff", + "crumbs": [ + "**Regression**", + "28  Blinder_Oaxaca, plot_Blinder_Oaxaca" + ] + }, + { + "objectID": "man/Blinder_Oaxaca.html#引数-argument", + "href": "man/Blinder_Oaxaca.html#引数-argument", + "title": "Blinder_Oaxaca, plot_Blinder_Oaxaca", + "section": "引数 Argument", + "text": "引数 Argument\n\nmodel1:statsmodels で作成した回帰分析の結果(必須)。\nmodel2:statsmodels で作成した回帰分析の結果(必須)。\ndiff_type (plot_Blinder_Oaxaca()のみ)list of str or str  グラフの描画に使用する要約統計量の種類。初期設定では observed_diff と unobserved_diff の両方を表示します。\nax:matplotlib の ax オブジェクト。複数のグラフを並べる場合などに使用します。   ## 使用例 Examples\n\nimport pandas as pd\nimport statsmodels.formula.api as smf\nimport py4stats as py4st\n\nwage1 = wooldridge.data('wage1')\n\nfit_female = smf.ols(\n 'lwage ~ educ + exper + expersq + tenure + tenursq + married', \n data = wage1.query('female == 1')\n ).fit()\n\nfit_male = smf.ols(\n 'lwage ~ educ + exper + expersq + tenure + tenursq + married', \n data = wage1.query('female == 0')\n ).fit()\npy4st.compare_ols(\n list_models = [fit_female, fit_male],\n model_name = ['female', 'male']\n )\n\n\n\nterm\nfemale\nmale\n\n\n\n\nIntercept\n0.3159 **(0.1401)\n0.2255 *(0.1302)\n\n\neduc\n0.0737 ***(0.0104)\n0.0830 ***(0.0089)\n\n\nexper\n0.0200 ***(0.0072)\n0.0329 ***(0.0076)\n\n\nexpersq\n-0.0004 ***(0.0002)\n-0.0006 ***(0.0002)\n\n\ntenure\n0.0391 ***(0.0117)\n0.0301 ***(0.0089)\n\n\ntenursq\n-0.0014 ***(0.0005)\n-0.0005 *(0.0003)\n\n\nmarried\n-0.0548 (0.0539)\n0.1718 ***(0.0595)\n\n\nrsquared_adj\n0.2446\n0.4509\n\n\nnobs\n252\n274\n\n\ndf\n6\n6\n\n\n\nwage_decomp = py4st.Blinder_Oaxaca(\n model1 = fit_female,\n model2 = fit_male\n)\nwage_decomp\n\n\n\nterms\nobserved_diff\nunobserved_diff\n\n\n\n\nIntercept\n0\n-0.0903337\n\n\neduc\n0.0390661\n0.114713\n\n\nexper\n0.0371577\n0.211177\n\n\nexpersq\n-0.0216026\n-0.0962631\n\n\ntenure\n0.0859831\n-0.0327949\n\n\ntenursq\n-0.0342727\n0.0378497\n\n\nmarried\n0.0278806\n0.118657\n\n\n\npy4st.plot_Blinder_Oaxaca(\n model1 = fit_female,\n model2 = fit_male\n)\n\n\n\nplot_Blinder_Oaxaca1\n\n\ndiff_type を指定することで、一方の統計量だけを表示することもできます。\npy4st.plot_Blinder_Oaxaca(\n model1 = fit_female,\n model2 = fit_male,\n diff_type = 'unobserved_diff'\n)\n\n\n\nplot_Blinder_Oaxaca2\n\n\nグラフのサイズや解像度を指定するには、次のように行います。\nfig, ax = plt.subplots(1, 2, figsize = (1.1 * 2 * 4, 4), sharey = True, dpi = 200)\n\npy4st.plot_Blinder_Oaxaca(\n model1 = fit_female,\n model2 = fit_male,\n ax = ax\n)\nfig.tight_layout()", + "crumbs": [ + "**Regression**", + "28  Blinder_Oaxaca, plot_Blinder_Oaxaca" + ] + }, + { + "objectID": "man/Blinder_Oaxaca.html#参考文献", + "href": "man/Blinder_Oaxaca.html#参考文献", + "title": "Blinder_Oaxaca, plot_Blinder_Oaxaca", + "section": "参考文献", + "text": "参考文献\n\n朝井 友紀子 (2014) 「労働市場における男女差の30年― 就業のサンプルセレクションと男女間賃金格差」『日本労働研究雑誌』, No.648, pp.6–16\n\n\nReturn to Function reference.", + "crumbs": [ + "**Regression**", + "28  Blinder_Oaxaca, plot_Blinder_Oaxaca" + ] + }, + { + "objectID": "man/tidy_heckit.html", + "href": "man/tidy_heckit.html", + "title": "heckit_helper.tidy_heckit", + "section": "", + "text": "概要\nR言語の broom::tidy() をオマージュした regression_tools.tidy() 関数の、py4etrics.heckit.HeckitResults クラス専用のメソッドです。regression_tools.tidy()はジェネリック関数として実装されているため、py4st.tidy(x) としてご利用いただけます。", + "crumbs": [ + "**heckit_helper**", + "29  heckit_helper.tidy_heckit" + ] + }, + { + "objectID": "man/tidy_heckit.html#概要", + "href": "man/tidy_heckit.html#概要", + "title": "heckit_helper.tidy_heckit", + "section": "", + "text": "tidy_heckit(\n model, \n name_selection = None, \n name_outcome = None, \n conf_level = 0.95\n )", + "crumbs": [ + "**heckit_helper**", + "29  heckit_helper.tidy_heckit" + ] + }, + { + "objectID": "man/tidy_heckit.html#引数-argument", + "href": "man/tidy_heckit.html#引数-argument", + "title": "heckit_helper.tidy_heckit", + "section": "引数 Argument", + "text": "引数 Argument\n\nx(必須)   Py4Etrics モジュールの py4etrics.heckit.Heckit() で作成された HeckitResults クラスのオブジェクト\nname_selection:list of str  term 列(index) のうち、第1段階の説明変数の名称として表示する文字列のリスト。指定しない場合(初期設定)、モデルの推定に使用された説明変数の名前がそのまま表示されます。\nname_outcome:list of str  term 列(index) のうち、第2段階の説明変数の名称として表示する文字列のリスト。指定しない場合(初期設定)、モデルの推定に使用された説明変数の名前がそのまま表示されます。\nconf_level:float  信頼区間の計算に用いる信頼係数。", + "crumbs": [ + "**heckit_helper**", + "29  heckit_helper.tidy_heckit" + ] + }, + { + "objectID": "man/tidy_heckit.html#返り値-value", + "href": "man/tidy_heckit.html#返り値-value", + "title": "heckit_helper.tidy_heckit", + "section": "返り値 Value", + "text": "返り値 Value\n 次の列を含む pands.DataFrame が出力されます。\n\nterm(index)  説明変数の名称\nestimate)  回帰係数の推定値\nstd_err 推定値 estimate の標準誤差\nstatistics estimate = 0 を帰無仮説とする仮説検定の標本検定統計量。x に代入されたモデルが sm.ols() によって作成されたものであれば \\(t\\) 統計量が表示され、sm.glm() によって作成されたものであれば \\(z\\) 統計量が表示されます。\np_value estimate = 0 を帰無仮説とする両側検定の標本p-値\nconf_lower  信頼区間の下側信頼限界\nconf_higher  信頼区間の上側信頼限界", + "crumbs": [ + "**heckit_helper**", + "29  heckit_helper.tidy_heckit" + ] + }, + { + "objectID": "man/tidy_heckit.html#使用例-examples", + "href": "man/tidy_heckit.html#使用例-examples", + "title": "heckit_helper.tidy_heckit", + "section": "使用例 Examples", + "text": "使用例 Examples\n heckit_helper モジュールはヘックマンの2段階推定(Heckit)を実行を Py4Etrics モジュールの py4etrics.heckit.Heckit() に依存しているため、事前のインストールをお願いします。\npip install git+https://github.com/Py4Etrics/py4etrics.git\nここでは wooldridge モジュールの mroz データを使い、春山(2023, Chap.24)のモデルを再現します。\nimport pandas as pd\nimport wooldridge\nimport py4stats as py4st\nfrom py4stats import heckit_helper\n\nmroz = wooldridge.data('mroz') # サンプルデータの読み込み\n\nmod_heckit, exog_outcome, exog_select = heckit_helper.Heckit_from_formula(\n selection = 'lwage ~ educ + exper + expersq + nwifeinc + age + kidslt6 + kidsge6',\n outcome = 'lwage ~ educ + exper + expersq',\n data = mroz\n)\n\nres_heckit = mod_heckit.fit(cov_type_2 = 'HC1')\n内部で functools.singledispatch を使用して定義しているため、heckit_helper モジュールの読み込み後は、py4st.tidy() 関数を呼び出すことで tidy_heckit() を実行することができます。\n# 初期設定で使用した場合\nprint(py4st.tidy(res_heckit).round(4))\n#> estimate std_err statistics p_value conf_lower conf_higher\n#> term \n#> O: Intercept -0.5781 0.3050 -1.8954 0.0580 -1.1759 0.0197\n#> O: educ 0.1091 0.0155 7.0261 0.0000 0.0786 0.1395\n#> O: exper 0.0439 0.0163 2.6989 0.0070 0.0120 0.0758\n#> O: expersq -0.0009 0.0004 -1.9574 0.0503 -0.0017 0.0000\n#> S: const 0.2701 0.5086 0.5310 0.5954 -0.7267 1.2669\n#> S: x1 0.1309 0.0253 5.1835 0.0000 0.0814 0.1804\n#> S: x2 0.1233 0.0187 6.5903 0.0000 0.0867 0.1600\n#> S: x3 -0.0019 0.0006 -3.1452 0.0017 -0.0031 -0.0007\n#> S: x4 -0.0120 0.0048 -2.4843 0.0130 -0.0215 -0.0025\n#> S: x5 -0.0529 0.0085 -6.2347 0.0000 -0.0695 -0.0362\n#> S: x6 -0.8683 0.1185 -7.3263 0.0000 -1.1006 -0.6360\n#> S: x7 0.0360 0.0435 0.8281 0.4076 -0.0492 0.1212\n 注意:内部で使用している statsmodels.iolib.summary.summary_params_frame() の仕様上、初期設定では第1段階の説明変数の名前が反映されません。説明変数の名前を反映するには name_selection 引数で指定してください。\nprint(py4st.tidy(res_heckit, name_selection = exog_select.columns).round(4))\n#> estimate std_err statistics p_value conf_lower conf_higher\n#> term \n#> O: Intercept -0.5781 0.3050 -1.8954 0.0580 -1.1759 0.0197\n#> O: educ 0.1091 0.0155 7.0261 0.0000 0.0786 0.1395\n#> O: exper 0.0439 0.0163 2.6989 0.0070 0.0120 0.0758\n#> O: expersq -0.0009 0.0004 -1.9574 0.0503 -0.0017 0.0000\n#> S: Intercept 0.2701 0.5086 0.5310 0.5954 -0.7267 1.2669\n#> S: educ 0.1309 0.0253 5.1835 0.0000 0.0814 0.1804\n#> S: exper 0.1233 0.0187 6.5903 0.0000 0.0867 0.1600\n#> S: expersq -0.0019 0.0006 -3.1452 0.0017 -0.0031 -0.0007\n#> S: nwifeinc -0.0120 0.0048 -2.4843 0.0130 -0.0215 -0.0025\n#> S: age -0.0529 0.0085 -6.2347 0.0000 -0.0695 -0.0362\n#> S: kidslt6 -0.8683 0.1185 -7.3263 0.0000 -1.1006 -0.6360\n#> S: kidsge6 0.0360 0.0435 0.8281 0.4076 -0.0492 0.1212\n\nReturn to Function reference.", + "crumbs": [ + "**heckit_helper**", + "29  heckit_helper.tidy_heckit" + ] + }, + { + "objectID": "man/Heckit_from_formula.html", + "href": "man/Heckit_from_formula.html", + "title": "heckit_helper.Heckit_from_formula", + "section": "", + "text": "概要", + "crumbs": [ + "**heckit_helper**", + "30  heckit_helper.Heckit_from_formula" + ] + }, + { + "objectID": "man/Heckit_from_formula.html#概要", + "href": "man/Heckit_from_formula.html#概要", + "title": "heckit_helper.Heckit_from_formula", + "section": "", + "text": "Heckit_from_formula(\n selection, \n outcome, \n data, \n **kwargs\n )", + "crumbs": [ + "**heckit_helper**", + "30  heckit_helper.Heckit_from_formula" + ] + }, + { + "objectID": "man/Heckit_from_formula.html#引数-argument", + "href": "man/Heckit_from_formula.html#引数-argument", + "title": "heckit_helper.Heckit_from_formula", + "section": "引数 Argument", + "text": "引数 Argument\n\nselectionstr(必須)  Type2トービットモデルのうち第1段階の selection equation(選択関数, 就業決定関数)の回帰式\noutcomestr(必須)  Type2トービットモデルのうち第2段階の regression equation(賃金関数)の回帰式\ndata:pandas.DataFrame(必須)\n**kwargs py4etrics.heckit.Heckit() に渡すその他の引数", + "crumbs": [ + "**heckit_helper**", + "30  heckit_helper.Heckit_from_formula" + ] + }, + { + "objectID": "man/Heckit_from_formula.html#返り値-value", + "href": "man/Heckit_from_formula.html#返り値-value", + "title": "heckit_helper.Heckit_from_formula", + "section": "返り値 Value", + "text": "返り値 Value\n 3つの要素を持つ tuple。左から順に次の3つのオブジェクトが出力されます。\n\npy4etrics.heckit.Heckit() から出力されたモデルの推定結果\n第2段階の regression equation(賃金関数)の説明変数からなる pd.DataFrame\n第1段階のselection equation(選択関数, 就業決定関数)の説明変数からなる pd.DataFrame", + "crumbs": [ + "**heckit_helper**", + "30  heckit_helper.Heckit_from_formula" + ] + }, + { + "objectID": "man/Heckit_from_formula.html#使用例-examples", + "href": "man/Heckit_from_formula.html#使用例-examples", + "title": "heckit_helper.Heckit_from_formula", + "section": "使用例 Examples", + "text": "使用例 Examples\n heckit_helper モジュールはヘックマンの2段階推定(Heckit)を実行を Py4Etrics モジュールの py4etrics.heckit.Heckit() に依存しているため、事前のインストールをお願いします。\npip install git+https://github.com/Py4Etrics/py4etrics.git\nここでは春山(2023, Chap.24)のモデルを再現するため、wooldridge モジュールから mroz データを読み込みます。\nimport pandas as pd\nimport wooldridge\nfrom py4stats import heckit_helper\n\nmroz = wooldridge.data('mroz') # サンプルデータの読み込み\nHeckit_from_formula() 関数を使い、モデルを推定します。なお、Type2トービットモデルを推定する場合、第2段階の回帰式 outcome で使用される説明変数は全て第1段階の回帰式 selection に含まれ、なおかつ selection に含まれるものの、outcome には含まれない説明変数が少なくとも1つは必要であることに注意してください(末石, 2015, p.117)。\nmod_heckit, exog_outcome, exog_select = \\\n heckit_helper.Heckit_from_formula(\n selection = 'lwage ~ educ + exper + expersq + nwifeinc + age + kidslt6 + kidsge6',\n outcome = 'lwage ~ educ + exper + expersq',\n data = mroz\n)\n\nres_heckit = mod_heckit.fit(cov_type_2 = 'HC1')\n\nprint(res_heckit.summary())\n#> Heckit Regression Results \n#> ================================================================================\n#> Dep. Variable: lwage R-squared: 0.156\n#> Model: Heckit Adj. R-squared: 0.150\n#> Method: Heckman Two-Step F-statistics: 26.148\n#> Date: Mon, 11 Mar 2024 Prob (F-statistic): 0.000\n#> Time: 08:40:39 Cov in 1st Stage: nonrobust\n#> No. Total Obs.: 753 Cov in 2nd Stage: HC1\n#> No. Censored Obs.: 325 \n#> No. Uncensored Obs.: 428 \n#> ==============================================================================\n#> coef std err z P>|z| [0.025 0.975]\n#> ------------------------------------------------------------------------------\n#> Intercept -0.5781 0.305 -1.895 0.058 -1.176 0.020\n#> educ 0.1091 0.016 7.026 0.000 0.079 0.139\n#> exper 0.0439 0.016 2.699 0.007 0.012 0.076\n#> expersq -0.0009 0.000 -1.957 0.050 -0.002 1.15e-06\n#> ==============================================================================\n#> coef std err z P>|z| [0.025 0.975]\n#> ------------------------------------------------------------------------------\n#> Intercept 0.2701 0.509 0.531 0.595 -0.727 1.267\n#> educ 0.1309 0.025 5.183 0.000 0.081 0.180\n#> exper 0.1233 0.019 6.590 0.000 0.087 0.160\n#> expersq -0.0019 0.001 -3.145 0.002 -0.003 -0.001\n#> nwifeinc -0.0120 0.005 -2.484 0.013 -0.022 -0.003\n#> age -0.0529 0.008 -6.235 0.000 -0.069 -0.036\n#> kidslt6 -0.8683 0.119 -7.326 0.000 -1.101 -0.636\n#> kidsge6 0.0360 0.043 0.828 0.408 -0.049 0.121\n#> ================================================================================\n#> coef std err z P>|z| [0.025 0.975]\n#> --------------------------------------------------------------------------------\n#> IMR (Lambda) 0.0323 0.134 0.241 0.809 -0.230 0.294\n#> =====================================\n#> rho: 0.049\n#> sigma: 0.664\n#> =====================================\n#> \n#> First table are the estimates for the regression (response) equation.\n#> Second table are the estimates for the selection equation.\n#> Third table is the estimate for the coef of the inverse Mills ratio (Heckman's Lambda).", + "crumbs": [ + "**heckit_helper**", + "30  heckit_helper.Heckit_from_formula" + ] + }, + { + "objectID": "man/Heckit_from_formula.html#参考文献", + "href": "man/Heckit_from_formula.html#参考文献", + "title": "heckit_helper.Heckit_from_formula", + "section": "参考文献", + "text": "参考文献\n\n末石直也(2015)『計量経済学:ミクロデータ分析へのいざない』 日本評論社.\n春山鉄源(2023) 『Pythonで学ぶ入門計量経済学』 https://py4etrics.github.io/index.html\n\n\nReturn to Function reference.", + "crumbs": [ + "**heckit_helper**", + "30  heckit_helper.Heckit_from_formula" + ] + }, + { + "objectID": "man/heckitmfx_compute.html", + "href": "man/heckitmfx_compute.html", + "title": "heckit_helper.heckitmfx_compute", + "section": "", + "text": "概要\nType2トービットモデルの限界効果を推定します。推定方法についてはダハナ, 勝又(2023, p.136)および Hoffmann, Kassouf(2005)を参照し、関数の実装についてはR言語の heckitmfx::heckitmfx_log() 関数を参考にしています。", + "crumbs": [ + "**heckit_helper**", + "31  heckit_helper.heckitmfx_compute" + ] + }, + { + "objectID": "man/heckitmfx_compute.html#概要", + "href": "man/heckitmfx_compute.html#概要", + "title": "heckit_helper.heckitmfx_compute", + "section": "", + "text": "heckitmfx_compute(\n model, \n exog_select, \n exog_outcome, \n exponentiate = False\n)", + "crumbs": [ + "**heckit_helper**", + "31  heckit_helper.heckitmfx_compute" + ] + }, + { + "objectID": "man/heckitmfx_compute.html#引数-argument", + "href": "man/heckitmfx_compute.html#引数-argument", + "title": "heckit_helper.heckitmfx_compute", + "section": "引数 Argument", + "text": "引数 Argument\n\nmodel(必須)   Py4Etrics モジュールの py4etrics.heckit.Heckit() で作成された HeckitResults クラスのオブジェクト\nexog_selectpd.DataFrame(必須)  Type2トービットモデルのうち第1段階の selection equation(選択関数, 就業決定関数)の説明変数からなる pd.DataFrame\nexog_outcomepd.DataFrame(必須)  Type2トービットモデルのうち第2段階の regression equation(賃金関数)の説明変数からなる pd.DataFrame\n\nこれらの引数は heckit_helper.Heckit_from_formula() の出力を使用することを想定しています(使用例を参照)。\n\nexponentiatebool  推定結果に指数関数を用いた変換を行うかどうかを表す論理値。もし False (初期設定)であれば限界効果と回帰係数の推定値をそのまま出力し、もし True であれば出力されるデータフレームのうち unconditional、conditional、selection、beta の列について指数関数 \\(100[\\exp(x - 1)]\\) を用いた変換を行います。例えば被説明変数は対数賃金であれば、変換後の限界効果はパーセンテージで表された賃金の変化率として解釈できます。", + "crumbs": [ + "**heckit_helper**", + "31  heckit_helper.heckitmfx_compute" + ] + }, + { + "objectID": "man/heckitmfx_compute.html#返り値-value", + "href": "man/heckitmfx_compute.html#返り値-value", + "title": "heckit_helper.heckitmfx_compute", + "section": "返り値 Value", + "text": "返り値 Value\n 次の列を含む pands.DataFrame が出力されます。\n\nterm(index)  説明変数の名称\nunconditional  Hoffmann, Kassouf(2005, p.6)の(14)式および(15)式に基づく条件付なしの平均限界効果(unconditional marginal effect)\nconditional  Hoffmann, Kassouf(2005, pp.4-5)の(8)式および(9)式に基づく条件付平均限界効果(conditional marginal effect)\nselection  Hoffmann, Kassouf(2005, p.6)の(14)式および(15)式の第3項に当たる間接効果\nbeta  第2段階の regression equation の回帰係数\ngamma  第1段階の selection equation の回帰係数", + "crumbs": [ + "**heckit_helper**", + "31  heckit_helper.heckitmfx_compute" + ] + }, + { + "objectID": "man/heckitmfx_compute.html#使用例-examples", + "href": "man/heckitmfx_compute.html#使用例-examples", + "title": "heckit_helper.heckitmfx_compute", + "section": "使用例 Examples", + "text": "使用例 Examples\n heckit_helper モジュールはヘックマンの2段階推定(Heckit)を実行を Py4Etrics モジュールの py4etrics.heckit.Heckit() に依存しているため、事前のインストールをお願いします。\npip install git+https://github.com/Py4Etrics/py4etrics.git\nここでは wooldridge モジュールの mroz データを使い、春山(2023, Chap.24)のモデルを再現します。\nimport pandas as pd\nimport wooldridge\nfrom py4stats import heckit_helper\n\nmroz = wooldridge.data('mroz') # サンプルデータの読み込み\n\nmod_heckit, exog_outcome, exog_select = \\\n heckit_helper.Heckit_from_formula(\n selection = 'lwage ~ educ + exper + expersq + nwifeinc + age + kidslt6 + kidsge6',\n outcome = 'lwage ~ educ + exper + expersq',\n data = mroz\n)\n\nres_heckit = mod_heckit.fit(cov_type_2 = 'HC1')\nprint(heckit_helper.heckitmfx_compute(\n res_heckit,\n exog_select = exog_select,\n exog_outcome = exog_outcome\n ).round(4))\n#> unconditional conditional selection beta gamma\n#> term \n#> age -0.0385 0.0010 -0.0395 0.0000 -0.0529\n#> educ 0.2045 0.1067 0.0978 0.1091 0.1309\n#> exper 0.1338 0.0417 0.0922 0.0439 0.1233\n#> expersq -0.0022 -0.0008 -0.0014 -0.0009 -0.0019\n#> kidsge6 0.0263 -0.0006 0.0269 0.0000 0.0360\n#> kidslt6 -0.6332 0.0157 -0.6489 0.0000 -0.8683\n#> nwifeinc -0.0088 0.0002 -0.0090 0.0000 -0.0120\n被説明変数の lwage は対数賃金であるため、exponentiate = True として指数関数 \\(100[\\exp(x - 1)]\\) を使った変換を行うことで、限界効果を賃金の変化率として解釈できるようになります。\nprint(heckit_helper.heckitmfx_compute(\n res_heckit,\n exog_select = exog_select,\n exog_outcome = exog_outcome,\n exponentiate = True\n ).round(4))\n#> unconditional conditional selection beta gamma\n#> term \n#> age -3.7809 0.0954 -3.8725 0.0000 -0.0529\n#> educ 22.6943 11.2606 10.2765 11.5235 0.1309\n#> exper 14.3206 4.2543 9.6555 4.4865 0.1233\n#> expersq -0.2233 -0.0825 -0.1409 -0.0859 -0.0019\n#> kidsge6 2.6604 -0.0649 2.7271 0.0000 0.0360\n#> kidslt6 -46.9117 1.5782 -47.7365 0.0000 -0.8683\n#> nwifeinc -0.8730 0.0217 -0.8945 0.0000 -0.0120", + "crumbs": [ + "**heckit_helper**", + "31  heckit_helper.heckitmfx_compute" + ] + }, + { + "objectID": "man/heckitmfx_compute.html#注意", + "href": "man/heckitmfx_compute.html#注意", + "title": "heckit_helper.heckitmfx_compute", + "section": "注意", + "text": "注意\n heckitmfx_compute() の実装は実験的なものであり、 Stata における margins コマンドなどの既存の手法とは計算結果が一致しない可能性があります。", + "crumbs": [ + "**heckit_helper**", + "31  heckit_helper.heckitmfx_compute" + ] + }, + { + "objectID": "man/heckitmfx_compute.html#参考文献", + "href": "man/heckitmfx_compute.html#参考文献", + "title": "heckit_helper.heckitmfx_compute", + "section": "参考文献", + "text": "参考文献\n\nダハナ・ウィラワン ドニ, 勝又壮太郎(2023) 『Rによるマーケティング・データ分析: 基礎から応用まで (ライブラリ データ分析への招待 4)』新世社.\n春山鉄源 (2023) 『Pythonで学ぶ入門計量経済学』. https://py4etrics.github.io/index.html\nHoffmann, Rodolfo, and Ana Lucia Kassouf. (2005). Deriving conditional and unconditional marginal effects in log earnings equations estimated by heckman’s procedure. Applied Economics, 37(11), 1303–1311. *** Return to Function reference.", + "crumbs": [ + "**heckit_helper**", + "31  heckit_helper.heckitmfx_compute" + ] + }, + { + "objectID": "man/arg_match.html", + "href": "man/arg_match.html", + "title": "building_block.arg_match", + "section": "", + "text": "概要\n引数のアサーション\nR言語の rlang::arg_match() をオマージュした関数で、文字列で与えられた引数のアサーションを行います。", + "crumbs": [ + "**building_block**", + "32  building_block.arg_match" + ] + }, + { + "objectID": "man/arg_match.html#概要", + "href": "man/arg_match.html#概要", + "title": "building_block.arg_match", + "section": "", + "text": "arg_match(\n arg: Union[str, Sequence[str], pd.Series, np.ndarray],\n values: Sequence[str],\n arg_name: Optional[str] = None,\n multiple: bool = False,\n any_missing: bool = False,\n all_missing: bool = False,\n nullable: bool = False\n )", + "crumbs": [ + "**building_block**", + "32  building_block.arg_match" + ] + }, + { + "objectID": "man/arg_match.html#引数-argument", + "href": "man/arg_match.html#引数-argument", + "title": "building_block.arg_match", + "section": "引数 Argument", + "text": "引数 Argument\n\narg(必須)str or list of str  適正かどうかを判断したい引数の値\nvalues(必須):list of str  引数 arg の適正な値のリスト\narg_name:str  エラーメッセージに表示する引数の名前。指定されなかった場合(初期設定)、引数 arg に代入されたオブジェクトの名称を表示します。なお、この機能は varname.argname()関数を使って実装されています。\nmultiple:bool  引数の値として複数の値を許容するかどうかを示すブール値。arg にリストが代入された場合、multiple = False(初期設定)であれば最初の値のみを出力し、multiple = True であればリストの値を全て出力します。\nany_missing:bool True の場合、欠測値(例:None、NaN、pd.NA など)が引数 arg の一部に含まれていても許容されます。\nall_missing: bool True の場合、すべての要素が欠測値であることを許容します。\nnullable: bool True の場合、引数そのものが None であることを許容します。", + "crumbs": [ + "**building_block**", + "32  building_block.arg_match" + ] + }, + { + "objectID": "man/arg_match.html#返り値-value", + "href": "man/arg_match.html#返り値-value", + "title": "building_block.arg_match", + "section": "返り値 Value", + "text": "返り値 Value\n 引数 arg に代入された値が、values に代入されたリストに含まれていればその値を返し、そうでなければエラーメッセージを出力します。エラーメッセージでは values に代入されたリストの値を arg の適正な値の候補として提示します。", + "crumbs": [ + "**building_block**", + "32  building_block.arg_match" + ] + }, + { + "objectID": "man/arg_match.html#使用例-examples", + "href": "man/arg_match.html#使用例-examples", + "title": "building_block.arg_match", + "section": "使用例 Examples", + "text": "使用例 Examples\nfrom py4stats import building_block as build\n\ndef my_faivarit(fruits):\n fruits = build.arg_match(\n fruits, arg_name = 'fruits',\n values = ['apple', 'orange', 'grape'], \n multiple = False\n )\n return fruits\n\nmy_faivarit('apple')\n#> 'apple'\n\nmy_faivarit('orang')\n#> ValueError: `fruits` must be one of 'apple', 'orange' or 'grape', not 'orang'.\n#> Did you mean 'orange'?\n\nmy_faivarit('ap')\n#> ValueError: `fruits` must be one of 'apple', 'orange' or 'grape', not 'ap'.\n#> Did you mean 'apple' or 'grape'?\n# arg に list を指定した場合\n# 初期設定では1つ目の要素だけ使用されます。\nmy_faivarit(['apple', 'orange'])\n#> 'apple'\n\n# multiple = True として再度関数を定義\ndef my_faivarit2(fruits):\n fruits = build.arg_match(\n fruits, arg_name = 'fruits',\n values = ['apple', 'orange', 'grape'], \n multiple = True\n )\n return fruits\n\nmy_faivarit2(['apple', 'orange'])\n#> ['apple', 'orange']\n\nmy_faivarit2(['apple', 'orang'])\n#> ValueError: `fruits` must be one of 'apple', 'orange' or 'grape', not 'orang'.\n#> Did you mean 'orange'?\n Py4Stats では eda_tools.tabyl()や regression_tools.compare_ols() など、文字列で指定する引数をもつ関数で、引数のアサーションに build.arg_match() を使用しています。\nimport py4stats as py4st\nimport pandas as pd\nfrom palmerpenguins import load_penguins\npenguins = load_penguins() # サンプルデータの読み込\n\npy4st.tabyl(penguins, 'island', 'species', normalize = 'ind')\n#> ValueError: `normalize` must be one of 'index', 'columns' or 'all', not 'ind'.\n#> Did you mean 'index'?\n\nReturn to Function reference.", + "crumbs": [ + "**building_block**", + "32  building_block.arg_match" + ] + }, + { + "objectID": "man/assert_dtype.html", + "href": "man/assert_dtype.html", + "title": "building_block.assert_dtypes", + "section": "", + "text": "概要\nデータ型による引数のアサーション\nR言語の checkmate パッケージの関数群をオマージュした、引数に代入された値が想定されたデータ型ではないときにエラーを出力する関数です。\nそれぞれの関数は第一引数 arg に代入された array-like オブジェクトの要素が、次の型ではない場合にエラーを出力します。", + "crumbs": [ + "**building_block**", + "33  building_block.assert_dtypes" + ] + }, + { + "objectID": "man/assert_dtype.html#概要", + "href": "man/assert_dtype.html#概要", + "title": "building_block.assert_dtypes", + "section": "", + "text": "assert_character(\n arg: Any, \n arg_name: Optional[str] = None,\n len_arg: Optional[int] = None,\n len_min: int = 1,\n len_max: Optional[int] = None,\n any_missing: bool = False,\n all_missing: bool = False,\n nullable: bool = False,\n scalar_only: bool = False\n )\n\nassert_logical(\n arg: Any, \n arg_name: Optional[str] = None,\n len_arg: Optional[int] = None,\n len_min: int = 1,\n len_max: Optional[int] = None,\n any_missing: bool = False,\n all_missing: bool = False,\n nullable: bool = False,\n scalar_only: bool = False\n )\n\nassert_numeric(\n arg: Any,\n arg_name: Optional[str] = None,\n lower = -float('inf'), \n upper = float('inf'), \n inclusive: Literal[\"both\", \"neither\", \"left\", \"right\"] = \"both\",\n len_arg: Optional[int] = None,\n len_min: int = 1,\n len_max: Optional[int] = None,\n any_missing: bool = False,\n all_missing: bool = False,\n nullable: bool = False,\n scalar_only: bool = False\n )\n\nassert_integer(\n arg: Any,\n arg_name: Optional[str] = None,\n lower = -float('inf'), \n upper = float('inf'), \n inclusive: Literal[\"both\", \"neither\", \"left\", \"right\"] = \"both\",\n len_arg: Optional[int] = None,\n len_min: int = 1,\n len_max: Optional[int] = None,\n any_missing: bool = False,\n all_missing: bool = False,\n nullable: bool = False,\n scalar_only: bool = False\n )\n\nassert_count(\n arg: Any,\n arg_name: Optional[str] = None,\n lower = 0, \n upper = float('inf'), \n inclusive: Literal[\"both\", \"neither\", \"left\", \"right\"] = \"both\",\n len_arg: Optional[int] = None,\n len_min: int = 1,\n len_max: Optional[int] = None,\n any_missing: bool = False,\n all_missing: bool = False,\n nullable: bool = False,\n scalar_only: bool = False\n )\n\nassert_float(\n arg: Any,\n arg_name: Optional[str] = None,\n lower = -float('inf'), \n upper = float('inf'), \n inclusive: Literal[\"both\", \"neither\", \"left\", \"right\"] = \"both\",\n len_arg: Optional[int] = None,\n len_min: int = 1,\n len_max: Optional[int] = None,\n any_missing: bool = False,\n all_missing: bool = False,\n nullable: bool = False,\n scalar_only: bool = False\n )\n\n\nassert_character():str\nassert_numeric():int or float\nassert_integer():int\nassert_count():int\nassert_float():float", + "crumbs": [ + "**building_block**", + "33  building_block.assert_dtypes" + ] + }, + { + "objectID": "man/assert_dtype.html#引数-argument", + "href": "man/assert_dtype.html#引数-argument", + "title": "building_block.assert_dtypes", + "section": "引数 Argument", + "text": "引数 Argument\n\narg(必須)array-like  適正かどうかを判断したい引数。検証対象となる引数。スカラー値、または array-like オブジェクト(例:list、NumPy 配列、pandas Series)を指定できます。\narg_name:str  エラーメッセージに表示する引数の名前。None の場合、可能であれば arg に渡された変数名が自動的に推定されます。なお、この機能は varname.argname()関数を使って実装されています。\nlower, upper:int or float  arg に代入されたオブジェクトの要素が取るべき値の最大値と最小値。\ninclusive:str  値の範囲チェックにおいて、境界値を含めるかどうかを表す文字列。 'both', 'neither', 'left', 'right' から選択できます。\n\n'both':lower <= x <= upper\n'neither':lower < x < upper\n'left':lower <= x < upper\n'right':lower < x <= upper\n\nlen_arg: int 引数の要素数を表す自然数:要素数をこの値と正確に一致させたい場合に指定します。len_arg を指定した場合、引数はちょうどこの個数の要素をもつ必要があります。  引数の長さは、None や np.nan などの欠測値を含む要素数をもとに判定されます。例えば引数の要素が arg = [1, None, 3] のとき、len_arg = 3なら正常として判定され、len_arg = 2 ならエラーが出されます。\nlen_min, len_max:: int 許容される最小の要素数と最大の要素数。len_max = None の場合、上限は設けられません。\nany_missing:bool True の場合、欠測値(例:None、NaN、pd.NA など)が引数 arg の一部に含まれていても許容されます。\nall_missing: bool True の場合、すべての要素が欠測値であることを許容します。\nnullable: bool True の場合、引数そのものが None であることを許容します。\nscalar_only: bool True の場合、スカラー値のみを許容します。この場合、1要素であっても、list や配列などの array-like オブジェクトは受け付けません。", + "crumbs": [ + "**building_block**", + "33  building_block.assert_dtypes" + ] + }, + { + "objectID": "man/assert_dtype.html#返り値-value", + "href": "man/assert_dtype.html#返り値-value", + "title": "building_block.assert_dtypes", + "section": "返り値 Value", + "text": "返り値 Value\n引数 arg に代入されたオブジェクトの全ての要素が、アサーションの条件を満たしていれば何も返さず、そうでなければエラーメッセージを出力します。", + "crumbs": [ + "**building_block**", + "33  building_block.assert_dtypes" + ] + }, + { + "objectID": "man/assert_dtype.html#使用例-examples", + "href": "man/assert_dtype.html#使用例-examples", + "title": "building_block.assert_dtypes", + "section": "使用例 Examples", + "text": "使用例 Examples\nfrom py4stats import building_block as build\nx = [1, 2, 3]\ny = ['A', 'B', 'C']\n\nbuild.assert_character(x, arg_name = 'x')\n#> TypeError: Argument `x` must be of type 'str'.\n\nbuild.assert_character(y, arg_name = 'y')\nbuild.assert_numeric(x, arg_name = 'x')\n\nbuild.assert_numeric(y, arg_name = 'y')\n#> TypeError: Argument `y` must be of type 'int' or 'float' with value(s) -inf <= x <= inf.\n\nz = [0.1, 0.3, 0.6]\nbuild.assert_numeric(z, arg_name = 'z', lower = 0, upper = 1)\n\nz.extend([2, 3])\nbuild.assert_numeric(z, arg_name = 'z', lower = 0, upper = 1)\n#> ValueError: Argument `z` must have value 0 <= x <= 1\n#> element '3' and '4' of 'z' not sutisfy the condtion.\n\nz = 1\nbuild.assert_numeric(\n z, arg_name = 'z', \n lower = 0, upper = 1, \n inclusive = 'left'\n )\n#> ValueError: Argument `z` must have value 0 <= x < 1.", + "crumbs": [ + "**building_block**", + "33  building_block.assert_dtypes" + ] + }, + { + "objectID": "man/assert_dtype.html#参照", + "href": "man/assert_dtype.html#参照", + "title": "building_block.assert_dtypes", + "section": "参照", + "text": "参照\n データ型の判定にはこちらの関数を使用しています。\n\nReturn to Function reference.", + "crumbs": [ + "**building_block**", + "33  building_block.assert_dtypes" + ] + }, + { + "objectID": "man/is_dtype.html", + "href": "man/is_dtype.html", + "title": "building_block.is_dtypes", + "section": "", + "text": "概要\nデータ型を判定する論理関数\n代入された値、あるいはリストの要素が特定のデータ型であるかどうかを判定する関数です。基本的には pandas.api.types.is_*() 関数のラッパー関数で、命名規則はR言語の同種の関数に基づいています。", + "crumbs": [ + "**building_block**", + "34  building_block.is_dtypes" + ] + }, + { + "objectID": "man/is_dtype.html#概要", + "href": "man/is_dtype.html#概要", + "title": "building_block.is_dtypes", + "section": "", + "text": "is_character(x)\n\nis_logical(x)\n\nis_numeric(x)\n\nis_integer(x)\n\nis_float(x)", + "crumbs": [ + "**building_block**", + "34  building_block.is_dtypes" + ] + }, + { + "objectID": "man/is_dtype.html#引数-argument", + "href": "man/is_dtype.html#引数-argument", + "title": "building_block.is_dtypes", + "section": "引数 Argument", + "text": "引数 Argument\n\nx(必須)array, list, or pd.Series", + "crumbs": [ + "**building_block**", + "34  building_block.is_dtypes" + ] + }, + { + "objectID": "man/is_dtype.html#返り値-value", + "href": "man/is_dtype.html#返り値-value", + "title": "building_block.is_dtypes", + "section": "返り値 Value", + "text": "返り値 Value\n引数 x が次の型であるときに、True を返します。\n\nis_character():str\nis_logical():bool\nis_numeric():int, float or bool\nis_integer():int or bool\nis_float():float", + "crumbs": [ + "**building_block**", + "34  building_block.is_dtypes" + ] + }, + { + "objectID": "man/is_dtype.html#使用例-examples", + "href": "man/is_dtype.html#使用例-examples", + "title": "building_block.is_dtypes", + "section": "使用例 Examples", + "text": "使用例 Examples\nfrom py4stats import building_block as build\nx_str = ['A', 'B']\nx_bool = [True, False, True]\nx_int = [1, 2, 3]\nx_float = [0, 1, 2.1, 0.5]\nx_list = [x_str, x_bool, x_int, x_float]\n\nprint([build.is_character(x) for x in x_list])\n#> [True, False, False, False]\n\nprint([build.is_logical(x) for x in x_list])\n#> [False, True, False, False]\n\nprint([build.is_numeric(x) for x in x_list])\n#> [False, True, True, True]\n\nprint([build.is_integer(x) for x in x_list])\n#> [False, False, True, False]\n\nprint([build.is_float(x) for x in x_list])\n#> [False, False, False, True]\n\nReturn to Function reference.", + "crumbs": [ + "**building_block**", + "34  building_block.is_dtypes" + ] + }, + { + "objectID": "man/miscellaneous.html", + "href": "man/miscellaneous.html", + "title": "building_block.style_number, style_percent, style_percent", + "section": "", + "text": "概要\n数字のフォーマットを変更する関数", + "crumbs": [ + "**building_block**", + "35  building_block.style_number, style_percent, style_percent" + ] + }, + { + "objectID": "man/miscellaneous.html#概要", + "href": "man/miscellaneous.html#概要", + "title": "building_block.style_number, style_percent, style_percent", + "section": "", + "text": "style_number(x, digits = 2, big_mark = ',')\n\nstyle_currency(x, symbol = '$', digits = 0, big_mark = ',')\n\nstyle_percent(x, digits = 2, unit = 100, symbol = '%')", + "crumbs": [ + "**building_block**", + "35  building_block.style_number, style_percent, style_percent" + ] + }, + { + "objectID": "man/miscellaneous.html#引数-argument", + "href": "man/miscellaneous.html#引数-argument", + "title": "building_block.style_number, style_percent, style_percent", + "section": "引数 Argument", + "text": "引数 Argument\n\nx:scalar or array-like of int or float\np_value:scalar or array-like of int or float\ndigits:int 小数点以下の桁数\nbig_mark:int 3桁毎の桁区切りに使用する記号。カンマ ',', アンダーバー '_', もしくは 非表示 '' から選ぶことができます。\nsymbol:str  貨幣記号を表す文字列", + "crumbs": [ + "**building_block**", + "35  building_block.style_number, style_percent, style_percent" + ] + }, + { + "objectID": "man/miscellaneous.html#返り値-value", + "href": "man/miscellaneous.html#返り値-value", + "title": "building_block.style_number, style_percent, style_percent", + "section": "返り値 Value", + "text": "返り値 Value\n 以下の値をもつ pd.Series を返します。\n\nbuilding_block.style_number(): 任意の数値に対して、小数点以下を桁数 digits に丸め、3桁区切り記号を通過した値を文字列として返します。f-string によるフォーマット f'{x:{big_mark}.{digits}f}' を用いて実装されています。\nbuilding_block.style_currency(): build.style_number() と同じく任意の数値に対して、小数点以下を桁数 digits に丸め、3桁区切り記号を通過した値を文字列として返しますが、さらに貨幣記号を追加します。f-string によるフォーマット f'{symbol}{x:{big_mark}.{digits}f}' を用いて実装されています。\nbuilding_block.style_percent(): 任意の数値をパーセンテージ表示に変換した値を文字列として返します。f-string によるフォーマット f'{x:,.{digits}%}' を用いて実装されています。", + "crumbs": [ + "**building_block**", + "35  building_block.style_number, style_percent, style_percent" + ] + }, + { + "objectID": "man/miscellaneous.html#使用例-examples", + "href": "man/miscellaneous.html#使用例-examples", + "title": "building_block.style_number, style_percent, style_percent", + "section": "使用例 Examples", + "text": "使用例 Examples\nimport numpy as np\nfrom py4stats import building_block as build\n\nx = [2000, 1000, 0.5, 0.11, 0.123]\n\nprint(build.style_number(x).to_list())\n#> ['2,000.00', '1,000.00', '0.50', '0.11', '0.12']\n\nprint(build.style_number(x, big_mark = '').to_list())\n#> ['2000.00', '1000.00', '0.50', '0.11', '0.12']\n\nprint(build.style_currency(x).to_list())\n#> ['$2,000', '$1,000', '$0', '$0', '$0']\npct = [0.11, 0.06, 0.05, 0.01, 0.00234]\n\nprint(build.style_percent(pct).to_list())\n#> ['11.00%', '6.00%', '5.00%', '1.00%', '0.23%']\n\nprint(build.style_percent(pct, unit = 1).to_list())\n#> ['0.11%', '0.06%', '0.05%', '0.01%', '0.00%']\n\nprint(build.style_percent(pct, unit = 1000, symbol = '‰').to_list())\n#> ['110.00‰', '60.00‰', '50.00‰', '10.00‰', '2.34‰']\n\nReturn to Function reference.", + "crumbs": [ + "**building_block**", + "35  building_block.style_number, style_percent, style_percent" + ] + }, + { + "objectID": "man/style_pvalue.html", + "href": "man/style_pvalue.html", + "title": "building_block.style_pvalue, ‘p_stars’", + "section": "", + "text": "概要\np-値のフォーマットを変更する関数\nR言語の style_pvalue() と gtools::stars.pval() をオマージュした関数でp-値を見やすい形のフォーマットに変換します。", + "crumbs": [ + "**building_block**", + "36  building_block.style_pvalue, 'p_stars'" + ] + }, + { + "objectID": "man/style_pvalue.html#概要", + "href": "man/style_pvalue.html#概要", + "title": "building_block.style_pvalue, ‘p_stars’", + "section": "", + "text": "style_pvalue(\n p_value: ArrayLike,\n digits: int = 3,\n prepend_p: bool = False,\n p_min: float = 0.001,\n p_max: float = 0.9\n )\n\np_stars(\n p_value, \n stars = {'***':0.01, '**':0.05, '*':0.1}\n )", + "crumbs": [ + "**building_block**", + "36  building_block.style_pvalue, 'p_stars'" + ] + }, + { + "objectID": "man/style_pvalue.html#引数-argument", + "href": "man/style_pvalue.html#引数-argument", + "title": "building_block.style_pvalue, ‘p_stars’", + "section": "引数 Argument", + "text": "引数 Argument\n\np_value:scalar or array-like of int or float\ndigits:int(style_pvalue() のみ)  小数点以下の桁数\nprepend_p:bool(style_pvalue() のみ)  出区力に接頭辞 ’p’ を追加するかどうかを表す論理値。False であれば追加されず、True であれば追加されます。\np_min:int(style_pvalue() のみ)  p-値を実数値で表示する最小値。p_value がこの値を下回る場合、’<p_min’ もしくは ’p<p_min’ の形で表示されます。\np_max:int(style_pvalue() のみ)  p-値を実数値で表示する最大値。p_value がこの値を下回る場合、’>p_max’ もしくは ’p>p_max’ の形で表示されます。\nstars:dict(p_stars() のみ)  有意性を示す記号を key に、表示を切り替える閾値を値(value)にもつ辞書オブジェクト。初期設定の stars = None の場合、{'***': 0.01, '**': 0.05, '*': 0.1} が使用されます。詳細は下記を参照して下さい。", + "crumbs": [ + "**building_block**", + "36  building_block.style_pvalue, 'p_stars'" + ] + }, + { + "objectID": "man/style_pvalue.html#返り値-value", + "href": "man/style_pvalue.html#返り値-value", + "title": "building_block.style_pvalue, ‘p_stars’", + "section": "返り値 Value", + "text": "返り値 Value\n フォーマットされたp-値を表す pd.Series を出力します。building_block.style_pvalue() では引数 p_value に与えられた数値を指定された桁数に丸めた値を表示し、指定された範囲を外れる値については ’<p_min’ や ’>p_max’の書式にへんかんします。  building_block.p_stars()では仮説検定の有意性を示すアスタリスク*` に変換します。初期設定ではアスタリスクはp-値の値に応じて次のように表示されます。\n\np ≤ 0.1 *\np ≤ 0.05 **\np ≤ 0.01 ***\np > 0.1 表示なし", + "crumbs": [ + "**building_block**", + "36  building_block.style_pvalue, 'p_stars'" + ] + }, + { + "objectID": "man/style_pvalue.html#使用例-examples", + "href": "man/style_pvalue.html#使用例-examples", + "title": "building_block.style_pvalue, ‘p_stars’", + "section": "使用例 Examples", + "text": "使用例 Examples\n\nfrom py4stats import building_block as build\np_value = [\n 0.999, 0.5028, 0.2514, 0.197, 0.10, \n 0.0999, 0.06, 0.03, 0.002, 0.0002\n ]\n\nprint(build.style_pvalue(p_value).to_list())\n#> ['>0.9', '0.503', '0.251', '0.197', '0.1', '0.1', '0.06', '0.03', '0.002', '<0.001']\n\nprint(build.style_pvalue(p_value, prepend_p = True).to_list())\n#> ['p>0.9', 'p=0.503', 'p=0.251', 'p=0.197', 'p=0.1', 'p=0.1', 'p=0.06', 'p=0.03', 'p=0.002', 'p<0.001']\n\nprint(build.p_stars(p_value).to_list())\n#> ['', '', '', '', '*', '*', '*', '**', '***', '***']\n\n# R言語の stats::summary.lm() や gtools::stars.pval() を再現する場合。\nstars_dict = {'***':0.001, '**':0.01, '*': 0.05, '.':0.1}\nprint(build.p_stars(p_value, stars = stars_dict).to_list())\n#> ['', '', '', '', '.', '.', '.', '*', '**', '***']\n\nReturn to Function reference.", + "crumbs": [ + "**building_block**", + "36  building_block.style_pvalue, 'p_stars'" + ] + }, + { + "objectID": "man/oxford_comma.html", + "href": "man/oxford_comma.html", + "title": "oxford_comma", + "section": "", + "text": "概要\n文字列のリストから並列文を作成\n文字列のリストを与えると、リストの要素を英文における並列文の形に変換する関数です。表記法については Wikipedia Serial comma を参照し、コードについては stack overflow:Grammatical List Join in Python [duplicate] を参照しました。", + "crumbs": [ + "**building_block**", + "37  oxford_comma" + ] + }, + { + "objectID": "man/oxford_comma.html#概要", + "href": "man/oxford_comma.html#概要", + "title": "oxford_comma", + "section": "", + "text": "oxford_comma(x, sep_last = 'and', quotation = True)\n\noxford_comma_and(x, quotation = True)\n\noxford_comma_or(x, quotation = True)", + "crumbs": [ + "**building_block**", + "37  oxford_comma" + ] + }, + { + "objectID": "man/oxford_comma.html#引数", + "href": "man/oxford_comma.html#引数", + "title": "oxford_comma", + "section": "引数", + "text": "引数\n\nx:str or list of str\nquotation: bool  リストの各要素にクオーテーションマーク ’’ を追加するかどうかを表す論理値。True(初期設定)であればクオーテーションマークを追加し、False であれば追加しません。\nsep_last: str oxford_comma() のみ  リストの最後の要素の直前に付加する単語を表す文字列。\n\nなお、oxford_comma_and(x) は oxford_comma(x, 'and') と、oxford_comma_or(x) は oxford_comma(x, 'or') と同等です。", + "crumbs": [ + "**building_block**", + "37  oxford_comma" + ] + }, + { + "objectID": "man/oxford_comma.html#使用例", + "href": "man/oxford_comma.html#使用例", + "title": "oxford_comma", + "section": "使用例", + "text": "使用例\nfrom py4stats import building_block as build\nx = ['A', 'B', 'C']\n\nprint(build.oxford_comma_and(x))\n#> 'A', 'B' and 'C'\n\nprint(build.oxford_comma_and(x, quotation = False))\n#> A, B and C\n\nprint(build.oxford_comma_or(x))\n#> 'A', 'B' or 'C'\nリストの要素が1つの場合、あるいは x に文字列が指定された場合はカンマなどを追加せずにそのまま出力します。\nprint(build.oxford_comma_or(['A']))\n#> 'A'\n\nprint(build.oxford_comma_or('A'))\n#> 'A'\n\nReturn to Function reference.", + "crumbs": [ + "**building_block**", + "37  oxford_comma" + ] + }, + { + "objectID": "articles/release_notes.html", + "href": "articles/release_notes.html", + "title": "Release Notes", + "section": "", + "text": "Py4Stats v0.3.0 2026-01-23", + "crumbs": [ + "**Articles**", + "38  Release Notes" + ] + }, + { + "objectID": "articles/release_notes.html#py4stats-v0.3.0-2026-01-23", + "href": "articles/release_notes.html#py4stats-v0.3.0-2026-01-23", + "title": "Release Notes", + "section": "", + "text": "概要(Summary)\nこのリリースでは Pyt4Stats に幾つかの関数の追加を行いました。 関数のリファクタリングとバグ修正を行いました。今回のリリースでは機能の追加や変更はありません。\n\n\n✨ 主な新機能 (New Features)\n\ndiagnose_category() 関数の追加\n\nデータフレームのカテゴリー変数の要約を提供する関数です。\n\nset_miss() 関数の追加\n\nSeries の非欠測要素のうち、指定された個数または割合を欠測値に置き換えます。\n\n\n\n\n🛠 修正と改善(Fixes /Improvements)\n\ncompare_group_means(), compare_group_median(), compare_df_cols(), compare_df_stats(): コードをリファクタリングし、引数と同じクラスのデータフレームを出力できるようにしました。この変更により、返り値が pd.DataFrame である場合でも、index が自動では設定されなくなりました。\ndiagnose(): dtype 列が、polars や pyarrow における列のクラスの表記に対してより忠実になるように修正しました。\nrelocate() 関数に、指定した列を最後列に配置する機能を追加し、エラーメッセージを改善しました。\nassert_character() および assert_numeric() 系関数のエラーメッセージを改善しました。\nその他、いくつかの関数のエラーメッセージを改善しました。", + "crumbs": [ + "**Articles**", + "38  Release Notes" + ] + }, + { + "objectID": "articles/release_notes.html#py4stats-v0.2.2-2026-01-19", + "href": "articles/release_notes.html#py4stats-v0.2.2-2026-01-19", + "title": "Release Notes", + "section": "Py4Stats v0.2.2 2026-01-19", + "text": "Py4Stats v0.2.2 2026-01-19\n\n概要(Summary)\n型ヒントに関する若干の修正と、バグ修正を行いました。今回のリリースでは機能の追加や変更はありません。\n\n\n🛠 修正と改善(Fixes /Improvements)\n\nbuilding_block.assert_numeric 系関数のリファクタリングを行いました。この変更でメインモジュールの関数の動作に変更はありません。\ncompare_group_means(), compare_group_median() のテストコードを実装しました。\ntabyl(): 第一引数 data と同じオブジェクト型をもつ DataFrame を出力できるように実装を修正しました。\ncheck_that(), check_viorate() : 第一引数 data と同じオブジェクト型をもつ DataFrame を出力できるように実装を修正しました。引き続きロジックのコア部分には pd.DataFrame.eval() を使用しており、使用方法に大きな変更はありません。\nis_number() 関数を修正し、pyarrow.lib.ChunkedArray オブジェクトを代入すると生じるエラーを解消しました。", + "crumbs": [ + "**Articles**", + "38  Release Notes" + ] + }, + { + "objectID": "articles/release_notes.html#py4stats-v0.2.1-2026-01-16", + "href": "articles/release_notes.html#py4stats-v0.2.1-2026-01-16", + "title": "Release Notes", + "section": "Py4Stats v0.2.1 2026-01-16", + "text": "Py4Stats v0.2.1 2026-01-16\n\n概要(Summary)\nこのリリースでは Pyt4Stats の各モジュールに幾つかの関数の追加を行いました。\n\n\n✨ 主な新機能 (New Features)\n\nplot_category() 関数の追加\n\nカテゴリ変数の回答分布を 100% 積み上げ横棒グラフとして描画する関数です。\n\nplot_miss_var() 関数の追加\n\nデータフレームの各変数について欠測値の量を横棒グラフとして可視化します。\n\nrelocate() 関数の追加\n\nデータフレームの列を、削除することなく並べ替えます。\n\nweighted_mean(), scale(), min_max() 関数の追加\n\nそれぞれ Series オブジェクトの加重平均の計算と、標準化を行う関数です。\n\n\n\n\n🛠 修正と改善(Fixes /Improvements)\n\neda_tools の Pandas ベース実装 eda_tools/_pands.py に、FutureWarning を実装しました。\nユーザビリティ向上のため、freq_table() 関数に sort_by 引数を導入しました。\n\nsort_by = 'frequency' なら度数分布表を頻度に応じてソートし(従来の sort = True に相当)、sort_by = 'values' なら subset で指定した列の値に応じてソートします(従来の sort = False に相当)。\nこの変更に合わせて、sort 引数は非推奨扱いに変更されています。\n\nPareto_plot() の aggfunc 引数に、np.mean など values 列を1次元配列として受け取って単一の数値を返す任意の関数を使用できるように改良を行いました。\nその他、py4stats ライブラリ全体のエラーメッセージ改善\nbuilding_block.assert_* 系関数の改良を行い、与えられた引数の要素数に関するアサーションと、None やリストを拒否する機能を追加しました。\ncmpare_ols() および cmpare_mfx() に stars 引数を追加し、有意性のアスタリスクの表示形式を変更できる機能を追加しました。また、その他エラーメッセージの改善を行なっています。\n\n\n\n⚠️ 既知の制限・注意点(Notes)\n\npyarrow.Table を使用する場合、plot_category() 関数の一部機能が制限されます。", + "crumbs": [ + "**Articles**", + "38  Release Notes" + ] + }, + { + "objectID": "articles/release_notes.html#py4stats-v0.1.0-2026-01-11", + "href": "articles/release_notes.html#py4stats-v0.1.0-2026-01-11", + "title": "Release Notes", + "section": "Py4Stats v0.1.0 2026-01-11", + "text": "Py4Stats v0.1.0 2026-01-11\n\n概要(Summary)\nこのリリースでは EDA モジュールの narwhals ベース実装を統合し、パフォーマンスと互換性を大幅に改善しました。いくつかの既知の挙動も修正されています。\n\n\n✨ 主な新機能 (New Features)\n\npy4stats.eda_tools が Pandas ベースの実装から narwhals ベース実装へ移行しました。\n\nこの変更により、複数バックエンド(pandas / polars / pyarrow)をサポートしました。\n\nPandas ベースの実装は、当面 py4stats ライブラリのサブモジュール eda_tools._pandas として維持されますが、将来的に廃止される予定です。\n\n\n\n🛠 修正と改善(Fixes /Improvements)\n\nbilding_block モジュールの名称を building_block に修正\nPy4Stats.building_block モジュールの assert_* 系関数の出力を AssertionError から ValueError に変更しました。\nPy4Stats.eda_tools モジュールの関数の bool 値の引数を中心に、型の不一致があった場合のエラーメッセージを改善しました。\n\n\n\n⚠️ 既知の制限・注意点(Notes)\n\nバックエンドの変更に伴い、py4st.freq_table()、py4st.diagnose()、py4st.tabyl() など、従来はインデックス(Index)付きの pandas.DataFrame データフレームが出力されていた関数で、インデックスのない pandas.DataFrame が出力されるように変更されました。\npolars / pyarrow のサポートは experimental であり、一部のエッジケースで動作に違いが出る可能性があります。詳細は Technical Notes および eda_tools開発状況 を参照してください。", + "crumbs": [ + "**Articles**", + "38  Release Notes" + ] + }, + { + "objectID": "articles/scaling_up_regression.html", + "href": "articles/scaling_up_regression.html", + "title": "scaling up regression", + "section": "", + "text": "複数の回帰式を比較する\nここでは実証分析の場面で便利な回帰分析の実装例を紹介します。\n異なる説明変数の組合せを比較したい場合、リスと内包表記を使って実装するとコードが簡潔で扱いやすくなります。まずは smf.ols() をもとに回帰式を受け取って回帰分析の結果を返す関数 fit_ols と、回帰式のリストlist_fml を定義します。\n回帰分析の実行部分は次のように記述します。\nこのとき list_fitted1 は回帰分析の推定結果を要素に持つリストであるため、py4st.compare_ols() にそのまま代入することができます。\nこの方法であれば、試したい回帰式のパターンが増えた場合でも、list_fml の要素を追加するだけで済むため、実行部分を変更する必要がありません。\n また、回帰係数を視覚的に比較するには次のようなコードを使うと良いでしょう。\n## グループ別の回帰分析\n次に、データセットのグループ別に回帰分析を行う場合を考えます。この場合、データを受け取ると回帰分析の結果を返す関数 group_ols を定義し、回帰式は固定しておきます。\n次に pd.DataFrame の .groupby() メソッドを使ってグループ分けを行い、続いて .apply() メソッドを使ってグループ別に回帰分析を実行します。ここでは、実行結果が回帰分析の結果を要素にもつ pd.Series になるので、.to_list() メソッドでリストに変換しています。\nここまでの準備ができれば、後は py4st.compare_ols() で分析結果を比較できます。", + "crumbs": [ + "**Articles**", + "39  scaling up regression" + ] + }, + { + "objectID": "articles/scaling_up_regression.html#複数の回帰式を比較する", + "href": "articles/scaling_up_regression.html#複数の回帰式を比較する", + "title": "scaling up regression", + "section": "", + "text": "# 回帰分析の推定\ndef fit_ols(fml, data):\n res = smf.ols(fml, data = data).fit()\n return res\n\nlist_fml = [\n 'body_mass_g ~ bill_length_mm + species',\n 'body_mass_g ~ bill_length_mm + bill_depth_mm + species',\n 'body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex'\n]\n\n# 回帰分析の実行\nlist_fitted1 = [fit_ols(fml, penguins) for fml in list_fml]\n\npy4st.compare_ols(list_models = list_fitted1) # 表の作成\n\n\n\n\n\n\n\n\n\nterm\nmodel 1\nmodel 2\nmodel 3\n\n\n\n\nIntercept\n153.7397\n-1742.7202 ***\n843.9812 **\n\n\n\n(268.9012)\n(313.7697)\n(403.5956)\n\n\nspecies[T.Chinstrap]\n-885.8121 ***\n-539.6864 ***\n-245.1516 ***\n\n\n\n(88.2502)\n(86.9425)\n(84.5952)\n\n\nspecies[T.Gentoo]\n578.6292 ***\n1492.8283 ***\n1443.3525 ***\n\n\n\n(75.3623)\n(118.4442)\n(107.7844)\n\n\nbill_length_mm\n91.4358 ***\n55.6461 ***\n26.5366 ***\n\n\n\n(6.8871)\n(7.2326)\n(7.2436)\n\n\nbill_depth_mm\n\n179.0434 ***\n87.9328 ***\n\n\n\n\n(19.0997)\n(20.2192)\n\n\nsex[T.male]\n\n\n437.2007 ***\n\n\n\n\n\n(49.1098)\n\n\nrsquared_adj\n0.7810\n0.8258\n0.8613\n\n\nnobs\n342\n342\n333\n\n\ndf\n3\n4\n5\n\n\n\n\nplt.rcParams[\"figure.autolayout\"] = True\n\nfig, ax = plt.subplots(1, 3, figsize = (3.2 * 5, 5), dpi = 100)\n\nfor k, mod in enumerate(list_fitted1):\n py4st.coefplot(mod, ax = ax[k])\n ax[k].set_xlim(-1200, 1800)\n ax[k].set_title(f'model {k + 1}')\n ax[k].set_xlabel(f'coefficient (n = {mod.nobs:,.0f})')\n\n\n# グループ別の回帰分析の実行\ndef group_ols(data):\n res = smf.ols(\n 'body_mass_g ~ bill_length_mm + bill_depth_mm + sex', \n data = data).fit()\n return res\n\npenguins2 = penguins.groupby('species')\n\nlist_fitted2 = penguins2.apply(group_ols).to_list()\n\nlist_groups = list(penguins2.groups.keys())\n\npy4st.compare_ols(\n list_models = list_fitted2,\n model_name = list_groups\n )\n\n\n\nterm\nAdelie\nChinstrap\nGentoo\n\n\n\n\nIntercept\n984.4166\n286.2540\n1829.0302 ***\n\n\n\n(601.1999)\n(980.5230)\n(638.6999)\n\n\nsex[T.male]\n476.6000 ***\n102.9407\n536.5500 ***\n\n\n\n(69.9994)\n(119.3246)\n(80.3899)\n\n\nbill_length_mm\n26.8589 **\n18.4218\n33.6324 ***\n\n\n\n(11.4707)\n(16.0333)\n(11.2907)\n\n\nbill_depth_mm\n78.5228 ***\n135.4873 **\n92.5900 **\n\n\n\n(25.1993)\n(51.1571)\n(41.9318)\n\n\nrsquared_adj\n0.5822\n0.3687\n0.6956\n\n\nnobs\n146\n68\n119\n\n\ndf\n3\n3\n3\n\n\n\nplt.rcParams[\"figure.autolayout\"] = True\n\nfig, ax = plt.subplots(1, 3, figsize = (3.2 * 5, 5), dpi = 100)\n\nfor k, mod in enumerate(list_fitted2):\n py4st.coefplot(mod, ax = ax[k])\n ax[k].set_xlim(-500, 1000)\n ax[k].set_title(list_groups[k])\n ax[k].set_xlabel(f'coefficient (n = {mod.nobs:,.0f})')\n\n\n\nscaling_up_regression2", + "crumbs": [ + "**Articles**", + "39  scaling up regression" + ] + }, + { + "objectID": "articles/scaling_up_regression.html#ブートストラップ回帰", + "href": "articles/scaling_up_regression.html#ブートストラップ回帰", + "title": "scaling up regression", + "section": "ブートストラップ回帰", + "text": "ブートストラップ回帰\n 前節でグループ別の回帰分析を行なった方法を応用すると、ブートストラップ法を簡単に実装することができます。\ndef est_ols(data):\n fitted = smf.ols(\n 'body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex',\n data = data).fit()\n return fitted\n 次にブートストラップ法の実行部分を作成します。ここでは pandas の DataFrame.sample() メソッドを使い、引数に frac = 1, replace = True を指定することで復元抽出を行います。また、ここでは反復回数を Efron, Hastie(2016, p.161)などで推奨されている \\(B = 1000\\) を指定しています。\n# ブートストラップ法の実装\nB = 1000 # ブートストラップ法の反復回数\nmodel_list = [\n penguins.sample(frac = 1, replace = True, random_state = 123)\\\n .pipe(est_ols) \n for b in range(B)\n]\n\nboot_sample = pd.concat([py4st.tidy(mod) for mod in model_list])\n\nlen(boot_sample)\n#> 6000\n次にブートストラップ統計量を集計して結果を確認しますが、ここではごく簡単に py4st.mean_qi() を使って、説明変数別に回帰係数の平均値と分位点を求めています。\nres = boot_sample.groupby(['term'])[['estimate']]\\\n .apply(py4st.mean_qi)\n\nprint(res.round(4))\n#> variable mean lower upper\n#> term \n#> Intercept 0 estimate 823.7098 823.7098 823.7098\n#> bill_depth_mm 0 estimate 109.9439 109.9439 109.9439\n#> bill_length_mm 0 estimate 17.8235 17.8235 17.8235\n#> sex[T.male] 0 estimate 474.2673 474.2673 474.2673\n#> species[T.Chinstrap] 0 estimate -191.4717 -191.4717 -191.4717\n#> species[T.Gentoo] 0 estimate 1487.5680 1487.5680 1487.5680\nブートストラップ法を使うと、次のような回帰係数の分布のグラフを描くこともできます。\nimport ptitprince as pt\n\nfig, ax = plt.subplots(figsize = (np.sqrt(2) * 3, 3), dpi = 150)\n\npt.RainCloud(\n data = boot_sample.sort_index().reset_index()\\\n .query('~term.str.contains(\"Intercept\")'),\n x = 'term',\n y = 'estimate',\n orient = 'h',\n ax = ax\n);\n\nax.axvline(0, ls = \"--\", color = '#969696');\n\n\n\nscaling_up_regression3\n\n\n\n補足\n\nデータセットが大きい場合、ブートストラップ法の実行には時間がかかるので boot_sample.to_csv('output/boot_sample.csv') を追加して保存しておいた方が、事後的な分析がしやすいと思います。\n今回のような通常の回帰分析であれば、回帰係数の標準誤差は簡単に計算できるためブートストラップ法を使う必要性を感じにくいですが、傾向スコアを用いたIPW推定量など、標準誤差の推定にブートストラップ法が必要になる場合もあります。\n今回は DataFrame.sample() メソッドを使ったごく簡単な方法でブートストラップ法を実装していますが、もう少し効率的な方法もあるのではないかと思います。", + "crumbs": [ + "**Articles**", + "39  scaling up regression" + ] + }, + { + "objectID": "articles/scaling_up_regression.html#参考文献", + "href": "articles/scaling_up_regression.html#参考文献", + "title": "scaling up regression", + "section": "参考文献", + "text": "参考文献\n\nEfron, Bradley, and Trevor Hastie. (2016). Computer age statistical inference. Cambridge University Press.\n末石直也(2015)『計量経済学:ミクロデータ分析へのいざない』 日本評論社.", + "crumbs": [ + "**Articles**", + "39  scaling up regression" + ] + }, + { + "objectID": "articles/narwhals_in_py4stats.html", + "href": "articles/narwhals_in_py4stats.html", + "title": "Technical Notes: py4stats.eda_tools における narwhals ベースの実装", + "section": "", + "text": "概要\npy4stats.eda_tools モジュールは、複数の DataFrame バックエンドに対して共通の API を提供することを目的として、narwhals ライブラリを用いて実装されています。\n本ドキュメントでは、本モジュールの内部実装に関する前提条件や、バックエンドの違いに起因する挙動上の注意点について説明します。\n通常の利用にあたって本ドキュメントを読む必要はありませんが、実装の詳細や挙動の違いが気になる場合には参考にしてください。", + "crumbs": [ + "**Articles**", + "40  Technical Notes: py4stats.eda_tools における narwhals ベースの実装" + ] + }, + { + "objectID": "articles/narwhals_in_py4stats.html#対応している-dataframe-バックエンドについて", + "href": "articles/narwhals_in_py4stats.html#対応している-dataframe-バックエンドについて", + "title": "Technical Notes: py4stats.eda_tools における narwhals ベースの実装", + "section": "対応している DataFrame バックエンドについて", + "text": "対応している DataFrame バックエンドについて\n py4stats.eda_tools モジュールの関数は、第一引数として narwhals.from_native() によって nw.DataFrame 型へ変換可能な DataFrame オブジェクトを受け取ります。\n具体的には、以下のようなバックエンドを想定しています。\n\npandas.DataFrame(主に動作検証を行っているバックエンド)\npolars.DataFrame(簡易的な動作確認のみ)\npyarrow.Table(簡易的な動作確認のみ)\n\n本ライブラリの動作確認は、基本的に pandas.DataFrame を用いて実施しています。そのため、polars や pyarrow を使用した場合には、バックエンド固有の仕様差や未検証の挙動により、一部の関数でエラーが発生する可能性があります。そのような挙動が確認された場合は、Issue 等での報告を歓迎します。\n また、バックエンド別の実装状況については eda_tools開発状況 も参照して下さい。", + "crumbs": [ + "**Articles**", + "40  Technical Notes: py4stats.eda_tools における narwhals ベースの実装" + ] + }, + { + "objectID": "articles/narwhals_in_py4stats.html#narwhals-を用いた関数の返り値の型について", + "href": "articles/narwhals_in_py4stats.html#narwhals-を用いた関数の返り値の型について", + "title": "Technical Notes: py4stats.eda_tools における narwhals ベースの実装", + "section": "narwhals を用いた関数の返り値の型について", + "text": "narwhals を用いた関数の返り値の型について\npy4stats.eda_tools モジュールの関数のうち、py4stats.diagnose() など、第一引数にデータフレームを取る関数の返り値の型は、to_native 引数の値によって変化します。  初期設定である to_nativ = True の場合には、第一引数に入力されたデータフレームと同じ型のデータフレームが出力され、to_nativ = False の場合には narwhals.DataFrame 型のデータフレームが出力されます。to_nativ = False のオプションは、主にライブラリ内部での利用や、データフレームのバックエンドに依存しない後続処理を行いたい場合を想定したオプションです。\nimport py4stats as py4st\nimport pandas as pd\nimport polars as pl\nimport pyarrow as pa\nimport wooldridge\nmroz_pd = wooldridge.data('mroz') # pd.DataFrame\nmroz_pl = pl.from_pandas(mroz_pd) # pl.DataFrame\nmroz_pa = pa.Table.from_pandas(mroz_pd) # pyarrow.lib.Table\n# to_nativ = True の場合(初期設定): 入力されたデータフレームと同じ型\n\nprint(type(py4st.diagnose(mroz_pd, to_native = True)))\n#> <class 'pandas.core.frame.DataFrame'>\n\nprint(type(py4st.diagnose(mroz_pl, to_native = True)))\n#> <class 'polars.dataframe.frame.DataFrame'>\n\nprint(type(py4st.diagnose(mroz_pa, to_native = True)))\n#> <class 'pyarrow.lib.Table'>\n# to_nativ = False の場合: narwhals.DataFrame 型\n\nprint(type(py4st.diagnose(mroz_pd, to_native = False)))\n#> <class 'narwhals.dataframe.DataFrame'>\n\nprint(type(py4st.diagnose(mroz_pl, to_native = False)))\n#> <class 'narwhals.dataframe.DataFrame'>\n\nprint(type(py4st.diagnose(mroz_pa, to_native = False)))\n#> <class 'narwhals.dataframe.DataFrame'>", + "crumbs": [ + "**Articles**", + "40  Technical Notes: py4stats.eda_tools における narwhals ベースの実装" + ] + }, + { + "objectID": "articles/narwhals_in_py4stats.html#narwhals-を用いた実装方針について", + "href": "articles/narwhals_in_py4stats.html#narwhals-を用いた実装方針について", + "title": "Technical Notes: py4stats.eda_tools における narwhals ベースの実装", + "section": "narwhals を用いた実装方針について", + "text": "narwhals を用いた実装方針について\n 内部実装では、関数の冒頭で\nnw.from_native(data)\nを用いて入力データを nw.DataFrame に変換し、以降の処理を narwhals の抽象 API 上で行っています。\nこの設計により、DataFrame バックエンドごとの差異を最小限に抑えつつ、将来的な拡張性を確保することを目的としています。\n一方で、narwhals は各バックエンドの完全な互換性を保証するものではないため、特定の操作や型変換についてはバックエンドごとに挙動が異なる場合があります。", + "crumbs": [ + "**Articles**", + "40  Technical Notes: py4stats.eda_tools における narwhals ベースの実装" + ] + }, + { + "objectID": "articles/narwhals_in_py4stats.html#pandas_flavor-を用いた-dataframe-メソッド登録について", + "href": "articles/narwhals_in_py4stats.html#pandas_flavor-を用いた-dataframe-メソッド登録について", + "title": "Technical Notes: py4stats.eda_tools における narwhals ベースの実装", + "section": " pandas_flavor を用いた DataFrame メソッド登録について", + "text": "pandas_flavor を用いた DataFrame メソッド登録について\npy4stats.eda_tools の関数のうち、単一の DataFrame オブジェクトを引数として受け取る関数については、pandas_flavor.register_dataframe_method を用いて DataFrame メソッドとして登録されています。その結果、以下のような使い方が可能です。\ndf.diagnose()\nただし、pandas_flavor は pandas の拡張を前提とした仕組みであるため、このメソッド形式の呼び出しは、pandas.DataFrame を対象としています。  polars.DataFrame や pyarrow ベースのオブジェクトを使用する場合には、関数として直接呼び出す形での利用を推奨します。\nimport py4stats as py4st\n\npy4st.diagnose(df)", + "crumbs": [ + "**Articles**", + "40  Technical Notes: py4stats.eda_tools における narwhals ベースの実装" + ] + }, + { + "objectID": "articles/narwhals_in_py4stats.html#今後について", + "href": "articles/narwhals_in_py4stats.html#今後について", + "title": "Technical Notes: py4stats.eda_tools における narwhals ベースの実装", + "section": "今後について", + "text": "今後について\n py4stats.eda_tools モジュールは、今後も narwhals ベースの実装を主軸として改良・拡張を行っていく予定です。一方で、従来の pandas ベースの実装については、互換性のために当面は保持される予定ですが、機能追加は行わない予定です。バックエンドごとの挙動差や制限事項については、必要に応じて本ドキュメントを更新していきます。", + "crumbs": [ + "**Articles**", + "40  Technical Notes: py4stats.eda_tools における narwhals ベースの実装" + ] + }, + { + "objectID": "articles/eda_tools_development_status.html", + "href": "articles/eda_tools_development_status.html", + "title": "eda_toolsの開発状況", + "section": "", + "text": "関数の実装状況一覧\n2026年1月24日", + "crumbs": [ + "**Articles**", + "41  eda_toolsの開発状況" + ] + }, + { + "objectID": "articles/eda_tools_development_status.html#関数の実装状況一覧", + "href": "articles/eda_tools_development_status.html#関数の実装状況一覧", + "title": "eda_toolsの開発状況", + "section": "", + "text": "関数の実装状況一覧\n\n\n\n\n\n\n\n\n\n\nfunctions\nInput\nPandas\nPolars\nPyarrow\n補足\n\n\n\n\nMean\npd.Series\n✅\n❌\n❌\npd.DataFrame.eval() での使用を想定した関数\n\n\nMedian\npd.Series\n✅\n❌\n❌\npd.DataFrame.eval() での使用を想定した関数\n\n\nMax\npd.Series\n✅\n❌\n❌\npd.DataFrame.eval() での使用を想定した関数\n\n\nMin\npd.Series\n✅\n❌\n❌\npd.DataFrame.eval() での使用を想定した関数\n\n\nPareto_plot\nDataFrame\n✅\n✅\n✅\n\n\n\nSum\npd.Series\n✅\n❌\n❌\npd.DataFrame.eval() での使用を想定した関数\n\n\ncheck_that\nDataFrame\n✅\n⭕️\n⭕️\n実装に pd.DataFrame.eval() を使用\n\n\ncheck_viorate\nDataFrame\n✅\n⭕️\n⭕️\n実装に pd.DataFrame.eval() を使用\n\n\ncompare_df_cols\nDataFrame\n✅\n✅\n✅\n\n\n\ncompare_df_record\nDataFrame\n✅\n✅\n✅\n\n\n\ncompare_df_stats\nDataFrame\n✅\n✅\n✅\n\n\n\ncompare_group_means\nDataFrame\n✅\n✅\n✅\n\n\n\ncompare_group_median\nDataFrame\n✅\n✅\n✅\n\n\n\ncrosstab\nDataFrame\n✅\n✅\n⭕️\nPyarrow は Polars 依存の実装\n\n\ndiagnose\nDataFrame\n✅\n✅\n✅\n\n\n\ndiagnose_category\nDataFrame\n✅\n✅\n✅\n\n\n\nfiltering_out\nDataFrame\n✅\n✅\n✅\n\n\n\nfreq_table\nDataFrame\n✅\n✅\n✅\n\n\n\nimplies_exper\npd.Series\n✅\n❌\n❌\npd.DataFrame.eval() での使用を想定した関数\n\n\nis_dummy\nDataFrame/Series\n✅\n✅\n✅\n\n\n\nis_number\nSeries\n✅\n✅\n✅\n\n\n\nis_ymd_like\nSeries\n✅\n✅\n✅\n\n\n\nis_ymd\nSeries\n✅\n✅\n✅\n\n\n\nmean_ci\nDataFrame/Series\n✅\n✅\n✅\n\n\n\nmean_qi\nDataFrame/Series\n✅\n✅\n✅\n\n\n\nmedian_qi\nDataFrame/Series\n✅\n✅\n✅\n\n\n\nmin_max\nSeries\n✅\n✅\n✅\n\n\n\nplot_mean_diff\nDataFrame\n✅\n✅\n✅\n\n\n\nplot_median_diff\nDataFrame\n✅\n✅\n✅\n\n\n\nplot_miss_var\nDataFrame\n✅\n✅\n✅\n\n\n\nscale\nSeries\n✅\n✅\n✅\n\n\n\nset_miss\nSeries\n✅\n✅\n✅\n\n\n\nrelocate\nDataFrame\n✅\n✅\n✅\n\n\n\nremove_constant\nDataFrame\n✅\n✅\n✅\n\n\n\nremove_empty\nDataFrame\n✅\n✅\n✅\n\n\n\ntabyl\nDataFrame\n✅\n⭕️\n⭕️\n一部の処理が Pandas 依存\n\n\nweighted_mean\nSeries\n✅\n✅\n✅", + "crumbs": [ + "**Articles**", + "41  eda_toolsの開発状況" + ] + }, + { + "objectID": "articles/eda_tools_development_status.html#凡例", + "href": "articles/eda_tools_development_status.html#凡例", + "title": "eda_toolsの開発状況", + "section": "凡例", + "text": "凡例\n\n✅ 実装済/テスト済\n⭕️ 実装済/テスト済(異なるバックエンドに依存)\n🔼 実装済/テスト未\n❌ 未実装", + "crumbs": [ + "**Articles**", + "41  eda_toolsの開発状況" + ] + }, + { + "objectID": "articles/narwhalsについての考察.html", + "href": "articles/narwhalsについての考察.html", + "title": "narwhals についての考察", + "section": "", + "text": "narwhals での再現が難しい Pandas の機能", + "crumbs": [ + "**Articles**", + "42  narwhals についての考察" + ] + }, + { + "objectID": "articles/narwhalsについての考察.html#narwhals-での再現が難しい-pandas-の機能", + "href": "articles/narwhalsについての考察.html#narwhals-での再現が難しい-pandas-の機能", + "title": "narwhals についての考察", + "section": "", + "text": "異なるデータフレーム間の二項演算\nPandas の場合、2つのデータフレーム df1 と df2 が共通の columns と index をもつ限り、df3 = df1 + df2 によって二項演算を行うことができ、このとき、columns と index をもつ要素同士が加算されます。しかし、narwhals には Pandas のような index が存在しないため、この計算は再現が困難です。\n\n\nデータフレームへの値の代入\nPandas の場合、df.loc[i, j] = x という形でデータフレーム df の i, j 要素に値 x を代入することができますが、narwhals ではこれに相当する演算 df[i, j] = x は禁止されています。\n異なるデータフレーム間の二項演算に制約があること、そしてデータフレームへの値の代入が難しいことから、tabyl() 関数では、集計後の作表処理の一部を Pandas に依存しています。\n\n\n任意の関数でグループ別集計を行う\n自作関数を使ってグループ別集計を行いたい場合、Pandas であれば df.groupby(group)[x].agg(my_func) で行うことができます。同じく narwhals でも\ndata_nw.group_by(nw.col(group)).agg(nw.col('x').mean())\nという形でグループ別の集計がサポートされているものの、ここで使用できる集計関数は narwhals で実装されているものに限定されるようで、次のような方法で自作関数を使用することはできません。\ndata_nw.group_by(nw.col(group)).agg(nw.col('x').my_func())\ndata_nw.group_by(nw.col(group)).agg(my_func(nw.col('x')))\n例えば Py4Stats では、Pareto_plot() 関数の内部実装に使用している make_rank_table() 関数において、任意の関数をグループ別集計に使うために、サブセッティングを使って group_by() メソッドの使用を回避するという変則的(かつ、おそらく非効率 )な実装を行なっています。\nstat_values = [\n aggfunc(\n data_nw.filter(nw.col(group) == g)[values]\n .drop_nulls().to_native()\n ) \n for g in group_value\n ]\nまた、上記の回避策のもう1つの問題として、data_nw.filter(nw.col(group) == g) では、複数の変数に基づくグループ化に対応できないことも挙げられます。make_rank_table() 関数については、Pareto_plot() 関数でパレート図を作図するときに横軸になる group が多変数だと対応できないので、group が1変数(= 引数として1つの文字列だけを受け付ける)とすることで妥協しています。\nただ、現時点で narwhals.GroupBy クラスに実装されているメソッドは .agg() しかなく、開発が進めばより柔軟な関数適用が可能になるのではないかと期待しています。", + "crumbs": [ + "**Articles**", + "42  narwhals についての考察" + ] + }, + { + "objectID": "articles/narwhalsについての考察.html#narwhals-におけるバックエンドとその書き換え", + "href": "articles/narwhalsについての考察.html#narwhals-におけるバックエンドとその書き換え", + "title": "narwhals についての考察", + "section": "narwhals におけるバックエンドとその書き換え", + "text": "narwhals におけるバックエンドとその書き換え\n\nバックエンドの基本的な理解\nnarwhals におけるバックエンドによる型変換の基本的な理解として(不正確かもしれませんが)、nw.from_native(data) の実行時に data の型に応じて backend が記録され、.to_native() メソッドを呼び出すと、記録された backend に応じて元の型に変換されます。\nbackend の情報は .select() .filter() などのメソッドを使って data_nw を加工しても保持され、これによって入力された input_pd と同じ型のデータフレームを返すことが可能になっています。\ndata_nw = nw.from_native(input_pd) # ここで backend が記録される\ndata_nw.implementation # -> Pandas\nresult = data_nw.to_native() # -> pd.DataFrame が出力される\n一方で、処理の途中で pd.DataFrame や pl.DataFrame などの native オブジェクトを経由した場合、改めて nw.from_native() を使って nw.DataFrame に変換し直したとしても、その時点で backend が上書きされるので、.to_native() メソッドを使用しても引数として入力された input_pd と同じ型に復元される保証はありません。\ndata_nw = nw.from_native(input_pd) # ここで backend が記録される\ndata_nw2 = nw.from_native(data_nw.to_polars()) # ここで backend が上書きされる\ndata_nw2.implementation # -> polars\nresult = data_nw2.to_native() # -> pl.DataFrame が出力される\n従って、result が input_pd と同じ型をもつことを保証するには、data_nw を nw.DataFrame クラスのまま維持する(≒ narwhals ベースのメソッドだけで処理を書く)必要があり、これが narwhals ベースの実装としてのあるべき姿だと思われます。\n一方で、一部の処理が特定のバックエンド(e.g. Pandas)に依存している場合にはどうするべきでしょうか。これには次のような2つの選択肢があると考えています。\n\n処理が依存しているバックエンドのオブジェクト(e.g. pd.DataFrame)として出力する〔推奨〕\nnarwhals の仕様を迂回してバックエンドを書き換える〔非推奨ですが次節で考察〕\n\nこれら2つの可能性の間での選択は、技術的な問題であると同時にユーザーとのコミュニケーションの問題です。入力と同型のデータフレームを返す関数の中に pd.DataFrame を返す関数が混ざっていることをユーザーにどう説明するのか。あるいは、narwhals の仕様を迂回をしたことで非効率性やカラムレベルでデータ型(dtype)の一貫性が失われる問題が生じたとして、それをユーザーにどう説明するのか、という問いです。\n\n\nバックエンドの書き換え (非推奨)\nいま、some_computation() として実装された処理の一部が Pandas に依存しており、結果が result_pd という pd.DataFrame 型のオブジェクトとして得られているとします。このとき、result_pd をもとのデータフレーム data_pl と同型にする方法の1つとして、result_pd を pd.Series.to_dict() などを使って辞書のリスト(list of dict)に変換したのち、nw.from_dicts() を使って data_pl と同じバックエンドをもつ nw.DataFrame に変換するという方法があります。\n以上の変換の実例を見てみましょう。まずは、data_pl\ndata_pl = pl.from_pandas(load_penguins())[:10, :2]\n\ndata_pl = data_pl.with_columns(\n pl.all().cast(pl.Categorical)\n )\nprint(type(data_pl))\n#> <class 'polars.dataframe.frame.DataFrame'>\nprint(data_pl.schema)\n#> Schema({'species': Categorical, 'island': Categorical})\n\ndata_nw_pl = nw.from_native(data_pl) # ここでバックエンドを記録、後ほど復元に使います。\n\n# 何かしらの処理の結果 pd.DataFrame に変換されたとする\nresult_pd = data_nw_pl.to_pandas()\nprint(type(result_pd))\n#> <class 'pandas.core.frame.DataFrame'>\n次に、pl.DataFrame 型をもつ result_pd を pl.DataFrame に変換します。\nここでポイントとなるのが、nw.from_dicts() 関数の引数の (1)schema 引数と、(2)backend引数に、それぞれ data_nw_pl から取得した値を入力することで、result_pl の列が data_pl と同じく Categorical 型になるようにしています(指定しないと String 型として解釈されてしまいます)。\n# Pandas -> polars の変換\ndict_list = [result_pd.loc[i, :].to_dict() for i in result_pd.index]\n\nresult_nw_pl = nw.from_dicts(\n dict_list, \n schema = data_nw_pl.schema, # (1)\n backend = data_nw_pl.implementation # (2)\n )\nresult_pl = result_nw_pl.to_native()\n\nprint(type(result_pl))\n#> <class 'polars.dataframe.frame.DataFrame'>\n\nprint(result_pl.schema)\n#> Schema({'species': Categorical, 'island': Categorical})\nまた、Series については、nw.Series.from_iterable() 関数を使うことで、次のようにバックエンドを書き換えることができます。\nx_pl = data_pl['island']\nprint(type(x_pl))\n#> <class 'polars.series.series.Series'>\nprint(x_pl.dtype)\n#> Categorical\n\nx_nw = nw.from_native(x_pl, allow_series = True)\nx_pd = x_nw.to_pandas()\nprint(type(x_pd))\n#> <class 'pandas.core.series.Series'>\nx_pl2 = nw.Series.from_iterable(\n name = x_pd.name,\n values = x_pd.to_list(),\n backend = x_nw.implementation,\n dtype = x_nw.dtype\n).to_native()\n\nprint(type(x_pl2))\n#> <class 'polars.series.series.Series'>\nprint(x_pl2.dtype)\n#> Categorical\nnarwhals の仕様を迂回してバックエンドを書き換えることは可能ですが、この方法には次のような問題があります。 ただし、以上のような方法でバックエンドの書き換えは可能ですが、\n\n小さいデータフレームでない限り時間がかかる\n\n恐らく、dict_list を作成するための for ループによるもの\n\n上記の (1) に代入する正しい schema が用意できないと、カラムレベルでデータ型の一貫性保証できない。\n\n特に2番目の問題点については、集計処理によって列名が変わった場合には正しい schema(≒ {列名:dtype} の辞書オブジェクト)を用意することが難しくなります。そして、schema を指定できないと、pd.Categorical、pl.Categorical あるいは pl.Enum といったカテゴリー変数は文字列型に変換されてしまい、データ型の一貫性が失われます。\nカラムレベルで型の一貫性が失われると、返り値が入力値とは異なる型になるよりも把握しづらく、また挙動の予測が難しいため、上記のような処理は採用するとしても、他に方法がないときの最終手段として扱うべきでしょう。", + "crumbs": [ + "**Articles**", + "42  narwhals についての考察" + ] + } +] \ No newline at end of file diff --git a/docs/site_libs/bootstrap/bootstrap-322e28c2ea576fd4147837fb8c5b7a3d.min.css b/docs/site_libs/bootstrap/bootstrap-322e28c2ea576fd4147837fb8c5b7a3d.min.css new file mode 100644 index 0000000..cd9146c --- /dev/null +++ b/docs/site_libs/bootstrap/bootstrap-322e28c2ea576fd4147837fb8c5b7a3d.min.css @@ -0,0 +1,12 @@ +/*! + * Bootstrap v5.3.1 (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */@import"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap";:root,[data-bs-theme=light]{--bs-blue: #2780e3;--bs-indigo: #6610f2;--bs-purple: #613d7c;--bs-pink: #e83e8c;--bs-red: #ff0039;--bs-orange: #f0ad4e;--bs-yellow: #ff7518;--bs-green: #3fb618;--bs-teal: #20c997;--bs-cyan: #9954bb;--bs-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-default: #343a40;--bs-primary: #2780e3;--bs-secondary: #343a40;--bs-success: #3fb618;--bs-info: #9954bb;--bs-warning: #ff7518;--bs-danger: #ff0039;--bs-light: #f8f9fa;--bs-dark: #343a40;--bs-default-rgb: 52, 58, 64;--bs-primary-rgb: 39, 128, 227;--bs-secondary-rgb: 52, 58, 64;--bs-success-rgb: 63, 182, 24;--bs-info-rgb: 153, 84, 187;--bs-warning-rgb: 255, 117, 24;--bs-danger-rgb: 255, 0, 57;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 52, 58, 64;--bs-primary-text-emphasis: rgb(15.6, 51.2, 90.8);--bs-secondary-text-emphasis: rgb(20.8, 23.2, 25.6);--bs-success-text-emphasis: rgb(25.2, 72.8, 9.6);--bs-info-text-emphasis: rgb(61.2, 33.6, 74.8);--bs-warning-text-emphasis: rgb(102, 46.8, 9.6);--bs-danger-text-emphasis: rgb(102, 0, 22.8);--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: rgb(211.8, 229.6, 249.4);--bs-secondary-bg-subtle: rgb(214.4, 215.6, 216.8);--bs-success-bg-subtle: rgb(216.6, 240.4, 208.8);--bs-info-bg-subtle: rgb(234.6, 220.8, 241.4);--bs-warning-bg-subtle: rgb(255, 227.4, 208.8);--bs-danger-bg-subtle: rgb(255, 204, 215.4);--bs-light-bg-subtle: rgb(251.5, 252, 252.5);--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: rgb(168.6, 204.2, 243.8);--bs-secondary-border-subtle: rgb(173.8, 176.2, 178.6);--bs-success-border-subtle: rgb(178.2, 225.8, 162.6);--bs-info-border-subtle: rgb(214.2, 186.6, 227.8);--bs-warning-border-subtle: rgb(255, 199.8, 162.6);--bs-danger-border-subtle: rgb(255, 153, 175.8);--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-body-font-size:1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #343a40;--bs-body-color-rgb: 52, 58, 64;--bs-body-bg: #fff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(52, 58, 64, 0.75);--bs-secondary-color-rgb: 52, 58, 64;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(52, 58, 64, 0.5);--bs-tertiary-color-rgb: 52, 58, 64;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #2761e3;--bs-link-color-rgb: 39, 97, 227;--bs-link-decoration: underline;--bs-link-hover-color: rgb(31.2, 77.6, 181.6);--bs-link-hover-color-rgb: 31, 78, 182;--bs-code-color: #7d12ba;--bs-highlight-bg: rgb(255, 227.4, 208.8);--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0.25rem;--bs-border-radius-sm: 0.2em;--bs-border-radius-lg: 0.5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(39, 128, 227, 0.25);--bs-form-valid-color: #3fb618;--bs-form-valid-border-color: #3fb618;--bs-form-invalid-color: #ff0039;--bs-form-invalid-border-color: #ff0039}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: rgb(42.5, 47.5, 52.5);--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: rgb(125.4, 178.8, 238.2);--bs-secondary-text-emphasis: rgb(133.2, 136.8, 140.4);--bs-success-text-emphasis: rgb(139.8, 211.2, 116.4);--bs-info-text-emphasis: rgb(193.8, 152.4, 214.2);--bs-warning-text-emphasis: rgb(255, 172.2, 116.4);--bs-danger-text-emphasis: rgb(255, 102, 136.2);--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: rgb(7.8, 25.6, 45.4);--bs-secondary-bg-subtle: rgb(10.4, 11.6, 12.8);--bs-success-bg-subtle: rgb(12.6, 36.4, 4.8);--bs-info-bg-subtle: rgb(30.6, 16.8, 37.4);--bs-warning-bg-subtle: rgb(51, 23.4, 4.8);--bs-danger-bg-subtle: rgb(51, 0, 11.4);--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: rgb(23.4, 76.8, 136.2);--bs-secondary-border-subtle: rgb(31.2, 34.8, 38.4);--bs-success-border-subtle: rgb(37.8, 109.2, 14.4);--bs-info-border-subtle: rgb(91.8, 50.4, 112.2);--bs-warning-border-subtle: rgb(153, 70.2, 14.4);--bs-danger-border-subtle: rgb(153, 0, 34.2);--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: rgb(125.4, 178.8, 238.2);--bs-link-hover-color: rgb(151.32, 194.04, 241.56);--bs-link-color-rgb: 125, 179, 238;--bs-link-hover-color-rgb: 151, 194, 242;--bs-code-color: white;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: rgb(139.8, 211.2, 116.4);--bs-form-valid-border-color: rgb(139.8, 211.2, 116.4);--bs-form-invalid-color: rgb(255, 102, 136.2);--bs-form-invalid-border-color: rgb(255, 102, 136.2)}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:1px solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f8f9fa;line-height:1.5;padding:.5rem;border:1px solid var(--bs-border-color, #dee2e6)}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);background-color:#f8f9fa;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#343a40}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:rgba(52,58,64,.75);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none !important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:rgba(52,58,64,.75)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-right:auto;margin-left:auto}@media(min-width: 576px){.container-sm,.container{max-width:540px}}@media(min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}body.quarto-light .dark-content{display:none !important}body.quarto-dark .light-content{display:none !important}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: #343a40;--bs-table-bg: #fff;--bs-table-border-color: #dee2e6;--bs-table-accent-bg: transparent;--bs-table-striped-color: #343a40;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #343a40;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #343a40;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(1px*2) solid rgb(153.5,156.5,159.5)}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: rgb(211.8, 229.6, 249.4);--bs-table-border-color: rgb(190.62, 206.64, 224.46);--bs-table-striped-bg: rgb(201.21, 218.12, 236.93);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(190.62, 206.64, 224.46);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(195.915, 212.38, 230.695);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: rgb(214.4, 215.6, 216.8);--bs-table-border-color: rgb(192.96, 194.04, 195.12);--bs-table-striped-bg: rgb(203.68, 204.82, 205.96);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(192.96, 194.04, 195.12);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(198.32, 199.43, 200.54);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: rgb(216.6, 240.4, 208.8);--bs-table-border-color: rgb(194.94, 216.36, 187.92);--bs-table-striped-bg: rgb(205.77, 228.38, 198.36);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(194.94, 216.36, 187.92);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(200.355, 222.37, 193.14);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: rgb(234.6, 220.8, 241.4);--bs-table-border-color: rgb(211.14, 198.72, 217.26);--bs-table-striped-bg: rgb(222.87, 209.76, 229.33);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(211.14, 198.72, 217.26);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(217.005, 204.24, 223.295);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: rgb(255, 227.4, 208.8);--bs-table-border-color: rgb(229.5, 204.66, 187.92);--bs-table-striped-bg: rgb(242.25, 216.03, 198.36);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(229.5, 204.66, 187.92);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(235.875, 210.345, 193.14);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: rgb(255, 204, 215.4);--bs-table-border-color: rgb(229.5, 183.6, 193.86);--bs-table-striped-bg: rgb(242.25, 193.8, 204.63);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(229.5, 183.6, 193.86);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(235.875, 188.7, 199.245);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: rgb(223.2, 224.1, 225);--bs-table-striped-bg: rgb(235.6, 236.55, 237.5);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(223.2, 224.1, 225);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(229.4, 230.325, 231.25);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #343a40;--bs-table-border-color: rgb(72.3, 77.7, 83.1);--bs-table-striped-bg: rgb(62.15, 67.85, 73.55);--bs-table-striped-color: #fff;--bs-table-active-bg: rgb(72.3, 77.7, 83.1);--bs-table-active-color: #fff;--bs-table-hover-bg: rgb(67.225, 72.775, 78.325);--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:rgba(52,58,64,.75)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-clip:padding-box;border:1px solid #dee2e6;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#343a40;background-color:#fff;border-color:rgb(147,191.5,241);outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:rgba(52,58,64,.75);opacity:1}.form-control:disabled{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#343a40;background-color:#f8f9fa;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#e9ecef}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#343a40;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2));padding:.25rem .5rem;font-size:0.875rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2));padding:.5rem 1rem;font-size:1.25rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + calc(1px * 2))}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2))}.form-control-color{width:3rem;height:calc(1.5em + 0.75rem + calc(1px * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important}.form-control-color::-webkit-color-swatch{border:0 !important}.form-control-color.form-control-sm{height:calc(1.5em + 0.5rem + calc(1px * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(1px * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #dee2e6;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:rgb(147,191.5,241);outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #343a40}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-reverse{padding-right:0;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:0;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{--bs-form-check-bg: #fff;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid #dee2e6;print-color-adjust:exact}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:rgb(147,191.5,241);outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#2780e3;border-color:#2780e3}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#2780e3;border-color:#2780e3;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{cursor:default;opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgb%28147, 191.5, 241%29'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:rgb(190.2,216.9,246.6)}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0)}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:rgb(190.2,216.9,246.6)}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:rgba(52,58,64,.75)}.form-range:disabled::-moz-range-thumb{background-color:rgba(52,58,64,.75)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(1px * 2));min-height:calc(3.5rem + calc(1px * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-control-plaintext~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:#fff}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:1px 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:#e9ecef}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;text-align:center;white-space:nowrap;background-color:#f8f9fa;border:1px solid #dee2e6}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(1px*-1)}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#3fb618}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#3fb618}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#3fb618;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#3fb618}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#3fb618}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#3fb618}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#3fb618}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#ff0039}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#ff0039}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#ff0039;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#ff0039}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#ff0039}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#ff0039}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#ff0039}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: 0.75rem;--bs-btn-padding-y: 0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: #343a40;--bs-btn-bg: transparent;--bs-btn-border-width: 1px;--bs-btn-border-color: transparent;--bs-btn-border-radius: 0.25rem;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 0.65;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-default{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(44.2, 49.3, 54.4);--bs-btn-hover-border-color: rgb(41.6, 46.4, 51.2);--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(41.6, 46.4, 51.2);--bs-btn-active-border-color: rgb(39, 43.5, 48);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-primary{--bs-btn-color: #fff;--bs-btn-bg: #2780e3;--bs-btn-border-color: #2780e3;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(33.15, 108.8, 192.95);--bs-btn-hover-border-color: rgb(31.2, 102.4, 181.6);--bs-btn-focus-shadow-rgb: 71, 147, 231;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(31.2, 102.4, 181.6);--bs-btn-active-border-color: rgb(29.25, 96, 170.25);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #2780e3;--bs-btn-disabled-border-color: #2780e3}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(44.2, 49.3, 54.4);--bs-btn-hover-border-color: rgb(41.6, 46.4, 51.2);--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(41.6, 46.4, 51.2);--bs-btn-active-border-color: rgb(39, 43.5, 48);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-success{--bs-btn-color: #fff;--bs-btn-bg: #3fb618;--bs-btn-border-color: #3fb618;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(53.55, 154.7, 20.4);--bs-btn-hover-border-color: rgb(50.4, 145.6, 19.2);--bs-btn-focus-shadow-rgb: 92, 193, 59;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(50.4, 145.6, 19.2);--bs-btn-active-border-color: rgb(47.25, 136.5, 18);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #3fb618;--bs-btn-disabled-border-color: #3fb618}.btn-info{--bs-btn-color: #fff;--bs-btn-bg: #9954bb;--bs-btn-border-color: #9954bb;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(130.05, 71.4, 158.95);--bs-btn-hover-border-color: rgb(122.4, 67.2, 149.6);--bs-btn-focus-shadow-rgb: 168, 110, 197;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(122.4, 67.2, 149.6);--bs-btn-active-border-color: rgb(114.75, 63, 140.25);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #9954bb;--bs-btn-disabled-border-color: #9954bb}.btn-warning{--bs-btn-color: #fff;--bs-btn-bg: #ff7518;--bs-btn-border-color: #ff7518;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(216.75, 99.45, 20.4);--bs-btn-hover-border-color: rgb(204, 93.6, 19.2);--bs-btn-focus-shadow-rgb: 255, 138, 59;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(204, 93.6, 19.2);--bs-btn-active-border-color: rgb(191.25, 87.75, 18);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #ff7518;--bs-btn-disabled-border-color: #ff7518}.btn-danger{--bs-btn-color: #fff;--bs-btn-bg: #ff0039;--bs-btn-border-color: #ff0039;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(216.75, 0, 48.45);--bs-btn-hover-border-color: rgb(204, 0, 45.6);--bs-btn-focus-shadow-rgb: 255, 38, 87;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(204, 0, 45.6);--bs-btn-active-border-color: rgb(191.25, 0, 42.75);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #ff0039;--bs-btn-disabled-border-color: #ff0039}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: rgb(210.8, 211.65, 212.5);--bs-btn-hover-border-color: rgb(198.4, 199.2, 200);--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: rgb(198.4, 199.2, 200);--bs-btn-active-border-color: rgb(186, 186.75, 187.5);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(82.45, 87.55, 92.65);--bs-btn-hover-border-color: rgb(72.3, 77.7, 83.1);--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(92.6, 97.4, 102.2);--bs-btn-active-border-color: rgb(72.3, 77.7, 83.1);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-outline-default{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-primary{--bs-btn-color: #2780e3;--bs-btn-border-color: #2780e3;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #2780e3;--bs-btn-hover-border-color: #2780e3;--bs-btn-focus-shadow-rgb: 39, 128, 227;--bs-btn-active-color: #fff;--bs-btn-active-bg: #2780e3;--bs-btn-active-border-color: #2780e3;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #2780e3;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #2780e3;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #3fb618;--bs-btn-border-color: #3fb618;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #3fb618;--bs-btn-hover-border-color: #3fb618;--bs-btn-focus-shadow-rgb: 63, 182, 24;--bs-btn-active-color: #fff;--bs-btn-active-bg: #3fb618;--bs-btn-active-border-color: #3fb618;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #3fb618;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #3fb618;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #9954bb;--bs-btn-border-color: #9954bb;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #9954bb;--bs-btn-hover-border-color: #9954bb;--bs-btn-focus-shadow-rgb: 153, 84, 187;--bs-btn-active-color: #fff;--bs-btn-active-bg: #9954bb;--bs-btn-active-border-color: #9954bb;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #9954bb;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #9954bb;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ff7518;--bs-btn-border-color: #ff7518;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #ff7518;--bs-btn-hover-border-color: #ff7518;--bs-btn-focus-shadow-rgb: 255, 117, 24;--bs-btn-active-color: #fff;--bs-btn-active-bg: #ff7518;--bs-btn-active-border-color: #ff7518;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ff7518;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ff7518;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #ff0039;--bs-btn-border-color: #ff0039;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #ff0039;--bs-btn-hover-border-color: #ff0039;--bs-btn-focus-shadow-rgb: 255, 0, 57;--bs-btn-active-color: #fff;--bs-btn-active-bg: #ff0039;--bs-btn-active-border-color: #ff0039;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ff0039;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ff0039;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: #2761e3;--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: rgb(31.2, 77.6, 181.6);--bs-btn-hover-border-color: transparent;--bs-btn-active-color: rgb(31.2, 77.6, 181.6);--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 71, 121, 231;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius: 0.5rem}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: 0.2em}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color: #343a40;--bs-dropdown-bg: #fff;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-border-radius: 0.25rem;--bs-dropdown-border-width: 1px;--bs-dropdown-inner-border-radius: calc(0.25rem - 1px);--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-dropdown-link-color: #343a40;--bs-dropdown-link-hover-color: #343a40;--bs-dropdown-link-hover-bg: #f8f9fa;--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #2780e3;--bs-dropdown-link-disabled-color: rgba(52, 58, 64, 0.5);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #2780e3;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(1px*-1)}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(1px*-1)}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: #2761e3;--bs-nav-link-hover-color: rgb(31.2, 77.6, 181.6);--bs-nav-link-disabled-color: rgba(52, 58, 64, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 1px;--bs-nav-tabs-border-color: #dee2e6;--bs-nav-tabs-border-radius: 0.25rem;--bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color: #000;--bs-nav-tabs-link-active-bg: #fff;--bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #fff;border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width))}.nav-pills{--bs-nav-pills-border-radius: 0.25rem;--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #2780e3}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: #000;gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: rgb(84.32, 84.66, 85);--bs-navbar-hover-color: rgba(31.2, 77.6, 181.6, 0.8);--bs-navbar-disabled-color: rgba(84.32, 84.66, 85, 0.75);--bs-navbar-active-color: rgb(31.2, 77.6, 181.6);--bs-navbar-brand-padding-y: 0.3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: rgb(84.32, 84.66, 85);--bs-navbar-brand-hover-color: rgb(31.2, 77.6, 181.6);--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25;--bs-navbar-toggler-padding-x: 0;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgb%2884.32, 84.66, 85%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(84.32, 84.66, 85, 0);--bs-navbar-toggler-border-radius: 0.25rem;--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);transition:var(--bs-navbar-toggler-transition)}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: rgb(84.32, 84.66, 85);--bs-navbar-hover-color: rgba(31.2, 77.6, 181.6, 0.8);--bs-navbar-disabled-color: rgba(84.32, 84.66, 85, 0.75);--bs-navbar-active-color: rgb(31.2, 77.6, 181.6);--bs-navbar-brand-color: rgb(84.32, 84.66, 85);--bs-navbar-brand-hover-color: rgb(31.2, 77.6, 181.6);--bs-navbar-toggler-border-color: rgba(84.32, 84.66, 85, 0);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgb%2884.32, 84.66, 85%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgb%2884.32, 84.66, 85%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: 1px;--bs-card-border-color: rgba(0, 0, 0, 0.175);--bs-card-border-radius: 0.25rem;--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(0.25rem - 1px);--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(52, 58, 64, 0.25);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: #fff;--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion{--bs-accordion-color: #343a40;--bs-accordion-bg: #fff;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: #dee2e6;--bs-accordion-border-width: 1px;--bs-accordion-border-radius: 0.25rem;--bs-accordion-inner-border-radius: calc(0.25rem - 1px);--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: #343a40;--bs-accordion-btn-bg: #fff;--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23343a40'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='rgb%2815.6, 51.2, 90.8%29'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: rgb(147, 191.5, 241);--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: rgb(15.6, 51.2, 90.8);--bs-accordion-active-bg: rgb(211.8, 229.6, 249.4)}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='rgb%28125.4, 178.8, 238.2%29'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='rgb%28125.4, 178.8, 238.2%29'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: rgba(52, 58, 64, 0.75);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: rgba(52, 58, 64, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color: #2761e3;--bs-pagination-bg: #fff;--bs-pagination-border-width: 1px;--bs-pagination-border-color: #dee2e6;--bs-pagination-border-radius: 0.25rem;--bs-pagination-hover-color: rgb(31.2, 77.6, 181.6);--bs-pagination-hover-bg: #f8f9fa;--bs-pagination-hover-border-color: #dee2e6;--bs-pagination-focus-color: rgb(31.2, 77.6, 181.6);--bs-pagination-focus-bg: #e9ecef;--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #2780e3;--bs-pagination-active-border-color: #2780e3;--bs-pagination-disabled-color: rgba(52, 58, 64, 0.75);--bs-pagination-disabled-bg: #e9ecef;--bs-pagination-disabled-border-color: #dee2e6;display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(1px*-1)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius: 0.5rem}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: 0.2em}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: 0.25rem;display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: 0 solid var(--bs-alert-border-color);--bs-alert-border-radius: 0.25rem;--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{--bs-alert-color: var(--bs-default-text-emphasis);--bs-alert-bg: var(--bs-default-bg-subtle);--bs-alert-border-color: var(--bs-default-border-subtle);--bs-alert-link-color: var(--bs-default-text-emphasis)}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress,.progress-stacked{--bs-progress-height: 0.5rem;--bs-progress-font-size:0.75rem;--bs-progress-bg: #e9ecef;--bs-progress-border-radius: 0.25rem;--bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #2780e3;--bs-progress-bar-transition: width 0.6s ease;display:flex;display:-webkit-flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg)}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: #343a40;--bs-list-group-bg: #fff;--bs-list-group-border-color: #dee2e6;--bs-list-group-border-width: 1px;--bs-list-group-border-radius: 0.25rem;--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: rgba(52, 58, 64, 0.75);--bs-list-group-action-hover-color: #000;--bs-list-group-action-hover-bg: #f8f9fa;--bs-list-group-action-active-color: #343a40;--bs-list-group-action-active-bg: #e9ecef;--bs-list-group-disabled-color: rgba(52, 58, 64, 0.75);--bs-list-group-disabled-bg: #fff;--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #2780e3;--bs-list-group-active-border-color: #2780e3;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{--bs-list-group-color: var(--bs-default-text-emphasis);--bs-list-group-bg: var(--bs-default-bg-subtle);--bs-list-group-border-color: var(--bs-default-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-default-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-default-border-subtle);--bs-list-group-active-color: var(--bs-default-bg-subtle);--bs-list-group-active-bg: var(--bs-default-text-emphasis);--bs-list-group-active-border-color: var(--bs-default-text-emphasis)}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(255, 255, 255, 0.85);--bs-toast-border-width: 1px;--bs-toast-border-color: rgba(0, 0, 0, 0.175);--bs-toast-border-radius: 0.25rem;--bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-toast-header-color: rgba(52, 58, 64, 0.75);--bs-toast-header-bg: rgba(255, 255, 255, 0.85);--bs-toast-header-border-color: rgba(0, 0, 0, 0.175);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color)}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: #fff;--bs-modal-border-color: rgba(0, 0, 0, 0.175);--bs-modal-border-width: 1px;--bs-modal-border-radius: 0.5rem;--bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-modal-inner-border-radius: calc(0.5rem - 1px);--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: #dee2e6;--bs-modal-header-border-width: 1px;--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: #dee2e6;--bs-modal-footer-border-width: 1px;position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color: #fff;--bs-tooltip-bg: #000;--bs-tooltip-border-radius: 0.25rem;--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.875rem;--bs-popover-bg: #fff;--bs-popover-border-width: 1px;--bs-popover-border-color: rgba(0, 0, 0, 0.175);--bs-popover-border-radius: 0.5rem;--bs-popover-inner-border-radius: calc(0.5rem - 1px);--bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: #e9ecef;--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: #343a40;--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: #343a40;--bs-offcanvas-bg: #fff;--bs-offcanvas-border-width: 1px;--bs-offcanvas-border-color: rgba(0, 0, 0, 0.175);--bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 575.98px)and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media(max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 767.98px)and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media(max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 991.98px)and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media(max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1199.98px)and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media(max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1399.98px)and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media(max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin-top:calc(-0.5*var(--bs-offcanvas-padding-y));margin-right:calc(-0.5*var(--bs-offcanvas-padding-x));margin-bottom:calc(-0.5*var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-default{color:#fff !important;background-color:RGBA(var(--bs-default-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-primary{color:#fff !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#fff !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#fff !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#fff !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#fff !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-default{color:RGBA(var(--bs-default-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-default-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-default:hover,.link-default:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(31, 102, 182, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(31, 102, 182, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(50, 146, 19, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(50, 146, 19, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(122, 67, 150, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(122, 67, 150, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(204, 94, 19, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(204, 94, 19, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(204, 0, 46, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(204, 0, 46, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;-webkit-flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{object-fit:contain !important}.object-fit-cover{object-fit:cover !important}.object-fit-fill{object-fit:fill !important}.object-fit-scale{object-fit:scale-down !important}.object-fit-none{object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.overflow-x-auto{overflow-x:auto !important}.overflow-x-hidden{overflow-x:hidden !important}.overflow-x-visible{overflow-x:visible !important}.overflow-x-scroll{overflow-x:scroll !important}.overflow-y-auto{overflow-y:auto !important}.overflow-y-hidden{overflow-y:hidden !important}.overflow-y-visible{overflow-y:visible !important}.overflow-y-scroll{overflow-y:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-inline-grid{display:inline-grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.focus-ring-default{--bs-focus-ring-color: rgba(var(--bs-default-rgb), var(--bs-focus-ring-opacity))}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-default{--bs-border-opacity: 1;border-color:rgba(var(--bs-default-rgb), var(--bs-border-opacity)) !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle) !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.border-opacity-10{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.row-gap-0{row-gap:0 !important}.row-gap-1{row-gap:.25rem !important}.row-gap-2{row-gap:.5rem !important}.row-gap-3{row-gap:1rem !important}.row-gap-4{row-gap:1.5rem !important}.row-gap-5{row-gap:3rem !important}.column-gap-0{column-gap:0 !important}.column-gap-1{column-gap:.25rem !important}.column-gap-2{column-gap:.5rem !important}.column-gap-3{column-gap:1rem !important}.column-gap-4{column-gap:1.5rem !important}.column-gap-5{column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-lighter{font-weight:lighter !important}.fw-light{font-weight:300 !important}.fw-normal{font-weight:400 !important}.fw-medium{font-weight:500 !important}.fw-semibold{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:hsla(0,0%,100%,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-default{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-default-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-border-radius-xxl) !important}.rounded-top-circle{border-top-left-radius:50% !important;border-top-right-radius:50% !important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-0{border-top-right-radius:0 !important;border-bottom-right-radius:0 !important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-border-radius-xxl) !important}.rounded-end-circle{border-top-right-radius:50% !important;border-bottom-right-radius:50% !important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-0{border-bottom-right-radius:0 !important;border-bottom-left-radius:0 !important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-border-radius-xxl) !important}.rounded-bottom-circle{border-bottom-right-radius:50% !important;border-bottom-left-radius:50% !important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-0{border-bottom-left-radius:0 !important;border-top-left-radius:0 !important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-border-radius-xxl) !important}.rounded-start-circle{border-bottom-left-radius:50% !important;border-top-left-radius:50% !important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-border-radius-pill) !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.z-n1{z-index:-1 !important}.z-0{z-index:0 !important}.z-1{z-index:1 !important}.z-2{z-index:2 !important}.z-3{z-index:3 !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.object-fit-sm-contain{object-fit:contain !important}.object-fit-sm-cover{object-fit:cover !important}.object-fit-sm-fill{object-fit:fill !important}.object-fit-sm-scale{object-fit:scale-down !important}.object-fit-sm-none{object-fit:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-inline-grid{display:inline-grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.row-gap-sm-0{row-gap:0 !important}.row-gap-sm-1{row-gap:.25rem !important}.row-gap-sm-2{row-gap:.5rem !important}.row-gap-sm-3{row-gap:1rem !important}.row-gap-sm-4{row-gap:1.5rem !important}.row-gap-sm-5{row-gap:3rem !important}.column-gap-sm-0{column-gap:0 !important}.column-gap-sm-1{column-gap:.25rem !important}.column-gap-sm-2{column-gap:.5rem !important}.column-gap-sm-3{column-gap:1rem !important}.column-gap-sm-4{column-gap:1.5rem !important}.column-gap-sm-5{column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{object-fit:contain !important}.object-fit-md-cover{object-fit:cover !important}.object-fit-md-fill{object-fit:fill !important}.object-fit-md-scale{object-fit:scale-down !important}.object-fit-md-none{object-fit:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-inline-grid{display:inline-grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.row-gap-md-0{row-gap:0 !important}.row-gap-md-1{row-gap:.25rem !important}.row-gap-md-2{row-gap:.5rem !important}.row-gap-md-3{row-gap:1rem !important}.row-gap-md-4{row-gap:1.5rem !important}.row-gap-md-5{row-gap:3rem !important}.column-gap-md-0{column-gap:0 !important}.column-gap-md-1{column-gap:.25rem !important}.column-gap-md-2{column-gap:.5rem !important}.column-gap-md-3{column-gap:1rem !important}.column-gap-md-4{column-gap:1.5rem !important}.column-gap-md-5{column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{object-fit:contain !important}.object-fit-lg-cover{object-fit:cover !important}.object-fit-lg-fill{object-fit:fill !important}.object-fit-lg-scale{object-fit:scale-down !important}.object-fit-lg-none{object-fit:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-inline-grid{display:inline-grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.row-gap-lg-0{row-gap:0 !important}.row-gap-lg-1{row-gap:.25rem !important}.row-gap-lg-2{row-gap:.5rem !important}.row-gap-lg-3{row-gap:1rem !important}.row-gap-lg-4{row-gap:1.5rem !important}.row-gap-lg-5{row-gap:3rem !important}.column-gap-lg-0{column-gap:0 !important}.column-gap-lg-1{column-gap:.25rem !important}.column-gap-lg-2{column-gap:.5rem !important}.column-gap-lg-3{column-gap:1rem !important}.column-gap-lg-4{column-gap:1.5rem !important}.column-gap-lg-5{column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{object-fit:contain !important}.object-fit-xl-cover{object-fit:cover !important}.object-fit-xl-fill{object-fit:fill !important}.object-fit-xl-scale{object-fit:scale-down !important}.object-fit-xl-none{object-fit:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-inline-grid{display:inline-grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.row-gap-xl-0{row-gap:0 !important}.row-gap-xl-1{row-gap:.25rem !important}.row-gap-xl-2{row-gap:.5rem !important}.row-gap-xl-3{row-gap:1rem !important}.row-gap-xl-4{row-gap:1.5rem !important}.row-gap-xl-5{row-gap:3rem !important}.column-gap-xl-0{column-gap:0 !important}.column-gap-xl-1{column-gap:.25rem !important}.column-gap-xl-2{column-gap:.5rem !important}.column-gap-xl-3{column-gap:1rem !important}.column-gap-xl-4{column-gap:1.5rem !important}.column-gap-xl-5{column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{object-fit:contain !important}.object-fit-xxl-cover{object-fit:cover !important}.object-fit-xxl-fill{object-fit:fill !important}.object-fit-xxl-scale{object-fit:scale-down !important}.object-fit-xxl-none{object-fit:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-inline-grid{display:inline-grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.row-gap-xxl-0{row-gap:0 !important}.row-gap-xxl-1{row-gap:.25rem !important}.row-gap-xxl-2{row-gap:.5rem !important}.row-gap-xxl-3{row-gap:1rem !important}.row-gap-xxl-4{row-gap:1.5rem !important}.row-gap-xxl-5{row-gap:3rem !important}.column-gap-xxl-0{column-gap:0 !important}.column-gap-xxl-1{column-gap:.25rem !important}.column-gap-xxl-2{column-gap:.5rem !important}.column-gap-xxl-3{column-gap:1rem !important}.column-gap-xxl-4{column-gap:1.5rem !important}.column-gap-xxl-5{column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#fff}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#fff}.bg-warning{color:#fff}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-inline-grid{display:inline-grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}.bg-blue{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #2780e3;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #613d7c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #613d7c;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #e83e8c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #e83e8c;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #ff0039;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #f0ad4e;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #f0ad4e;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ff7518;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #3fb618;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #9954bb;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #343a40}.bg-default{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-primary{--bslib-color-fg: #2780e3}.bg-primary{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff}.text-secondary{--bslib-color-fg: #343a40}.bg-secondary{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-success{--bslib-color-fg: #3fb618}.bg-success{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff}.text-info{--bslib-color-fg: #9954bb}.bg-info{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff}.text-warning{--bslib-color-fg: #ff7518}.bg-warning{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff}.text-danger{--bslib-color-fg: #ff0039}.bg-danger{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #343a40}.bg-dark{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.bg-gradient-blue-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(64.2, 83.2, 233);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(64.2,83.2,233);color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(62.2, 101.2, 185.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(62.2,101.2,185.8);color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(116.2, 101.6, 192.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(116.2,101.6,192.2);color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(125.4, 76.8, 159);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(125.4,76.8,159);color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(119.4, 146, 167.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(119.4,146,167.4);color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(125.4, 123.6, 145.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(125.4,123.6,145.8);color:#fff}.bg-gradient-blue-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(48.6, 149.6, 145.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(48.6,149.6,145.8);color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(36.2, 157.2, 196.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(36.2,157.2,196.6);color:#fff}.bg-gradient-blue-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(84.6, 110.4, 211);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(84.6,110.4,211);color:#fff}.bg-gradient-indigo-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(76.8, 60.8, 236);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(76.8,60.8,236);color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(100, 34, 194.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(100,34,194.8);color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(154, 34.4, 201.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(154,34.4,201.2);color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(163.2, 9.6, 168);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(163.2,9.6,168);color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(157.2, 78.8, 176.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(157.2,78.8,176.4);color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(163.2, 56.4, 154.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(163.2,56.4,154.8);color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(86.4, 82.4, 154.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(86.4,82.4,154.8);color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(74, 90, 205.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(74,90,205.6);color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(122.4, 43.2, 220);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(122.4,43.2,220);color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(73.8, 87.8, 165.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(73.8,87.8,165.2);color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(99, 43, 171.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(99,43,171.2);color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(151, 61.4, 130.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(151,61.4,130.4);color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(160.2, 36.6, 97.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(160.2,36.6,97.2);color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(154.2, 105.8, 105.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(154.2,105.8,105.6);color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(160.2, 83.4, 84);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(160.2,83.4,84);color:#fff}.bg-gradient-purple-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(83.4, 109.4, 84);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(83.4,109.4,84);color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(71, 117, 134.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(71,117,134.8);color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(119.4, 70.2, 149.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(119.4,70.2,149.2);color:#fff}.bg-gradient-pink-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(154.8, 88.4, 174.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(154.8,88.4,174.8);color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(180, 43.6, 180.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(180,43.6,180.8);color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(178, 61.6, 133.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(178,61.6,133.6);color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(241.2, 37.2, 106.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(241.2,37.2,106.8);color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(235.2, 106.4, 115.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(235.2,106.4,115.2);color:#fff}.bg-gradient-pink-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(241.2, 84, 93.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(241.2,84,93.6);color:#fff}.bg-gradient-pink-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(164.4, 110, 93.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(164.4,110,93.6);color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(152, 117.6, 144.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(152,117.6,144.4);color:#fff}.bg-gradient-pink-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(200.4, 70.8, 158.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(200.4,70.8,158.8);color:#fff}.bg-gradient-red-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(168.6, 51.2, 125);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(168.6,51.2,125);color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(193.8, 6.4, 131);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(193.8,6.4,131);color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(191.8, 24.4, 83.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(191.8,24.4,83.8);color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(245.8, 24.8, 90.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(245.8,24.8,90.2);color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(249, 69.2, 65.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(249,69.2,65.4);color:#fff}.bg-gradient-red-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(255, 46.8, 43.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(255,46.8,43.8);color:#fff}.bg-gradient-red-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(178.2, 72.8, 43.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(178.2,72.8,43.8);color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(165.8, 80.4, 94.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(165.8,80.4,94.6);color:#fff}.bg-gradient-red-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(214.2, 33.6, 109);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(214.2,33.6,109);color:#fff}.bg-gradient-orange-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(159.6, 155, 137.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(159.6,155,137.6);color:#fff}.bg-gradient-orange-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(184.8, 110.2, 143.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(184.8,110.2,143.6);color:#fff}.bg-gradient-orange-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(182.8, 128.2, 96.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(182.8,128.2,96.4);color:#fff}.bg-gradient-orange-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(236.8, 128.6, 102.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(236.8,128.6,102.8);color:#fff}.bg-gradient-orange-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(246, 103.8, 69.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(246,103.8,69.6);color:#fff}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: rgb(246, 150.6, 56.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(246,150.6,56.4);color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: rgb(169.2, 176.6, 56.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(169.2,176.6,56.4);color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: rgb(156.8, 184.2, 107.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(156.8,184.2,107.2);color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(205.2, 137.4, 121.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(205.2,137.4,121.6);color:#fff}.bg-gradient-yellow-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(168.6, 121.4, 105.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(168.6,121.4,105.2);color:#fff}.bg-gradient-yellow-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(193.8, 76.6, 111.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(193.8,76.6,111.2);color:#fff}.bg-gradient-yellow-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(191.8, 94.6, 64);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(191.8,94.6,64);color:#fff}.bg-gradient-yellow-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(245.8, 95, 70.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(245.8,95,70.4);color:#fff}.bg-gradient-yellow-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(255, 70.2, 37.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(255,70.2,37.2);color:#fff}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: rgb(249, 139.4, 45.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(249,139.4,45.6);color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(178.2, 143, 24);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(178.2,143,24);color:#fff}.bg-gradient-yellow-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(165.8, 150.6, 74.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(165.8,150.6,74.8);color:#fff}.bg-gradient-yellow-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(214.2, 103.8, 89.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(214.2,103.8,89.2);color:#fff}.bg-gradient-green-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(53.4, 160.4, 105.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(53.4,160.4,105.2);color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(78.6, 115.6, 111.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(78.6,115.6,111.2);color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(76.6, 133.6, 64);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(76.6,133.6,64);color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(130.6, 134, 70.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(130.6,134,70.4);color:#fff}.bg-gradient-green-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(139.8, 109.2, 37.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(139.8,109.2,37.2);color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: rgb(133.8, 178.4, 45.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(133.8,178.4,45.6);color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(139.8, 156, 24);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(139.8,156,24);color:#fff}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: rgb(50.6, 189.6, 74.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(50.6,189.6,74.8);color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(99, 142.8, 89.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(99,142.8,89.2);color:#fff}.bg-gradient-teal-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(34.8, 171.8, 181.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(34.8,171.8,181.4);color:#fff}.bg-gradient-teal-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(60, 127, 187.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(60,127,187.4);color:#fff}.bg-gradient-teal-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(58, 145, 140.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(58,145,140.2);color:#fff}.bg-gradient-teal-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(112, 145.4, 146.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(112,145.4,146.6);color:#fff}.bg-gradient-teal-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(121.2, 120.6, 113.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(121.2,120.6,113.4);color:#fff}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: rgb(115.2, 189.8, 121.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(115.2,189.8,121.8);color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(121.2, 167.4, 100.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(121.2,167.4,100.2);color:#fff}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: rgb(44.4, 193.4, 100.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(44.4,193.4,100.2);color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(80.4, 154.2, 165.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(80.4,154.2,165.4);color:#fff}.bg-gradient-cyan-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(107.4, 101.6, 203);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(107.4,101.6,203);color:#fff}.bg-gradient-cyan-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(132.6, 56.8, 209);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(132.6,56.8,209);color:#fff}.bg-gradient-cyan-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(130.6, 74.8, 161.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(130.6,74.8,161.8);color:#fff}.bg-gradient-cyan-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(184.6, 75.2, 168.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(184.6,75.2,168.2);color:#fff}.bg-gradient-cyan-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(193.8, 50.4, 135);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(193.8,50.4,135);color:#fff}.bg-gradient-cyan-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(187.8, 119.6, 143.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(187.8,119.6,143.4);color:#fff}.bg-gradient-cyan-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(193.8, 97.2, 121.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(193.8,97.2,121.8);color:#fff}.bg-gradient-cyan-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(117, 123.2, 121.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(117,123.2,121.8);color:#fff}.bg-gradient-cyan-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(104.6, 130.8, 172.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(104.6,130.8,172.6);color:#fff}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.bg-blue{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #2780e3;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #613d7c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #613d7c;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #e83e8c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #e83e8c;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #ff0039;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #f0ad4e;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #f0ad4e;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ff7518;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #3fb618;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #9954bb;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #343a40}.bg-default{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-primary{--bslib-color-fg: #2780e3}.bg-primary{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff}.text-secondary{--bslib-color-fg: #343a40}.bg-secondary{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-success{--bslib-color-fg: #3fb618}.bg-success{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff}.text-info{--bslib-color-fg: #9954bb}.bg-info{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff}.text-warning{--bslib-color-fg: #ff7518}.bg-warning{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff}.text-danger{--bslib-color-fg: #ff0039}.bg-danger{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #343a40}.bg-dark{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.bg-gradient-blue-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(64.2, 83.2, 233);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(64.2,83.2,233);color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(62.2, 101.2, 185.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(62.2,101.2,185.8);color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(116.2, 101.6, 192.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(116.2,101.6,192.2);color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(125.4, 76.8, 159);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(125.4,76.8,159);color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(119.4, 146, 167.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(119.4,146,167.4);color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(125.4, 123.6, 145.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(125.4,123.6,145.8);color:#fff}.bg-gradient-blue-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(48.6, 149.6, 145.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(48.6,149.6,145.8);color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(36.2, 157.2, 196.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(36.2,157.2,196.6);color:#fff}.bg-gradient-blue-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(84.6, 110.4, 211);background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(84.6,110.4,211);color:#fff}.bg-gradient-indigo-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(76.8, 60.8, 236);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(76.8,60.8,236);color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(100, 34, 194.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(100,34,194.8);color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(154, 34.4, 201.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(154,34.4,201.2);color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(163.2, 9.6, 168);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(163.2,9.6,168);color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(157.2, 78.8, 176.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(157.2,78.8,176.4);color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(163.2, 56.4, 154.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(163.2,56.4,154.8);color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(86.4, 82.4, 154.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(86.4,82.4,154.8);color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(74, 90, 205.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(74,90,205.6);color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(122.4, 43.2, 220);background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(122.4,43.2,220);color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(73.8, 87.8, 165.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(73.8,87.8,165.2);color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(99, 43, 171.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(99,43,171.2);color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(151, 61.4, 130.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(151,61.4,130.4);color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(160.2, 36.6, 97.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(160.2,36.6,97.2);color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(154.2, 105.8, 105.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(154.2,105.8,105.6);color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(160.2, 83.4, 84);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(160.2,83.4,84);color:#fff}.bg-gradient-purple-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(83.4, 109.4, 84);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(83.4,109.4,84);color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(71, 117, 134.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(71,117,134.8);color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(119.4, 70.2, 149.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(119.4,70.2,149.2);color:#fff}.bg-gradient-pink-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(154.8, 88.4, 174.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(154.8,88.4,174.8);color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(180, 43.6, 180.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(180,43.6,180.8);color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(178, 61.6, 133.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(178,61.6,133.6);color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(241.2, 37.2, 106.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(241.2,37.2,106.8);color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(235.2, 106.4, 115.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(235.2,106.4,115.2);color:#fff}.bg-gradient-pink-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(241.2, 84, 93.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(241.2,84,93.6);color:#fff}.bg-gradient-pink-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(164.4, 110, 93.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(164.4,110,93.6);color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(152, 117.6, 144.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(152,117.6,144.4);color:#fff}.bg-gradient-pink-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(200.4, 70.8, 158.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(200.4,70.8,158.8);color:#fff}.bg-gradient-red-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(168.6, 51.2, 125);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(168.6,51.2,125);color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(193.8, 6.4, 131);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(193.8,6.4,131);color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(191.8, 24.4, 83.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(191.8,24.4,83.8);color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(245.8, 24.8, 90.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(245.8,24.8,90.2);color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(249, 69.2, 65.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(249,69.2,65.4);color:#fff}.bg-gradient-red-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(255, 46.8, 43.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(255,46.8,43.8);color:#fff}.bg-gradient-red-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(178.2, 72.8, 43.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(178.2,72.8,43.8);color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(165.8, 80.4, 94.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(165.8,80.4,94.6);color:#fff}.bg-gradient-red-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(214.2, 33.6, 109);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(214.2,33.6,109);color:#fff}.bg-gradient-orange-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(159.6, 155, 137.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(159.6,155,137.6);color:#fff}.bg-gradient-orange-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(184.8, 110.2, 143.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(184.8,110.2,143.6);color:#fff}.bg-gradient-orange-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(182.8, 128.2, 96.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(182.8,128.2,96.4);color:#fff}.bg-gradient-orange-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(236.8, 128.6, 102.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(236.8,128.6,102.8);color:#fff}.bg-gradient-orange-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(246, 103.8, 69.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(246,103.8,69.6);color:#fff}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: rgb(246, 150.6, 56.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(246,150.6,56.4);color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: rgb(169.2, 176.6, 56.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(169.2,176.6,56.4);color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: rgb(156.8, 184.2, 107.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(156.8,184.2,107.2);color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(205.2, 137.4, 121.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(205.2,137.4,121.6);color:#fff}.bg-gradient-yellow-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(168.6, 121.4, 105.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(168.6,121.4,105.2);color:#fff}.bg-gradient-yellow-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(193.8, 76.6, 111.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(193.8,76.6,111.2);color:#fff}.bg-gradient-yellow-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(191.8, 94.6, 64);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(191.8,94.6,64);color:#fff}.bg-gradient-yellow-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(245.8, 95, 70.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(245.8,95,70.4);color:#fff}.bg-gradient-yellow-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(255, 70.2, 37.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(255,70.2,37.2);color:#fff}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: rgb(249, 139.4, 45.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(249,139.4,45.6);color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(178.2, 143, 24);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(178.2,143,24);color:#fff}.bg-gradient-yellow-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(165.8, 150.6, 74.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(165.8,150.6,74.8);color:#fff}.bg-gradient-yellow-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(214.2, 103.8, 89.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(214.2,103.8,89.2);color:#fff}.bg-gradient-green-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(53.4, 160.4, 105.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(53.4,160.4,105.2);color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(78.6, 115.6, 111.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(78.6,115.6,111.2);color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(76.6, 133.6, 64);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(76.6,133.6,64);color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(130.6, 134, 70.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(130.6,134,70.4);color:#fff}.bg-gradient-green-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(139.8, 109.2, 37.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(139.8,109.2,37.2);color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: rgb(133.8, 178.4, 45.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(133.8,178.4,45.6);color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(139.8, 156, 24);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(139.8,156,24);color:#fff}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: rgb(50.6, 189.6, 74.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(50.6,189.6,74.8);color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(99, 142.8, 89.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(99,142.8,89.2);color:#fff}.bg-gradient-teal-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(34.8, 171.8, 181.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(34.8,171.8,181.4);color:#fff}.bg-gradient-teal-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(60, 127, 187.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(60,127,187.4);color:#fff}.bg-gradient-teal-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(58, 145, 140.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(58,145,140.2);color:#fff}.bg-gradient-teal-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(112, 145.4, 146.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(112,145.4,146.6);color:#fff}.bg-gradient-teal-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(121.2, 120.6, 113.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(121.2,120.6,113.4);color:#fff}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: rgb(115.2, 189.8, 121.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(115.2,189.8,121.8);color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(121.2, 167.4, 100.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(121.2,167.4,100.2);color:#fff}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: rgb(44.4, 193.4, 100.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(44.4,193.4,100.2);color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #fff;--bslib-color-bg: rgb(80.4, 154.2, 165.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) rgb(80.4,154.2,165.4);color:#fff}.bg-gradient-cyan-blue{--bslib-color-fg: #fff;--bslib-color-bg: rgb(107.4, 101.6, 203);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) rgb(107.4,101.6,203);color:#fff}.bg-gradient-cyan-indigo{--bslib-color-fg: #fff;--bslib-color-bg: rgb(132.6, 56.8, 209);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) rgb(132.6,56.8,209);color:#fff}.bg-gradient-cyan-purple{--bslib-color-fg: #fff;--bslib-color-bg: rgb(130.6, 74.8, 161.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) rgb(130.6,74.8,161.8);color:#fff}.bg-gradient-cyan-pink{--bslib-color-fg: #fff;--bslib-color-bg: rgb(184.6, 75.2, 168.2);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) rgb(184.6,75.2,168.2);color:#fff}.bg-gradient-cyan-red{--bslib-color-fg: #fff;--bslib-color-bg: rgb(193.8, 50.4, 135);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) rgb(193.8,50.4,135);color:#fff}.bg-gradient-cyan-orange{--bslib-color-fg: #fff;--bslib-color-bg: rgb(187.8, 119.6, 143.4);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) rgb(187.8,119.6,143.4);color:#fff}.bg-gradient-cyan-yellow{--bslib-color-fg: #fff;--bslib-color-bg: rgb(193.8, 97.2, 121.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) rgb(193.8,97.2,121.8);color:#fff}.bg-gradient-cyan-green{--bslib-color-fg: #fff;--bslib-color-bg: rgb(117, 123.2, 121.8);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) rgb(117,123.2,121.8);color:#fff}.bg-gradient-cyan-teal{--bslib-color-fg: #fff;--bslib-color-bg: rgb(104.6, 130.8, 172.6);background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) rgb(104.6,130.8,172.6);color:#fff}:root{--bslib-value-box-shadow: none;--bslib-value-box-border-width-auto-yes: var(--bslib-value-box-border-width-baseline);--bslib-value-box-border-width-auto-no: 0;--bslib-value-box-border-width-baseline: 1px}.bslib-value-box{border-width:var(--bslib-value-box-border-width-auto-no, var(--bslib-value-box-border-width-baseline));container-name:bslib-value-box;container-type:inline-size}.bslib-value-box.card{box-shadow:var(--bslib-value-box-shadow)}.bslib-value-box.border-auto{border-width:var(--bslib-value-box-border-width-auto-yes, var(--bslib-value-box-border-width-baseline))}.bslib-value-box.default{--bslib-value-box-bg-default: var(--bs-card-bg, #fff);--bslib-value-box-border-color-default: var(--bs-card-border-color, rgba(0, 0, 0, 0.175));color:var(--bslib-value-box-color);background-color:var(--bslib-value-box-bg, var(--bslib-value-box-bg-default));border-color:var(--bslib-value-box-border-color, var(--bslib-value-box-border-color-default))}.bslib-value-box .value-box-grid{display:grid;grid-template-areas:"left right";align-items:center;overflow:hidden}.bslib-value-box .value-box-showcase{height:100%;max-height:var(---bslib-value-box-showcase-max-h, 100%)}.bslib-value-box .value-box-showcase,.bslib-value-box .value-box-showcase>.html-fill-item{width:100%}.bslib-value-box[data-full-screen=true] .value-box-showcase{max-height:var(---bslib-value-box-showcase-max-h-fs, 100%)}@media screen and (min-width: 575.98px){@container bslib-value-box (max-width: 300px){.bslib-value-box:not(.showcase-bottom) .value-box-grid{grid-template-columns:1fr !important;grid-template-rows:auto auto;grid-template-areas:"top" "bottom"}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-showcase{grid-area:top !important}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-area{grid-area:bottom !important;justify-content:end}}}.bslib-value-box .value-box-area{justify-content:center;padding:1.5rem 1rem;font-size:.9rem;font-weight:500}.bslib-value-box .value-box-area *{margin-bottom:0;margin-top:0}.bslib-value-box .value-box-title{font-size:1rem;margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2}.bslib-value-box .value-box-title:empty::after{content:" "}.bslib-value-box .value-box-value{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2}@media(min-width: 1200px){.bslib-value-box .value-box-value{font-size:1.65rem}}.bslib-value-box .value-box-value:empty::after{content:" "}.bslib-value-box .value-box-showcase{align-items:center;justify-content:center;margin-top:auto;margin-bottom:auto;padding:1rem}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{opacity:.85;min-width:50px;max-width:125%}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{font-size:4rem}.bslib-value-box.showcase-top-right .value-box-grid{grid-template-columns:1fr var(---bslib-value-box-showcase-w, 50%)}.bslib-value-box.showcase-top-right .value-box-grid .value-box-showcase{grid-area:right;margin-left:auto;align-self:start;align-items:end;padding-left:0;padding-bottom:0}.bslib-value-box.showcase-top-right .value-box-grid .value-box-area{grid-area:left;align-self:end}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid{grid-template-columns:auto var(---bslib-value-box-showcase-w-fs, 1fr)}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid>div{align-self:center}.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-showcase{margin-top:0}@container bslib-value-box (max-width: 300px){.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-grid .value-box-showcase{padding-left:1rem}}.bslib-value-box.showcase-left-center .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w, 30%) auto}.bslib-value-box.showcase-left-center[data-full-screen=true] .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w-fs, 1fr) auto}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-showcase{grid-area:left}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-area{grid-area:right}.bslib-value-box.showcase-bottom .value-box-grid{grid-template-columns:1fr;grid-template-rows:1fr var(---bslib-value-box-showcase-h, auto);grid-template-areas:"top" "bottom";overflow:hidden}.bslib-value-box.showcase-bottom .value-box-grid .value-box-showcase{grid-area:bottom;padding:0;margin:0}.bslib-value-box.showcase-bottom .value-box-grid .value-box-area{grid-area:top}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid{grid-template-rows:1fr var(---bslib-value-box-showcase-h-fs, 2fr)}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid .value-box-showcase{padding:1rem}[data-bs-theme=dark] .bslib-value-box{--bslib-value-box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 50%)}@media(min-width: 576px){.nav:not(.nav-hidden){display:flex !important;display:-webkit-flex !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column){float:none !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.bslib-nav-spacer{margin-left:auto !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.form-inline{margin-top:auto;margin-bottom:auto}.nav:not(.nav-hidden).nav-stacked{flex-direction:column;-webkit-flex-direction:column;height:100%}.nav:not(.nav-hidden).nav-stacked>.bslib-nav-spacer{margin-top:auto !important}}.bslib-card{overflow:auto}.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card[data-full-screen=true]>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border=true]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius=true]){border-top-left-radius:0;border-top-right-radius:0}[data-full-screen=true]{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:var(--bslib-full-screen-enter-bottom, 0.2rem);right:var(--bslib-full-screen-enter-right, 0);top:var(--bslib-full-screen-enter-top);left:var(--bslib-full-screen-enter-left);color:var(--bslib-color-fg, var(--bs-card-color));background-color:var(--bslib-color-bg, var(--bs-card-bg, var(--bs-body-bg)));border:var(--bs-card-border-width) solid var(--bslib-color-fg, var(--bs-card-border-color));box-shadow:0 2px 4px rgba(0,0,0,.15);margin:.2rem .4rem;padding:.55rem !important;font-size:.8rem;cursor:pointer;opacity:.7;z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card[data-full-screen=false]:hover>*>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>*>.bslib-full-screen-enter{display:none}@media(max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}}.bslib-grid{display:grid !important;gap:var(--bslib-spacer, 1rem);height:var(--bslib-grid-height)}.bslib-grid.grid{grid-template-columns:repeat(var(--bs-columns, 12), minmax(0, 1fr));grid-template-rows:unset;grid-auto-rows:var(--bslib-grid--row-heights);--bslib-grid--row-heights--xs: unset;--bslib-grid--row-heights--sm: unset;--bslib-grid--row-heights--md: unset;--bslib-grid--row-heights--lg: unset;--bslib-grid--row-heights--xl: unset;--bslib-grid--row-heights--xxl: unset}.bslib-grid.grid.bslib-grid--row-heights--xs{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xs)}@media(min-width: 576px){.bslib-grid.grid.bslib-grid--row-heights--sm{--bslib-grid--row-heights: var(--bslib-grid--row-heights--sm)}}@media(min-width: 768px){.bslib-grid.grid.bslib-grid--row-heights--md{--bslib-grid--row-heights: var(--bslib-grid--row-heights--md)}}@media(min-width: 992px){.bslib-grid.grid.bslib-grid--row-heights--lg{--bslib-grid--row-heights: var(--bslib-grid--row-heights--lg)}}@media(min-width: 1200px){.bslib-grid.grid.bslib-grid--row-heights--xl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xl)}}@media(min-width: 1400px){.bslib-grid.grid.bslib-grid--row-heights--xxl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xxl)}}.bslib-grid>*>.shiny-input-container{width:100%}.bslib-grid-item{grid-column:auto/span 1}@media(max-width: 767.98px){.bslib-grid-item{grid-column:1/-1}}@media(max-width: 575.98px){.bslib-grid{grid-template-columns:1fr !important;height:var(--bslib-grid-height-mobile)}.bslib-grid.grid{height:unset !important;grid-auto-rows:var(--bslib-grid--row-heights--xs, auto)}}.accordion .accordion-header{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2;color:var(--bs-heading-color);margin-bottom:0}@media(min-width: 1200px){.accordion .accordion-header{font-size:1.65rem}}.accordion .accordion-icon:not(:empty){margin-right:.75rem;display:flex}.accordion .accordion-button:not(.collapsed){box-shadow:none}.accordion .accordion-button:not(.collapsed):focus{box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.navbar+.container-fluid:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-sm:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-md:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-lg:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xl:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xxl:has(>.tab-content>.tab-pane.active.html-fill-container){padding-left:0;padding-right:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container{padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child){padding:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]){border-left:none;border-right:none;border-bottom:none}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]){border-radius:0}.navbar+div>.bslib-sidebar-layout{border-top:var(--bslib-sidebar-border)}html{height:100%}.bslib-page-fill{width:100%;height:100%;margin:0;padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}@media(max-width: 575.98px){.bslib-page-fill{height:var(--bslib-page-fill-mobile-height, auto)}}:root{--bslib-page-sidebar-title-bg: #f8f9fa;--bslib-page-sidebar-title-color: #000}.bslib-page-title{background-color:var(--bslib-page-sidebar-title-bg);color:var(--bslib-page-sidebar-title-color);font-size:1.25rem;font-weight:300;padding:var(--bslib-spacer, 1rem);padding-left:1.5rem;margin-bottom:0;border-bottom:1px solid #dee2e6}.bslib-sidebar-layout{--bslib-sidebar-transition-duration: 500ms;--bslib-sidebar-transition-easing-x: cubic-bezier(0.8, 0.78, 0.22, 1.07);--bslib-sidebar-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-border-radius: var(--bs-border-radius);--bslib-sidebar-vert-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--bslib-sidebar-fg: var(--bs-emphasis-color, black);--bslib-sidebar-main-fg: var(--bs-card-color, var(--bs-body-color));--bslib-sidebar-main-bg: var(--bs-card-bg, var(--bs-body-bg));--bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1);--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);--bslib-sidebar-icon-button-size: calc(var(--bslib-sidebar-icon-size, 1rem) * 2);--bslib-sidebar-padding-icon: calc(var(--bslib-sidebar-icon-button-size, 2rem) * 1.5);--bslib-collapse-toggle-border-radius: var(--bs-border-radius, 0.25rem);--bslib-collapse-toggle-transform: 0deg;--bslib-sidebar-toggle-transition-easing: cubic-bezier(1, 0, 0, 1);--bslib-collapse-toggle-right-transform: 180deg;--bslib-sidebar-column-main: minmax(0, 1fr);display:grid !important;grid-template-columns:min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px)) var(--bslib-sidebar-column-main);position:relative;transition:grid-template-columns ease-in-out var(--bslib-sidebar-transition-duration);border:var(--bslib-sidebar-border);border-radius:var(--bslib-sidebar-border-radius)}@media(prefers-reduced-motion: reduce){.bslib-sidebar-layout{transition:none}}.bslib-sidebar-layout[data-bslib-sidebar-border=false]{border:none}.bslib-sidebar-layout[data-bslib-sidebar-border-radius=false]{border-radius:initial}.bslib-sidebar-layout>.main,.bslib-sidebar-layout>.sidebar{grid-row:1/2;border-radius:inherit;overflow:auto}.bslib-sidebar-layout>.main{grid-column:2/3;border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--bslib-sidebar-padding);transition:padding var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);color:var(--bslib-sidebar-main-fg);background-color:var(--bslib-sidebar-main-bg)}.bslib-sidebar-layout>.sidebar{grid-column:1/2;width:100%;height:100%;border-right:var(--bslib-sidebar-vert-border);border-top-right-radius:0;border-bottom-right-radius:0;color:var(--bslib-sidebar-fg);background-color:var(--bslib-sidebar-bg);backdrop-filter:blur(5px)}.bslib-sidebar-layout>.sidebar>.sidebar-content{display:flex;flex-direction:column;gap:var(--bslib-spacer, 1rem);padding:var(--bslib-sidebar-padding);padding-top:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout>.sidebar>.sidebar-content>:last-child:not(.sidebar-title){margin-bottom:0}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion{margin-left:calc(-1*var(--bslib-sidebar-padding));margin-right:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:last-child{margin-bottom:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child){margin-bottom:1rem}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion .accordion-body{display:flex;flex-direction:column}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:first-child) .accordion-item:first-child{border-top:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child) .accordion-item:last-child{border-bottom:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content.has-accordion>.sidebar-title{border-bottom:none;padding-bottom:0}.bslib-sidebar-layout>.sidebar .shiny-input-container{width:100%}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar>.sidebar-content{padding-top:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.collapse-toggle{grid-row:1/2;grid-column:1/2;display:inline-flex;align-items:center;position:absolute;right:calc(var(--bslib-sidebar-icon-size));top:calc(var(--bslib-sidebar-icon-size, 1rem)/2);border:none;border-radius:var(--bslib-collapse-toggle-border-radius);height:var(--bslib-sidebar-icon-button-size, 2rem);width:var(--bslib-sidebar-icon-button-size, 2rem);display:flex;align-items:center;justify-content:center;padding:0;color:var(--bslib-sidebar-fg);background-color:unset;transition:color var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),top var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),right var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),left var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover{background-color:var(--bslib-sidebar-toggle-bg)}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon{opacity:.8;width:var(--bslib-sidebar-icon-size);height:var(--bslib-sidebar-icon-size);transform:rotateY(var(--bslib-collapse-toggle-transform));transition:transform var(--bslib-sidebar-toggle-transition-easing) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover>.collapse-icon{opacity:1}.bslib-sidebar-layout .sidebar-title{font-size:1.25rem;line-height:1.25;margin-top:0;margin-bottom:1rem;padding-bottom:1rem;border-bottom:var(--bslib-sidebar-border)}.bslib-sidebar-layout.sidebar-right{grid-template-columns:var(--bslib-sidebar-column-main) min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px))}.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/2;border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout.sidebar-right>.sidebar{grid-column:2/3;border-right:none;border-left:var(--bslib-sidebar-vert-border);border-top-left-radius:0;border-bottom-left-radius:0}.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-column:2/3;left:var(--bslib-sidebar-icon-size);right:unset;border:var(--bslib-collapse-toggle-border)}.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transform:rotateY(var(--bslib-collapse-toggle-right-transform))}.bslib-sidebar-layout.sidebar-collapsed{--bslib-collapse-toggle-transform: 180deg;--bslib-collapse-toggle-right-transform: 0deg;--bslib-sidebar-vert-border: none;grid-template-columns:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right{grid-template-columns:minmax(0, 1fr) 0}.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning)>.sidebar>*{display:none}.bslib-sidebar-layout.sidebar-collapsed>.main{border-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed:not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle{color:var(--bslib-sidebar-main-fg);top:calc(var(--bslib-sidebar-overlap-counter, 0)*(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)) + var(--bslib-sidebar-icon-size, 1rem)/2);right:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.collapse-toggle{left:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));right:unset}@media(min-width: 576px){.bslib-sidebar-layout.transitioning>.sidebar>.sidebar-content{display:none}}@media(max-width: 575.98px){.bslib-sidebar-layout[data-bslib-sidebar-open=desktop]{--bslib-sidebar-js-init-collapsed: true}.bslib-sidebar-layout>.sidebar,.bslib-sidebar-layout.sidebar-right>.sidebar{border:none}.bslib-sidebar-layout>.main,.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/3}.bslib-sidebar-layout[data-bslib-sidebar-open=always]{display:block !important}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar{max-height:var(--bslib-sidebar-max-height-mobile);overflow-y:auto;border-top:var(--bslib-sidebar-vert-border)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]){grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.sidebar{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.collapse-toggle{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed.sidebar-right{grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always])>.main{opacity:0;transition:opacity var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed>.main{opacity:1}}.html-fill-container{display:flex;flex-direction:column;min-height:0;min-width:0}.html-fill-container>.html-fill-item{flex:1 1 auto;min-height:0;min-width:0}.html-fill-container>:not(.html-fill-item){flex:0 0 auto}.sidebar-item .chapter-number{color:#343a40}.quarto-container{min-height:calc(100vh - 132px)}body.hypothesis-enabled #quarto-header{margin-right:16px}footer.footer .nav-footer,#quarto-header>nav{padding-left:1em;padding-right:1em}footer.footer div.nav-footer p:first-child{margin-top:0}footer.footer div.nav-footer p:last-child{margin-bottom:0}#quarto-content>*{padding-top:14px}#quarto-content>#quarto-sidebar-glass{padding-top:0px}@media(max-width: 991.98px){#quarto-content>*{padding-top:0}#quarto-content .subtitle{padding-top:14px}#quarto-content section:first-of-type h2:first-of-type,#quarto-content section:first-of-type .h2:first-of-type{margin-top:1rem}}.headroom-target,header.headroom{will-change:transform;transition:position 200ms linear;transition:all 200ms linear}header.headroom--pinned{transform:translateY(0%)}header.headroom--unpinned{transform:translateY(-100%)}.navbar-container{width:100%}.navbar-brand{overflow:hidden;text-overflow:ellipsis}.navbar-brand-container{max-width:calc(100% - 115px);min-width:0;display:flex;align-items:center}@media(min-width: 992px){.navbar-brand-container{margin-right:1em}}.navbar-brand.navbar-brand-logo{margin-right:4px;display:inline-flex}.navbar-toggler{flex-basis:content;flex-shrink:0}.navbar .navbar-brand-container{order:2}.navbar .navbar-toggler{order:1}.navbar .navbar-container>.navbar-nav{order:20}.navbar .navbar-container>.navbar-brand-container{margin-left:0 !important;margin-right:0 !important}.navbar .navbar-collapse{order:20}.navbar #quarto-search{order:4;margin-left:auto}.navbar .navbar-toggler{margin-right:.5em}.navbar-collapse .quarto-navbar-tools{margin-left:.5em}.navbar-logo{max-height:24px;width:auto;padding-right:4px}nav .nav-item:not(.compact){padding-top:1px}nav .nav-link i,nav .dropdown-item i{padding-right:1px}.navbar-expand-lg .navbar-nav .nav-link{padding-left:.6rem;padding-right:.6rem}nav .nav-item.compact .nav-link{padding-left:.5rem;padding-right:.5rem;font-size:1.1rem}.navbar .quarto-navbar-tools{order:3}.navbar .quarto-navbar-tools div.dropdown{display:inline-block}.navbar .quarto-navbar-tools .quarto-navigation-tool{color:rgb(84.32,84.66,85)}.navbar .quarto-navbar-tools .quarto-navigation-tool:hover{color:rgb(31.2,77.6,181.6)}.navbar-nav .dropdown-menu{min-width:220px;font-size:.9rem}.navbar .navbar-nav .nav-link.dropdown-toggle::after{opacity:.75;vertical-align:.175em}.navbar ul.dropdown-menu{padding-top:0;padding-bottom:0}.navbar .dropdown-header{text-transform:uppercase;font-size:.8rem;padding:0 .5rem}.navbar .dropdown-item{padding:.4rem .5rem}.navbar .dropdown-item>i.bi{margin-left:.1rem;margin-right:.25em}.sidebar #quarto-search{margin-top:-1px}.sidebar #quarto-search svg.aa-SubmitIcon{width:16px;height:16px}.sidebar-navigation a{color:inherit}.sidebar-title{margin-top:.25rem;padding-bottom:.5rem;font-size:1.3rem;line-height:1.6rem;visibility:visible}.sidebar-title>a{font-size:inherit;text-decoration:none}.sidebar-title .sidebar-tools-main{margin-top:-6px}@media(max-width: 991.98px){#quarto-sidebar div.sidebar-header{padding-top:.2em}}.sidebar-header-stacked .sidebar-title{margin-top:.6rem}.sidebar-logo{max-width:90%;padding-bottom:.5rem}.sidebar-logo-link{text-decoration:none}.sidebar-navigation li a{text-decoration:none}.sidebar-navigation .quarto-navigation-tool{opacity:.7;font-size:.875rem}#quarto-sidebar>nav>.sidebar-tools-main{margin-left:14px}.sidebar-tools-main{display:inline-flex;margin-left:0px;order:2}.sidebar-tools-main:not(.tools-wide){vertical-align:middle}.sidebar-navigation .quarto-navigation-tool.dropdown-toggle::after{display:none}.sidebar.sidebar-navigation>*{padding-top:1em}.sidebar-item{margin-bottom:.2em;line-height:1rem;margin-top:.4rem}.sidebar-section{padding-left:.5em;padding-bottom:.2em}.sidebar-item .sidebar-item-container{display:flex;justify-content:space-between;cursor:pointer}.sidebar-item-toggle:hover{cursor:pointer}.sidebar-item .sidebar-item-toggle .bi{font-size:.7rem;text-align:center}.sidebar-item .sidebar-item-toggle .bi-chevron-right::before{transition:transform 200ms ease}.sidebar-item .sidebar-item-toggle[aria-expanded=false] .bi-chevron-right::before{transform:none}.sidebar-item .sidebar-item-toggle[aria-expanded=true] .bi-chevron-right::before{transform:rotate(90deg)}.sidebar-item-text{width:100%}.sidebar-navigation .sidebar-divider{margin-left:0;margin-right:0;margin-top:.5rem;margin-bottom:.5rem}@media(max-width: 991.98px){.quarto-secondary-nav{display:block}.quarto-secondary-nav button.quarto-search-button{padding-right:0em;padding-left:2em}.quarto-secondary-nav button.quarto-btn-toggle{margin-left:-0.75rem;margin-right:.15rem}.quarto-secondary-nav nav.quarto-title-breadcrumbs{display:none}.quarto-secondary-nav nav.quarto-page-breadcrumbs{display:flex;align-items:center;padding-right:1em;margin-left:-0.25em}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{text-decoration:none}.quarto-secondary-nav nav.quarto-page-breadcrumbs ol.breadcrumb{margin-bottom:0}}@media(min-width: 992px){.quarto-secondary-nav{display:none}}.quarto-title-breadcrumbs .breadcrumb{margin-bottom:.5em;font-size:.9rem}.quarto-title-breadcrumbs .breadcrumb li:last-of-type a{color:#6c757d}.quarto-secondary-nav .quarto-btn-toggle{color:hsl(0,0%,35%)}.quarto-secondary-nav[aria-expanded=false] .quarto-btn-toggle .bi-chevron-right::before{transform:none}.quarto-secondary-nav[aria-expanded=true] .quarto-btn-toggle .bi-chevron-right::before{transform:rotate(90deg)}.quarto-secondary-nav .quarto-btn-toggle .bi-chevron-right::before{transition:transform 200ms ease}.quarto-secondary-nav{cursor:pointer}.no-decor{text-decoration:none}.quarto-secondary-nav-title{margin-top:.3em;color:hsl(0,0%,35%);padding-top:4px}.quarto-secondary-nav nav.quarto-page-breadcrumbs{color:hsl(0,0%,35%)}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{color:hsl(0,0%,35%)}.quarto-secondary-nav nav.quarto-page-breadcrumbs a:hover{color:rgba(32.76,81.48,190.68,.8)}.quarto-secondary-nav nav.quarto-page-breadcrumbs .breadcrumb-item::before{color:hsl(0,0%,55%)}.breadcrumb-item{line-height:1.2rem}div.sidebar-item-container{color:hsl(0,0%,35%)}div.sidebar-item-container:hover,div.sidebar-item-container:focus{color:rgba(32.76,81.48,190.68,.8)}div.sidebar-item-container.disabled{color:hsla(0,0%,35%,.75)}div.sidebar-item-container .active,div.sidebar-item-container .show>.nav-link,div.sidebar-item-container .sidebar-link>code{color:rgb(32.76,81.48,190.68)}div.sidebar.sidebar-navigation.rollup.quarto-sidebar-toggle-contents,nav.sidebar.sidebar-navigation:not(.rollup){background-color:#fff}@media(max-width: 991.98px){.sidebar-navigation .sidebar-item a,.nav-page .nav-page-text,.sidebar-navigation{font-size:1rem}.sidebar-navigation ul.sidebar-section.depth1 .sidebar-section-item{font-size:1.1rem}.sidebar-logo{display:none}.sidebar.sidebar-navigation{position:static;border-bottom:1px solid #dee2e6}.sidebar.sidebar-navigation.collapsing{position:fixed;z-index:1000}.sidebar.sidebar-navigation.show{position:fixed;z-index:1000}.sidebar.sidebar-navigation{min-height:100%}nav.quarto-secondary-nav{background-color:#fff;border-bottom:1px solid #dee2e6}.quarto-banner nav.quarto-secondary-nav{background-color:#f8f9fa;color:rgb(84.32,84.66,85);border-top:1px solid #dee2e6}.sidebar .sidebar-footer{visibility:visible;padding-top:1rem;position:inherit}.sidebar-tools-collapse{display:block}}#quarto-sidebar{transition:width .15s ease-in}#quarto-sidebar>*{padding-right:1em}@media(max-width: 991.98px){#quarto-sidebar .sidebar-menu-container{white-space:nowrap;min-width:225px}#quarto-sidebar.show{transition:width .15s ease-out}}@media(min-width: 992px){#quarto-sidebar{display:flex;flex-direction:column}.nav-page .nav-page-text,.sidebar-navigation .sidebar-section .sidebar-item{font-size:.875rem}.sidebar-navigation .sidebar-item{font-size:.925rem}.sidebar.sidebar-navigation{display:block;position:sticky}.sidebar-search{width:100%}.sidebar .sidebar-footer{visibility:visible}}@media(min-width: 992px){#quarto-sidebar-glass{display:none}}@media(max-width: 991.98px){#quarto-sidebar-glass{position:fixed;top:0;bottom:0;left:0;right:0;background-color:hsla(0,0%,100%,0);transition:background-color .15s ease-in;z-index:-1}#quarto-sidebar-glass.collapsing{z-index:1000}#quarto-sidebar-glass.show{transition:background-color .15s ease-out;background-color:hsla(0,0%,40%,.4);z-index:1000}}.sidebar .sidebar-footer{padding:.5rem 1rem;align-self:flex-end;color:#6c757d;width:100%}.quarto-page-breadcrumbs .breadcrumb-item+.breadcrumb-item,.quarto-page-breadcrumbs .breadcrumb-item{padding-right:.33em;padding-left:0}.quarto-page-breadcrumbs .breadcrumb-item::before{padding-right:.33em}.quarto-sidebar-footer{font-size:.875em}.sidebar-section .bi-chevron-right{vertical-align:middle}.sidebar-section .bi-chevron-right::before{font-size:.9em}.notransition{-webkit-transition:none !important;-moz-transition:none !important;-o-transition:none !important;transition:none !important}.btn:focus:not(:focus-visible){box-shadow:none}.page-navigation{display:flex;justify-content:space-between}.nav-page{padding-bottom:.75em}.nav-page .bi{font-size:1.8rem;vertical-align:middle}.nav-page .nav-page-text{padding-left:.25em;padding-right:.25em}.nav-page a{color:#6c757d;text-decoration:none;display:flex;align-items:center}.nav-page a:hover{color:rgb(31.2,77.6,181.6)}.nav-footer .toc-actions{padding-bottom:.5em;padding-top:.5em}.nav-footer .toc-actions a,.nav-footer .toc-actions a:hover{text-decoration:none}.nav-footer .toc-actions ul{display:flex;list-style:none}.nav-footer .toc-actions ul :first-child{margin-left:auto}.nav-footer .toc-actions ul :last-child{margin-right:auto}.nav-footer .toc-actions ul li{padding-right:1.5em}.nav-footer .toc-actions ul li i.bi{padding-right:.4em}.nav-footer .toc-actions ul li:last-of-type{padding-right:0}.nav-footer{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:baseline;text-align:center;padding-top:.5rem;padding-bottom:.5rem;background-color:#fff}body.nav-fixed{padding-top:64px}.nav-footer-contents{color:#6c757d;margin-top:.25rem}.nav-footer{min-height:3.5em;color:hsl(0,0%,46%)}.nav-footer a{color:hsl(0,0%,46%)}.nav-footer .nav-footer-left{font-size:.825em}.nav-footer .nav-footer-center{font-size:.825em}.nav-footer .nav-footer-right{font-size:.825em}.nav-footer-left .footer-items,.nav-footer-center .footer-items,.nav-footer-right .footer-items{display:inline-flex;padding-top:.3em;padding-bottom:.3em;margin-bottom:0em}.nav-footer-left .footer-items .nav-link,.nav-footer-center .footer-items .nav-link,.nav-footer-right .footer-items .nav-link{padding-left:.6em;padding-right:.6em}@media(min-width: 768px){.nav-footer-left{flex:1 1 0px;text-align:left}}@media(max-width: 575.98px){.nav-footer-left{margin-bottom:1em;flex:100%}}@media(min-width: 768px){.nav-footer-right{flex:1 1 0px;text-align:right}}@media(max-width: 575.98px){.nav-footer-right{margin-bottom:1em;flex:100%}}.nav-footer-center{text-align:center;min-height:3em}@media(min-width: 768px){.nav-footer-center{flex:1 1 0px}}.nav-footer-center .footer-items{justify-content:center}@media(max-width: 767.98px){.nav-footer-center{margin-bottom:1em;flex:100%}}@media(max-width: 767.98px){.nav-footer-center{margin-top:3em;order:10}}.navbar .quarto-reader-toggle.reader .quarto-reader-toggle-btn{background-color:rgb(84.32,84.66,85);border-radius:3px}@media(max-width: 991.98px){.quarto-reader-toggle{display:none}}.quarto-reader-toggle.reader.quarto-navigation-tool .quarto-reader-toggle-btn{background-color:hsl(0,0%,35%);border-radius:3px}.quarto-reader-toggle .quarto-reader-toggle-btn{display:inline-flex;padding-left:.2em;padding-right:.2em;margin-left:-0.2em;margin-right:-0.2em;text-align:center}.navbar .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}#quarto-back-to-top{display:none;position:fixed;bottom:50px;background-color:#fff;border-radius:.25rem;box-shadow:0 .2rem .5rem #6c757d,0 0 .05rem #6c757d;color:#6c757d;text-decoration:none;font-size:.9em;text-align:center;left:50%;padding:.4rem .8rem;transform:translate(-50%, 0)}#quarto-announcement{padding:.5em;display:flex;justify-content:space-between;margin-bottom:0;font-size:.9em}#quarto-announcement .quarto-announcement-content{margin-right:auto}#quarto-announcement .quarto-announcement-content p{margin-bottom:0}#quarto-announcement .quarto-announcement-icon{margin-right:.5em;font-size:1.2em;margin-top:-0.15em}#quarto-announcement .quarto-announcement-action{cursor:pointer}.aa-DetachedSearchButtonQuery{display:none}.aa-DetachedOverlay ul.aa-List,#quarto-search-results ul.aa-List{list-style:none;padding-left:0}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{background-color:#fff;position:absolute;z-index:2000}#quarto-search-results .aa-Panel{max-width:400px}#quarto-search input{font-size:.925rem}@media(min-width: 992px){.navbar #quarto-search{margin-left:.25rem;order:999}}.navbar.navbar-expand-sm #quarto-search,.navbar.navbar-expand-md #quarto-search{order:999}@media(min-width: 992px){.navbar .quarto-navbar-tools{order:900}}@media(min-width: 992px){.navbar .quarto-navbar-tools.tools-end{margin-left:auto !important}}@media(max-width: 991.98px){#quarto-sidebar .sidebar-search{display:none}}#quarto-sidebar .sidebar-search .aa-Autocomplete{width:100%}.navbar .aa-Autocomplete .aa-Form{width:180px}.navbar #quarto-search.type-overlay .aa-Autocomplete{width:40px}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form{background-color:inherit;border:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form:focus-within{box-shadow:none;outline:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper{display:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper:focus-within{display:inherit}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-Label svg,.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-LoadingIndicator svg{width:26px;height:26px;color:rgb(84.32,84.66,85);opacity:1}.navbar #quarto-search.type-overlay .aa-Autocomplete svg.aa-SubmitIcon{width:26px;height:26px;color:rgb(84.32,84.66,85);opacity:1}.aa-Autocomplete .aa-Form,.aa-DetachedFormContainer .aa-Form{align-items:center;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;color:#343a40;display:flex;line-height:1em;margin:0;position:relative;width:100%}.aa-Autocomplete .aa-Form:focus-within,.aa-DetachedFormContainer .aa-Form:focus-within{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix{align-items:center;display:flex;flex-shrink:0;order:1}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{cursor:initial;flex-shrink:0;padding:0;text-align:left}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg{color:#343a40;opacity:.5}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton{appearance:none;background:none;border:0;margin:0}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{align-items:center;display:flex;justify-content:center}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapper,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper{order:3;position:relative;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input{appearance:none;background:none;border:0;color:#343a40;font:inherit;height:calc(1.5em + .1rem + 2px);padding:0;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::placeholder,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::placeholder{color:#343a40;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input:focus{border-color:none;box-shadow:none;outline:none}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix{align-items:center;display:flex;order:4}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton{align-items:center;background:none;border:0;color:#343a40;opacity:.8;cursor:pointer;display:flex;margin:0;width:calc(1.5em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus{color:#343a40;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg{width:calc(1.5em + 0.75rem + calc(1px * 2))}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton{border:none;align-items:center;background:none;color:#343a40;opacity:.4;font-size:.7rem;cursor:pointer;display:none;margin:0;width:calc(1em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus{color:#343a40;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden]{display:none}.aa-PanelLayout:empty{display:none}.quarto-search-no-results.no-query{display:none}.aa-Source:has(.no-query){display:none}#quarto-search-results .aa-Panel{border:solid #dee2e6 1px}#quarto-search-results .aa-SourceNoResults{width:398px}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{max-height:65vh;overflow-y:auto;font-size:.925rem}.aa-DetachedOverlay .aa-SourceNoResults,#quarto-search-results .aa-SourceNoResults{height:60px;display:flex;justify-content:center;align-items:center}.aa-DetachedOverlay .search-error,#quarto-search-results .search-error{padding-top:10px;padding-left:20px;padding-right:20px;cursor:default}.aa-DetachedOverlay .search-error .search-error-title,#quarto-search-results .search-error .search-error-title{font-size:1.1rem;margin-bottom:.5rem}.aa-DetachedOverlay .search-error .search-error-title .search-error-icon,#quarto-search-results .search-error .search-error-title .search-error-icon{margin-right:8px}.aa-DetachedOverlay .search-error .search-error-text,#quarto-search-results .search-error .search-error-text{font-weight:300}.aa-DetachedOverlay .search-result-text,#quarto-search-results .search-result-text{font-weight:300;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.2rem;max-height:2.4rem}.aa-DetachedOverlay .aa-SourceHeader .search-result-header,#quarto-search-results .aa-SourceHeader .search-result-header{font-size:.875rem;background-color:hsl(0,0%,95%);padding-left:14px;padding-bottom:4px;padding-top:4px}.aa-DetachedOverlay .aa-SourceHeader .search-result-header-no-results,#quarto-search-results .aa-SourceHeader .search-result-header-no-results{display:none}.aa-DetachedOverlay .aa-SourceFooter .algolia-search-logo,#quarto-search-results .aa-SourceFooter .algolia-search-logo{width:110px;opacity:.85;margin:8px;float:right}.aa-DetachedOverlay .search-result-section,#quarto-search-results .search-result-section{font-size:.925em}.aa-DetachedOverlay a.search-result-link,#quarto-search-results a.search-result-link{color:inherit;text-decoration:none}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item,#quarto-search-results li.aa-Item[aria-selected=true] .search-item{background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text-container{color:#fff;background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=true] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-match.mark{color:#fff;background-color:rgb(75.1180327869,149.2360655738,231.6819672131)}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item,#quarto-search-results li.aa-Item[aria-selected=false] .search-item{background-color:#fff}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text-container{color:#343a40}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=false] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-match.mark{color:inherit;background-color:rgb(228.6196721311,239.4893442623,251.5803278689)}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container{background-color:#fff;color:#343a40}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container{padding-top:0px}.aa-DetachedOverlay li.aa-Item .search-result-doc.document-selectable .search-result-text-container,#quarto-search-results li.aa-Item .search-result-doc.document-selectable .search-result-text-container{margin-top:-4px}.aa-DetachedOverlay .aa-Item,#quarto-search-results .aa-Item{cursor:pointer}.aa-DetachedOverlay .aa-Item .search-item,#quarto-search-results .aa-Item .search-item{border-left:none;border-right:none;border-top:none;background-color:#fff;border-color:#dee2e6;color:#343a40}.aa-DetachedOverlay .aa-Item .search-item p,#quarto-search-results .aa-Item .search-item p{margin-top:0;margin-bottom:0}.aa-DetachedOverlay .aa-Item .search-item i.bi,#quarto-search-results .aa-Item .search-item i.bi{padding-left:8px;padding-right:8px;font-size:1.3em}.aa-DetachedOverlay .aa-Item .search-item .search-result-title,#quarto-search-results .aa-Item .search-item .search-result-title{margin-top:.3em;margin-bottom:0em}.aa-DetachedOverlay .aa-Item .search-item .search-result-crumbs,#quarto-search-results .aa-Item .search-item .search-result-crumbs{white-space:nowrap;text-overflow:ellipsis;font-size:.8em;font-weight:300;margin-right:1em}.aa-DetachedOverlay .aa-Item .search-item .search-result-crumbs:not(.search-result-crumbs-wrap),#quarto-search-results .aa-Item .search-item .search-result-crumbs:not(.search-result-crumbs-wrap){max-width:30%;margin-left:auto;margin-top:.5em;margin-bottom:.1rem}.aa-DetachedOverlay .aa-Item .search-item .search-result-crumbs.search-result-crumbs-wrap,#quarto-search-results .aa-Item .search-item .search-result-crumbs.search-result-crumbs-wrap{flex-basis:100%;margin-top:0em;margin-bottom:.2em;margin-left:37px}.aa-DetachedOverlay .aa-Item .search-result-title-container,#quarto-search-results .aa-Item .search-result-title-container{font-size:1em;display:flex;flex-wrap:wrap;padding:6px 4px 6px 4px}.aa-DetachedOverlay .aa-Item .search-result-text-container,#quarto-search-results .aa-Item .search-result-text-container{padding-bottom:8px;padding-right:8px;margin-left:42px}.aa-DetachedOverlay .aa-Item .search-result-doc-section,.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-doc-section,#quarto-search-results .aa-Item .search-result-more{padding-top:8px;padding-bottom:8px;padding-left:44px}.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-more{font-size:.8em;font-weight:400}.aa-DetachedOverlay .aa-Item .search-result-doc,#quarto-search-results .aa-Item .search-result-doc{border-top:1px solid #dee2e6}.aa-DetachedSearchButton{background:none;border:none}.aa-DetachedSearchButton .aa-DetachedSearchButtonPlaceholder{display:none}.navbar .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:rgb(84.32,84.66,85)}.sidebar-tools-collapse #quarto-search,.sidebar-tools-main #quarto-search{display:inline}.sidebar-tools-collapse #quarto-search .aa-Autocomplete,.sidebar-tools-main #quarto-search .aa-Autocomplete{display:inline}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton{padding-left:4px;padding-right:4px}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:hsl(0,0%,35%)}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon{margin-top:-3px}.aa-DetachedContainer{background:hsla(0,0%,100%,.65);width:90%;bottom:0;box-shadow:rgba(222,226,230,.6) 0 0 0 1px;outline:currentColor none medium;display:flex;flex-direction:column;left:0;margin:0;overflow:hidden;padding:0;position:fixed;right:0;top:0;z-index:1101}.aa-DetachedContainer::after{height:32px}.aa-DetachedContainer .aa-SourceHeader{margin:var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px}.aa-DetachedContainer .aa-Panel{background-color:#fff;border-radius:0;box-shadow:none;flex-grow:1;margin:0;padding:0;position:relative}.aa-DetachedContainer .aa-PanelLayout{bottom:0;box-shadow:none;left:0;margin:0;max-height:none;overflow-y:auto;position:absolute;right:0;top:0;width:100%}.aa-DetachedFormContainer{background-color:#fff;border-bottom:1px solid #dee2e6;display:flex;flex-direction:row;justify-content:space-between;margin:0;padding:.5em}.aa-DetachedCancelButton{background:none;font-size:.8em;border:0;border-radius:3px;color:#343a40;cursor:pointer;margin:0 0 0 .5em;padding:0 .5em}.aa-DetachedCancelButton:hover,.aa-DetachedCancelButton:focus{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-DetachedContainer--modal{bottom:inherit;height:auto;margin:0 auto;position:absolute;top:100px;border-radius:6px;max-width:850px}@media(max-width: 575.98px){.aa-DetachedContainer--modal{width:100%;top:0px;border-radius:0px;border:none}}.aa-DetachedContainer--modal .aa-PanelLayout{max-height:var(--aa-detached-modal-max-height);padding-bottom:var(--aa-spacing-half);position:static}.aa-Detached{height:100vh;overflow:hidden}.aa-DetachedOverlay{background-color:rgba(52,58,64,.4);position:fixed;left:0;right:0;top:0;margin:0;padding:0;height:100vh;z-index:1100}.quarto-dashboard.nav-fixed.dashboard-sidebar #quarto-content.quarto-dashboard-content{padding:0em}.quarto-dashboard #quarto-content.quarto-dashboard-content{padding:1em}.quarto-dashboard #quarto-content.quarto-dashboard-content>*{padding-top:0}@media(min-width: 576px){.quarto-dashboard{height:100%}}.quarto-dashboard .card.valuebox.bslib-card.bg-primary{background-color:#5397e9 !important}.quarto-dashboard .card.valuebox.bslib-card.bg-secondary{background-color:#343a40 !important}.quarto-dashboard .card.valuebox.bslib-card.bg-success{background-color:#3aa716 !important}.quarto-dashboard .card.valuebox.bslib-card.bg-info{background-color:rgba(153,84,187,.7019607843) !important}.quarto-dashboard .card.valuebox.bslib-card.bg-warning{background-color:#fa6400 !important}.quarto-dashboard .card.valuebox.bslib-card.bg-danger{background-color:rgba(255,0,57,.7019607843) !important}.quarto-dashboard .card.valuebox.bslib-card.bg-light{background-color:#f8f9fa !important}.quarto-dashboard .card.valuebox.bslib-card.bg-dark{background-color:#343a40 !important}.quarto-dashboard.dashboard-fill{display:flex;flex-direction:column}.quarto-dashboard #quarto-appendix{display:none}.quarto-dashboard #quarto-header #quarto-dashboard-header{border-top:solid 1px rgb(218.25,223.5,228.75);border-bottom:solid 1px rgb(218.25,223.5,228.75)}.quarto-dashboard #quarto-header #quarto-dashboard-header>nav{padding-left:1em;padding-right:1em}.quarto-dashboard #quarto-header #quarto-dashboard-header>nav .navbar-brand-container{padding-left:0}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-toggler{margin-right:0}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-toggler-icon{height:1em;width:1em;background-image:url('data:image/svg+xml,')}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-brand-container{padding-right:1em}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-title{font-size:1.1em}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-nav{font-size:.9em}.quarto-dashboard #quarto-dashboard-header .navbar{padding:0}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-container{padding-left:1em}.quarto-dashboard #quarto-dashboard-header .navbar.slim .navbar-brand-container .nav-link,.quarto-dashboard #quarto-dashboard-header .navbar.slim .navbar-nav .nav-link{padding:.7em}.quarto-dashboard #quarto-dashboard-header .navbar .quarto-color-scheme-toggle{order:9}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-toggler{margin-left:.5em;order:10}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-nav .nav-link{padding:.5em;height:100%;display:flex;align-items:center}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-nav .active{background-color:rgb(224.2,228.6,233)}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-brand-container{padding:.5em .5em .5em 0;display:flex;flex-direction:row;margin-right:2em;align-items:center}@media(max-width: 767.98px){.quarto-dashboard #quarto-dashboard-header .navbar .navbar-brand-container{margin-right:auto}}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-collapse{align-self:stretch}@media(min-width: 768px){.quarto-dashboard #quarto-dashboard-header .navbar .navbar-collapse{order:8}}@media(max-width: 767.98px){.quarto-dashboard #quarto-dashboard-header .navbar .navbar-collapse{order:1000;padding-bottom:.5em}}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-collapse .navbar-nav{align-self:stretch}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-title{font-size:1.25em;line-height:1.1em;display:flex;flex-direction:row;flex-wrap:wrap;align-items:baseline}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-title .navbar-title-text{margin-right:.4em}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-title a{text-decoration:none;color:inherit}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-subtitle,.quarto-dashboard #quarto-dashboard-header .navbar .navbar-author{font-size:.9rem;margin-right:.5em}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-author{margin-left:auto}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-logo{max-height:48px;min-height:30px;object-fit:cover;margin-right:1em}.quarto-dashboard #quarto-dashboard-header .navbar .quarto-dashboard-links{order:9;padding-right:1em}.quarto-dashboard #quarto-dashboard-header .navbar .quarto-dashboard-link-text{margin-left:.25em}.quarto-dashboard #quarto-dashboard-header .navbar .quarto-dashboard-link{padding-right:0em;padding-left:.7em;text-decoration:none;color:rgb(84.32,84.66,85)}.quarto-dashboard .page-layout-custom .tab-content{padding:0;border:none}.quarto-dashboard-img-contain{height:100%;width:100%;object-fit:contain}@media(max-width: 575.98px){.quarto-dashboard .bslib-grid{grid-template-rows:minmax(1em, max-content) !important}.quarto-dashboard .sidebar-content{height:inherit}.quarto-dashboard .page-layout-custom{min-height:100vh}}.quarto-dashboard.dashboard-toolbar>.page-layout-custom,.quarto-dashboard.dashboard-sidebar>.page-layout-custom{padding:0}.quarto-dashboard .quarto-dashboard-content.quarto-dashboard-pages{padding:0}.quarto-dashboard .callout{margin-bottom:0;margin-top:0}.quarto-dashboard .html-fill-container figure{overflow:hidden}.quarto-dashboard bslib-tooltip .rounded-pill{border:solid #6c757d 1px}.quarto-dashboard bslib-tooltip .rounded-pill .svg{fill:#343a40}.quarto-dashboard .tabset .dashboard-card-no-title .nav-tabs{margin-left:0;margin-right:auto}.quarto-dashboard .tabset .tab-content{border:none}.quarto-dashboard .tabset .card-header .nav-link[role=tab]{margin-top:-6px;padding-top:6px;padding-bottom:6px}.quarto-dashboard .card.valuebox,.quarto-dashboard .card.bslib-value-box{min-height:3rem}.quarto-dashboard .card.valuebox .card-body,.quarto-dashboard .card.bslib-value-box .card-body{padding:0}.quarto-dashboard .bslib-value-box .value-box-value{font-size:clamp(.1em,15cqw,5em)}.quarto-dashboard .bslib-value-box .value-box-showcase .bi{font-size:clamp(.1em,max(18cqw,5.2cqh),5em);text-align:center;height:1em}.quarto-dashboard .bslib-value-box .value-box-showcase .bi::before{vertical-align:1em}.quarto-dashboard .bslib-value-box .value-box-area{margin-top:auto;margin-bottom:auto}.quarto-dashboard .card figure.quarto-float{display:flex;flex-direction:column;align-items:center}.quarto-dashboard .dashboard-scrolling{padding:1em}.quarto-dashboard .full-height{height:100%}.quarto-dashboard .showcase-bottom .value-box-grid{display:grid;grid-template-columns:1fr;grid-template-rows:1fr auto;grid-template-areas:"top" "bottom"}.quarto-dashboard .showcase-bottom .value-box-grid .value-box-showcase{grid-area:bottom;padding:0;margin:0}.quarto-dashboard .showcase-bottom .value-box-grid .value-box-showcase i.bi{font-size:4rem}.quarto-dashboard .showcase-bottom .value-box-grid .value-box-area{grid-area:top}.quarto-dashboard .tab-content{margin-bottom:0}.quarto-dashboard .bslib-card .bslib-navs-card-title{justify-content:stretch;align-items:end}.quarto-dashboard .card-header{display:flex;flex-wrap:wrap;justify-content:space-between}.quarto-dashboard .card-header .card-title{display:flex;flex-direction:column;justify-content:center;margin-bottom:0}.quarto-dashboard .tabset .card-toolbar{margin-bottom:1em}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout{border:none;gap:var(--bslib-spacer, 1rem)}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout>.main{padding:0}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout>.sidebar{border-radius:.25rem;border:1px solid rgba(0,0,0,.175)}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout>.collapse-toggle{display:none}@media(max-width: 767.98px){.quarto-dashboard .bslib-grid>.bslib-sidebar-layout{grid-template-columns:1fr;grid-template-rows:max-content 1fr}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout>.main{grid-column:1;grid-row:2}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout .sidebar{grid-column:1;grid-row:1}}.quarto-dashboard .sidebar-right .sidebar{padding-left:2.5em}.quarto-dashboard .sidebar-right .collapse-toggle{left:2px}.quarto-dashboard .quarto-dashboard .sidebar-right button.collapse-toggle:not(.transitioning){left:unset}.quarto-dashboard aside.sidebar{padding-left:1em;padding-right:1em;background-color:rgba(52,58,64,.25);color:#343a40}.quarto-dashboard .bslib-sidebar-layout>div.main{padding:.7em}.quarto-dashboard .bslib-sidebar-layout button.collapse-toggle{margin-top:.3em}.quarto-dashboard .bslib-sidebar-layout .collapse-toggle{top:0}.quarto-dashboard .bslib-sidebar-layout.sidebar-collapsed:not(.transitioning):not(.sidebar-right) .collapse-toggle{left:2px}.quarto-dashboard .sidebar>section>.h3:first-of-type{margin-top:0em}.quarto-dashboard .sidebar .h3,.quarto-dashboard .sidebar .h4,.quarto-dashboard .sidebar .h5,.quarto-dashboard .sidebar .h6{margin-top:.5em}.quarto-dashboard .sidebar form{flex-direction:column;align-items:start;margin-bottom:1em}.quarto-dashboard .sidebar form div[class*=oi-][class$=-input]{flex-direction:column}.quarto-dashboard .sidebar form[class*=oi-][class$=-toggle]{flex-direction:row-reverse;align-items:center;justify-content:start}.quarto-dashboard .sidebar form input[type=range]{margin-top:.5em;margin-right:.8em;margin-left:1em}.quarto-dashboard .sidebar label{width:fit-content}.quarto-dashboard .sidebar .card-body{margin-bottom:2em}.quarto-dashboard .sidebar .shiny-input-container{margin-bottom:1em}.quarto-dashboard .sidebar .shiny-options-group{margin-top:0}.quarto-dashboard .sidebar .control-label{margin-bottom:.3em}.quarto-dashboard .card .card-body .quarto-layout-row{align-items:stretch}.quarto-dashboard .toolbar{font-size:.9em;display:flex;flex-direction:row;border-top:solid 1px hsl(210,3.0456852792%,74.5490196078%);padding:1em;flex-wrap:wrap;background-color:rgba(52,58,64,.25)}.quarto-dashboard .toolbar .cell-output-display{display:flex}.quarto-dashboard .toolbar .shiny-input-container{padding-bottom:.5em;margin-bottom:.5em;width:inherit}.quarto-dashboard .toolbar .shiny-input-container>.checkbox:first-child{margin-top:6px}.quarto-dashboard .toolbar>*:last-child{margin-right:0}.quarto-dashboard .toolbar>*>*{margin-right:1em;align-items:baseline}.quarto-dashboard .toolbar>*>*>a{text-decoration:none;margin-top:auto;margin-bottom:auto}.quarto-dashboard .toolbar .shiny-input-container{padding-bottom:0;margin-bottom:0}.quarto-dashboard .toolbar .shiny-input-container>*{flex-shrink:0;flex-grow:0}.quarto-dashboard .toolbar .form-group.shiny-input-container:not([role=group])>label{margin-bottom:0}.quarto-dashboard .toolbar .shiny-input-container.no-baseline{align-items:start;padding-top:6px}.quarto-dashboard .toolbar .shiny-input-container{display:flex;align-items:baseline}.quarto-dashboard .toolbar .shiny-input-container label{padding-right:.4em}.quarto-dashboard .toolbar .shiny-input-container .bslib-input-switch{margin-top:6px}.quarto-dashboard .toolbar input[type=text]{line-height:1;width:inherit}.quarto-dashboard .toolbar .input-daterange{width:inherit}.quarto-dashboard .toolbar .input-daterange input[type=text]{height:2.4em;width:10em}.quarto-dashboard .toolbar .input-daterange .input-group-addon{height:auto;padding:0;margin-left:-5px !important;margin-right:-5px}.quarto-dashboard .toolbar .input-daterange .input-group-addon .input-group-text{padding-top:0;padding-bottom:0;height:100%}.quarto-dashboard .toolbar span.irs.irs--shiny{width:10em}.quarto-dashboard .toolbar span.irs.irs--shiny .irs-line{top:9px}.quarto-dashboard .toolbar span.irs.irs--shiny .irs-min,.quarto-dashboard .toolbar span.irs.irs--shiny .irs-max,.quarto-dashboard .toolbar span.irs.irs--shiny .irs-from,.quarto-dashboard .toolbar span.irs.irs--shiny .irs-to,.quarto-dashboard .toolbar span.irs.irs--shiny .irs-single{top:20px}.quarto-dashboard .toolbar span.irs.irs--shiny .irs-bar{top:8px}.quarto-dashboard .toolbar span.irs.irs--shiny .irs-handle{top:0px}.quarto-dashboard .toolbar .shiny-input-checkboxgroup>label{margin-top:6px}.quarto-dashboard .toolbar .shiny-input-checkboxgroup>.shiny-options-group{margin-top:0;align-items:baseline}.quarto-dashboard .toolbar .shiny-input-radiogroup>label{margin-top:6px}.quarto-dashboard .toolbar .shiny-input-radiogroup>.shiny-options-group{align-items:baseline;margin-top:0}.quarto-dashboard .toolbar .shiny-input-radiogroup>.shiny-options-group>.radio{margin-right:.3em}.quarto-dashboard .toolbar .form-select{padding-top:.2em;padding-bottom:.2em}.quarto-dashboard .toolbar .shiny-input-select{min-width:6em}.quarto-dashboard .toolbar div.checkbox{margin-bottom:0px}.quarto-dashboard .toolbar>.checkbox:first-child{margin-top:6px}.quarto-dashboard .toolbar form{width:fit-content}.quarto-dashboard .toolbar form label{padding-top:.2em;padding-bottom:.2em;width:fit-content}.quarto-dashboard .toolbar form input[type=date]{width:fit-content}.quarto-dashboard .toolbar form input[type=color]{width:3em}.quarto-dashboard .toolbar form button{padding:.4em}.quarto-dashboard .toolbar form select{width:fit-content}.quarto-dashboard .toolbar>*{font-size:.9em;flex-grow:0}.quarto-dashboard .toolbar .shiny-input-container label{margin-bottom:1px}.quarto-dashboard .toolbar-bottom{margin-top:1em;margin-bottom:0 !important;order:2}.quarto-dashboard .quarto-dashboard-content>.dashboard-toolbar-container>.toolbar-content>.tab-content>.tab-pane>*:not(.bslib-sidebar-layout){padding:1em}.quarto-dashboard .quarto-dashboard-content>.dashboard-toolbar-container>.toolbar-content>*:not(.tab-content){padding:1em}.quarto-dashboard .quarto-dashboard-content>.tab-content>.dashboard-page>.dashboard-toolbar-container>.toolbar-content,.quarto-dashboard .quarto-dashboard-content>.tab-content>.dashboard-page:not(.dashboard-sidebar-container)>*:not(.dashboard-toolbar-container){padding:1em}.quarto-dashboard .toolbar-content{padding:0}.quarto-dashboard .quarto-dashboard-content.quarto-dashboard-pages .tab-pane>.dashboard-toolbar-container .toolbar{border-radius:0;margin-bottom:0}.quarto-dashboard .dashboard-toolbar-container.toolbar-toplevel .toolbar{border-bottom:1px solid rgba(0,0,0,.175)}.quarto-dashboard .dashboard-toolbar-container.toolbar-toplevel .toolbar-bottom{margin-top:0}.quarto-dashboard .dashboard-toolbar-container:not(.toolbar-toplevel) .toolbar{margin-bottom:1em;border-top:none;border-radius:.25rem;border:1px solid rgba(0,0,0,.175)}.quarto-dashboard .vega-embed.has-actions details{width:1.7em;height:2em;position:absolute !important;top:0;right:0}.quarto-dashboard .dashboard-toolbar-container{padding:0}.quarto-dashboard .card .card-header p:last-child,.quarto-dashboard .card .card-footer p:last-child{margin-bottom:0}.quarto-dashboard .card .card-body>.h4:first-child{margin-top:0}.quarto-dashboard .card .card-body{z-index:4}@media(max-width: 767.98px){.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_length,.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_info,.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_paginate{text-align:initial}.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_filter{text-align:right}.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_paginate ul.pagination{justify-content:initial}}.quarto-dashboard .card .card-body .itables .dataTables_wrapper{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;padding-top:0}.quarto-dashboard .card .card-body .itables .dataTables_wrapper table{flex-shrink:0}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dt-buttons{margin-bottom:.5em;margin-left:auto;width:fit-content;float:right}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dt-buttons.btn-group{background:#fff;border:none}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dt-buttons .btn-secondary{background-color:#fff;background-image:none;border:solid #dee2e6 1px;padding:.2em .7em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dt-buttons .btn span{font-size:.8em;color:#343a40}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_info{margin-left:.5em;margin-bottom:.5em;padding-top:0}@media(min-width: 768px){.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_info{font-size:.875em}}@media(max-width: 767.98px){.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_info{font-size:.8em}}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_filter{margin-bottom:.5em;font-size:.875em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_filter input[type=search]{padding:1px 5px 1px 5px;font-size:.875em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_length{flex-basis:1 1 50%;margin-bottom:.5em;font-size:.875em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_length select{padding:.4em 3em .4em .5em;font-size:.875em;margin-left:.2em;margin-right:.2em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_paginate{flex-shrink:0}@media(min-width: 768px){.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_paginate{margin-left:auto}}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_paginate ul.pagination .paginate_button .page-link{font-size:.8em}.quarto-dashboard .card .card-footer{font-size:.9em}.quarto-dashboard .card .card-toolbar{display:flex;flex-grow:1;flex-direction:row;width:100%;flex-wrap:wrap}.quarto-dashboard .card .card-toolbar>*{font-size:.8em;flex-grow:0}.quarto-dashboard .card .card-toolbar>.card-title{font-size:1em;flex-grow:1;align-self:flex-start;margin-top:.1em}.quarto-dashboard .card .card-toolbar .cell-output-display{display:flex}.quarto-dashboard .card .card-toolbar .shiny-input-container{padding-bottom:.5em;margin-bottom:.5em;width:inherit}.quarto-dashboard .card .card-toolbar .shiny-input-container>.checkbox:first-child{margin-top:6px}.quarto-dashboard .card .card-toolbar>*:last-child{margin-right:0}.quarto-dashboard .card .card-toolbar>*>*{margin-right:1em;align-items:baseline}.quarto-dashboard .card .card-toolbar>*>*>a{text-decoration:none;margin-top:auto;margin-bottom:auto}.quarto-dashboard .card .card-toolbar form{width:fit-content}.quarto-dashboard .card .card-toolbar form label{padding-top:.2em;padding-bottom:.2em;width:fit-content}.quarto-dashboard .card .card-toolbar form input[type=date]{width:fit-content}.quarto-dashboard .card .card-toolbar form input[type=color]{width:3em}.quarto-dashboard .card .card-toolbar form button{padding:.4em}.quarto-dashboard .card .card-toolbar form select{width:fit-content}.quarto-dashboard .card .card-toolbar .cell-output-display{display:flex}.quarto-dashboard .card .card-toolbar .shiny-input-container{padding-bottom:.5em;margin-bottom:.5em;width:inherit}.quarto-dashboard .card .card-toolbar .shiny-input-container>.checkbox:first-child{margin-top:6px}.quarto-dashboard .card .card-toolbar>*:last-child{margin-right:0}.quarto-dashboard .card .card-toolbar>*>*{margin-right:1em;align-items:baseline}.quarto-dashboard .card .card-toolbar>*>*>a{text-decoration:none;margin-top:auto;margin-bottom:auto}.quarto-dashboard .card .card-toolbar .shiny-input-container{padding-bottom:0;margin-bottom:0}.quarto-dashboard .card .card-toolbar .shiny-input-container>*{flex-shrink:0;flex-grow:0}.quarto-dashboard .card .card-toolbar .form-group.shiny-input-container:not([role=group])>label{margin-bottom:0}.quarto-dashboard .card .card-toolbar .shiny-input-container.no-baseline{align-items:start;padding-top:6px}.quarto-dashboard .card .card-toolbar .shiny-input-container{display:flex;align-items:baseline}.quarto-dashboard .card .card-toolbar .shiny-input-container label{padding-right:.4em}.quarto-dashboard .card .card-toolbar .shiny-input-container .bslib-input-switch{margin-top:6px}.quarto-dashboard .card .card-toolbar input[type=text]{line-height:1;width:inherit}.quarto-dashboard .card .card-toolbar .input-daterange{width:inherit}.quarto-dashboard .card .card-toolbar .input-daterange input[type=text]{height:2.4em;width:10em}.quarto-dashboard .card .card-toolbar .input-daterange .input-group-addon{height:auto;padding:0;margin-left:-5px !important;margin-right:-5px}.quarto-dashboard .card .card-toolbar .input-daterange .input-group-addon .input-group-text{padding-top:0;padding-bottom:0;height:100%}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny{width:10em}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-line{top:9px}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-min,.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-max,.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-from,.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-to,.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-single{top:20px}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-bar{top:8px}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-handle{top:0px}.quarto-dashboard .card .card-toolbar .shiny-input-checkboxgroup>label{margin-top:6px}.quarto-dashboard .card .card-toolbar .shiny-input-checkboxgroup>.shiny-options-group{margin-top:0;align-items:baseline}.quarto-dashboard .card .card-toolbar .shiny-input-radiogroup>label{margin-top:6px}.quarto-dashboard .card .card-toolbar .shiny-input-radiogroup>.shiny-options-group{align-items:baseline;margin-top:0}.quarto-dashboard .card .card-toolbar .shiny-input-radiogroup>.shiny-options-group>.radio{margin-right:.3em}.quarto-dashboard .card .card-toolbar .form-select{padding-top:.2em;padding-bottom:.2em}.quarto-dashboard .card .card-toolbar .shiny-input-select{min-width:6em}.quarto-dashboard .card .card-toolbar div.checkbox{margin-bottom:0px}.quarto-dashboard .card .card-toolbar>.checkbox:first-child{margin-top:6px}.quarto-dashboard .card-body>table>thead{border-top:none}.quarto-dashboard .card-body>.table>:not(caption)>*>*{background-color:#fff}.tableFloatingHeaderOriginal{background-color:#fff;position:sticky !important;top:0 !important}.dashboard-data-table{margin-top:-1px}div.value-box-area span.observablehq--number{font-size:calc(clamp(.1em,15cqw,5em)*1.25);line-height:1.2;color:inherit;font-family:var(--bs-body-font-family)}.quarto-listing{padding-bottom:1em}.listing-pagination{padding-top:.5em}ul.pagination{float:right;padding-left:8px;padding-top:.5em}ul.pagination li{padding-right:.75em}ul.pagination li.disabled a,ul.pagination li.active a{color:#fff;text-decoration:none}ul.pagination li:last-of-type{padding-right:0}.listing-actions-group{display:flex}.quarto-listing-filter{margin-bottom:1em;width:200px;margin-left:auto}.quarto-listing-sort{margin-bottom:1em;margin-right:auto;width:auto}.quarto-listing-sort .input-group-text{font-size:.8em}.input-group-text{border-right:none}.quarto-listing-sort select.form-select{font-size:.8em}.listing-no-matching{text-align:center;padding-top:2em;padding-bottom:3em;font-size:1em}#quarto-margin-sidebar .quarto-listing-category{padding-top:0;font-size:1rem}#quarto-margin-sidebar .quarto-listing-category-title{cursor:pointer;font-weight:600;font-size:1rem}.quarto-listing-category .category{cursor:pointer}.quarto-listing-category .category.active{font-weight:600}.quarto-listing-category.category-cloud{display:flex;flex-wrap:wrap;align-items:baseline}.quarto-listing-category.category-cloud .category{padding-right:5px}.quarto-listing-category.category-cloud .category-cloud-1{font-size:.75em}.quarto-listing-category.category-cloud .category-cloud-2{font-size:.95em}.quarto-listing-category.category-cloud .category-cloud-3{font-size:1.15em}.quarto-listing-category.category-cloud .category-cloud-4{font-size:1.35em}.quarto-listing-category.category-cloud .category-cloud-5{font-size:1.55em}.quarto-listing-category.category-cloud .category-cloud-6{font-size:1.75em}.quarto-listing-category.category-cloud .category-cloud-7{font-size:1.95em}.quarto-listing-category.category-cloud .category-cloud-8{font-size:2.15em}.quarto-listing-category.category-cloud .category-cloud-9{font-size:2.35em}.quarto-listing-category.category-cloud .category-cloud-10{font-size:2.55em}.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-1{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-2{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-3{grid-template-columns:repeat(3, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-3{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-3{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-4{grid-template-columns:repeat(4, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-4{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-4{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-5{grid-template-columns:repeat(5, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-5{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-5{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-6{grid-template-columns:repeat(6, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-6{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-6{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-7{grid-template-columns:repeat(7, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-7{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-7{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-8{grid-template-columns:repeat(8, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-8{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-8{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-9{grid-template-columns:repeat(9, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-9{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-9{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-10{grid-template-columns:repeat(10, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-10{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-10{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-11{grid-template-columns:repeat(11, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-11{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-11{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-12{grid-template-columns:repeat(12, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-12{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-12{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-grid{gap:1.5em}.quarto-grid-item.borderless{border:none}.quarto-grid-item.borderless .listing-categories .listing-category:last-of-type,.quarto-grid-item.borderless .listing-categories .listing-category:first-of-type{padding-left:0}.quarto-grid-item.borderless .listing-categories .listing-category{border:0}.quarto-grid-link{text-decoration:none;color:inherit}.quarto-grid-link:hover{text-decoration:none;color:inherit}.quarto-grid-item h5.title,.quarto-grid-item .title.h5{margin-top:0;margin-bottom:0}.quarto-grid-item .card-footer{display:flex;justify-content:space-between;font-size:.8em}.quarto-grid-item .card-footer p{margin-bottom:0}.quarto-grid-item p.card-img-top{margin-bottom:0}.quarto-grid-item p.card-img-top>img{object-fit:cover}.quarto-grid-item .card-other-values{margin-top:.5em;font-size:.8em}.quarto-grid-item .card-other-values tr{margin-bottom:.5em}.quarto-grid-item .card-other-values tr>td:first-of-type{font-weight:600;padding-right:1em;padding-left:1em;vertical-align:top}.quarto-grid-item div.post-contents{display:flex;flex-direction:column;text-decoration:none;height:100%}.quarto-grid-item .listing-item-img-placeholder{background-color:rgba(52,58,64,.25);flex-shrink:0}.quarto-grid-item .card-attribution{padding-top:1em;display:flex;gap:1em;text-transform:uppercase;color:#6c757d;font-weight:500;flex-grow:10;align-items:flex-end}.quarto-grid-item .description{padding-bottom:1em}.quarto-grid-item .card-attribution .date{align-self:flex-end}.quarto-grid-item .card-attribution.justify{justify-content:space-between}.quarto-grid-item .card-attribution.start{justify-content:flex-start}.quarto-grid-item .card-attribution.end{justify-content:flex-end}.quarto-grid-item .card-title{margin-bottom:.1em}.quarto-grid-item .card-subtitle{padding-top:.25em}.quarto-grid-item .card-text{font-size:.9em}.quarto-grid-item .listing-reading-time{padding-bottom:.25em}.quarto-grid-item .card-text-small{font-size:.8em}.quarto-grid-item .card-subtitle.subtitle{font-size:.9em;font-weight:600;padding-bottom:.5em}.quarto-grid-item .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}.quarto-grid-item .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}.quarto-grid-item.card-right{text-align:right}.quarto-grid-item.card-right .listing-categories{justify-content:flex-end}.quarto-grid-item.card-left{text-align:left}.quarto-grid-item.card-center{text-align:center}.quarto-grid-item.card-center .listing-description{text-align:justify}.quarto-grid-item.card-center .listing-categories{justify-content:center}table.quarto-listing-table td.image{padding:0px}table.quarto-listing-table td.image img{width:100%;max-width:50px;object-fit:contain}table.quarto-listing-table a{text-decoration:none;word-break:keep-all}table.quarto-listing-table th a{color:inherit}table.quarto-listing-table th a.asc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table th a.desc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table.table-hover td{cursor:pointer}.quarto-post.image-left{flex-direction:row}.quarto-post.image-right{flex-direction:row-reverse}@media(max-width: 767.98px){.quarto-post.image-right,.quarto-post.image-left{gap:0em;flex-direction:column}.quarto-post .metadata{padding-bottom:1em;order:2}.quarto-post .body{order:1}.quarto-post .thumbnail{order:3}}.list.quarto-listing-default div:last-of-type{border-bottom:none}@media(min-width: 992px){.quarto-listing-container-default{margin-right:2em}}div.quarto-post{display:flex;gap:2em;margin-bottom:1.5em;border-bottom:1px solid #dee2e6}@media(max-width: 767.98px){div.quarto-post{padding-bottom:1em}}div.quarto-post .metadata{flex-basis:20%;flex-grow:0;margin-top:.2em;flex-shrink:10}div.quarto-post .thumbnail{flex-basis:30%;flex-grow:0;flex-shrink:0}div.quarto-post .thumbnail img{margin-top:.4em;width:100%;object-fit:cover}div.quarto-post .body{flex-basis:45%;flex-grow:1;flex-shrink:0}div.quarto-post .body h3.listing-title,div.quarto-post .body .listing-title.h3{margin-top:0px;margin-bottom:0px;border-bottom:none}div.quarto-post .body .listing-subtitle{font-size:.875em;margin-bottom:.5em;margin-top:.2em}div.quarto-post .body .description{font-size:.9em}div.quarto-post .body pre code{white-space:pre-wrap}div.quarto-post a{color:#343a40;text-decoration:none}div.quarto-post .metadata{display:flex;flex-direction:column;font-size:.8em;font-family:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";flex-basis:33%}div.quarto-post .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}div.quarto-post .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}div.quarto-post .listing-description{margin-bottom:.5em}div.quarto-about-jolla{display:flex !important;flex-direction:column;align-items:center;margin-top:10%;padding-bottom:1em}div.quarto-about-jolla .about-image{object-fit:cover;margin-left:auto;margin-right:auto;margin-bottom:1.5em}div.quarto-about-jolla img.round{border-radius:50%}div.quarto-about-jolla img.rounded{border-radius:10px}div.quarto-about-jolla .quarto-title h1.title,div.quarto-about-jolla .quarto-title .title.h1{text-align:center}div.quarto-about-jolla .quarto-title .description{text-align:center}div.quarto-about-jolla h2,div.quarto-about-jolla .h2{border-bottom:none}div.quarto-about-jolla .about-sep{width:60%}div.quarto-about-jolla main{text-align:center}div.quarto-about-jolla .about-links{display:flex}@media(min-width: 992px){div.quarto-about-jolla .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-jolla .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-jolla .about-link{color:rgb(97.724137931,109,120.275862069);text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-jolla .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-jolla .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-jolla .about-link:hover{color:#2761e3}div.quarto-about-jolla .about-link i.bi{margin-right:.15em}div.quarto-about-solana{display:flex !important;flex-direction:column;padding-top:3em !important;padding-bottom:1em}div.quarto-about-solana .about-entity{display:flex !important;align-items:start;justify-content:space-between}@media(min-width: 992px){div.quarto-about-solana .about-entity{flex-direction:row}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity{flex-direction:column-reverse;align-items:center;text-align:center}}div.quarto-about-solana .about-entity .entity-contents{display:flex;flex-direction:column}@media(max-width: 767.98px){div.quarto-about-solana .about-entity .entity-contents{width:100%}}div.quarto-about-solana .about-entity .about-image{object-fit:cover}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-image{margin-bottom:1.5em}}div.quarto-about-solana .about-entity img.round{border-radius:50%}div.quarto-about-solana .about-entity img.rounded{border-radius:10px}div.quarto-about-solana .about-entity .about-links{display:flex;justify-content:left;padding-bottom:1.2em}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-solana .about-entity .about-link{color:rgb(97.724137931,109,120.275862069);text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-solana .about-entity .about-link:hover{color:#2761e3}div.quarto-about-solana .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-solana .about-contents{padding-right:1.5em;flex-basis:0;flex-grow:1}div.quarto-about-solana .about-contents main.content{margin-top:0}div.quarto-about-solana .about-contents h2,div.quarto-about-solana .about-contents .h2{border-bottom:none}div.quarto-about-trestles{display:flex !important;flex-direction:row;padding-top:3em !important;padding-bottom:1em}@media(max-width: 991.98px){div.quarto-about-trestles{flex-direction:column;padding-top:0em !important}}div.quarto-about-trestles .about-entity{display:flex !important;flex-direction:column;align-items:center;text-align:center;padding-right:1em}@media(min-width: 992px){div.quarto-about-trestles .about-entity{flex:0 0 42%}}div.quarto-about-trestles .about-entity .about-image{object-fit:cover;margin-bottom:1.5em}div.quarto-about-trestles .about-entity img.round{border-radius:50%}div.quarto-about-trestles .about-entity img.rounded{border-radius:10px}div.quarto-about-trestles .about-entity .about-links{display:flex;justify-content:center}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-trestles .about-entity .about-link{color:rgb(97.724137931,109,120.275862069);text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-trestles .about-entity .about-link:hover{color:#2761e3}div.quarto-about-trestles .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-trestles .about-contents{flex-basis:0;flex-grow:1}div.quarto-about-trestles .about-contents h2,div.quarto-about-trestles .about-contents .h2{border-bottom:none}@media(min-width: 992px){div.quarto-about-trestles .about-contents{border-left:solid 1px #dee2e6;padding-left:1.5em}}div.quarto-about-trestles .about-contents main.content{margin-top:0}div.quarto-about-marquee{padding-bottom:1em}div.quarto-about-marquee .about-contents{display:flex;flex-direction:column}div.quarto-about-marquee .about-image{max-height:550px;margin-bottom:1.5em;object-fit:cover}div.quarto-about-marquee img.round{border-radius:50%}div.quarto-about-marquee img.rounded{border-radius:10px}div.quarto-about-marquee h2,div.quarto-about-marquee .h2{border-bottom:none}div.quarto-about-marquee .about-links{display:flex;justify-content:center;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-marquee .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-marquee .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-marquee .about-link{color:rgb(97.724137931,109,120.275862069);text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-marquee .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-marquee .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-marquee .about-link:hover{color:#2761e3}div.quarto-about-marquee .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-marquee .about-link{border:none}}div.quarto-about-broadside{display:flex;flex-direction:column;padding-bottom:1em}div.quarto-about-broadside .about-main{display:flex !important;padding-top:0 !important}@media(min-width: 992px){div.quarto-about-broadside .about-main{flex-direction:row;align-items:flex-start}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main{flex-direction:column}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main .about-entity{flex-shrink:0;width:100%;height:450px;margin-bottom:1.5em;background-size:cover;background-repeat:no-repeat}}@media(min-width: 992px){div.quarto-about-broadside .about-main .about-entity{flex:0 10 50%;margin-right:1.5em;width:100%;height:100%;background-size:100%;background-repeat:no-repeat}}div.quarto-about-broadside .about-main .about-contents{padding-top:14px;flex:0 0 50%}div.quarto-about-broadside h2,div.quarto-about-broadside .h2{border-bottom:none}div.quarto-about-broadside .about-sep{margin-top:1.5em;width:60%;align-self:center}div.quarto-about-broadside .about-links{display:flex;justify-content:center;column-gap:20px;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-broadside .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-broadside .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-broadside .about-link{color:rgb(97.724137931,109,120.275862069);text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-broadside .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-broadside .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-broadside .about-link:hover{color:#2761e3}div.quarto-about-broadside .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-broadside .about-link{border:none}}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.25rem;color:#343a40;font-size:.875rem}.tippy-box[data-theme~=quarto]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=quarto]>.tippy-arrow:after,.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=quarto]>.tippy-arrow:after{border-color:rgba(0,0,0,0);border-style:solid}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-6px}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-6px}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-6px}.tippy-box[data-placement^=left]>.tippy-arrow:before{right:-6px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:after{border-top-color:#dee2e6;border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:#dee2e6;border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:15px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:after{border-left-color:#dee2e6;border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:#dee2e6}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow{fill:#343a40}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px}.top-right{position:absolute;top:1em;right:1em}.visually-hidden{border:0;clip:rect(0 0 0 0);height:auto;margin:0;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}figure.figure{display:block}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p,.quarto-figure-left>figure>div{text-align:left}.quarto-figure-center>figure>p,.quarto-figure-center>figure>div{text-align:center}.quarto-figure-right>figure>p,.quarto-figure-right>figure>div{text-align:right}.quarto-figure>figure>div.cell-annotation,.quarto-figure>figure>div code{text-align:left}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption.quarto-float-caption-bottom{margin-bottom:.5em}figure>figcaption.quarto-float-caption-top{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link{position:absolute;top:.6em;right:.5em}div[id^=tbl-]>.anchorjs-link{position:absolute;top:.7em;right:.3em}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,table.table{margin-top:.5rem;margin-bottom:.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-top{margin-top:.5rem;margin-bottom:.25rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-bottom{padding-top:.25rem;margin-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:#6c757d}details>summary>p:only-child{display:inline}div.code-copy-outer-scaffold{position:relative}dd code:not(.sourceCode),p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.footnote-back{margin-left:.2em}.tippy-content{overflow-x:auto}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x),.knitsql-table:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}a{text-underline-offset:3px}.callout pre.sourceCode{padding-left:0}div.ansi-escaped-output{font-family:monospace;display:block}/*! +* +* ansi colors from IPython notebook's +* +* we also add `bright-[color]-` synonyms for the `-[color]-intense` classes since +* that seems to be what ansi_up emits +* +*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-black,.ansi-bright-black-fg{color:#282c36}.ansi-black-intense-black,.ansi-bright-black-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-red,.ansi-bright-red-fg{color:#b22b31}.ansi-red-intense-red,.ansi-bright-red-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-green,.ansi-bright-green-fg{color:#007427}.ansi-green-intense-green,.ansi-bright-green-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-yellow,.ansi-bright-yellow-fg{color:#b27d12}.ansi-yellow-intense-yellow,.ansi-bright-yellow-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-blue,.ansi-bright-blue-fg{color:#0065ca}.ansi-blue-intense-blue,.ansi-bright-blue-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-magenta,.ansi-bright-magenta-fg{color:#a03196}.ansi-magenta-intense-magenta,.ansi-bright-magenta-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-cyan,.ansi-bright-cyan-fg{color:#258f8f}.ansi-cyan-intense-cyan,.ansi-bright-cyan-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-white,.ansi-bright-white-fg{color:#a1a6b2}.ansi-white-intense-white,.ansi-bright-white-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #fff;--quarto-body-color: #343a40;--quarto-text-muted: #6c757d;--quarto-border-color: #dee2e6;--quarto-border-width: 1px}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:rgba(0,0,0,0)}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}.code-annotation-tip-content{word-wrap:break-word}.code-annotation-container-hidden{display:none !important}dl.code-annotation-container-grid{display:grid;grid-template-columns:min-content auto}dl.code-annotation-container-grid dt{grid-column:1}dl.code-annotation-container-grid dd{grid-column:2}pre.sourceCode.code-annotation-code{padding-right:0}code.sourceCode .code-annotation-anchor{z-index:100;position:relative;float:right;background-color:rgba(0,0,0,0)}input[type=checkbox]{margin-right:.5ch}:root{--mermaid-bg-color: #fff;--mermaid-edge-color: #343a40;--mermaid-node-fg-color: #343a40;--mermaid-fg-color: #343a40;--mermaid-fg-color--lighter: rgb(74.8620689655, 83.5, 92.1379310345);--mermaid-fg-color--lightest: rgb(97.724137931, 109, 120.275862069);--mermaid-font-family: Source Sans Pro, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;--mermaid-label-bg-color: #fff;--mermaid-label-fg-color: #2780e3;--mermaid-node-bg-color: rgba(39, 128, 227, 0.1);--mermaid-node-fg-color: #343a40}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button-tooltip{font-size:.75em}div.code-copy-outer-scaffold:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}div.code-copy-outer-scaffold:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}div.code-copy-outer-scaffold:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}div.code-copy-outer-scaffold:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(1050px - 3em)) [body-content-end] 1.5em [body-end] 21px [body-end-outset] minmax(45px, 87px) [page-end-inset] 21px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(1050px - 3em)) [body-content-end] 1.5em [body-end] 21px [body-end-outset] 21px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(1050px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(0px, 120px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1050px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 150px) [page-end-inset] minmax(50px, 100px) [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(0px, 120px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(0px, 120px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] minmax(15px, 30px) [body-end-outset] minmax(30px, 90px) [page-end-inset] minmax(15px, 30px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(30px, 60px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(950px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(0px, 120px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(0px, 120px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(950px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(30px, 90px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] minmax(15px, 30px) [body-end-outset] minmax(30px, 90px) [page-end-inset] minmax(15px, 30px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 21px [body-end-outset] minmax(45px, 87px) [page-end-inset] 21px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 21px [body-end-outset] minmax(45px, 87px) [page-end-inset] 21px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1450px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1.5em [body-content-start] minmax(500px, calc(950px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(45px, 90px) [page-end-inset] 15px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(950px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(15px, 30px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(950px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(15px, 30px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(950px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(15px, 30px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(950px - 3em)) [body-content-end] 1.5em [body-end] 21px [body-end-outset] minmax(45px, 87px) [page-end-inset] 21px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(950px - 3em)) [body-content-end] 1.5em [body-end] 30px [body-end-outset] minmax(45px, 90px) [page-end-inset] 15px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left .page-columns.page-full>*,.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right .page-columns.page-full>*,.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;opacity:.999}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse,#quarto-content.page-columns #quarto-margin-sidebar.collapsing,#quarto-content.page-columns #quarto-sidebar.collapsing{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}.zindex-content{z-index:998;opacity:.999}.zindex-modal{z-index:1055;opacity:.999}.zindex-over-content{z-index:999;opacity:.999}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside:not(.footnotes):not(.sidebar),.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}#quarto-sidebar-toc-left{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{color:inherit;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{margin-top:0}main.content>p:has(+section){margin-bottom:2rem}main.content>section:first-of-type>h2:nth-child(1),main.content>section:first-of-type>.h2:nth-child(1){margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3{font-weight:600}h3,.h3,h4,.h4{opacity:.9;margin-top:1.5rem}h5,.h5,h6,.h6{opacity:.9}.header-section-number{color:hsl(210,10.3448275862%,47.7450980392%)}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,.figure-caption,.subfigure-caption,.table-caption,figcaption,caption{font-size:.9rem;color:hsl(210,10.3448275862%,47.7450980392%)}.quarto-layout-cell[data-ref-parent] caption{color:hsl(210,10.3448275862%,47.7450980392%)}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:hsl(210,10.3448275862%,47.7450980392%);font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse):first-child{padding-bottom:.5em;display:block}.column-margin.column-container>*:not(.collapse):not(:first-child){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.nav-tabs .nav-item{margin-top:1px;cursor:pointer}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:0}.tab-pane>p:nth-child(1){padding-top:0}.tab-pane>p:last-child{margin-bottom:0}.tab-pane>pre:last-child{margin-bottom:0}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65)}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.875em;overflow-y:visible !important;padding:.4em}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:hsl(210,10.3448275862%,47.7450980392%)}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p code.sourceCode,li code.sourceCode,td code.sourceCode{background-color:rgba(233,236,239,.65)}p pre code:not(.sourceCode),li pre code:not(.sourceCode),pre code:not(.sourceCode){background-color:initial}p code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:rgba(233,236,239,.65);padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode),nav td code:not(.sourceCode){background-color:rgba(0,0,0,0);padding:0}td code:not(.sourceCode){white-space:pre-wrap}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:#6c757d;background-color:rgba(0,0,0,0);transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:#6c757d;margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#2761e3}.quarto-notebook-link::before{display:inline-block;height:.75rem;width:.75rem;margin-bottom:0em;margin-right:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}.toc-actions i.bi,.quarto-code-links i.bi,.quarto-other-links i.bi,.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em;font-size:.8rem}.quarto-other-links-text-target .quarto-code-links i.bi,.quarto-other-links-text-target .quarto-other-links i.bi{margin-right:.2em}.quarto-other-formats-text-target .quarto-alternate-formats i.bi{margin-right:.1em}.toc-actions i.bi.empty,.quarto-code-links i.bi.empty,.quarto-other-links i.bi.empty,.quarto-alternate-notebooks i.bi.empty,.quarto-alternate-formats i.bi.empty{padding-left:1em}.quarto-notebook h2,.quarto-notebook .h2{border-bottom:none}.quarto-notebook .cell-container{display:flex}.quarto-notebook .cell-container .cell{flex-grow:4}.quarto-notebook .cell-container .cell-decorator{padding-top:1.5em;padding-right:1em;text-align:right}.quarto-notebook .cell-container.code-fold .cell-decorator{padding-top:3em}.quarto-notebook .cell-code code{white-space:pre-wrap}.quarto-notebook .cell .cell-output-stderr pre code,.quarto-notebook .cell .cell-output-stdout pre code{white-space:pre-wrap;overflow-wrap:anywhere}.toc-actions,.quarto-alternate-formats,.quarto-other-links,.quarto-code-links,.quarto-alternate-notebooks{padding-left:0em}.sidebar .toc-actions a,.sidebar .quarto-alternate-formats a,.sidebar .quarto-other-links a,.sidebar .quarto-code-links a,.sidebar .quarto-alternate-notebooks a,.sidebar nav[role=doc-toc] a{text-decoration:none}.sidebar .toc-actions a:hover,.sidebar .quarto-other-links a:hover,.sidebar .quarto-code-links a:hover,.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#2761e3}.sidebar .toc-actions h2,.sidebar .toc-actions .h2,.sidebar .quarto-code-links h2,.sidebar .quarto-code-links .h2,.sidebar .quarto-other-links h2,.sidebar .quarto-other-links .h2,.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2,.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-weight:500;margin-bottom:.2rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .toc-actions>h2,.sidebar .toc-actions>.h2,.sidebar .quarto-code-links>h2,.sidebar .quarto-code-links>.h2,.sidebar .quarto-other-links>h2,.sidebar .quarto-other-links>.h2,.sidebar .quarto-alternate-notebooks>h2,.sidebar .quarto-alternate-notebooks>.h2,.sidebar .quarto-alternate-formats>h2,.sidebar .quarto-alternate-formats>.h2{font-size:.8rem}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar .toc-actions h2>ul a,.sidebar .toc-actions .h2>ul a,.sidebar .quarto-code-links h2>ul a,.sidebar .quarto-code-links .h2>ul a,.sidebar .quarto-other-links h2>ul a,.sidebar .quarto-other-links .h2>ul a,.sidebar .quarto-alternate-notebooks h2>ul a,.sidebar .quarto-alternate-notebooks .h2>ul a,.sidebar .quarto-alternate-formats h2>ul a,.sidebar .quarto-alternate-formats .h2>ul a{border-left:none;padding-left:.6rem}.sidebar .toc-actions ul a:empty,.sidebar .quarto-code-links ul a:empty,.sidebar .quarto-other-links ul a:empty,.sidebar .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .toc-actions ul,.sidebar .quarto-code-links ul,.sidebar .quarto-other-links ul,.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul{padding-left:0;list-style:none}.sidebar nav[role=doc-toc] ul{list-style:none;padding-left:0;list-style:none}.sidebar nav[role=doc-toc]>ul{margin-left:.45em}.quarto-margin-sidebar nav[role=doc-toc]{padding-left:.5em}.sidebar .toc-actions>ul,.sidebar .quarto-code-links>ul,.sidebar .quarto-other-links>ul,.sidebar .quarto-alternate-notebooks>ul,.sidebar .quarto-alternate-formats>ul{font-size:.8rem}.sidebar nav[role=doc-toc]>ul{font-size:.875rem}.sidebar .toc-actions ul li a,.sidebar .quarto-code-links ul li a,.sidebar .quarto-other-links ul li a,.sidebar .quarto-alternate-notebooks ul li a,.sidebar .quarto-alternate-formats ul li a,.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #2761e3;color:#2761e3 !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#2761e3 !important}kbd,.kbd{color:#343a40;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}.quarto-appendix-contents div.hanging-indent{margin-left:0em}.quarto-appendix-contents div.hanging-indent div.csl-entry{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.25rem;overflow-wrap:break-word}.callout .callout-title-container{overflow-wrap:anywhere}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400;margin-bottom:-0.4em;margin-top:.5em}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout:not(.no-icon).callout-titled.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-titled>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-empty-content>.callout-header{margin-bottom:0em;border-bottom-right-radius:calc(0.25rem + -1px)}.callout>.callout-header.collapsed{border-bottom-right-radius:calc(0.25rem + -1px)}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em;border-top-right-radius:calc(0.25rem + -1px)}.callout.callout-style-default .callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body>:first-child{padding-top:.5rem;margin-top:0}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-titled .callout-body>:last-child:not(.sourceCode),.callout.callout-titled .callout-body>div>:last-child:not(.sourceCode){padding-bottom:.5rem;margin-bottom:0}.callout:not(.callout-titled) .callout-body>:first-child,.callout:not(.callout-titled) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-titled) .callout-body>:last-child,.callout:not(.callout-titled) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-title-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:#6c757d}div.callout.callout-style-default>.callout-header{background-color:#6c757d}div.callout-note.callout{border-left-color:#2780e3}div.callout-note.callout-style-default>.callout-header{background-color:rgb(233.4,242.3,252.2)}div.callout-note:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#3fb618}div.callout-tip.callout-style-default>.callout-header{background-color:rgb(235.8,247.7,231.9)}div.callout-tip:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ff7518}div.callout-warning.callout-style-default>.callout-header{background-color:rgb(255,241.2,231.9)}div.callout-warning:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#f0ad4e}div.callout-caution.callout-style-default>.callout-header{background-color:rgb(253.5,246.8,237.3)}div.callout-caution:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#ff0039}div.callout-important.callout-style-default>.callout-header{background-color:rgb(255,229.5,235.2)}div.callout-important:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.sidebar-navigation{padding-left:20px}.navbar{background-color:#f8f9fa;color:rgb(84.32,84.66,85)}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:hsl(0,0%,98%)}#quarto-content .quarto-sidebar-toggle-title{color:#343a40}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}@media(max-width: 767.98px){.sidebar-menu-container{padding-bottom:5em}}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .footnotes ol{margin-left:.5em}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{--bs-btn-color: rgb(202.22, 203.78, 205.34);--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: rgb(202.22, 203.78, 205.34);--bs-btn-hover-bg: rgb(82.45, 87.55, 92.65);--bs-btn-hover-border-color: rgb(72.3, 77.7, 83.1);--bs-btn-focus-shadow-rgb: 75, 80, 85;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(92.6, 97.4, 102.2);--bs-btn-active-border-color: rgb(72.3, 77.7, 83.1);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}nav.quarto-secondary-nav.color-navbar{background-color:#f8f9fa;color:rgb(84.32,84.66,85)}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:rgb(84.32,84.66,85)}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:1em}body.nav-sidebar #title-block-header{margin-block-end:0}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}.code-annotated .code-copy-button{margin-right:1.25em;margin-top:0;padding-bottom:0;padding-top:3px}.code-annotation-gutter-bg{background-color:#fff}.code-annotation-gutter{background-color:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:rgb(74.8620689655,83.5,92.1379310345);border:solid rgb(74.8620689655,83.5,92.1379310345) 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:var(--quarto-hl-co-color);border:solid var(--quarto-hl-co-color) 1px;border-radius:50%;height:18px;width:18px;font-size:9px;margin-top:2px}code.sourceCode button.code-annotation-anchor{padding:2px;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none}code.sourceCode a.code-annotation-anchor{line-height:18px;text-align:center;vertical-align:middle;cursor:default;text-decoration:none}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table{border-top:1px solid rgb(214.4,215.6,216.8);border-bottom:1px solid rgb(214.4,215.6,216.8)}.table>thead{border-top-width:0;border-bottom:1px solid rgb(153.5,156.5,159.5)}.table a{word-break:break-word}.table>:not(caption)>*>*{background-color:unset;color:unset}#quarto-document-content .crosstalk-input .checkbox input[type=checkbox],#quarto-document-content .crosstalk-input .checkbox-inline input[type=checkbox]{position:unset;margin-top:unset;margin-left:unset}#quarto-document-content .row{margin-left:unset;margin-right:unset}.quarto-xref{white-space:nowrap}#quarto-draft-alert{margin-top:0px;margin-bottom:0px;padding:.3em;text-align:center;font-size:.9em}#quarto-draft-alert i{margin-right:.3em}#quarto-back-to-top{z-index:1000}pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:0.875em;font-weight:400}pre code{font-family:inherit;font-size:inherit;font-weight:inherit}code{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:0.875em;font-weight:400}a{background-color:rgba(0,0,0,0);font-weight:400;text-decoration:underline}.screen-reader-only{position:absolute;clip:rect(0 0 0 0);border:0;height:1px;margin:-1px;overflow:hidden;padding:0;width:1px}a.external:after{content:"";background-image:url('data:image/svg+xml,');background-size:contain;background-repeat:no-repeat;background-position:center center;margin-left:.2em;padding-right:.75em}div.sourceCode code a.external:after{content:none}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:rgb(84.32,84.66,85);background:#f8f9fa}.quarto-title-banner a{color:rgb(84.32,84.66,85)}.quarto-title-banner h1,.quarto-title-banner .h1,.quarto-title-banner h2,.quarto-title-banner .h2{color:rgb(84.32,84.66,85)}.quarto-title-banner .code-tools-button{color:hsl(210,.4016064257%,53.2%)}.quarto-title-banner .code-tools-button:hover{color:rgb(84.32,84.66,85)}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}@media(max-width: 767.98px){body.hypothesis-enabled #title-block-header>*{padding-right:20px}}main.quarto-banner-title-block>section:first-child>h2,main.quarto-banner-title-block>section:first-child>.h2,main.quarto-banner-title-block>section:first-child>h3,main.quarto-banner-title-block>section:first-child>.h3,main.quarto-banner-title-block>section:first-child>h4,main.quarto-banner-title-block>section:first-child>.h4{margin-top:0}.quarto-title .quarto-categories{display:flex;flex-wrap:wrap;row-gap:.5em;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.25rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}.quarto-title-meta-container{display:grid;grid-template-columns:1fr auto}.quarto-title-meta-column-end{display:flex;flex-direction:column;padding-left:1em}.quarto-title-meta-column-end a .bi{margin-right:.3em}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr);grid-column-gap:1em}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-0.2em;height:.8em;width:.8em}#title-block-header.quarto-title-block.default .quarto-title-author-email{opacity:.7}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.1em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .keywords,#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .keywords>p,#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .keywords>p:last-of-type,#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .keywords .block-title,#title-block-header.quarto-title-block.default .description .block-title,#title-block-header.quarto-title-block.default .abstract .block-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:minmax(max-content, 1fr) 1fr;grid-column-gap:1em}.quarto-title-tools-only{display:flex;justify-content:right}body{-webkit-font-smoothing:antialiased}.badge.bg-light{color:#343a40}.progress .progress-bar{font-size:8px;line-height:8px}:root{--quarto-scss-export-gray-300: #dee2e6;--quarto-scss-export-gray-500: #adb5bd;--quarto-scss-export-gray-600: #6c757d;--quarto-scss-export-gray-800: #343a40;--quarto-scss-export-card-cap-bg: rgba(52, 58, 64, 0.25);--quarto-scss-export-border-color: #dee2e6;--quarto-scss-export-text-muted: #6c757d;--quarto-scss-export-white: #fff;--quarto-scss-export-gray-100: #f8f9fa;--quarto-scss-export-gray-200: #e9ecef;--quarto-scss-export-gray-400: #ced4da;--quarto-scss-export-gray-700: #495057;--quarto-scss-export-gray-900: #212529;--quarto-scss-export-black: #000;--quarto-scss-export-blue: #2780e3;--quarto-scss-export-indigo: #6610f2;--quarto-scss-export-purple: #613d7c;--quarto-scss-export-pink: #e83e8c;--quarto-scss-export-red: #ff0039;--quarto-scss-export-orange: #f0ad4e;--quarto-scss-export-yellow: #ff7518;--quarto-scss-export-green: #3fb618;--quarto-scss-export-teal: #20c997;--quarto-scss-export-cyan: #9954bb;--quarto-scss-export-primary: #2780e3;--quarto-scss-export-secondary: #343a40;--quarto-scss-export-success: #3fb618;--quarto-scss-export-info: #9954bb;--quarto-scss-export-warning: #ff7518;--quarto-scss-export-danger: #ff0039;--quarto-scss-export-light: #f8f9fa;--quarto-scss-export-dark: #343a40;--quarto-scss-export-body-color: #343a40;--quarto-scss-export-title-banner-color: ;--quarto-scss-export-title-banner-bg: ;--quarto-scss-export-btn-code-copy-color: #5E5E5E;--quarto-scss-export-btn-code-copy-color-active: #4758AB;--quarto-scss-export-sidebar-bg: #fff;--quarto-scss-export-link-color: #2761e3;--quarto-scss-export-link-color-bg: transparent;--quarto-scss-export-code-color: #7d12ba;--quarto-scss-export-code-bg: #f8f9fa;--quarto-scss-export-toc-color: #2761e3;--quarto-scss-export-toc-active-border: #2761e3;--quarto-scss-export-toc-inactive-border: #e9ecef;--quarto-scss-export-navbar-default: #2780e3;--quarto-scss-export-navbar-hl-override: false;--quarto-scss-export-navbar-bg: #f8f9fa;--quarto-scss-export-btn-bg: #343a40;--quarto-scss-export-btn-fg: rgb(202.22, 203.78, 205.34);--quarto-scss-export-body-contrast-bg: #fff;--quarto-scss-export-body-contrast-color: #343a40;--quarto-scss-export-navbar-fg: rgb(84.32, 84.66, 85);--quarto-scss-export-navbar-hl: rgb(31.2, 77.6, 181.6);--quarto-scss-export-navbar-brand: rgb(84.32, 84.66, 85);--quarto-scss-export-navbar-brand-hl: rgb(31.2, 77.6, 181.6);--quarto-scss-export-navbar-toggler-border-color: rgba(84.32, 84.66, 85, 0);--quarto-scss-export-navbar-hover-color: rgba(31.2, 77.6, 181.6, 0.8);--quarto-scss-export-navbar-disabled-color: rgba(84.32, 84.66, 85, 0.75);--quarto-scss-export-sidebar-fg: rgb(89.25, 89.25, 89.25);--quarto-scss-export-title-block-color: #343a40;--quarto-scss-export-title-block-contast-color: #fff;--quarto-scss-export-footer-bg: #fff;--quarto-scss-export-footer-fg: rgb(117.3, 117.3, 117.3);--quarto-scss-export-popover-bg: #fff;--quarto-scss-export-input-bg: #fff;--quarto-scss-export-input-border-color: #dee2e6;--quarto-scss-export-code-annotation-higlight-color: rgba(170, 170, 170, 0.2666666667);--quarto-scss-export-code-annotation-higlight-bg: rgba(170, 170, 170, 0.1333333333);--quarto-scss-export-table-group-separator-color: rgb(153.5, 156.5, 159.5);--quarto-scss-export-table-group-separator-color-lighter: rgb(214.4, 215.6, 216.8);--quarto-scss-export-link-decoration: underline;--quarto-scss-export-table-border-color: #dee2e6;--quarto-scss-export-sidebar-glass-bg: rgba(102, 102, 102, 0.4);--quarto-scss-export-color-contrast-dark: #000;--quarto-scss-export-color-contrast-light: #fff;--quarto-scss-export-blue-100: rgb(211.8, 229.6, 249.4);--quarto-scss-export-blue-200: rgb(168.6, 204.2, 243.8);--quarto-scss-export-blue-300: rgb(125.4, 178.8, 238.2);--quarto-scss-export-blue-400: rgb(82.2, 153.4, 232.6);--quarto-scss-export-blue-500: #2780e3;--quarto-scss-export-blue-600: rgb(31.2, 102.4, 181.6);--quarto-scss-export-blue-700: rgb(23.4, 76.8, 136.2);--quarto-scss-export-blue-800: rgb(15.6, 51.2, 90.8);--quarto-scss-export-blue-900: rgb(7.8, 25.6, 45.4);--quarto-scss-export-indigo-100: rgb(224.4, 207.2, 252.4);--quarto-scss-export-indigo-200: rgb(193.8, 159.4, 249.8);--quarto-scss-export-indigo-300: rgb(163.2, 111.6, 247.2);--quarto-scss-export-indigo-400: rgb(132.6, 63.8, 244.6);--quarto-scss-export-indigo-500: #6610f2;--quarto-scss-export-indigo-600: rgb(81.6, 12.8, 193.6);--quarto-scss-export-indigo-700: rgb(61.2, 9.6, 145.2);--quarto-scss-export-indigo-800: rgb(40.8, 6.4, 96.8);--quarto-scss-export-indigo-900: rgb(20.4, 3.2, 48.4);--quarto-scss-export-purple-100: rgb(223.4, 216.2, 228.8);--quarto-scss-export-purple-200: rgb(191.8, 177.4, 202.6);--quarto-scss-export-purple-300: rgb(160.2, 138.6, 176.4);--quarto-scss-export-purple-400: rgb(128.6, 99.8, 150.2);--quarto-scss-export-purple-500: #613d7c;--quarto-scss-export-purple-600: rgb(77.6, 48.8, 99.2);--quarto-scss-export-purple-700: rgb(58.2, 36.6, 74.4);--quarto-scss-export-purple-800: rgb(38.8, 24.4, 49.6);--quarto-scss-export-purple-900: rgb(19.4, 12.2, 24.8);--quarto-scss-export-pink-100: rgb(250.4, 216.4, 232);--quarto-scss-export-pink-200: rgb(245.8, 177.8, 209);--quarto-scss-export-pink-300: rgb(241.2, 139.2, 186);--quarto-scss-export-pink-400: rgb(236.6, 100.6, 163);--quarto-scss-export-pink-500: #e83e8c;--quarto-scss-export-pink-600: rgb(185.6, 49.6, 112);--quarto-scss-export-pink-700: rgb(139.2, 37.2, 84);--quarto-scss-export-pink-800: rgb(92.8, 24.8, 56);--quarto-scss-export-pink-900: rgb(46.4, 12.4, 28);--quarto-scss-export-red-100: rgb(255, 204, 215.4);--quarto-scss-export-red-200: rgb(255, 153, 175.8);--quarto-scss-export-red-300: rgb(255, 102, 136.2);--quarto-scss-export-red-400: rgb(255, 51, 96.6);--quarto-scss-export-red-500: #ff0039;--quarto-scss-export-red-600: rgb(204, 0, 45.6);--quarto-scss-export-red-700: rgb(153, 0, 34.2);--quarto-scss-export-red-800: rgb(102, 0, 22.8);--quarto-scss-export-red-900: rgb(51, 0, 11.4);--quarto-scss-export-orange-100: rgb(252, 238.6, 219.6);--quarto-scss-export-orange-200: rgb(249, 222.2, 184.2);--quarto-scss-export-orange-300: rgb(246, 205.8, 148.8);--quarto-scss-export-orange-400: rgb(243, 189.4, 113.4);--quarto-scss-export-orange-500: #f0ad4e;--quarto-scss-export-orange-600: rgb(192, 138.4, 62.4);--quarto-scss-export-orange-700: rgb(144, 103.8, 46.8);--quarto-scss-export-orange-800: rgb(96, 69.2, 31.2);--quarto-scss-export-orange-900: rgb(48, 34.6, 15.6);--quarto-scss-export-yellow-100: rgb(255, 227.4, 208.8);--quarto-scss-export-yellow-200: rgb(255, 199.8, 162.6);--quarto-scss-export-yellow-300: rgb(255, 172.2, 116.4);--quarto-scss-export-yellow-400: rgb(255, 144.6, 70.2);--quarto-scss-export-yellow-500: #ff7518;--quarto-scss-export-yellow-600: rgb(204, 93.6, 19.2);--quarto-scss-export-yellow-700: rgb(153, 70.2, 14.4);--quarto-scss-export-yellow-800: rgb(102, 46.8, 9.6);--quarto-scss-export-yellow-900: rgb(51, 23.4, 4.8);--quarto-scss-export-green-100: rgb(216.6, 240.4, 208.8);--quarto-scss-export-green-200: rgb(178.2, 225.8, 162.6);--quarto-scss-export-green-300: rgb(139.8, 211.2, 116.4);--quarto-scss-export-green-400: rgb(101.4, 196.6, 70.2);--quarto-scss-export-green-500: #3fb618;--quarto-scss-export-green-600: rgb(50.4, 145.6, 19.2);--quarto-scss-export-green-700: rgb(37.8, 109.2, 14.4);--quarto-scss-export-green-800: rgb(25.2, 72.8, 9.6);--quarto-scss-export-green-900: rgb(12.6, 36.4, 4.8);--quarto-scss-export-teal-100: rgb(210.4, 244.2, 234.2);--quarto-scss-export-teal-200: rgb(165.8, 233.4, 213.4);--quarto-scss-export-teal-300: rgb(121.2, 222.6, 192.6);--quarto-scss-export-teal-400: rgb(76.6, 211.8, 171.8);--quarto-scss-export-teal-500: #20c997;--quarto-scss-export-teal-600: rgb(25.6, 160.8, 120.8);--quarto-scss-export-teal-700: rgb(19.2, 120.6, 90.6);--quarto-scss-export-teal-800: rgb(12.8, 80.4, 60.4);--quarto-scss-export-teal-900: rgb(6.4, 40.2, 30.2);--quarto-scss-export-cyan-100: rgb(234.6, 220.8, 241.4);--quarto-scss-export-cyan-200: rgb(214.2, 186.6, 227.8);--quarto-scss-export-cyan-300: rgb(193.8, 152.4, 214.2);--quarto-scss-export-cyan-400: rgb(173.4, 118.2, 200.6);--quarto-scss-export-cyan-500: #9954bb;--quarto-scss-export-cyan-600: rgb(122.4, 67.2, 149.6);--quarto-scss-export-cyan-700: rgb(91.8, 50.4, 112.2);--quarto-scss-export-cyan-800: rgb(61.2, 33.6, 74.8);--quarto-scss-export-cyan-900: rgb(30.6, 16.8, 37.4);--quarto-scss-export-default: #343a40;--quarto-scss-export-primary-text-emphasis: rgb(15.6, 51.2, 90.8);--quarto-scss-export-secondary-text-emphasis: rgb(20.8, 23.2, 25.6);--quarto-scss-export-success-text-emphasis: rgb(25.2, 72.8, 9.6);--quarto-scss-export-info-text-emphasis: rgb(61.2, 33.6, 74.8);--quarto-scss-export-warning-text-emphasis: rgb(102, 46.8, 9.6);--quarto-scss-export-danger-text-emphasis: rgb(102, 0, 22.8);--quarto-scss-export-light-text-emphasis: #495057;--quarto-scss-export-dark-text-emphasis: #495057;--quarto-scss-export-primary-bg-subtle: rgb(211.8, 229.6, 249.4);--quarto-scss-export-secondary-bg-subtle: rgb(214.4, 215.6, 216.8);--quarto-scss-export-success-bg-subtle: rgb(216.6, 240.4, 208.8);--quarto-scss-export-info-bg-subtle: rgb(234.6, 220.8, 241.4);--quarto-scss-export-warning-bg-subtle: rgb(255, 227.4, 208.8);--quarto-scss-export-danger-bg-subtle: rgb(255, 204, 215.4);--quarto-scss-export-light-bg-subtle: rgb(251.5, 252, 252.5);--quarto-scss-export-dark-bg-subtle: #ced4da;--quarto-scss-export-primary-border-subtle: rgb(168.6, 204.2, 243.8);--quarto-scss-export-secondary-border-subtle: rgb(173.8, 176.2, 178.6);--quarto-scss-export-success-border-subtle: rgb(178.2, 225.8, 162.6);--quarto-scss-export-info-border-subtle: rgb(214.2, 186.6, 227.8);--quarto-scss-export-warning-border-subtle: rgb(255, 199.8, 162.6);--quarto-scss-export-danger-border-subtle: rgb(255, 153, 175.8);--quarto-scss-export-light-border-subtle: #e9ecef;--quarto-scss-export-dark-border-subtle: #adb5bd;--quarto-scss-export-body-text-align: ;--quarto-scss-export-body-bg: #fff;--quarto-scss-export-body-secondary-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-body-secondary-bg: #e9ecef;--quarto-scss-export-body-tertiary-color: rgba(52, 58, 64, 0.5);--quarto-scss-export-body-tertiary-bg: #f8f9fa;--quarto-scss-export-body-emphasis-color: #000;--quarto-scss-export-link-hover-color: rgb(31.2, 77.6, 181.6);--quarto-scss-export-link-hover-decoration: ;--quarto-scss-export-border-color-translucent: rgba(0, 0, 0, 0.175);--quarto-scss-export-component-active-bg: #2780e3;--quarto-scss-export-component-active-color: #fff;--quarto-scss-export-focus-ring-color: rgba(39, 128, 227, 0.25);--quarto-scss-export-headings-font-family: ;--quarto-scss-export-headings-font-style: ;--quarto-scss-export-display-font-family: ;--quarto-scss-export-display-font-style: ;--quarto-scss-export-blockquote-footer-color: #6c757d;--quarto-scss-export-blockquote-border-color: #e9ecef;--quarto-scss-export-hr-bg-color: ;--quarto-scss-export-hr-height: ;--quarto-scss-export-hr-border-color: ;--quarto-scss-export-legend-font-weight: ;--quarto-scss-export-mark-bg: rgb(255, 227.4, 208.8);--quarto-scss-export-table-color: #343a40;--quarto-scss-export-table-bg: #fff;--quarto-scss-export-table-accent-bg: transparent;--quarto-scss-export-table-th-font-weight: ;--quarto-scss-export-table-striped-color: #343a40;--quarto-scss-export-table-striped-bg: rgba(0, 0, 0, 0.05);--quarto-scss-export-table-active-color: #343a40;--quarto-scss-export-table-active-bg: rgba(0, 0, 0, 0.1);--quarto-scss-export-table-hover-color: #343a40;--quarto-scss-export-table-hover-bg: rgba(0, 0, 0, 0.075);--quarto-scss-export-table-caption-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-input-btn-font-family: ;--quarto-scss-export-input-btn-focus-color: rgba(39, 128, 227, 0.25);--quarto-scss-export-btn-color: #343a40;--quarto-scss-export-btn-font-family: ;--quarto-scss-export-btn-white-space: ;--quarto-scss-export-btn-link-color: #2761e3;--quarto-scss-export-btn-link-hover-color: rgb(31.2, 77.6, 181.6);--quarto-scss-export-btn-link-disabled-color: #6c757d;--quarto-scss-export-form-text-font-style: ;--quarto-scss-export-form-text-font-weight: ;--quarto-scss-export-form-text-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-form-label-font-size: ;--quarto-scss-export-form-label-font-style: ;--quarto-scss-export-form-label-font-weight: ;--quarto-scss-export-form-label-color: ;--quarto-scss-export-input-font-family: ;--quarto-scss-export-input-disabled-color: ;--quarto-scss-export-input-disabled-bg: #e9ecef;--quarto-scss-export-input-disabled-border-color: ;--quarto-scss-export-input-color: #343a40;--quarto-scss-export-input-focus-bg: #fff;--quarto-scss-export-input-focus-border-color: rgb(147, 191.5, 241);--quarto-scss-export-input-focus-color: #343a40;--quarto-scss-export-input-placeholder-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-input-plaintext-color: #343a40;--quarto-scss-export-form-check-label-color: ;--quarto-scss-export-form-check-transition: ;--quarto-scss-export-form-check-input-bg: #fff;--quarto-scss-export-form-check-input-focus-border: rgb(147, 191.5, 241);--quarto-scss-export-form-check-input-checked-color: #fff;--quarto-scss-export-form-check-input-checked-bg-color: #2780e3;--quarto-scss-export-form-check-input-checked-border-color: #2780e3;--quarto-scss-export-form-check-input-indeterminate-color: #fff;--quarto-scss-export-form-check-input-indeterminate-bg-color: #2780e3;--quarto-scss-export-form-check-input-indeterminate-border-color: #2780e3;--quarto-scss-export-form-switch-color: rgba(0, 0, 0, 0.25);--quarto-scss-export-form-switch-focus-color: rgb(147, 191.5, 241);--quarto-scss-export-form-switch-checked-color: #fff;--quarto-scss-export-input-group-addon-color: #343a40;--quarto-scss-export-input-group-addon-bg: #f8f9fa;--quarto-scss-export-input-group-addon-border-color: #dee2e6;--quarto-scss-export-form-select-font-family: ;--quarto-scss-export-form-select-color: #343a40;--quarto-scss-export-form-select-bg: #fff;--quarto-scss-export-form-select-disabled-color: ;--quarto-scss-export-form-select-disabled-bg: #e9ecef;--quarto-scss-export-form-select-disabled-border-color: ;--quarto-scss-export-form-select-indicator-color: #343a40;--quarto-scss-export-form-select-border-color: #dee2e6;--quarto-scss-export-form-select-focus-border-color: rgb(147, 191.5, 241);--quarto-scss-export-form-range-track-bg: #f8f9fa;--quarto-scss-export-form-range-thumb-bg: #2780e3;--quarto-scss-export-form-range-thumb-active-bg: rgb(190.2, 216.9, 246.6);--quarto-scss-export-form-range-thumb-disabled-bg: rgba(52, 58, 64, 0.75);--quarto-scss-export-form-file-button-color: #343a40;--quarto-scss-export-form-file-button-bg: #f8f9fa;--quarto-scss-export-form-file-button-hover-bg: #e9ecef;--quarto-scss-export-form-floating-label-disabled-color: #6c757d;--quarto-scss-export-form-feedback-font-style: ;--quarto-scss-export-form-feedback-valid-color: #3fb618;--quarto-scss-export-form-feedback-invalid-color: #ff0039;--quarto-scss-export-form-feedback-icon-valid-color: #3fb618;--quarto-scss-export-form-feedback-icon-invalid-color: #ff0039;--quarto-scss-export-form-valid-color: #3fb618;--quarto-scss-export-form-valid-border-color: #3fb618;--quarto-scss-export-form-invalid-color: #ff0039;--quarto-scss-export-form-invalid-border-color: #ff0039;--quarto-scss-export-nav-link-font-size: ;--quarto-scss-export-nav-link-font-weight: ;--quarto-scss-export-nav-link-color: #2761e3;--quarto-scss-export-nav-link-hover-color: rgb(31.2, 77.6, 181.6);--quarto-scss-export-nav-link-disabled-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-nav-tabs-border-color: #dee2e6;--quarto-scss-export-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--quarto-scss-export-nav-tabs-link-active-color: #000;--quarto-scss-export-nav-tabs-link-active-bg: #fff;--quarto-scss-export-nav-pills-link-active-bg: #2780e3;--quarto-scss-export-nav-pills-link-active-color: #fff;--quarto-scss-export-nav-underline-link-active-color: #000;--quarto-scss-export-navbar-padding-x: ;--quarto-scss-export-navbar-light-contrast: #000;--quarto-scss-export-navbar-dark-contrast: #000;--quarto-scss-export-navbar-light-icon-color: rgba(0, 0, 0, 0.75);--quarto-scss-export-navbar-dark-icon-color: rgba(0, 0, 0, 0.75);--quarto-scss-export-dropdown-color: #343a40;--quarto-scss-export-dropdown-bg: #fff;--quarto-scss-export-dropdown-border-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--quarto-scss-export-dropdown-link-color: #343a40;--quarto-scss-export-dropdown-link-hover-color: #343a40;--quarto-scss-export-dropdown-link-hover-bg: #f8f9fa;--quarto-scss-export-dropdown-link-active-bg: #2780e3;--quarto-scss-export-dropdown-link-active-color: #fff;--quarto-scss-export-dropdown-link-disabled-color: rgba(52, 58, 64, 0.5);--quarto-scss-export-dropdown-header-color: #6c757d;--quarto-scss-export-dropdown-dark-color: #dee2e6;--quarto-scss-export-dropdown-dark-bg: #343a40;--quarto-scss-export-dropdown-dark-border-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-dropdown-dark-divider-bg: rgba(0, 0, 0, 0.175);--quarto-scss-export-dropdown-dark-box-shadow: ;--quarto-scss-export-dropdown-dark-link-color: #dee2e6;--quarto-scss-export-dropdown-dark-link-hover-color: #fff;--quarto-scss-export-dropdown-dark-link-hover-bg: rgba(255, 255, 255, 0.15);--quarto-scss-export-dropdown-dark-link-active-color: #fff;--quarto-scss-export-dropdown-dark-link-active-bg: #2780e3;--quarto-scss-export-dropdown-dark-link-disabled-color: #adb5bd;--quarto-scss-export-dropdown-dark-header-color: #adb5bd;--quarto-scss-export-pagination-color: #2761e3;--quarto-scss-export-pagination-bg: #fff;--quarto-scss-export-pagination-border-color: #dee2e6;--quarto-scss-export-pagination-focus-color: rgb(31.2, 77.6, 181.6);--quarto-scss-export-pagination-focus-bg: #e9ecef;--quarto-scss-export-pagination-hover-color: rgb(31.2, 77.6, 181.6);--quarto-scss-export-pagination-hover-bg: #f8f9fa;--quarto-scss-export-pagination-hover-border-color: #dee2e6;--quarto-scss-export-pagination-active-color: #fff;--quarto-scss-export-pagination-active-bg: #2780e3;--quarto-scss-export-pagination-active-border-color: #2780e3;--quarto-scss-export-pagination-disabled-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-pagination-disabled-bg: #e9ecef;--quarto-scss-export-pagination-disabled-border-color: #dee2e6;--quarto-scss-export-card-title-color: ;--quarto-scss-export-card-subtitle-color: ;--quarto-scss-export-card-border-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-card-box-shadow: ;--quarto-scss-export-card-cap-color: ;--quarto-scss-export-card-height: ;--quarto-scss-export-card-color: ;--quarto-scss-export-card-bg: #fff;--quarto-scss-export-accordion-color: #343a40;--quarto-scss-export-accordion-bg: #fff;--quarto-scss-export-accordion-border-color: #dee2e6;--quarto-scss-export-accordion-button-color: #343a40;--quarto-scss-export-accordion-button-bg: #fff;--quarto-scss-export-accordion-button-active-bg: rgb(211.8, 229.6, 249.4);--quarto-scss-export-accordion-button-active-color: rgb(15.6, 51.2, 90.8);--quarto-scss-export-accordion-button-focus-border-color: rgb(147, 191.5, 241);--quarto-scss-export-accordion-icon-color: #343a40;--quarto-scss-export-accordion-icon-active-color: rgb(15.6, 51.2, 90.8);--quarto-scss-export-tooltip-color: #fff;--quarto-scss-export-tooltip-bg: #000;--quarto-scss-export-tooltip-margin: ;--quarto-scss-export-tooltip-arrow-color: ;--quarto-scss-export-form-feedback-tooltip-line-height: ;--quarto-scss-export-popover-border-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-popover-header-bg: #e9ecef;--quarto-scss-export-popover-body-color: #343a40;--quarto-scss-export-popover-arrow-color: #fff;--quarto-scss-export-popover-arrow-outer-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-toast-color: ;--quarto-scss-export-toast-background-color: rgba(255, 255, 255, 0.85);--quarto-scss-export-toast-border-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-toast-header-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-toast-header-background-color: rgba(255, 255, 255, 0.85);--quarto-scss-export-toast-header-border-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-badge-color: #fff;--quarto-scss-export-modal-content-color: ;--quarto-scss-export-modal-content-bg: #fff;--quarto-scss-export-modal-content-border-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-modal-backdrop-bg: #000;--quarto-scss-export-modal-header-border-color: #dee2e6;--quarto-scss-export-modal-footer-bg: ;--quarto-scss-export-modal-footer-border-color: #dee2e6;--quarto-scss-export-progress-bg: #e9ecef;--quarto-scss-export-progress-bar-color: #fff;--quarto-scss-export-progress-bar-bg: #2780e3;--quarto-scss-export-list-group-color: #343a40;--quarto-scss-export-list-group-bg: #fff;--quarto-scss-export-list-group-border-color: #dee2e6;--quarto-scss-export-list-group-hover-bg: #f8f9fa;--quarto-scss-export-list-group-active-bg: #2780e3;--quarto-scss-export-list-group-active-color: #fff;--quarto-scss-export-list-group-active-border-color: #2780e3;--quarto-scss-export-list-group-disabled-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-list-group-disabled-bg: #fff;--quarto-scss-export-list-group-action-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-list-group-action-hover-color: #000;--quarto-scss-export-list-group-action-active-color: #343a40;--quarto-scss-export-list-group-action-active-bg: #e9ecef;--quarto-scss-export-thumbnail-bg: #fff;--quarto-scss-export-thumbnail-border-color: #dee2e6;--quarto-scss-export-figure-caption-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-breadcrumb-font-size: ;--quarto-scss-export-breadcrumb-bg: ;--quarto-scss-export-breadcrumb-divider-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-breadcrumb-active-color: rgba(52, 58, 64, 0.75);--quarto-scss-export-breadcrumb-border-radius: ;--quarto-scss-export-carousel-control-color: #fff;--quarto-scss-export-carousel-indicator-active-bg: #fff;--quarto-scss-export-carousel-caption-color: #fff;--quarto-scss-export-carousel-dark-indicator-active-bg: #000;--quarto-scss-export-carousel-dark-caption-color: #000;--quarto-scss-export-btn-close-color: #000;--quarto-scss-export-offcanvas-border-color: rgba(0, 0, 0, 0.175);--quarto-scss-export-offcanvas-bg-color: #fff;--quarto-scss-export-offcanvas-color: #343a40;--quarto-scss-export-offcanvas-backdrop-bg: #000;--quarto-scss-export-code-color-dark: white;--quarto-scss-export-kbd-color: #fff;--quarto-scss-export-kbd-bg: #343a40;--quarto-scss-export-nested-kbd-font-weight: ;--quarto-scss-export-pre-bg: #f8f9fa;--quarto-scss-export-pre-color: #000;--quarto-scss-export-bslib-page-sidebar-title-bg: #f8f9fa;--quarto-scss-export-bslib-page-sidebar-title-color: #000;--quarto-scss-export-bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--quarto-scss-export-bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1);--quarto-scss-export-sidebar-color: rgb(89.25, 89.25, 89.25);--quarto-scss-export-sidebar-hover-color: rgba(32.76, 81.48, 190.68, 0.8);--quarto-scss-export-sidebar-disabled-color: rgba(89.25, 89.25, 89.25, 0.75);--quarto-scss-export-valuebox-bg-primary: #5397e9;--quarto-scss-export-valuebox-bg-secondary: #343a40;--quarto-scss-export-valuebox-bg-success: #3aa716;--quarto-scss-export-valuebox-bg-info: rgba(153, 84, 187, 0.7019607843);--quarto-scss-export-valuebox-bg-warning: #fa6400;--quarto-scss-export-valuebox-bg-danger: rgba(255, 0, 57, 0.7019607843);--quarto-scss-export-valuebox-bg-light: #f8f9fa;--quarto-scss-export-valuebox-bg-dark: #343a40;--quarto-scss-export-mermaid-bg-color: #fff;--quarto-scss-export-mermaid-edge-color: #343a40;--quarto-scss-export-mermaid-node-fg-color: #343a40;--quarto-scss-export-mermaid-fg-color: #343a40;--quarto-scss-export-mermaid-fg-color--lighter: rgb(74.8620689655, 83.5, 92.1379310345);--quarto-scss-export-mermaid-fg-color--lightest: rgb(97.724137931, 109, 120.275862069);--quarto-scss-export-mermaid-label-bg-color: #fff;--quarto-scss-export-mermaid-label-fg-color: #2780e3;--quarto-scss-export-mermaid-node-bg-color: rgba(39, 128, 227, 0.1);--quarto-scss-export-code-block-border-left-color: #dee2e6;--quarto-scss-export-callout-color-note: #2780e3;--quarto-scss-export-callout-color-tip: #3fb618;--quarto-scss-export-callout-color-important: #ff0039;--quarto-scss-export-callout-color-caution: #f0ad4e;--quarto-scss-export-callout-color-warning: #ff7518} \ No newline at end of file diff --git a/docs/site_libs/bootstrap/bootstrap-icons.css b/docs/site_libs/bootstrap/bootstrap-icons.css new file mode 100644 index 0000000..82b40f5 --- /dev/null +++ b/docs/site_libs/bootstrap/bootstrap-icons.css @@ -0,0 +1,2106 @@ +/*! + * Bootstrap Icons v1.13.1 (https://icons.getbootstrap.com/) + * Copyright 2019-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) + */ + +@font-face { + font-display: block; + font-family: "bootstrap-icons"; + src: +url("./bootstrap-icons.woff?e34853135f9e39acf64315236852cd5a") format("woff"); +} + +.bi::before, +[class^="bi-"]::before, +[class*=" bi-"]::before { + display: inline-block; + font-family: bootstrap-icons !important; + font-style: normal; + font-weight: normal !important; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: -.125em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.bi-123::before { content: "\f67f"; } +.bi-alarm-fill::before { content: "\f101"; } +.bi-alarm::before { content: "\f102"; } +.bi-align-bottom::before { content: "\f103"; } +.bi-align-center::before { content: "\f104"; } +.bi-align-end::before { content: "\f105"; } +.bi-align-middle::before { content: "\f106"; } +.bi-align-start::before { content: "\f107"; } +.bi-align-top::before { content: "\f108"; } +.bi-alt::before { content: "\f109"; } +.bi-app-indicator::before { content: "\f10a"; } +.bi-app::before { content: "\f10b"; } +.bi-archive-fill::before { content: "\f10c"; } +.bi-archive::before { content: "\f10d"; } +.bi-arrow-90deg-down::before { content: "\f10e"; } +.bi-arrow-90deg-left::before { content: "\f10f"; } +.bi-arrow-90deg-right::before { content: "\f110"; } +.bi-arrow-90deg-up::before { content: "\f111"; } +.bi-arrow-bar-down::before { content: "\f112"; } +.bi-arrow-bar-left::before { content: "\f113"; } +.bi-arrow-bar-right::before { content: "\f114"; } +.bi-arrow-bar-up::before { content: "\f115"; } +.bi-arrow-clockwise::before { content: "\f116"; } +.bi-arrow-counterclockwise::before { content: "\f117"; } +.bi-arrow-down-circle-fill::before { content: "\f118"; } +.bi-arrow-down-circle::before { content: "\f119"; } +.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } +.bi-arrow-down-left-circle::before { content: "\f11b"; } +.bi-arrow-down-left-square-fill::before { content: "\f11c"; } +.bi-arrow-down-left-square::before { content: "\f11d"; } +.bi-arrow-down-left::before { content: "\f11e"; } +.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } +.bi-arrow-down-right-circle::before { content: "\f120"; } +.bi-arrow-down-right-square-fill::before { content: "\f121"; } +.bi-arrow-down-right-square::before { content: "\f122"; } +.bi-arrow-down-right::before { content: "\f123"; } +.bi-arrow-down-short::before { content: "\f124"; } +.bi-arrow-down-square-fill::before { content: "\f125"; } +.bi-arrow-down-square::before { content: "\f126"; } +.bi-arrow-down-up::before { content: "\f127"; } +.bi-arrow-down::before { content: "\f128"; } +.bi-arrow-left-circle-fill::before { content: "\f129"; } +.bi-arrow-left-circle::before { content: "\f12a"; } +.bi-arrow-left-right::before { content: "\f12b"; } +.bi-arrow-left-short::before { content: "\f12c"; } +.bi-arrow-left-square-fill::before { content: "\f12d"; } +.bi-arrow-left-square::before { content: "\f12e"; } +.bi-arrow-left::before { content: "\f12f"; } +.bi-arrow-repeat::before { content: "\f130"; } +.bi-arrow-return-left::before { content: "\f131"; } +.bi-arrow-return-right::before { content: "\f132"; } +.bi-arrow-right-circle-fill::before { content: "\f133"; } +.bi-arrow-right-circle::before { content: "\f134"; } +.bi-arrow-right-short::before { content: "\f135"; } +.bi-arrow-right-square-fill::before { content: "\f136"; } +.bi-arrow-right-square::before { content: "\f137"; } +.bi-arrow-right::before { content: "\f138"; } +.bi-arrow-up-circle-fill::before { content: "\f139"; } +.bi-arrow-up-circle::before { content: "\f13a"; } +.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } +.bi-arrow-up-left-circle::before { content: "\f13c"; } +.bi-arrow-up-left-square-fill::before { content: "\f13d"; } +.bi-arrow-up-left-square::before { content: "\f13e"; } +.bi-arrow-up-left::before { content: "\f13f"; } +.bi-arrow-up-right-circle-fill::before { content: "\f140"; } +.bi-arrow-up-right-circle::before { content: "\f141"; } +.bi-arrow-up-right-square-fill::before { content: "\f142"; } +.bi-arrow-up-right-square::before { content: "\f143"; } +.bi-arrow-up-right::before { content: "\f144"; } +.bi-arrow-up-short::before { content: "\f145"; } +.bi-arrow-up-square-fill::before { content: "\f146"; } +.bi-arrow-up-square::before { content: "\f147"; } +.bi-arrow-up::before { content: "\f148"; } +.bi-arrows-angle-contract::before { content: "\f149"; } +.bi-arrows-angle-expand::before { content: "\f14a"; } +.bi-arrows-collapse::before { content: "\f14b"; } +.bi-arrows-expand::before { content: "\f14c"; } +.bi-arrows-fullscreen::before { content: "\f14d"; } +.bi-arrows-move::before { content: "\f14e"; } +.bi-aspect-ratio-fill::before { content: "\f14f"; } +.bi-aspect-ratio::before { content: "\f150"; } +.bi-asterisk::before { content: "\f151"; } +.bi-at::before { content: "\f152"; } +.bi-award-fill::before { content: "\f153"; } +.bi-award::before { content: "\f154"; } +.bi-back::before { content: "\f155"; } +.bi-backspace-fill::before { content: "\f156"; } +.bi-backspace-reverse-fill::before { content: "\f157"; } +.bi-backspace-reverse::before { content: "\f158"; } +.bi-backspace::before { content: "\f159"; } +.bi-badge-3d-fill::before { content: "\f15a"; } +.bi-badge-3d::before { content: "\f15b"; } +.bi-badge-4k-fill::before { content: "\f15c"; } +.bi-badge-4k::before { content: "\f15d"; } +.bi-badge-8k-fill::before { content: "\f15e"; } +.bi-badge-8k::before { content: "\f15f"; } +.bi-badge-ad-fill::before { content: "\f160"; } +.bi-badge-ad::before { content: "\f161"; } +.bi-badge-ar-fill::before { content: "\f162"; } +.bi-badge-ar::before { content: "\f163"; } +.bi-badge-cc-fill::before { content: "\f164"; } +.bi-badge-cc::before { content: "\f165"; } +.bi-badge-hd-fill::before { content: "\f166"; } +.bi-badge-hd::before { content: "\f167"; } +.bi-badge-tm-fill::before { content: "\f168"; } +.bi-badge-tm::before { content: "\f169"; } +.bi-badge-vo-fill::before { content: "\f16a"; } +.bi-badge-vo::before { content: "\f16b"; } +.bi-badge-vr-fill::before { content: "\f16c"; } +.bi-badge-vr::before { content: "\f16d"; } +.bi-badge-wc-fill::before { content: "\f16e"; } +.bi-badge-wc::before { content: "\f16f"; } +.bi-bag-check-fill::before { content: "\f170"; } +.bi-bag-check::before { content: "\f171"; } +.bi-bag-dash-fill::before { content: "\f172"; } +.bi-bag-dash::before { content: "\f173"; } +.bi-bag-fill::before { content: "\f174"; } +.bi-bag-plus-fill::before { content: "\f175"; } +.bi-bag-plus::before { content: "\f176"; } +.bi-bag-x-fill::before { content: "\f177"; } +.bi-bag-x::before { content: "\f178"; } +.bi-bag::before { content: "\f179"; } +.bi-bar-chart-fill::before { content: "\f17a"; } +.bi-bar-chart-line-fill::before { content: "\f17b"; } +.bi-bar-chart-line::before { content: "\f17c"; } +.bi-bar-chart-steps::before { content: "\f17d"; } +.bi-bar-chart::before { content: "\f17e"; } +.bi-basket-fill::before { content: "\f17f"; } +.bi-basket::before { content: "\f180"; } +.bi-basket2-fill::before { content: "\f181"; } +.bi-basket2::before { content: "\f182"; } +.bi-basket3-fill::before { content: "\f183"; } +.bi-basket3::before { content: "\f184"; } +.bi-battery-charging::before { content: "\f185"; } +.bi-battery-full::before { content: "\f186"; } +.bi-battery-half::before { content: "\f187"; } +.bi-battery::before { content: "\f188"; } +.bi-bell-fill::before { content: "\f189"; } +.bi-bell::before { content: "\f18a"; } +.bi-bezier::before { content: "\f18b"; } +.bi-bezier2::before { content: "\f18c"; } +.bi-bicycle::before { content: "\f18d"; } +.bi-binoculars-fill::before { content: "\f18e"; } +.bi-binoculars::before { content: "\f18f"; } +.bi-blockquote-left::before { content: "\f190"; } +.bi-blockquote-right::before { content: "\f191"; } +.bi-book-fill::before { content: "\f192"; } +.bi-book-half::before { content: "\f193"; } +.bi-book::before { content: "\f194"; } +.bi-bookmark-check-fill::before { content: "\f195"; } +.bi-bookmark-check::before { content: "\f196"; } +.bi-bookmark-dash-fill::before { content: "\f197"; } +.bi-bookmark-dash::before { content: "\f198"; } +.bi-bookmark-fill::before { content: "\f199"; } +.bi-bookmark-heart-fill::before { content: "\f19a"; } +.bi-bookmark-heart::before { content: "\f19b"; } +.bi-bookmark-plus-fill::before { content: "\f19c"; } +.bi-bookmark-plus::before { content: "\f19d"; } +.bi-bookmark-star-fill::before { content: "\f19e"; } +.bi-bookmark-star::before { content: "\f19f"; } +.bi-bookmark-x-fill::before { content: "\f1a0"; } +.bi-bookmark-x::before { content: "\f1a1"; } +.bi-bookmark::before { content: "\f1a2"; } +.bi-bookmarks-fill::before { content: "\f1a3"; } +.bi-bookmarks::before { content: "\f1a4"; } +.bi-bookshelf::before { content: "\f1a5"; } +.bi-bootstrap-fill::before { content: "\f1a6"; } +.bi-bootstrap-reboot::before { content: "\f1a7"; } +.bi-bootstrap::before { content: "\f1a8"; } +.bi-border-all::before { content: "\f1a9"; } +.bi-border-bottom::before { content: "\f1aa"; } +.bi-border-center::before { content: "\f1ab"; } +.bi-border-inner::before { content: "\f1ac"; } +.bi-border-left::before { content: "\f1ad"; } +.bi-border-middle::before { content: "\f1ae"; } +.bi-border-outer::before { content: "\f1af"; } +.bi-border-right::before { content: "\f1b0"; } +.bi-border-style::before { content: "\f1b1"; } +.bi-border-top::before { content: "\f1b2"; } +.bi-border-width::before { content: "\f1b3"; } +.bi-border::before { content: "\f1b4"; } +.bi-bounding-box-circles::before { content: "\f1b5"; } +.bi-bounding-box::before { content: "\f1b6"; } +.bi-box-arrow-down-left::before { content: "\f1b7"; } +.bi-box-arrow-down-right::before { content: "\f1b8"; } +.bi-box-arrow-down::before { content: "\f1b9"; } +.bi-box-arrow-in-down-left::before { content: "\f1ba"; } +.bi-box-arrow-in-down-right::before { content: "\f1bb"; } +.bi-box-arrow-in-down::before { content: "\f1bc"; } +.bi-box-arrow-in-left::before { content: "\f1bd"; } +.bi-box-arrow-in-right::before { content: "\f1be"; } +.bi-box-arrow-in-up-left::before { content: "\f1bf"; } +.bi-box-arrow-in-up-right::before { content: "\f1c0"; } +.bi-box-arrow-in-up::before { content: "\f1c1"; } +.bi-box-arrow-left::before { content: "\f1c2"; } +.bi-box-arrow-right::before { content: "\f1c3"; } +.bi-box-arrow-up-left::before { content: "\f1c4"; } +.bi-box-arrow-up-right::before { content: "\f1c5"; } +.bi-box-arrow-up::before { content: "\f1c6"; } +.bi-box-seam::before { content: "\f1c7"; } +.bi-box::before { content: "\f1c8"; } +.bi-braces::before { content: "\f1c9"; } +.bi-bricks::before { content: "\f1ca"; } +.bi-briefcase-fill::before { content: "\f1cb"; } +.bi-briefcase::before { content: "\f1cc"; } +.bi-brightness-alt-high-fill::before { content: "\f1cd"; } +.bi-brightness-alt-high::before { content: "\f1ce"; } +.bi-brightness-alt-low-fill::before { content: "\f1cf"; } +.bi-brightness-alt-low::before { content: "\f1d0"; } +.bi-brightness-high-fill::before { content: "\f1d1"; } +.bi-brightness-high::before { content: "\f1d2"; } +.bi-brightness-low-fill::before { content: "\f1d3"; } +.bi-brightness-low::before { content: "\f1d4"; } +.bi-broadcast-pin::before { content: "\f1d5"; } +.bi-broadcast::before { content: "\f1d6"; } +.bi-brush-fill::before { content: "\f1d7"; } +.bi-brush::before { content: "\f1d8"; } +.bi-bucket-fill::before { content: "\f1d9"; } +.bi-bucket::before { content: "\f1da"; } +.bi-bug-fill::before { content: "\f1db"; } +.bi-bug::before { content: "\f1dc"; } +.bi-building::before { content: "\f1dd"; } +.bi-bullseye::before { content: "\f1de"; } +.bi-calculator-fill::before { content: "\f1df"; } +.bi-calculator::before { content: "\f1e0"; } +.bi-calendar-check-fill::before { content: "\f1e1"; } +.bi-calendar-check::before { content: "\f1e2"; } +.bi-calendar-date-fill::before { content: "\f1e3"; } +.bi-calendar-date::before { content: "\f1e4"; } +.bi-calendar-day-fill::before { content: "\f1e5"; } +.bi-calendar-day::before { content: "\f1e6"; } +.bi-calendar-event-fill::before { content: "\f1e7"; } +.bi-calendar-event::before { content: "\f1e8"; } +.bi-calendar-fill::before { content: "\f1e9"; } +.bi-calendar-minus-fill::before { content: "\f1ea"; } +.bi-calendar-minus::before { content: "\f1eb"; } +.bi-calendar-month-fill::before { content: "\f1ec"; } +.bi-calendar-month::before { content: "\f1ed"; } +.bi-calendar-plus-fill::before { content: "\f1ee"; } +.bi-calendar-plus::before { content: "\f1ef"; } +.bi-calendar-range-fill::before { content: "\f1f0"; } +.bi-calendar-range::before { content: "\f1f1"; } +.bi-calendar-week-fill::before { content: "\f1f2"; } +.bi-calendar-week::before { content: "\f1f3"; } +.bi-calendar-x-fill::before { content: "\f1f4"; } +.bi-calendar-x::before { content: "\f1f5"; } +.bi-calendar::before { content: "\f1f6"; } +.bi-calendar2-check-fill::before { content: "\f1f7"; } +.bi-calendar2-check::before { content: "\f1f8"; } +.bi-calendar2-date-fill::before { content: "\f1f9"; } +.bi-calendar2-date::before { content: "\f1fa"; } +.bi-calendar2-day-fill::before { content: "\f1fb"; } +.bi-calendar2-day::before { content: "\f1fc"; } +.bi-calendar2-event-fill::before { content: "\f1fd"; } +.bi-calendar2-event::before { content: "\f1fe"; } +.bi-calendar2-fill::before { content: "\f1ff"; } +.bi-calendar2-minus-fill::before { content: "\f200"; } +.bi-calendar2-minus::before { content: "\f201"; } +.bi-calendar2-month-fill::before { content: "\f202"; } +.bi-calendar2-month::before { content: "\f203"; } +.bi-calendar2-plus-fill::before { content: "\f204"; } +.bi-calendar2-plus::before { content: "\f205"; } +.bi-calendar2-range-fill::before { content: "\f206"; } +.bi-calendar2-range::before { content: "\f207"; } +.bi-calendar2-week-fill::before { content: "\f208"; } +.bi-calendar2-week::before { content: "\f209"; } +.bi-calendar2-x-fill::before { content: "\f20a"; } +.bi-calendar2-x::before { content: "\f20b"; } +.bi-calendar2::before { content: "\f20c"; } +.bi-calendar3-event-fill::before { content: "\f20d"; } +.bi-calendar3-event::before { content: "\f20e"; } +.bi-calendar3-fill::before { content: "\f20f"; } +.bi-calendar3-range-fill::before { content: "\f210"; } +.bi-calendar3-range::before { content: "\f211"; } +.bi-calendar3-week-fill::before { content: "\f212"; } +.bi-calendar3-week::before { content: "\f213"; } +.bi-calendar3::before { content: "\f214"; } +.bi-calendar4-event::before { content: "\f215"; } +.bi-calendar4-range::before { content: "\f216"; } +.bi-calendar4-week::before { content: "\f217"; } +.bi-calendar4::before { content: "\f218"; } +.bi-camera-fill::before { content: "\f219"; } +.bi-camera-reels-fill::before { content: "\f21a"; } +.bi-camera-reels::before { content: "\f21b"; } +.bi-camera-video-fill::before { content: "\f21c"; } +.bi-camera-video-off-fill::before { content: "\f21d"; } +.bi-camera-video-off::before { content: "\f21e"; } +.bi-camera-video::before { content: "\f21f"; } +.bi-camera::before { content: "\f220"; } +.bi-camera2::before { content: "\f221"; } +.bi-capslock-fill::before { content: "\f222"; } +.bi-capslock::before { content: "\f223"; } +.bi-card-checklist::before { content: "\f224"; } +.bi-card-heading::before { content: "\f225"; } +.bi-card-image::before { content: "\f226"; } +.bi-card-list::before { content: "\f227"; } +.bi-card-text::before { content: "\f228"; } +.bi-caret-down-fill::before { content: "\f229"; } +.bi-caret-down-square-fill::before { content: "\f22a"; } +.bi-caret-down-square::before { content: "\f22b"; } +.bi-caret-down::before { content: "\f22c"; } +.bi-caret-left-fill::before { content: "\f22d"; } +.bi-caret-left-square-fill::before { content: "\f22e"; } +.bi-caret-left-square::before { content: "\f22f"; } +.bi-caret-left::before { content: "\f230"; } +.bi-caret-right-fill::before { content: "\f231"; } +.bi-caret-right-square-fill::before { content: "\f232"; } +.bi-caret-right-square::before { content: "\f233"; } +.bi-caret-right::before { content: "\f234"; } +.bi-caret-up-fill::before { content: "\f235"; } +.bi-caret-up-square-fill::before { content: "\f236"; } +.bi-caret-up-square::before { content: "\f237"; } +.bi-caret-up::before { content: "\f238"; } +.bi-cart-check-fill::before { content: "\f239"; } +.bi-cart-check::before { content: "\f23a"; } +.bi-cart-dash-fill::before { content: "\f23b"; } +.bi-cart-dash::before { content: "\f23c"; } +.bi-cart-fill::before { content: "\f23d"; } +.bi-cart-plus-fill::before { content: "\f23e"; } +.bi-cart-plus::before { content: "\f23f"; } +.bi-cart-x-fill::before { content: "\f240"; } +.bi-cart-x::before { content: "\f241"; } +.bi-cart::before { content: "\f242"; } +.bi-cart2::before { content: "\f243"; } +.bi-cart3::before { content: "\f244"; } +.bi-cart4::before { content: "\f245"; } +.bi-cash-stack::before { content: "\f246"; } +.bi-cash::before { content: "\f247"; } +.bi-cast::before { content: "\f248"; } +.bi-chat-dots-fill::before { content: "\f249"; } +.bi-chat-dots::before { content: "\f24a"; } +.bi-chat-fill::before { content: "\f24b"; } +.bi-chat-left-dots-fill::before { content: "\f24c"; } +.bi-chat-left-dots::before { content: "\f24d"; } +.bi-chat-left-fill::before { content: "\f24e"; } +.bi-chat-left-quote-fill::before { content: "\f24f"; } +.bi-chat-left-quote::before { content: "\f250"; } +.bi-chat-left-text-fill::before { content: "\f251"; } +.bi-chat-left-text::before { content: "\f252"; } +.bi-chat-left::before { content: "\f253"; } +.bi-chat-quote-fill::before { content: "\f254"; } +.bi-chat-quote::before { content: "\f255"; } +.bi-chat-right-dots-fill::before { content: "\f256"; } +.bi-chat-right-dots::before { content: "\f257"; } +.bi-chat-right-fill::before { content: "\f258"; } +.bi-chat-right-quote-fill::before { content: "\f259"; } +.bi-chat-right-quote::before { content: "\f25a"; } +.bi-chat-right-text-fill::before { content: "\f25b"; } +.bi-chat-right-text::before { content: "\f25c"; } +.bi-chat-right::before { content: "\f25d"; } +.bi-chat-square-dots-fill::before { content: "\f25e"; } +.bi-chat-square-dots::before { content: "\f25f"; } +.bi-chat-square-fill::before { content: "\f260"; } +.bi-chat-square-quote-fill::before { content: "\f261"; } +.bi-chat-square-quote::before { content: "\f262"; } +.bi-chat-square-text-fill::before { content: "\f263"; } +.bi-chat-square-text::before { content: "\f264"; } +.bi-chat-square::before { content: "\f265"; } +.bi-chat-text-fill::before { content: "\f266"; } +.bi-chat-text::before { content: "\f267"; } +.bi-chat::before { content: "\f268"; } +.bi-check-all::before { content: "\f269"; } +.bi-check-circle-fill::before { content: "\f26a"; } +.bi-check-circle::before { content: "\f26b"; } +.bi-check-square-fill::before { content: "\f26c"; } +.bi-check-square::before { content: "\f26d"; } +.bi-check::before { content: "\f26e"; } +.bi-check2-all::before { content: "\f26f"; } +.bi-check2-circle::before { content: "\f270"; } +.bi-check2-square::before { content: "\f271"; } +.bi-check2::before { content: "\f272"; } +.bi-chevron-bar-contract::before { content: "\f273"; } +.bi-chevron-bar-down::before { content: "\f274"; } +.bi-chevron-bar-expand::before { content: "\f275"; } +.bi-chevron-bar-left::before { content: "\f276"; } +.bi-chevron-bar-right::before { content: "\f277"; } +.bi-chevron-bar-up::before { content: "\f278"; } +.bi-chevron-compact-down::before { content: "\f279"; } +.bi-chevron-compact-left::before { content: "\f27a"; } +.bi-chevron-compact-right::before { content: "\f27b"; } +.bi-chevron-compact-up::before { content: "\f27c"; } +.bi-chevron-contract::before { content: "\f27d"; } +.bi-chevron-double-down::before { content: "\f27e"; } +.bi-chevron-double-left::before { content: "\f27f"; } +.bi-chevron-double-right::before { content: "\f280"; } +.bi-chevron-double-up::before { content: "\f281"; } +.bi-chevron-down::before { content: "\f282"; } +.bi-chevron-expand::before { content: "\f283"; } +.bi-chevron-left::before { content: "\f284"; } +.bi-chevron-right::before { content: "\f285"; } +.bi-chevron-up::before { content: "\f286"; } +.bi-circle-fill::before { content: "\f287"; } +.bi-circle-half::before { content: "\f288"; } +.bi-circle-square::before { content: "\f289"; } +.bi-circle::before { content: "\f28a"; } +.bi-clipboard-check::before { content: "\f28b"; } +.bi-clipboard-data::before { content: "\f28c"; } +.bi-clipboard-minus::before { content: "\f28d"; } +.bi-clipboard-plus::before { content: "\f28e"; } +.bi-clipboard-x::before { content: "\f28f"; } +.bi-clipboard::before { content: "\f290"; } +.bi-clock-fill::before { content: "\f291"; } +.bi-clock-history::before { content: "\f292"; } +.bi-clock::before { content: "\f293"; } +.bi-cloud-arrow-down-fill::before { content: "\f294"; } +.bi-cloud-arrow-down::before { content: "\f295"; } +.bi-cloud-arrow-up-fill::before { content: "\f296"; } +.bi-cloud-arrow-up::before { content: "\f297"; } +.bi-cloud-check-fill::before { content: "\f298"; } +.bi-cloud-check::before { content: "\f299"; } +.bi-cloud-download-fill::before { content: "\f29a"; } +.bi-cloud-download::before { content: "\f29b"; } +.bi-cloud-drizzle-fill::before { content: "\f29c"; } +.bi-cloud-drizzle::before { content: "\f29d"; } +.bi-cloud-fill::before { content: "\f29e"; } +.bi-cloud-fog-fill::before { content: "\f29f"; } +.bi-cloud-fog::before { content: "\f2a0"; } +.bi-cloud-fog2-fill::before { content: "\f2a1"; } +.bi-cloud-fog2::before { content: "\f2a2"; } +.bi-cloud-hail-fill::before { content: "\f2a3"; } +.bi-cloud-hail::before { content: "\f2a4"; } +.bi-cloud-haze-fill::before { content: "\f2a6"; } +.bi-cloud-haze::before { content: "\f2a7"; } +.bi-cloud-haze2-fill::before { content: "\f2a8"; } +.bi-cloud-lightning-fill::before { content: "\f2a9"; } +.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } +.bi-cloud-lightning-rain::before { content: "\f2ab"; } +.bi-cloud-lightning::before { content: "\f2ac"; } +.bi-cloud-minus-fill::before { content: "\f2ad"; } +.bi-cloud-minus::before { content: "\f2ae"; } +.bi-cloud-moon-fill::before { content: "\f2af"; } +.bi-cloud-moon::before { content: "\f2b0"; } +.bi-cloud-plus-fill::before { content: "\f2b1"; } +.bi-cloud-plus::before { content: "\f2b2"; } +.bi-cloud-rain-fill::before { content: "\f2b3"; } +.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } +.bi-cloud-rain-heavy::before { content: "\f2b5"; } +.bi-cloud-rain::before { content: "\f2b6"; } +.bi-cloud-slash-fill::before { content: "\f2b7"; } +.bi-cloud-slash::before { content: "\f2b8"; } +.bi-cloud-sleet-fill::before { content: "\f2b9"; } +.bi-cloud-sleet::before { content: "\f2ba"; } +.bi-cloud-snow-fill::before { content: "\f2bb"; } +.bi-cloud-snow::before { content: "\f2bc"; } +.bi-cloud-sun-fill::before { content: "\f2bd"; } +.bi-cloud-sun::before { content: "\f2be"; } +.bi-cloud-upload-fill::before { content: "\f2bf"; } +.bi-cloud-upload::before { content: "\f2c0"; } +.bi-cloud::before { content: "\f2c1"; } +.bi-clouds-fill::before { content: "\f2c2"; } +.bi-clouds::before { content: "\f2c3"; } +.bi-cloudy-fill::before { content: "\f2c4"; } +.bi-cloudy::before { content: "\f2c5"; } +.bi-code-slash::before { content: "\f2c6"; } +.bi-code-square::before { content: "\f2c7"; } +.bi-code::before { content: "\f2c8"; } +.bi-collection-fill::before { content: "\f2c9"; } +.bi-collection-play-fill::before { content: "\f2ca"; } +.bi-collection-play::before { content: "\f2cb"; } +.bi-collection::before { content: "\f2cc"; } +.bi-columns-gap::before { content: "\f2cd"; } +.bi-columns::before { content: "\f2ce"; } +.bi-command::before { content: "\f2cf"; } +.bi-compass-fill::before { content: "\f2d0"; } +.bi-compass::before { content: "\f2d1"; } +.bi-cone-striped::before { content: "\f2d2"; } +.bi-cone::before { content: "\f2d3"; } +.bi-controller::before { content: "\f2d4"; } +.bi-cpu-fill::before { content: "\f2d5"; } +.bi-cpu::before { content: "\f2d6"; } +.bi-credit-card-2-back-fill::before { content: "\f2d7"; } +.bi-credit-card-2-back::before { content: "\f2d8"; } +.bi-credit-card-2-front-fill::before { content: "\f2d9"; } +.bi-credit-card-2-front::before { content: "\f2da"; } +.bi-credit-card-fill::before { content: "\f2db"; } +.bi-credit-card::before { content: "\f2dc"; } +.bi-crop::before { content: "\f2dd"; } +.bi-cup-fill::before { content: "\f2de"; } +.bi-cup-straw::before { content: "\f2df"; } +.bi-cup::before { content: "\f2e0"; } +.bi-cursor-fill::before { content: "\f2e1"; } +.bi-cursor-text::before { content: "\f2e2"; } +.bi-cursor::before { content: "\f2e3"; } +.bi-dash-circle-dotted::before { content: "\f2e4"; } +.bi-dash-circle-fill::before { content: "\f2e5"; } +.bi-dash-circle::before { content: "\f2e6"; } +.bi-dash-square-dotted::before { content: "\f2e7"; } +.bi-dash-square-fill::before { content: "\f2e8"; } +.bi-dash-square::before { content: "\f2e9"; } +.bi-dash::before { content: "\f2ea"; } +.bi-diagram-2-fill::before { content: "\f2eb"; } +.bi-diagram-2::before { content: "\f2ec"; } +.bi-diagram-3-fill::before { content: "\f2ed"; } +.bi-diagram-3::before { content: "\f2ee"; } +.bi-diamond-fill::before { content: "\f2ef"; } +.bi-diamond-half::before { content: "\f2f0"; } +.bi-diamond::before { content: "\f2f1"; } +.bi-dice-1-fill::before { content: "\f2f2"; } +.bi-dice-1::before { content: "\f2f3"; } +.bi-dice-2-fill::before { content: "\f2f4"; } +.bi-dice-2::before { content: "\f2f5"; } +.bi-dice-3-fill::before { content: "\f2f6"; } +.bi-dice-3::before { content: "\f2f7"; } +.bi-dice-4-fill::before { content: "\f2f8"; } +.bi-dice-4::before { content: "\f2f9"; } +.bi-dice-5-fill::before { content: "\f2fa"; } +.bi-dice-5::before { content: "\f2fb"; } +.bi-dice-6-fill::before { content: "\f2fc"; } +.bi-dice-6::before { content: "\f2fd"; } +.bi-disc-fill::before { content: "\f2fe"; } +.bi-disc::before { content: "\f2ff"; } +.bi-discord::before { content: "\f300"; } +.bi-display-fill::before { content: "\f301"; } +.bi-display::before { content: "\f302"; } +.bi-distribute-horizontal::before { content: "\f303"; } +.bi-distribute-vertical::before { content: "\f304"; } +.bi-door-closed-fill::before { content: "\f305"; } +.bi-door-closed::before { content: "\f306"; } +.bi-door-open-fill::before { content: "\f307"; } +.bi-door-open::before { content: "\f308"; } +.bi-dot::before { content: "\f309"; } +.bi-download::before { content: "\f30a"; } +.bi-droplet-fill::before { content: "\f30b"; } +.bi-droplet-half::before { content: "\f30c"; } +.bi-droplet::before { content: "\f30d"; } +.bi-earbuds::before { content: "\f30e"; } +.bi-easel-fill::before { content: "\f30f"; } +.bi-easel::before { content: "\f310"; } +.bi-egg-fill::before { content: "\f311"; } +.bi-egg-fried::before { content: "\f312"; } +.bi-egg::before { content: "\f313"; } +.bi-eject-fill::before { content: "\f314"; } +.bi-eject::before { content: "\f315"; } +.bi-emoji-angry-fill::before { content: "\f316"; } +.bi-emoji-angry::before { content: "\f317"; } +.bi-emoji-dizzy-fill::before { content: "\f318"; } +.bi-emoji-dizzy::before { content: "\f319"; } +.bi-emoji-expressionless-fill::before { content: "\f31a"; } +.bi-emoji-expressionless::before { content: "\f31b"; } +.bi-emoji-frown-fill::before { content: "\f31c"; } +.bi-emoji-frown::before { content: "\f31d"; } +.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } +.bi-emoji-heart-eyes::before { content: "\f31f"; } +.bi-emoji-laughing-fill::before { content: "\f320"; } +.bi-emoji-laughing::before { content: "\f321"; } +.bi-emoji-neutral-fill::before { content: "\f322"; } +.bi-emoji-neutral::before { content: "\f323"; } +.bi-emoji-smile-fill::before { content: "\f324"; } +.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } +.bi-emoji-smile-upside-down::before { content: "\f326"; } +.bi-emoji-smile::before { content: "\f327"; } +.bi-emoji-sunglasses-fill::before { content: "\f328"; } +.bi-emoji-sunglasses::before { content: "\f329"; } +.bi-emoji-wink-fill::before { content: "\f32a"; } +.bi-emoji-wink::before { content: "\f32b"; } +.bi-envelope-fill::before { content: "\f32c"; } +.bi-envelope-open-fill::before { content: "\f32d"; } +.bi-envelope-open::before { content: "\f32e"; } +.bi-envelope::before { content: "\f32f"; } +.bi-eraser-fill::before { content: "\f330"; } +.bi-eraser::before { content: "\f331"; } +.bi-exclamation-circle-fill::before { content: "\f332"; } +.bi-exclamation-circle::before { content: "\f333"; } +.bi-exclamation-diamond-fill::before { content: "\f334"; } +.bi-exclamation-diamond::before { content: "\f335"; } +.bi-exclamation-octagon-fill::before { content: "\f336"; } +.bi-exclamation-octagon::before { content: "\f337"; } +.bi-exclamation-square-fill::before { content: "\f338"; } +.bi-exclamation-square::before { content: "\f339"; } +.bi-exclamation-triangle-fill::before { content: "\f33a"; } +.bi-exclamation-triangle::before { content: "\f33b"; } +.bi-exclamation::before { content: "\f33c"; } +.bi-exclude::before { content: "\f33d"; } +.bi-eye-fill::before { content: "\f33e"; } +.bi-eye-slash-fill::before { content: "\f33f"; } +.bi-eye-slash::before { content: "\f340"; } +.bi-eye::before { content: "\f341"; } +.bi-eyedropper::before { content: "\f342"; } +.bi-eyeglasses::before { content: "\f343"; } +.bi-facebook::before { content: "\f344"; } +.bi-file-arrow-down-fill::before { content: "\f345"; } +.bi-file-arrow-down::before { content: "\f346"; } +.bi-file-arrow-up-fill::before { content: "\f347"; } +.bi-file-arrow-up::before { content: "\f348"; } +.bi-file-bar-graph-fill::before { content: "\f349"; } +.bi-file-bar-graph::before { content: "\f34a"; } +.bi-file-binary-fill::before { content: "\f34b"; } +.bi-file-binary::before { content: "\f34c"; } +.bi-file-break-fill::before { content: "\f34d"; } +.bi-file-break::before { content: "\f34e"; } +.bi-file-check-fill::before { content: "\f34f"; } +.bi-file-check::before { content: "\f350"; } +.bi-file-code-fill::before { content: "\f351"; } +.bi-file-code::before { content: "\f352"; } +.bi-file-diff-fill::before { content: "\f353"; } +.bi-file-diff::before { content: "\f354"; } +.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } +.bi-file-earmark-arrow-down::before { content: "\f356"; } +.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } +.bi-file-earmark-arrow-up::before { content: "\f358"; } +.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } +.bi-file-earmark-bar-graph::before { content: "\f35a"; } +.bi-file-earmark-binary-fill::before { content: "\f35b"; } +.bi-file-earmark-binary::before { content: "\f35c"; } +.bi-file-earmark-break-fill::before { content: "\f35d"; } +.bi-file-earmark-break::before { content: "\f35e"; } +.bi-file-earmark-check-fill::before { content: "\f35f"; } +.bi-file-earmark-check::before { content: "\f360"; } +.bi-file-earmark-code-fill::before { content: "\f361"; } +.bi-file-earmark-code::before { content: "\f362"; } +.bi-file-earmark-diff-fill::before { content: "\f363"; } +.bi-file-earmark-diff::before { content: "\f364"; } +.bi-file-earmark-easel-fill::before { content: "\f365"; } +.bi-file-earmark-easel::before { content: "\f366"; } +.bi-file-earmark-excel-fill::before { content: "\f367"; } +.bi-file-earmark-excel::before { content: "\f368"; } +.bi-file-earmark-fill::before { content: "\f369"; } +.bi-file-earmark-font-fill::before { content: "\f36a"; } +.bi-file-earmark-font::before { content: "\f36b"; } +.bi-file-earmark-image-fill::before { content: "\f36c"; } +.bi-file-earmark-image::before { content: "\f36d"; } +.bi-file-earmark-lock-fill::before { content: "\f36e"; } +.bi-file-earmark-lock::before { content: "\f36f"; } +.bi-file-earmark-lock2-fill::before { content: "\f370"; } +.bi-file-earmark-lock2::before { content: "\f371"; } +.bi-file-earmark-medical-fill::before { content: "\f372"; } +.bi-file-earmark-medical::before { content: "\f373"; } +.bi-file-earmark-minus-fill::before { content: "\f374"; } +.bi-file-earmark-minus::before { content: "\f375"; } +.bi-file-earmark-music-fill::before { content: "\f376"; } +.bi-file-earmark-music::before { content: "\f377"; } +.bi-file-earmark-person-fill::before { content: "\f378"; } +.bi-file-earmark-person::before { content: "\f379"; } +.bi-file-earmark-play-fill::before { content: "\f37a"; } +.bi-file-earmark-play::before { content: "\f37b"; } +.bi-file-earmark-plus-fill::before { content: "\f37c"; } +.bi-file-earmark-plus::before { content: "\f37d"; } +.bi-file-earmark-post-fill::before { content: "\f37e"; } +.bi-file-earmark-post::before { content: "\f37f"; } +.bi-file-earmark-ppt-fill::before { content: "\f380"; } +.bi-file-earmark-ppt::before { content: "\f381"; } +.bi-file-earmark-richtext-fill::before { content: "\f382"; } +.bi-file-earmark-richtext::before { content: "\f383"; } +.bi-file-earmark-ruled-fill::before { content: "\f384"; } +.bi-file-earmark-ruled::before { content: "\f385"; } +.bi-file-earmark-slides-fill::before { content: "\f386"; } +.bi-file-earmark-slides::before { content: "\f387"; } +.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } +.bi-file-earmark-spreadsheet::before { content: "\f389"; } +.bi-file-earmark-text-fill::before { content: "\f38a"; } +.bi-file-earmark-text::before { content: "\f38b"; } +.bi-file-earmark-word-fill::before { content: "\f38c"; } +.bi-file-earmark-word::before { content: "\f38d"; } +.bi-file-earmark-x-fill::before { content: "\f38e"; } +.bi-file-earmark-x::before { content: "\f38f"; } +.bi-file-earmark-zip-fill::before { content: "\f390"; } +.bi-file-earmark-zip::before { content: "\f391"; } +.bi-file-earmark::before { content: "\f392"; } +.bi-file-easel-fill::before { content: "\f393"; } +.bi-file-easel::before { content: "\f394"; } +.bi-file-excel-fill::before { content: "\f395"; } +.bi-file-excel::before { content: "\f396"; } +.bi-file-fill::before { content: "\f397"; } +.bi-file-font-fill::before { content: "\f398"; } +.bi-file-font::before { content: "\f399"; } +.bi-file-image-fill::before { content: "\f39a"; } +.bi-file-image::before { content: "\f39b"; } +.bi-file-lock-fill::before { content: "\f39c"; } +.bi-file-lock::before { content: "\f39d"; } +.bi-file-lock2-fill::before { content: "\f39e"; } +.bi-file-lock2::before { content: "\f39f"; } +.bi-file-medical-fill::before { content: "\f3a0"; } +.bi-file-medical::before { content: "\f3a1"; } +.bi-file-minus-fill::before { content: "\f3a2"; } +.bi-file-minus::before { content: "\f3a3"; } +.bi-file-music-fill::before { content: "\f3a4"; } +.bi-file-music::before { content: "\f3a5"; } +.bi-file-person-fill::before { content: "\f3a6"; } +.bi-file-person::before { content: "\f3a7"; } +.bi-file-play-fill::before { content: "\f3a8"; } +.bi-file-play::before { content: "\f3a9"; } +.bi-file-plus-fill::before { content: "\f3aa"; } +.bi-file-plus::before { content: "\f3ab"; } +.bi-file-post-fill::before { content: "\f3ac"; } +.bi-file-post::before { content: "\f3ad"; } +.bi-file-ppt-fill::before { content: "\f3ae"; } +.bi-file-ppt::before { content: "\f3af"; } +.bi-file-richtext-fill::before { content: "\f3b0"; } +.bi-file-richtext::before { content: "\f3b1"; } +.bi-file-ruled-fill::before { content: "\f3b2"; } +.bi-file-ruled::before { content: "\f3b3"; } +.bi-file-slides-fill::before { content: "\f3b4"; } +.bi-file-slides::before { content: "\f3b5"; } +.bi-file-spreadsheet-fill::before { content: "\f3b6"; } +.bi-file-spreadsheet::before { content: "\f3b7"; } +.bi-file-text-fill::before { content: "\f3b8"; } +.bi-file-text::before { content: "\f3b9"; } +.bi-file-word-fill::before { content: "\f3ba"; } +.bi-file-word::before { content: "\f3bb"; } +.bi-file-x-fill::before { content: "\f3bc"; } +.bi-file-x::before { content: "\f3bd"; } +.bi-file-zip-fill::before { content: "\f3be"; } +.bi-file-zip::before { content: "\f3bf"; } +.bi-file::before { content: "\f3c0"; } +.bi-files-alt::before { content: "\f3c1"; } +.bi-files::before { content: "\f3c2"; } +.bi-film::before { content: "\f3c3"; } +.bi-filter-circle-fill::before { content: "\f3c4"; } +.bi-filter-circle::before { content: "\f3c5"; } +.bi-filter-left::before { content: "\f3c6"; } +.bi-filter-right::before { content: "\f3c7"; } +.bi-filter-square-fill::before { content: "\f3c8"; } +.bi-filter-square::before { content: "\f3c9"; } +.bi-filter::before { content: "\f3ca"; } +.bi-flag-fill::before { content: "\f3cb"; } +.bi-flag::before { content: "\f3cc"; } +.bi-flower1::before { content: "\f3cd"; } +.bi-flower2::before { content: "\f3ce"; } +.bi-flower3::before { content: "\f3cf"; } +.bi-folder-check::before { content: "\f3d0"; } +.bi-folder-fill::before { content: "\f3d1"; } +.bi-folder-minus::before { content: "\f3d2"; } +.bi-folder-plus::before { content: "\f3d3"; } +.bi-folder-symlink-fill::before { content: "\f3d4"; } +.bi-folder-symlink::before { content: "\f3d5"; } +.bi-folder-x::before { content: "\f3d6"; } +.bi-folder::before { content: "\f3d7"; } +.bi-folder2-open::before { content: "\f3d8"; } +.bi-folder2::before { content: "\f3d9"; } +.bi-fonts::before { content: "\f3da"; } +.bi-forward-fill::before { content: "\f3db"; } +.bi-forward::before { content: "\f3dc"; } +.bi-front::before { content: "\f3dd"; } +.bi-fullscreen-exit::before { content: "\f3de"; } +.bi-fullscreen::before { content: "\f3df"; } +.bi-funnel-fill::before { content: "\f3e0"; } +.bi-funnel::before { content: "\f3e1"; } +.bi-gear-fill::before { content: "\f3e2"; } +.bi-gear-wide-connected::before { content: "\f3e3"; } +.bi-gear-wide::before { content: "\f3e4"; } +.bi-gear::before { content: "\f3e5"; } +.bi-gem::before { content: "\f3e6"; } +.bi-geo-alt-fill::before { content: "\f3e7"; } +.bi-geo-alt::before { content: "\f3e8"; } +.bi-geo-fill::before { content: "\f3e9"; } +.bi-geo::before { content: "\f3ea"; } +.bi-gift-fill::before { content: "\f3eb"; } +.bi-gift::before { content: "\f3ec"; } +.bi-github::before { content: "\f3ed"; } +.bi-globe::before { content: "\f3ee"; } +.bi-globe2::before { content: "\f3ef"; } +.bi-google::before { content: "\f3f0"; } +.bi-graph-down::before { content: "\f3f1"; } +.bi-graph-up::before { content: "\f3f2"; } +.bi-grid-1x2-fill::before { content: "\f3f3"; } +.bi-grid-1x2::before { content: "\f3f4"; } +.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } +.bi-grid-3x2-gap::before { content: "\f3f6"; } +.bi-grid-3x2::before { content: "\f3f7"; } +.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } +.bi-grid-3x3-gap::before { content: "\f3f9"; } +.bi-grid-3x3::before { content: "\f3fa"; } +.bi-grid-fill::before { content: "\f3fb"; } +.bi-grid::before { content: "\f3fc"; } +.bi-grip-horizontal::before { content: "\f3fd"; } +.bi-grip-vertical::before { content: "\f3fe"; } +.bi-hammer::before { content: "\f3ff"; } +.bi-hand-index-fill::before { content: "\f400"; } +.bi-hand-index-thumb-fill::before { content: "\f401"; } +.bi-hand-index-thumb::before { content: "\f402"; } +.bi-hand-index::before { content: "\f403"; } +.bi-hand-thumbs-down-fill::before { content: "\f404"; } +.bi-hand-thumbs-down::before { content: "\f405"; } +.bi-hand-thumbs-up-fill::before { content: "\f406"; } +.bi-hand-thumbs-up::before { content: "\f407"; } +.bi-handbag-fill::before { content: "\f408"; } +.bi-handbag::before { content: "\f409"; } +.bi-hash::before { content: "\f40a"; } +.bi-hdd-fill::before { content: "\f40b"; } +.bi-hdd-network-fill::before { content: "\f40c"; } +.bi-hdd-network::before { content: "\f40d"; } +.bi-hdd-rack-fill::before { content: "\f40e"; } +.bi-hdd-rack::before { content: "\f40f"; } +.bi-hdd-stack-fill::before { content: "\f410"; } +.bi-hdd-stack::before { content: "\f411"; } +.bi-hdd::before { content: "\f412"; } +.bi-headphones::before { content: "\f413"; } +.bi-headset::before { content: "\f414"; } +.bi-heart-fill::before { content: "\f415"; } +.bi-heart-half::before { content: "\f416"; } +.bi-heart::before { content: "\f417"; } +.bi-heptagon-fill::before { content: "\f418"; } +.bi-heptagon-half::before { content: "\f419"; } +.bi-heptagon::before { content: "\f41a"; } +.bi-hexagon-fill::before { content: "\f41b"; } +.bi-hexagon-half::before { content: "\f41c"; } +.bi-hexagon::before { content: "\f41d"; } +.bi-hourglass-bottom::before { content: "\f41e"; } +.bi-hourglass-split::before { content: "\f41f"; } +.bi-hourglass-top::before { content: "\f420"; } +.bi-hourglass::before { content: "\f421"; } +.bi-house-door-fill::before { content: "\f422"; } +.bi-house-door::before { content: "\f423"; } +.bi-house-fill::before { content: "\f424"; } +.bi-house::before { content: "\f425"; } +.bi-hr::before { content: "\f426"; } +.bi-hurricane::before { content: "\f427"; } +.bi-image-alt::before { content: "\f428"; } +.bi-image-fill::before { content: "\f429"; } +.bi-image::before { content: "\f42a"; } +.bi-images::before { content: "\f42b"; } +.bi-inbox-fill::before { content: "\f42c"; } +.bi-inbox::before { content: "\f42d"; } +.bi-inboxes-fill::before { content: "\f42e"; } +.bi-inboxes::before { content: "\f42f"; } +.bi-info-circle-fill::before { content: "\f430"; } +.bi-info-circle::before { content: "\f431"; } +.bi-info-square-fill::before { content: "\f432"; } +.bi-info-square::before { content: "\f433"; } +.bi-info::before { content: "\f434"; } +.bi-input-cursor-text::before { content: "\f435"; } +.bi-input-cursor::before { content: "\f436"; } +.bi-instagram::before { content: "\f437"; } +.bi-intersect::before { content: "\f438"; } +.bi-journal-album::before { content: "\f439"; } +.bi-journal-arrow-down::before { content: "\f43a"; } +.bi-journal-arrow-up::before { content: "\f43b"; } +.bi-journal-bookmark-fill::before { content: "\f43c"; } +.bi-journal-bookmark::before { content: "\f43d"; } +.bi-journal-check::before { content: "\f43e"; } +.bi-journal-code::before { content: "\f43f"; } +.bi-journal-medical::before { content: "\f440"; } +.bi-journal-minus::before { content: "\f441"; } +.bi-journal-plus::before { content: "\f442"; } +.bi-journal-richtext::before { content: "\f443"; } +.bi-journal-text::before { content: "\f444"; } +.bi-journal-x::before { content: "\f445"; } +.bi-journal::before { content: "\f446"; } +.bi-journals::before { content: "\f447"; } +.bi-joystick::before { content: "\f448"; } +.bi-justify-left::before { content: "\f449"; } +.bi-justify-right::before { content: "\f44a"; } +.bi-justify::before { content: "\f44b"; } +.bi-kanban-fill::before { content: "\f44c"; } +.bi-kanban::before { content: "\f44d"; } +.bi-key-fill::before { content: "\f44e"; } +.bi-key::before { content: "\f44f"; } +.bi-keyboard-fill::before { content: "\f450"; } +.bi-keyboard::before { content: "\f451"; } +.bi-ladder::before { content: "\f452"; } +.bi-lamp-fill::before { content: "\f453"; } +.bi-lamp::before { content: "\f454"; } +.bi-laptop-fill::before { content: "\f455"; } +.bi-laptop::before { content: "\f456"; } +.bi-layer-backward::before { content: "\f457"; } +.bi-layer-forward::before { content: "\f458"; } +.bi-layers-fill::before { content: "\f459"; } +.bi-layers-half::before { content: "\f45a"; } +.bi-layers::before { content: "\f45b"; } +.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } +.bi-layout-sidebar-inset::before { content: "\f45d"; } +.bi-layout-sidebar-reverse::before { content: "\f45e"; } +.bi-layout-sidebar::before { content: "\f45f"; } +.bi-layout-split::before { content: "\f460"; } +.bi-layout-text-sidebar-reverse::before { content: "\f461"; } +.bi-layout-text-sidebar::before { content: "\f462"; } +.bi-layout-text-window-reverse::before { content: "\f463"; } +.bi-layout-text-window::before { content: "\f464"; } +.bi-layout-three-columns::before { content: "\f465"; } +.bi-layout-wtf::before { content: "\f466"; } +.bi-life-preserver::before { content: "\f467"; } +.bi-lightbulb-fill::before { content: "\f468"; } +.bi-lightbulb-off-fill::before { content: "\f469"; } +.bi-lightbulb-off::before { content: "\f46a"; } +.bi-lightbulb::before { content: "\f46b"; } +.bi-lightning-charge-fill::before { content: "\f46c"; } +.bi-lightning-charge::before { content: "\f46d"; } +.bi-lightning-fill::before { content: "\f46e"; } +.bi-lightning::before { content: "\f46f"; } +.bi-link-45deg::before { content: "\f470"; } +.bi-link::before { content: "\f471"; } +.bi-linkedin::before { content: "\f472"; } +.bi-list-check::before { content: "\f473"; } +.bi-list-nested::before { content: "\f474"; } +.bi-list-ol::before { content: "\f475"; } +.bi-list-stars::before { content: "\f476"; } +.bi-list-task::before { content: "\f477"; } +.bi-list-ul::before { content: "\f478"; } +.bi-list::before { content: "\f479"; } +.bi-lock-fill::before { content: "\f47a"; } +.bi-lock::before { content: "\f47b"; } +.bi-mailbox::before { content: "\f47c"; } +.bi-mailbox2::before { content: "\f47d"; } +.bi-map-fill::before { content: "\f47e"; } +.bi-map::before { content: "\f47f"; } +.bi-markdown-fill::before { content: "\f480"; } +.bi-markdown::before { content: "\f481"; } +.bi-mask::before { content: "\f482"; } +.bi-megaphone-fill::before { content: "\f483"; } +.bi-megaphone::before { content: "\f484"; } +.bi-menu-app-fill::before { content: "\f485"; } +.bi-menu-app::before { content: "\f486"; } +.bi-menu-button-fill::before { content: "\f487"; } +.bi-menu-button-wide-fill::before { content: "\f488"; } +.bi-menu-button-wide::before { content: "\f489"; } +.bi-menu-button::before { content: "\f48a"; } +.bi-menu-down::before { content: "\f48b"; } +.bi-menu-up::before { content: "\f48c"; } +.bi-mic-fill::before { content: "\f48d"; } +.bi-mic-mute-fill::before { content: "\f48e"; } +.bi-mic-mute::before { content: "\f48f"; } +.bi-mic::before { content: "\f490"; } +.bi-minecart-loaded::before { content: "\f491"; } +.bi-minecart::before { content: "\f492"; } +.bi-moisture::before { content: "\f493"; } +.bi-moon-fill::before { content: "\f494"; } +.bi-moon-stars-fill::before { content: "\f495"; } +.bi-moon-stars::before { content: "\f496"; } +.bi-moon::before { content: "\f497"; } +.bi-mouse-fill::before { content: "\f498"; } +.bi-mouse::before { content: "\f499"; } +.bi-mouse2-fill::before { content: "\f49a"; } +.bi-mouse2::before { content: "\f49b"; } +.bi-mouse3-fill::before { content: "\f49c"; } +.bi-mouse3::before { content: "\f49d"; } +.bi-music-note-beamed::before { content: "\f49e"; } +.bi-music-note-list::before { content: "\f49f"; } +.bi-music-note::before { content: "\f4a0"; } +.bi-music-player-fill::before { content: "\f4a1"; } +.bi-music-player::before { content: "\f4a2"; } +.bi-newspaper::before { content: "\f4a3"; } +.bi-node-minus-fill::before { content: "\f4a4"; } +.bi-node-minus::before { content: "\f4a5"; } +.bi-node-plus-fill::before { content: "\f4a6"; } +.bi-node-plus::before { content: "\f4a7"; } +.bi-nut-fill::before { content: "\f4a8"; } +.bi-nut::before { content: "\f4a9"; } +.bi-octagon-fill::before { content: "\f4aa"; } +.bi-octagon-half::before { content: "\f4ab"; } +.bi-octagon::before { content: "\f4ac"; } +.bi-option::before { content: "\f4ad"; } +.bi-outlet::before { content: "\f4ae"; } +.bi-paint-bucket::before { content: "\f4af"; } +.bi-palette-fill::before { content: "\f4b0"; } +.bi-palette::before { content: "\f4b1"; } +.bi-palette2::before { content: "\f4b2"; } +.bi-paperclip::before { content: "\f4b3"; } +.bi-paragraph::before { content: "\f4b4"; } +.bi-patch-check-fill::before { content: "\f4b5"; } +.bi-patch-check::before { content: "\f4b6"; } +.bi-patch-exclamation-fill::before { content: "\f4b7"; } +.bi-patch-exclamation::before { content: "\f4b8"; } +.bi-patch-minus-fill::before { content: "\f4b9"; } +.bi-patch-minus::before { content: "\f4ba"; } +.bi-patch-plus-fill::before { content: "\f4bb"; } +.bi-patch-plus::before { content: "\f4bc"; } +.bi-patch-question-fill::before { content: "\f4bd"; } +.bi-patch-question::before { content: "\f4be"; } +.bi-pause-btn-fill::before { content: "\f4bf"; } +.bi-pause-btn::before { content: "\f4c0"; } +.bi-pause-circle-fill::before { content: "\f4c1"; } +.bi-pause-circle::before { content: "\f4c2"; } +.bi-pause-fill::before { content: "\f4c3"; } +.bi-pause::before { content: "\f4c4"; } +.bi-peace-fill::before { content: "\f4c5"; } +.bi-peace::before { content: "\f4c6"; } +.bi-pen-fill::before { content: "\f4c7"; } +.bi-pen::before { content: "\f4c8"; } +.bi-pencil-fill::before { content: "\f4c9"; } +.bi-pencil-square::before { content: "\f4ca"; } +.bi-pencil::before { content: "\f4cb"; } +.bi-pentagon-fill::before { content: "\f4cc"; } +.bi-pentagon-half::before { content: "\f4cd"; } +.bi-pentagon::before { content: "\f4ce"; } +.bi-people-fill::before { content: "\f4cf"; } +.bi-people::before { content: "\f4d0"; } +.bi-percent::before { content: "\f4d1"; } +.bi-person-badge-fill::before { content: "\f4d2"; } +.bi-person-badge::before { content: "\f4d3"; } +.bi-person-bounding-box::before { content: "\f4d4"; } +.bi-person-check-fill::before { content: "\f4d5"; } +.bi-person-check::before { content: "\f4d6"; } +.bi-person-circle::before { content: "\f4d7"; } +.bi-person-dash-fill::before { content: "\f4d8"; } +.bi-person-dash::before { content: "\f4d9"; } +.bi-person-fill::before { content: "\f4da"; } +.bi-person-lines-fill::before { content: "\f4db"; } +.bi-person-plus-fill::before { content: "\f4dc"; } +.bi-person-plus::before { content: "\f4dd"; } +.bi-person-square::before { content: "\f4de"; } +.bi-person-x-fill::before { content: "\f4df"; } +.bi-person-x::before { content: "\f4e0"; } +.bi-person::before { content: "\f4e1"; } +.bi-phone-fill::before { content: "\f4e2"; } +.bi-phone-landscape-fill::before { content: "\f4e3"; } +.bi-phone-landscape::before { content: "\f4e4"; } +.bi-phone-vibrate-fill::before { content: "\f4e5"; } +.bi-phone-vibrate::before { content: "\f4e6"; } +.bi-phone::before { content: "\f4e7"; } +.bi-pie-chart-fill::before { content: "\f4e8"; } +.bi-pie-chart::before { content: "\f4e9"; } +.bi-pin-angle-fill::before { content: "\f4ea"; } +.bi-pin-angle::before { content: "\f4eb"; } +.bi-pin-fill::before { content: "\f4ec"; } +.bi-pin::before { content: "\f4ed"; } +.bi-pip-fill::before { content: "\f4ee"; } +.bi-pip::before { content: "\f4ef"; } +.bi-play-btn-fill::before { content: "\f4f0"; } +.bi-play-btn::before { content: "\f4f1"; } +.bi-play-circle-fill::before { content: "\f4f2"; } +.bi-play-circle::before { content: "\f4f3"; } +.bi-play-fill::before { content: "\f4f4"; } +.bi-play::before { content: "\f4f5"; } +.bi-plug-fill::before { content: "\f4f6"; } +.bi-plug::before { content: "\f4f7"; } +.bi-plus-circle-dotted::before { content: "\f4f8"; } +.bi-plus-circle-fill::before { content: "\f4f9"; } +.bi-plus-circle::before { content: "\f4fa"; } +.bi-plus-square-dotted::before { content: "\f4fb"; } +.bi-plus-square-fill::before { content: "\f4fc"; } +.bi-plus-square::before { content: "\f4fd"; } +.bi-plus::before { content: "\f4fe"; } +.bi-power::before { content: "\f4ff"; } +.bi-printer-fill::before { content: "\f500"; } +.bi-printer::before { content: "\f501"; } +.bi-puzzle-fill::before { content: "\f502"; } +.bi-puzzle::before { content: "\f503"; } +.bi-question-circle-fill::before { content: "\f504"; } +.bi-question-circle::before { content: "\f505"; } +.bi-question-diamond-fill::before { content: "\f506"; } +.bi-question-diamond::before { content: "\f507"; } +.bi-question-octagon-fill::before { content: "\f508"; } +.bi-question-octagon::before { content: "\f509"; } +.bi-question-square-fill::before { content: "\f50a"; } +.bi-question-square::before { content: "\f50b"; } +.bi-question::before { content: "\f50c"; } +.bi-rainbow::before { content: "\f50d"; } +.bi-receipt-cutoff::before { content: "\f50e"; } +.bi-receipt::before { content: "\f50f"; } +.bi-reception-0::before { content: "\f510"; } +.bi-reception-1::before { content: "\f511"; } +.bi-reception-2::before { content: "\f512"; } +.bi-reception-3::before { content: "\f513"; } +.bi-reception-4::before { content: "\f514"; } +.bi-record-btn-fill::before { content: "\f515"; } +.bi-record-btn::before { content: "\f516"; } +.bi-record-circle-fill::before { content: "\f517"; } +.bi-record-circle::before { content: "\f518"; } +.bi-record-fill::before { content: "\f519"; } +.bi-record::before { content: "\f51a"; } +.bi-record2-fill::before { content: "\f51b"; } +.bi-record2::before { content: "\f51c"; } +.bi-reply-all-fill::before { content: "\f51d"; } +.bi-reply-all::before { content: "\f51e"; } +.bi-reply-fill::before { content: "\f51f"; } +.bi-reply::before { content: "\f520"; } +.bi-rss-fill::before { content: "\f521"; } +.bi-rss::before { content: "\f522"; } +.bi-rulers::before { content: "\f523"; } +.bi-save-fill::before { content: "\f524"; } +.bi-save::before { content: "\f525"; } +.bi-save2-fill::before { content: "\f526"; } +.bi-save2::before { content: "\f527"; } +.bi-scissors::before { content: "\f528"; } +.bi-screwdriver::before { content: "\f529"; } +.bi-search::before { content: "\f52a"; } +.bi-segmented-nav::before { content: "\f52b"; } +.bi-server::before { content: "\f52c"; } +.bi-share-fill::before { content: "\f52d"; } +.bi-share::before { content: "\f52e"; } +.bi-shield-check::before { content: "\f52f"; } +.bi-shield-exclamation::before { content: "\f530"; } +.bi-shield-fill-check::before { content: "\f531"; } +.bi-shield-fill-exclamation::before { content: "\f532"; } +.bi-shield-fill-minus::before { content: "\f533"; } +.bi-shield-fill-plus::before { content: "\f534"; } +.bi-shield-fill-x::before { content: "\f535"; } +.bi-shield-fill::before { content: "\f536"; } +.bi-shield-lock-fill::before { content: "\f537"; } +.bi-shield-lock::before { content: "\f538"; } +.bi-shield-minus::before { content: "\f539"; } +.bi-shield-plus::before { content: "\f53a"; } +.bi-shield-shaded::before { content: "\f53b"; } +.bi-shield-slash-fill::before { content: "\f53c"; } +.bi-shield-slash::before { content: "\f53d"; } +.bi-shield-x::before { content: "\f53e"; } +.bi-shield::before { content: "\f53f"; } +.bi-shift-fill::before { content: "\f540"; } +.bi-shift::before { content: "\f541"; } +.bi-shop-window::before { content: "\f542"; } +.bi-shop::before { content: "\f543"; } +.bi-shuffle::before { content: "\f544"; } +.bi-signpost-2-fill::before { content: "\f545"; } +.bi-signpost-2::before { content: "\f546"; } +.bi-signpost-fill::before { content: "\f547"; } +.bi-signpost-split-fill::before { content: "\f548"; } +.bi-signpost-split::before { content: "\f549"; } +.bi-signpost::before { content: "\f54a"; } +.bi-sim-fill::before { content: "\f54b"; } +.bi-sim::before { content: "\f54c"; } +.bi-skip-backward-btn-fill::before { content: "\f54d"; } +.bi-skip-backward-btn::before { content: "\f54e"; } +.bi-skip-backward-circle-fill::before { content: "\f54f"; } +.bi-skip-backward-circle::before { content: "\f550"; } +.bi-skip-backward-fill::before { content: "\f551"; } +.bi-skip-backward::before { content: "\f552"; } +.bi-skip-end-btn-fill::before { content: "\f553"; } +.bi-skip-end-btn::before { content: "\f554"; } +.bi-skip-end-circle-fill::before { content: "\f555"; } +.bi-skip-end-circle::before { content: "\f556"; } +.bi-skip-end-fill::before { content: "\f557"; } +.bi-skip-end::before { content: "\f558"; } +.bi-skip-forward-btn-fill::before { content: "\f559"; } +.bi-skip-forward-btn::before { content: "\f55a"; } +.bi-skip-forward-circle-fill::before { content: "\f55b"; } +.bi-skip-forward-circle::before { content: "\f55c"; } +.bi-skip-forward-fill::before { content: "\f55d"; } +.bi-skip-forward::before { content: "\f55e"; } +.bi-skip-start-btn-fill::before { content: "\f55f"; } +.bi-skip-start-btn::before { content: "\f560"; } +.bi-skip-start-circle-fill::before { content: "\f561"; } +.bi-skip-start-circle::before { content: "\f562"; } +.bi-skip-start-fill::before { content: "\f563"; } +.bi-skip-start::before { content: "\f564"; } +.bi-slack::before { content: "\f565"; } +.bi-slash-circle-fill::before { content: "\f566"; } +.bi-slash-circle::before { content: "\f567"; } +.bi-slash-square-fill::before { content: "\f568"; } +.bi-slash-square::before { content: "\f569"; } +.bi-slash::before { content: "\f56a"; } +.bi-sliders::before { content: "\f56b"; } +.bi-smartwatch::before { content: "\f56c"; } +.bi-snow::before { content: "\f56d"; } +.bi-snow2::before { content: "\f56e"; } +.bi-snow3::before { content: "\f56f"; } +.bi-sort-alpha-down-alt::before { content: "\f570"; } +.bi-sort-alpha-down::before { content: "\f571"; } +.bi-sort-alpha-up-alt::before { content: "\f572"; } +.bi-sort-alpha-up::before { content: "\f573"; } +.bi-sort-down-alt::before { content: "\f574"; } +.bi-sort-down::before { content: "\f575"; } +.bi-sort-numeric-down-alt::before { content: "\f576"; } +.bi-sort-numeric-down::before { content: "\f577"; } +.bi-sort-numeric-up-alt::before { content: "\f578"; } +.bi-sort-numeric-up::before { content: "\f579"; } +.bi-sort-up-alt::before { content: "\f57a"; } +.bi-sort-up::before { content: "\f57b"; } +.bi-soundwave::before { content: "\f57c"; } +.bi-speaker-fill::before { content: "\f57d"; } +.bi-speaker::before { content: "\f57e"; } +.bi-speedometer::before { content: "\f57f"; } +.bi-speedometer2::before { content: "\f580"; } +.bi-spellcheck::before { content: "\f581"; } +.bi-square-fill::before { content: "\f582"; } +.bi-square-half::before { content: "\f583"; } +.bi-square::before { content: "\f584"; } +.bi-stack::before { content: "\f585"; } +.bi-star-fill::before { content: "\f586"; } +.bi-star-half::before { content: "\f587"; } +.bi-star::before { content: "\f588"; } +.bi-stars::before { content: "\f589"; } +.bi-stickies-fill::before { content: "\f58a"; } +.bi-stickies::before { content: "\f58b"; } +.bi-sticky-fill::before { content: "\f58c"; } +.bi-sticky::before { content: "\f58d"; } +.bi-stop-btn-fill::before { content: "\f58e"; } +.bi-stop-btn::before { content: "\f58f"; } +.bi-stop-circle-fill::before { content: "\f590"; } +.bi-stop-circle::before { content: "\f591"; } +.bi-stop-fill::before { content: "\f592"; } +.bi-stop::before { content: "\f593"; } +.bi-stoplights-fill::before { content: "\f594"; } +.bi-stoplights::before { content: "\f595"; } +.bi-stopwatch-fill::before { content: "\f596"; } +.bi-stopwatch::before { content: "\f597"; } +.bi-subtract::before { content: "\f598"; } +.bi-suit-club-fill::before { content: "\f599"; } +.bi-suit-club::before { content: "\f59a"; } +.bi-suit-diamond-fill::before { content: "\f59b"; } +.bi-suit-diamond::before { content: "\f59c"; } +.bi-suit-heart-fill::before { content: "\f59d"; } +.bi-suit-heart::before { content: "\f59e"; } +.bi-suit-spade-fill::before { content: "\f59f"; } +.bi-suit-spade::before { content: "\f5a0"; } +.bi-sun-fill::before { content: "\f5a1"; } +.bi-sun::before { content: "\f5a2"; } +.bi-sunglasses::before { content: "\f5a3"; } +.bi-sunrise-fill::before { content: "\f5a4"; } +.bi-sunrise::before { content: "\f5a5"; } +.bi-sunset-fill::before { content: "\f5a6"; } +.bi-sunset::before { content: "\f5a7"; } +.bi-symmetry-horizontal::before { content: "\f5a8"; } +.bi-symmetry-vertical::before { content: "\f5a9"; } +.bi-table::before { content: "\f5aa"; } +.bi-tablet-fill::before { content: "\f5ab"; } +.bi-tablet-landscape-fill::before { content: "\f5ac"; } +.bi-tablet-landscape::before { content: "\f5ad"; } +.bi-tablet::before { content: "\f5ae"; } +.bi-tag-fill::before { content: "\f5af"; } +.bi-tag::before { content: "\f5b0"; } +.bi-tags-fill::before { content: "\f5b1"; } +.bi-tags::before { content: "\f5b2"; } +.bi-telegram::before { content: "\f5b3"; } +.bi-telephone-fill::before { content: "\f5b4"; } +.bi-telephone-forward-fill::before { content: "\f5b5"; } +.bi-telephone-forward::before { content: "\f5b6"; } +.bi-telephone-inbound-fill::before { content: "\f5b7"; } +.bi-telephone-inbound::before { content: "\f5b8"; } +.bi-telephone-minus-fill::before { content: "\f5b9"; } +.bi-telephone-minus::before { content: "\f5ba"; } +.bi-telephone-outbound-fill::before { content: "\f5bb"; } +.bi-telephone-outbound::before { content: "\f5bc"; } +.bi-telephone-plus-fill::before { content: "\f5bd"; } +.bi-telephone-plus::before { content: "\f5be"; } +.bi-telephone-x-fill::before { content: "\f5bf"; } +.bi-telephone-x::before { content: "\f5c0"; } +.bi-telephone::before { content: "\f5c1"; } +.bi-terminal-fill::before { content: "\f5c2"; } +.bi-terminal::before { content: "\f5c3"; } +.bi-text-center::before { content: "\f5c4"; } +.bi-text-indent-left::before { content: "\f5c5"; } +.bi-text-indent-right::before { content: "\f5c6"; } +.bi-text-left::before { content: "\f5c7"; } +.bi-text-paragraph::before { content: "\f5c8"; } +.bi-text-right::before { content: "\f5c9"; } +.bi-textarea-resize::before { content: "\f5ca"; } +.bi-textarea-t::before { content: "\f5cb"; } +.bi-textarea::before { content: "\f5cc"; } +.bi-thermometer-half::before { content: "\f5cd"; } +.bi-thermometer-high::before { content: "\f5ce"; } +.bi-thermometer-low::before { content: "\f5cf"; } +.bi-thermometer-snow::before { content: "\f5d0"; } +.bi-thermometer-sun::before { content: "\f5d1"; } +.bi-thermometer::before { content: "\f5d2"; } +.bi-three-dots-vertical::before { content: "\f5d3"; } +.bi-three-dots::before { content: "\f5d4"; } +.bi-toggle-off::before { content: "\f5d5"; } +.bi-toggle-on::before { content: "\f5d6"; } +.bi-toggle2-off::before { content: "\f5d7"; } +.bi-toggle2-on::before { content: "\f5d8"; } +.bi-toggles::before { content: "\f5d9"; } +.bi-toggles2::before { content: "\f5da"; } +.bi-tools::before { content: "\f5db"; } +.bi-tornado::before { content: "\f5dc"; } +.bi-trash-fill::before { content: "\f5dd"; } +.bi-trash::before { content: "\f5de"; } +.bi-trash2-fill::before { content: "\f5df"; } +.bi-trash2::before { content: "\f5e0"; } +.bi-tree-fill::before { content: "\f5e1"; } +.bi-tree::before { content: "\f5e2"; } +.bi-triangle-fill::before { content: "\f5e3"; } +.bi-triangle-half::before { content: "\f5e4"; } +.bi-triangle::before { content: "\f5e5"; } +.bi-trophy-fill::before { content: "\f5e6"; } +.bi-trophy::before { content: "\f5e7"; } +.bi-tropical-storm::before { content: "\f5e8"; } +.bi-truck-flatbed::before { content: "\f5e9"; } +.bi-truck::before { content: "\f5ea"; } +.bi-tsunami::before { content: "\f5eb"; } +.bi-tv-fill::before { content: "\f5ec"; } +.bi-tv::before { content: "\f5ed"; } +.bi-twitch::before { content: "\f5ee"; } +.bi-twitter::before { content: "\f5ef"; } +.bi-type-bold::before { content: "\f5f0"; } +.bi-type-h1::before { content: "\f5f1"; } +.bi-type-h2::before { content: "\f5f2"; } +.bi-type-h3::before { content: "\f5f3"; } +.bi-type-italic::before { content: "\f5f4"; } +.bi-type-strikethrough::before { content: "\f5f5"; } +.bi-type-underline::before { content: "\f5f6"; } +.bi-type::before { content: "\f5f7"; } +.bi-ui-checks-grid::before { content: "\f5f8"; } +.bi-ui-checks::before { content: "\f5f9"; } +.bi-ui-radios-grid::before { content: "\f5fa"; } +.bi-ui-radios::before { content: "\f5fb"; } +.bi-umbrella-fill::before { content: "\f5fc"; } +.bi-umbrella::before { content: "\f5fd"; } +.bi-union::before { content: "\f5fe"; } +.bi-unlock-fill::before { content: "\f5ff"; } +.bi-unlock::before { content: "\f600"; } +.bi-upc-scan::before { content: "\f601"; } +.bi-upc::before { content: "\f602"; } +.bi-upload::before { content: "\f603"; } +.bi-vector-pen::before { content: "\f604"; } +.bi-view-list::before { content: "\f605"; } +.bi-view-stacked::before { content: "\f606"; } +.bi-vinyl-fill::before { content: "\f607"; } +.bi-vinyl::before { content: "\f608"; } +.bi-voicemail::before { content: "\f609"; } +.bi-volume-down-fill::before { content: "\f60a"; } +.bi-volume-down::before { content: "\f60b"; } +.bi-volume-mute-fill::before { content: "\f60c"; } +.bi-volume-mute::before { content: "\f60d"; } +.bi-volume-off-fill::before { content: "\f60e"; } +.bi-volume-off::before { content: "\f60f"; } +.bi-volume-up-fill::before { content: "\f610"; } +.bi-volume-up::before { content: "\f611"; } +.bi-vr::before { content: "\f612"; } +.bi-wallet-fill::before { content: "\f613"; } +.bi-wallet::before { content: "\f614"; } +.bi-wallet2::before { content: "\f615"; } +.bi-watch::before { content: "\f616"; } +.bi-water::before { content: "\f617"; } +.bi-whatsapp::before { content: "\f618"; } +.bi-wifi-1::before { content: "\f619"; } +.bi-wifi-2::before { content: "\f61a"; } +.bi-wifi-off::before { content: "\f61b"; } +.bi-wifi::before { content: "\f61c"; } +.bi-wind::before { content: "\f61d"; } +.bi-window-dock::before { content: "\f61e"; } +.bi-window-sidebar::before { content: "\f61f"; } +.bi-window::before { content: "\f620"; } +.bi-wrench::before { content: "\f621"; } +.bi-x-circle-fill::before { content: "\f622"; } +.bi-x-circle::before { content: "\f623"; } +.bi-x-diamond-fill::before { content: "\f624"; } +.bi-x-diamond::before { content: "\f625"; } +.bi-x-octagon-fill::before { content: "\f626"; } +.bi-x-octagon::before { content: "\f627"; } +.bi-x-square-fill::before { content: "\f628"; } +.bi-x-square::before { content: "\f629"; } +.bi-x::before { content: "\f62a"; } +.bi-youtube::before { content: "\f62b"; } +.bi-zoom-in::before { content: "\f62c"; } +.bi-zoom-out::before { content: "\f62d"; } +.bi-bank::before { content: "\f62e"; } +.bi-bank2::before { content: "\f62f"; } +.bi-bell-slash-fill::before { content: "\f630"; } +.bi-bell-slash::before { content: "\f631"; } +.bi-cash-coin::before { content: "\f632"; } +.bi-check-lg::before { content: "\f633"; } +.bi-coin::before { content: "\f634"; } +.bi-currency-bitcoin::before { content: "\f635"; } +.bi-currency-dollar::before { content: "\f636"; } +.bi-currency-euro::before { content: "\f637"; } +.bi-currency-exchange::before { content: "\f638"; } +.bi-currency-pound::before { content: "\f639"; } +.bi-currency-yen::before { content: "\f63a"; } +.bi-dash-lg::before { content: "\f63b"; } +.bi-exclamation-lg::before { content: "\f63c"; } +.bi-file-earmark-pdf-fill::before { content: "\f63d"; } +.bi-file-earmark-pdf::before { content: "\f63e"; } +.bi-file-pdf-fill::before { content: "\f63f"; } +.bi-file-pdf::before { content: "\f640"; } +.bi-gender-ambiguous::before { content: "\f641"; } +.bi-gender-female::before { content: "\f642"; } +.bi-gender-male::before { content: "\f643"; } +.bi-gender-trans::before { content: "\f644"; } +.bi-headset-vr::before { content: "\f645"; } +.bi-info-lg::before { content: "\f646"; } +.bi-mastodon::before { content: "\f647"; } +.bi-messenger::before { content: "\f648"; } +.bi-piggy-bank-fill::before { content: "\f649"; } +.bi-piggy-bank::before { content: "\f64a"; } +.bi-pin-map-fill::before { content: "\f64b"; } +.bi-pin-map::before { content: "\f64c"; } +.bi-plus-lg::before { content: "\f64d"; } +.bi-question-lg::before { content: "\f64e"; } +.bi-recycle::before { content: "\f64f"; } +.bi-reddit::before { content: "\f650"; } +.bi-safe-fill::before { content: "\f651"; } +.bi-safe2-fill::before { content: "\f652"; } +.bi-safe2::before { content: "\f653"; } +.bi-sd-card-fill::before { content: "\f654"; } +.bi-sd-card::before { content: "\f655"; } +.bi-skype::before { content: "\f656"; } +.bi-slash-lg::before { content: "\f657"; } +.bi-translate::before { content: "\f658"; } +.bi-x-lg::before { content: "\f659"; } +.bi-safe::before { content: "\f65a"; } +.bi-apple::before { content: "\f65b"; } +.bi-microsoft::before { content: "\f65d"; } +.bi-windows::before { content: "\f65e"; } +.bi-behance::before { content: "\f65c"; } +.bi-dribbble::before { content: "\f65f"; } +.bi-line::before { content: "\f660"; } +.bi-medium::before { content: "\f661"; } +.bi-paypal::before { content: "\f662"; } +.bi-pinterest::before { content: "\f663"; } +.bi-signal::before { content: "\f664"; } +.bi-snapchat::before { content: "\f665"; } +.bi-spotify::before { content: "\f666"; } +.bi-stack-overflow::before { content: "\f667"; } +.bi-strava::before { content: "\f668"; } +.bi-wordpress::before { content: "\f669"; } +.bi-vimeo::before { content: "\f66a"; } +.bi-activity::before { content: "\f66b"; } +.bi-easel2-fill::before { content: "\f66c"; } +.bi-easel2::before { content: "\f66d"; } +.bi-easel3-fill::before { content: "\f66e"; } +.bi-easel3::before { content: "\f66f"; } +.bi-fan::before { content: "\f670"; } +.bi-fingerprint::before { content: "\f671"; } +.bi-graph-down-arrow::before { content: "\f672"; } +.bi-graph-up-arrow::before { content: "\f673"; } +.bi-hypnotize::before { content: "\f674"; } +.bi-magic::before { content: "\f675"; } +.bi-person-rolodex::before { content: "\f676"; } +.bi-person-video::before { content: "\f677"; } +.bi-person-video2::before { content: "\f678"; } +.bi-person-video3::before { content: "\f679"; } +.bi-person-workspace::before { content: "\f67a"; } +.bi-radioactive::before { content: "\f67b"; } +.bi-webcam-fill::before { content: "\f67c"; } +.bi-webcam::before { content: "\f67d"; } +.bi-yin-yang::before { content: "\f67e"; } +.bi-bandaid-fill::before { content: "\f680"; } +.bi-bandaid::before { content: "\f681"; } +.bi-bluetooth::before { content: "\f682"; } +.bi-body-text::before { content: "\f683"; } +.bi-boombox::before { content: "\f684"; } +.bi-boxes::before { content: "\f685"; } +.bi-dpad-fill::before { content: "\f686"; } +.bi-dpad::before { content: "\f687"; } +.bi-ear-fill::before { content: "\f688"; } +.bi-ear::before { content: "\f689"; } +.bi-envelope-check-fill::before { content: "\f68b"; } +.bi-envelope-check::before { content: "\f68c"; } +.bi-envelope-dash-fill::before { content: "\f68e"; } +.bi-envelope-dash::before { content: "\f68f"; } +.bi-envelope-exclamation-fill::before { content: "\f691"; } +.bi-envelope-exclamation::before { content: "\f692"; } +.bi-envelope-plus-fill::before { content: "\f693"; } +.bi-envelope-plus::before { content: "\f694"; } +.bi-envelope-slash-fill::before { content: "\f696"; } +.bi-envelope-slash::before { content: "\f697"; } +.bi-envelope-x-fill::before { content: "\f699"; } +.bi-envelope-x::before { content: "\f69a"; } +.bi-explicit-fill::before { content: "\f69b"; } +.bi-explicit::before { content: "\f69c"; } +.bi-git::before { content: "\f69d"; } +.bi-infinity::before { content: "\f69e"; } +.bi-list-columns-reverse::before { content: "\f69f"; } +.bi-list-columns::before { content: "\f6a0"; } +.bi-meta::before { content: "\f6a1"; } +.bi-nintendo-switch::before { content: "\f6a4"; } +.bi-pc-display-horizontal::before { content: "\f6a5"; } +.bi-pc-display::before { content: "\f6a6"; } +.bi-pc-horizontal::before { content: "\f6a7"; } +.bi-pc::before { content: "\f6a8"; } +.bi-playstation::before { content: "\f6a9"; } +.bi-plus-slash-minus::before { content: "\f6aa"; } +.bi-projector-fill::before { content: "\f6ab"; } +.bi-projector::before { content: "\f6ac"; } +.bi-qr-code-scan::before { content: "\f6ad"; } +.bi-qr-code::before { content: "\f6ae"; } +.bi-quora::before { content: "\f6af"; } +.bi-quote::before { content: "\f6b0"; } +.bi-robot::before { content: "\f6b1"; } +.bi-send-check-fill::before { content: "\f6b2"; } +.bi-send-check::before { content: "\f6b3"; } +.bi-send-dash-fill::before { content: "\f6b4"; } +.bi-send-dash::before { content: "\f6b5"; } +.bi-send-exclamation-fill::before { content: "\f6b7"; } +.bi-send-exclamation::before { content: "\f6b8"; } +.bi-send-fill::before { content: "\f6b9"; } +.bi-send-plus-fill::before { content: "\f6ba"; } +.bi-send-plus::before { content: "\f6bb"; } +.bi-send-slash-fill::before { content: "\f6bc"; } +.bi-send-slash::before { content: "\f6bd"; } +.bi-send-x-fill::before { content: "\f6be"; } +.bi-send-x::before { content: "\f6bf"; } +.bi-send::before { content: "\f6c0"; } +.bi-steam::before { content: "\f6c1"; } +.bi-terminal-dash::before { content: "\f6c3"; } +.bi-terminal-plus::before { content: "\f6c4"; } +.bi-terminal-split::before { content: "\f6c5"; } +.bi-ticket-detailed-fill::before { content: "\f6c6"; } +.bi-ticket-detailed::before { content: "\f6c7"; } +.bi-ticket-fill::before { content: "\f6c8"; } +.bi-ticket-perforated-fill::before { content: "\f6c9"; } +.bi-ticket-perforated::before { content: "\f6ca"; } +.bi-ticket::before { content: "\f6cb"; } +.bi-tiktok::before { content: "\f6cc"; } +.bi-window-dash::before { content: "\f6cd"; } +.bi-window-desktop::before { content: "\f6ce"; } +.bi-window-fullscreen::before { content: "\f6cf"; } +.bi-window-plus::before { content: "\f6d0"; } +.bi-window-split::before { content: "\f6d1"; } +.bi-window-stack::before { content: "\f6d2"; } +.bi-window-x::before { content: "\f6d3"; } +.bi-xbox::before { content: "\f6d4"; } +.bi-ethernet::before { content: "\f6d5"; } +.bi-hdmi-fill::before { content: "\f6d6"; } +.bi-hdmi::before { content: "\f6d7"; } +.bi-usb-c-fill::before { content: "\f6d8"; } +.bi-usb-c::before { content: "\f6d9"; } +.bi-usb-fill::before { content: "\f6da"; } +.bi-usb-plug-fill::before { content: "\f6db"; } +.bi-usb-plug::before { content: "\f6dc"; } +.bi-usb-symbol::before { content: "\f6dd"; } +.bi-usb::before { content: "\f6de"; } +.bi-boombox-fill::before { content: "\f6df"; } +.bi-displayport::before { content: "\f6e1"; } +.bi-gpu-card::before { content: "\f6e2"; } +.bi-memory::before { content: "\f6e3"; } +.bi-modem-fill::before { content: "\f6e4"; } +.bi-modem::before { content: "\f6e5"; } +.bi-motherboard-fill::before { content: "\f6e6"; } +.bi-motherboard::before { content: "\f6e7"; } +.bi-optical-audio-fill::before { content: "\f6e8"; } +.bi-optical-audio::before { content: "\f6e9"; } +.bi-pci-card::before { content: "\f6ea"; } +.bi-router-fill::before { content: "\f6eb"; } +.bi-router::before { content: "\f6ec"; } +.bi-thunderbolt-fill::before { content: "\f6ef"; } +.bi-thunderbolt::before { content: "\f6f0"; } +.bi-usb-drive-fill::before { content: "\f6f1"; } +.bi-usb-drive::before { content: "\f6f2"; } +.bi-usb-micro-fill::before { content: "\f6f3"; } +.bi-usb-micro::before { content: "\f6f4"; } +.bi-usb-mini-fill::before { content: "\f6f5"; } +.bi-usb-mini::before { content: "\f6f6"; } +.bi-cloud-haze2::before { content: "\f6f7"; } +.bi-device-hdd-fill::before { content: "\f6f8"; } +.bi-device-hdd::before { content: "\f6f9"; } +.bi-device-ssd-fill::before { content: "\f6fa"; } +.bi-device-ssd::before { content: "\f6fb"; } +.bi-displayport-fill::before { content: "\f6fc"; } +.bi-mortarboard-fill::before { content: "\f6fd"; } +.bi-mortarboard::before { content: "\f6fe"; } +.bi-terminal-x::before { content: "\f6ff"; } +.bi-arrow-through-heart-fill::before { content: "\f700"; } +.bi-arrow-through-heart::before { content: "\f701"; } +.bi-badge-sd-fill::before { content: "\f702"; } +.bi-badge-sd::before { content: "\f703"; } +.bi-bag-heart-fill::before { content: "\f704"; } +.bi-bag-heart::before { content: "\f705"; } +.bi-balloon-fill::before { content: "\f706"; } +.bi-balloon-heart-fill::before { content: "\f707"; } +.bi-balloon-heart::before { content: "\f708"; } +.bi-balloon::before { content: "\f709"; } +.bi-box2-fill::before { content: "\f70a"; } +.bi-box2-heart-fill::before { content: "\f70b"; } +.bi-box2-heart::before { content: "\f70c"; } +.bi-box2::before { content: "\f70d"; } +.bi-braces-asterisk::before { content: "\f70e"; } +.bi-calendar-heart-fill::before { content: "\f70f"; } +.bi-calendar-heart::before { content: "\f710"; } +.bi-calendar2-heart-fill::before { content: "\f711"; } +.bi-calendar2-heart::before { content: "\f712"; } +.bi-chat-heart-fill::before { content: "\f713"; } +.bi-chat-heart::before { content: "\f714"; } +.bi-chat-left-heart-fill::before { content: "\f715"; } +.bi-chat-left-heart::before { content: "\f716"; } +.bi-chat-right-heart-fill::before { content: "\f717"; } +.bi-chat-right-heart::before { content: "\f718"; } +.bi-chat-square-heart-fill::before { content: "\f719"; } +.bi-chat-square-heart::before { content: "\f71a"; } +.bi-clipboard-check-fill::before { content: "\f71b"; } +.bi-clipboard-data-fill::before { content: "\f71c"; } +.bi-clipboard-fill::before { content: "\f71d"; } +.bi-clipboard-heart-fill::before { content: "\f71e"; } +.bi-clipboard-heart::before { content: "\f71f"; } +.bi-clipboard-minus-fill::before { content: "\f720"; } +.bi-clipboard-plus-fill::before { content: "\f721"; } +.bi-clipboard-pulse::before { content: "\f722"; } +.bi-clipboard-x-fill::before { content: "\f723"; } +.bi-clipboard2-check-fill::before { content: "\f724"; } +.bi-clipboard2-check::before { content: "\f725"; } +.bi-clipboard2-data-fill::before { content: "\f726"; } +.bi-clipboard2-data::before { content: "\f727"; } +.bi-clipboard2-fill::before { content: "\f728"; } +.bi-clipboard2-heart-fill::before { content: "\f729"; } +.bi-clipboard2-heart::before { content: "\f72a"; } +.bi-clipboard2-minus-fill::before { content: "\f72b"; } +.bi-clipboard2-minus::before { content: "\f72c"; } +.bi-clipboard2-plus-fill::before { content: "\f72d"; } +.bi-clipboard2-plus::before { content: "\f72e"; } +.bi-clipboard2-pulse-fill::before { content: "\f72f"; } +.bi-clipboard2-pulse::before { content: "\f730"; } +.bi-clipboard2-x-fill::before { content: "\f731"; } +.bi-clipboard2-x::before { content: "\f732"; } +.bi-clipboard2::before { content: "\f733"; } +.bi-emoji-kiss-fill::before { content: "\f734"; } +.bi-emoji-kiss::before { content: "\f735"; } +.bi-envelope-heart-fill::before { content: "\f736"; } +.bi-envelope-heart::before { content: "\f737"; } +.bi-envelope-open-heart-fill::before { content: "\f738"; } +.bi-envelope-open-heart::before { content: "\f739"; } +.bi-envelope-paper-fill::before { content: "\f73a"; } +.bi-envelope-paper-heart-fill::before { content: "\f73b"; } +.bi-envelope-paper-heart::before { content: "\f73c"; } +.bi-envelope-paper::before { content: "\f73d"; } +.bi-filetype-aac::before { content: "\f73e"; } +.bi-filetype-ai::before { content: "\f73f"; } +.bi-filetype-bmp::before { content: "\f740"; } +.bi-filetype-cs::before { content: "\f741"; } +.bi-filetype-css::before { content: "\f742"; } +.bi-filetype-csv::before { content: "\f743"; } +.bi-filetype-doc::before { content: "\f744"; } +.bi-filetype-docx::before { content: "\f745"; } +.bi-filetype-exe::before { content: "\f746"; } +.bi-filetype-gif::before { content: "\f747"; } +.bi-filetype-heic::before { content: "\f748"; } +.bi-filetype-html::before { content: "\f749"; } +.bi-filetype-java::before { content: "\f74a"; } +.bi-filetype-jpg::before { content: "\f74b"; } +.bi-filetype-js::before { content: "\f74c"; } +.bi-filetype-jsx::before { content: "\f74d"; } +.bi-filetype-key::before { content: "\f74e"; } +.bi-filetype-m4p::before { content: "\f74f"; } +.bi-filetype-md::before { content: "\f750"; } +.bi-filetype-mdx::before { content: "\f751"; } +.bi-filetype-mov::before { content: "\f752"; } +.bi-filetype-mp3::before { content: "\f753"; } +.bi-filetype-mp4::before { content: "\f754"; } +.bi-filetype-otf::before { content: "\f755"; } +.bi-filetype-pdf::before { content: "\f756"; } +.bi-filetype-php::before { content: "\f757"; } +.bi-filetype-png::before { content: "\f758"; } +.bi-filetype-ppt::before { content: "\f75a"; } +.bi-filetype-psd::before { content: "\f75b"; } +.bi-filetype-py::before { content: "\f75c"; } +.bi-filetype-raw::before { content: "\f75d"; } +.bi-filetype-rb::before { content: "\f75e"; } +.bi-filetype-sass::before { content: "\f75f"; } +.bi-filetype-scss::before { content: "\f760"; } +.bi-filetype-sh::before { content: "\f761"; } +.bi-filetype-svg::before { content: "\f762"; } +.bi-filetype-tiff::before { content: "\f763"; } +.bi-filetype-tsx::before { content: "\f764"; } +.bi-filetype-ttf::before { content: "\f765"; } +.bi-filetype-txt::before { content: "\f766"; } +.bi-filetype-wav::before { content: "\f767"; } +.bi-filetype-woff::before { content: "\f768"; } +.bi-filetype-xls::before { content: "\f76a"; } +.bi-filetype-xml::before { content: "\f76b"; } +.bi-filetype-yml::before { content: "\f76c"; } +.bi-heart-arrow::before { content: "\f76d"; } +.bi-heart-pulse-fill::before { content: "\f76e"; } +.bi-heart-pulse::before { content: "\f76f"; } +.bi-heartbreak-fill::before { content: "\f770"; } +.bi-heartbreak::before { content: "\f771"; } +.bi-hearts::before { content: "\f772"; } +.bi-hospital-fill::before { content: "\f773"; } +.bi-hospital::before { content: "\f774"; } +.bi-house-heart-fill::before { content: "\f775"; } +.bi-house-heart::before { content: "\f776"; } +.bi-incognito::before { content: "\f777"; } +.bi-magnet-fill::before { content: "\f778"; } +.bi-magnet::before { content: "\f779"; } +.bi-person-heart::before { content: "\f77a"; } +.bi-person-hearts::before { content: "\f77b"; } +.bi-phone-flip::before { content: "\f77c"; } +.bi-plugin::before { content: "\f77d"; } +.bi-postage-fill::before { content: "\f77e"; } +.bi-postage-heart-fill::before { content: "\f77f"; } +.bi-postage-heart::before { content: "\f780"; } +.bi-postage::before { content: "\f781"; } +.bi-postcard-fill::before { content: "\f782"; } +.bi-postcard-heart-fill::before { content: "\f783"; } +.bi-postcard-heart::before { content: "\f784"; } +.bi-postcard::before { content: "\f785"; } +.bi-search-heart-fill::before { content: "\f786"; } +.bi-search-heart::before { content: "\f787"; } +.bi-sliders2-vertical::before { content: "\f788"; } +.bi-sliders2::before { content: "\f789"; } +.bi-trash3-fill::before { content: "\f78a"; } +.bi-trash3::before { content: "\f78b"; } +.bi-valentine::before { content: "\f78c"; } +.bi-valentine2::before { content: "\f78d"; } +.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } +.bi-wrench-adjustable-circle::before { content: "\f78f"; } +.bi-wrench-adjustable::before { content: "\f790"; } +.bi-filetype-json::before { content: "\f791"; } +.bi-filetype-pptx::before { content: "\f792"; } +.bi-filetype-xlsx::before { content: "\f793"; } +.bi-1-circle-fill::before { content: "\f796"; } +.bi-1-circle::before { content: "\f797"; } +.bi-1-square-fill::before { content: "\f798"; } +.bi-1-square::before { content: "\f799"; } +.bi-2-circle-fill::before { content: "\f79c"; } +.bi-2-circle::before { content: "\f79d"; } +.bi-2-square-fill::before { content: "\f79e"; } +.bi-2-square::before { content: "\f79f"; } +.bi-3-circle-fill::before { content: "\f7a2"; } +.bi-3-circle::before { content: "\f7a3"; } +.bi-3-square-fill::before { content: "\f7a4"; } +.bi-3-square::before { content: "\f7a5"; } +.bi-4-circle-fill::before { content: "\f7a8"; } +.bi-4-circle::before { content: "\f7a9"; } +.bi-4-square-fill::before { content: "\f7aa"; } +.bi-4-square::before { content: "\f7ab"; } +.bi-5-circle-fill::before { content: "\f7ae"; } +.bi-5-circle::before { content: "\f7af"; } +.bi-5-square-fill::before { content: "\f7b0"; } +.bi-5-square::before { content: "\f7b1"; } +.bi-6-circle-fill::before { content: "\f7b4"; } +.bi-6-circle::before { content: "\f7b5"; } +.bi-6-square-fill::before { content: "\f7b6"; } +.bi-6-square::before { content: "\f7b7"; } +.bi-7-circle-fill::before { content: "\f7ba"; } +.bi-7-circle::before { content: "\f7bb"; } +.bi-7-square-fill::before { content: "\f7bc"; } +.bi-7-square::before { content: "\f7bd"; } +.bi-8-circle-fill::before { content: "\f7c0"; } +.bi-8-circle::before { content: "\f7c1"; } +.bi-8-square-fill::before { content: "\f7c2"; } +.bi-8-square::before { content: "\f7c3"; } +.bi-9-circle-fill::before { content: "\f7c6"; } +.bi-9-circle::before { content: "\f7c7"; } +.bi-9-square-fill::before { content: "\f7c8"; } +.bi-9-square::before { content: "\f7c9"; } +.bi-airplane-engines-fill::before { content: "\f7ca"; } +.bi-airplane-engines::before { content: "\f7cb"; } +.bi-airplane-fill::before { content: "\f7cc"; } +.bi-airplane::before { content: "\f7cd"; } +.bi-alexa::before { content: "\f7ce"; } +.bi-alipay::before { content: "\f7cf"; } +.bi-android::before { content: "\f7d0"; } +.bi-android2::before { content: "\f7d1"; } +.bi-box-fill::before { content: "\f7d2"; } +.bi-box-seam-fill::before { content: "\f7d3"; } +.bi-browser-chrome::before { content: "\f7d4"; } +.bi-browser-edge::before { content: "\f7d5"; } +.bi-browser-firefox::before { content: "\f7d6"; } +.bi-browser-safari::before { content: "\f7d7"; } +.bi-c-circle-fill::before { content: "\f7da"; } +.bi-c-circle::before { content: "\f7db"; } +.bi-c-square-fill::before { content: "\f7dc"; } +.bi-c-square::before { content: "\f7dd"; } +.bi-capsule-pill::before { content: "\f7de"; } +.bi-capsule::before { content: "\f7df"; } +.bi-car-front-fill::before { content: "\f7e0"; } +.bi-car-front::before { content: "\f7e1"; } +.bi-cassette-fill::before { content: "\f7e2"; } +.bi-cassette::before { content: "\f7e3"; } +.bi-cc-circle-fill::before { content: "\f7e6"; } +.bi-cc-circle::before { content: "\f7e7"; } +.bi-cc-square-fill::before { content: "\f7e8"; } +.bi-cc-square::before { content: "\f7e9"; } +.bi-cup-hot-fill::before { content: "\f7ea"; } +.bi-cup-hot::before { content: "\f7eb"; } +.bi-currency-rupee::before { content: "\f7ec"; } +.bi-dropbox::before { content: "\f7ed"; } +.bi-escape::before { content: "\f7ee"; } +.bi-fast-forward-btn-fill::before { content: "\f7ef"; } +.bi-fast-forward-btn::before { content: "\f7f0"; } +.bi-fast-forward-circle-fill::before { content: "\f7f1"; } +.bi-fast-forward-circle::before { content: "\f7f2"; } +.bi-fast-forward-fill::before { content: "\f7f3"; } +.bi-fast-forward::before { content: "\f7f4"; } +.bi-filetype-sql::before { content: "\f7f5"; } +.bi-fire::before { content: "\f7f6"; } +.bi-google-play::before { content: "\f7f7"; } +.bi-h-circle-fill::before { content: "\f7fa"; } +.bi-h-circle::before { content: "\f7fb"; } +.bi-h-square-fill::before { content: "\f7fc"; } +.bi-h-square::before { content: "\f7fd"; } +.bi-indent::before { content: "\f7fe"; } +.bi-lungs-fill::before { content: "\f7ff"; } +.bi-lungs::before { content: "\f800"; } +.bi-microsoft-teams::before { content: "\f801"; } +.bi-p-circle-fill::before { content: "\f804"; } +.bi-p-circle::before { content: "\f805"; } +.bi-p-square-fill::before { content: "\f806"; } +.bi-p-square::before { content: "\f807"; } +.bi-pass-fill::before { content: "\f808"; } +.bi-pass::before { content: "\f809"; } +.bi-prescription::before { content: "\f80a"; } +.bi-prescription2::before { content: "\f80b"; } +.bi-r-circle-fill::before { content: "\f80e"; } +.bi-r-circle::before { content: "\f80f"; } +.bi-r-square-fill::before { content: "\f810"; } +.bi-r-square::before { content: "\f811"; } +.bi-repeat-1::before { content: "\f812"; } +.bi-repeat::before { content: "\f813"; } +.bi-rewind-btn-fill::before { content: "\f814"; } +.bi-rewind-btn::before { content: "\f815"; } +.bi-rewind-circle-fill::before { content: "\f816"; } +.bi-rewind-circle::before { content: "\f817"; } +.bi-rewind-fill::before { content: "\f818"; } +.bi-rewind::before { content: "\f819"; } +.bi-train-freight-front-fill::before { content: "\f81a"; } +.bi-train-freight-front::before { content: "\f81b"; } +.bi-train-front-fill::before { content: "\f81c"; } +.bi-train-front::before { content: "\f81d"; } +.bi-train-lightrail-front-fill::before { content: "\f81e"; } +.bi-train-lightrail-front::before { content: "\f81f"; } +.bi-truck-front-fill::before { content: "\f820"; } +.bi-truck-front::before { content: "\f821"; } +.bi-ubuntu::before { content: "\f822"; } +.bi-unindent::before { content: "\f823"; } +.bi-unity::before { content: "\f824"; } +.bi-universal-access-circle::before { content: "\f825"; } +.bi-universal-access::before { content: "\f826"; } +.bi-virus::before { content: "\f827"; } +.bi-virus2::before { content: "\f828"; } +.bi-wechat::before { content: "\f829"; } +.bi-yelp::before { content: "\f82a"; } +.bi-sign-stop-fill::before { content: "\f82b"; } +.bi-sign-stop-lights-fill::before { content: "\f82c"; } +.bi-sign-stop-lights::before { content: "\f82d"; } +.bi-sign-stop::before { content: "\f82e"; } +.bi-sign-turn-left-fill::before { content: "\f82f"; } +.bi-sign-turn-left::before { content: "\f830"; } +.bi-sign-turn-right-fill::before { content: "\f831"; } +.bi-sign-turn-right::before { content: "\f832"; } +.bi-sign-turn-slight-left-fill::before { content: "\f833"; } +.bi-sign-turn-slight-left::before { content: "\f834"; } +.bi-sign-turn-slight-right-fill::before { content: "\f835"; } +.bi-sign-turn-slight-right::before { content: "\f836"; } +.bi-sign-yield-fill::before { content: "\f837"; } +.bi-sign-yield::before { content: "\f838"; } +.bi-ev-station-fill::before { content: "\f839"; } +.bi-ev-station::before { content: "\f83a"; } +.bi-fuel-pump-diesel-fill::before { content: "\f83b"; } +.bi-fuel-pump-diesel::before { content: "\f83c"; } +.bi-fuel-pump-fill::before { content: "\f83d"; } +.bi-fuel-pump::before { content: "\f83e"; } +.bi-0-circle-fill::before { content: "\f83f"; } +.bi-0-circle::before { content: "\f840"; } +.bi-0-square-fill::before { content: "\f841"; } +.bi-0-square::before { content: "\f842"; } +.bi-rocket-fill::before { content: "\f843"; } +.bi-rocket-takeoff-fill::before { content: "\f844"; } +.bi-rocket-takeoff::before { content: "\f845"; } +.bi-rocket::before { content: "\f846"; } +.bi-stripe::before { content: "\f847"; } +.bi-subscript::before { content: "\f848"; } +.bi-superscript::before { content: "\f849"; } +.bi-trello::before { content: "\f84a"; } +.bi-envelope-at-fill::before { content: "\f84b"; } +.bi-envelope-at::before { content: "\f84c"; } +.bi-regex::before { content: "\f84d"; } +.bi-text-wrap::before { content: "\f84e"; } +.bi-sign-dead-end-fill::before { content: "\f84f"; } +.bi-sign-dead-end::before { content: "\f850"; } +.bi-sign-do-not-enter-fill::before { content: "\f851"; } +.bi-sign-do-not-enter::before { content: "\f852"; } +.bi-sign-intersection-fill::before { content: "\f853"; } +.bi-sign-intersection-side-fill::before { content: "\f854"; } +.bi-sign-intersection-side::before { content: "\f855"; } +.bi-sign-intersection-t-fill::before { content: "\f856"; } +.bi-sign-intersection-t::before { content: "\f857"; } +.bi-sign-intersection-y-fill::before { content: "\f858"; } +.bi-sign-intersection-y::before { content: "\f859"; } +.bi-sign-intersection::before { content: "\f85a"; } +.bi-sign-merge-left-fill::before { content: "\f85b"; } +.bi-sign-merge-left::before { content: "\f85c"; } +.bi-sign-merge-right-fill::before { content: "\f85d"; } +.bi-sign-merge-right::before { content: "\f85e"; } +.bi-sign-no-left-turn-fill::before { content: "\f85f"; } +.bi-sign-no-left-turn::before { content: "\f860"; } +.bi-sign-no-parking-fill::before { content: "\f861"; } +.bi-sign-no-parking::before { content: "\f862"; } +.bi-sign-no-right-turn-fill::before { content: "\f863"; } +.bi-sign-no-right-turn::before { content: "\f864"; } +.bi-sign-railroad-fill::before { content: "\f865"; } +.bi-sign-railroad::before { content: "\f866"; } +.bi-building-add::before { content: "\f867"; } +.bi-building-check::before { content: "\f868"; } +.bi-building-dash::before { content: "\f869"; } +.bi-building-down::before { content: "\f86a"; } +.bi-building-exclamation::before { content: "\f86b"; } +.bi-building-fill-add::before { content: "\f86c"; } +.bi-building-fill-check::before { content: "\f86d"; } +.bi-building-fill-dash::before { content: "\f86e"; } +.bi-building-fill-down::before { content: "\f86f"; } +.bi-building-fill-exclamation::before { content: "\f870"; } +.bi-building-fill-gear::before { content: "\f871"; } +.bi-building-fill-lock::before { content: "\f872"; } +.bi-building-fill-slash::before { content: "\f873"; } +.bi-building-fill-up::before { content: "\f874"; } +.bi-building-fill-x::before { content: "\f875"; } +.bi-building-fill::before { content: "\f876"; } +.bi-building-gear::before { content: "\f877"; } +.bi-building-lock::before { content: "\f878"; } +.bi-building-slash::before { content: "\f879"; } +.bi-building-up::before { content: "\f87a"; } +.bi-building-x::before { content: "\f87b"; } +.bi-buildings-fill::before { content: "\f87c"; } +.bi-buildings::before { content: "\f87d"; } +.bi-bus-front-fill::before { content: "\f87e"; } +.bi-bus-front::before { content: "\f87f"; } +.bi-ev-front-fill::before { content: "\f880"; } +.bi-ev-front::before { content: "\f881"; } +.bi-globe-americas::before { content: "\f882"; } +.bi-globe-asia-australia::before { content: "\f883"; } +.bi-globe-central-south-asia::before { content: "\f884"; } +.bi-globe-europe-africa::before { content: "\f885"; } +.bi-house-add-fill::before { content: "\f886"; } +.bi-house-add::before { content: "\f887"; } +.bi-house-check-fill::before { content: "\f888"; } +.bi-house-check::before { content: "\f889"; } +.bi-house-dash-fill::before { content: "\f88a"; } +.bi-house-dash::before { content: "\f88b"; } +.bi-house-down-fill::before { content: "\f88c"; } +.bi-house-down::before { content: "\f88d"; } +.bi-house-exclamation-fill::before { content: "\f88e"; } +.bi-house-exclamation::before { content: "\f88f"; } +.bi-house-gear-fill::before { content: "\f890"; } +.bi-house-gear::before { content: "\f891"; } +.bi-house-lock-fill::before { content: "\f892"; } +.bi-house-lock::before { content: "\f893"; } +.bi-house-slash-fill::before { content: "\f894"; } +.bi-house-slash::before { content: "\f895"; } +.bi-house-up-fill::before { content: "\f896"; } +.bi-house-up::before { content: "\f897"; } +.bi-house-x-fill::before { content: "\f898"; } +.bi-house-x::before { content: "\f899"; } +.bi-person-add::before { content: "\f89a"; } +.bi-person-down::before { content: "\f89b"; } +.bi-person-exclamation::before { content: "\f89c"; } +.bi-person-fill-add::before { content: "\f89d"; } +.bi-person-fill-check::before { content: "\f89e"; } +.bi-person-fill-dash::before { content: "\f89f"; } +.bi-person-fill-down::before { content: "\f8a0"; } +.bi-person-fill-exclamation::before { content: "\f8a1"; } +.bi-person-fill-gear::before { content: "\f8a2"; } +.bi-person-fill-lock::before { content: "\f8a3"; } +.bi-person-fill-slash::before { content: "\f8a4"; } +.bi-person-fill-up::before { content: "\f8a5"; } +.bi-person-fill-x::before { content: "\f8a6"; } +.bi-person-gear::before { content: "\f8a7"; } +.bi-person-lock::before { content: "\f8a8"; } +.bi-person-slash::before { content: "\f8a9"; } +.bi-person-up::before { content: "\f8aa"; } +.bi-scooter::before { content: "\f8ab"; } +.bi-taxi-front-fill::before { content: "\f8ac"; } +.bi-taxi-front::before { content: "\f8ad"; } +.bi-amd::before { content: "\f8ae"; } +.bi-database-add::before { content: "\f8af"; } +.bi-database-check::before { content: "\f8b0"; } +.bi-database-dash::before { content: "\f8b1"; } +.bi-database-down::before { content: "\f8b2"; } +.bi-database-exclamation::before { content: "\f8b3"; } +.bi-database-fill-add::before { content: "\f8b4"; } +.bi-database-fill-check::before { content: "\f8b5"; } +.bi-database-fill-dash::before { content: "\f8b6"; } +.bi-database-fill-down::before { content: "\f8b7"; } +.bi-database-fill-exclamation::before { content: "\f8b8"; } +.bi-database-fill-gear::before { content: "\f8b9"; } +.bi-database-fill-lock::before { content: "\f8ba"; } +.bi-database-fill-slash::before { content: "\f8bb"; } +.bi-database-fill-up::before { content: "\f8bc"; } +.bi-database-fill-x::before { content: "\f8bd"; } +.bi-database-fill::before { content: "\f8be"; } +.bi-database-gear::before { content: "\f8bf"; } +.bi-database-lock::before { content: "\f8c0"; } +.bi-database-slash::before { content: "\f8c1"; } +.bi-database-up::before { content: "\f8c2"; } +.bi-database-x::before { content: "\f8c3"; } +.bi-database::before { content: "\f8c4"; } +.bi-houses-fill::before { content: "\f8c5"; } +.bi-houses::before { content: "\f8c6"; } +.bi-nvidia::before { content: "\f8c7"; } +.bi-person-vcard-fill::before { content: "\f8c8"; } +.bi-person-vcard::before { content: "\f8c9"; } +.bi-sina-weibo::before { content: "\f8ca"; } +.bi-tencent-qq::before { content: "\f8cb"; } +.bi-wikipedia::before { content: "\f8cc"; } +.bi-alphabet-uppercase::before { content: "\f2a5"; } +.bi-alphabet::before { content: "\f68a"; } +.bi-amazon::before { content: "\f68d"; } +.bi-arrows-collapse-vertical::before { content: "\f690"; } +.bi-arrows-expand-vertical::before { content: "\f695"; } +.bi-arrows-vertical::before { content: "\f698"; } +.bi-arrows::before { content: "\f6a2"; } +.bi-ban-fill::before { content: "\f6a3"; } +.bi-ban::before { content: "\f6b6"; } +.bi-bing::before { content: "\f6c2"; } +.bi-cake::before { content: "\f6e0"; } +.bi-cake2::before { content: "\f6ed"; } +.bi-cookie::before { content: "\f6ee"; } +.bi-copy::before { content: "\f759"; } +.bi-crosshair::before { content: "\f769"; } +.bi-crosshair2::before { content: "\f794"; } +.bi-emoji-astonished-fill::before { content: "\f795"; } +.bi-emoji-astonished::before { content: "\f79a"; } +.bi-emoji-grimace-fill::before { content: "\f79b"; } +.bi-emoji-grimace::before { content: "\f7a0"; } +.bi-emoji-grin-fill::before { content: "\f7a1"; } +.bi-emoji-grin::before { content: "\f7a6"; } +.bi-emoji-surprise-fill::before { content: "\f7a7"; } +.bi-emoji-surprise::before { content: "\f7ac"; } +.bi-emoji-tear-fill::before { content: "\f7ad"; } +.bi-emoji-tear::before { content: "\f7b2"; } +.bi-envelope-arrow-down-fill::before { content: "\f7b3"; } +.bi-envelope-arrow-down::before { content: "\f7b8"; } +.bi-envelope-arrow-up-fill::before { content: "\f7b9"; } +.bi-envelope-arrow-up::before { content: "\f7be"; } +.bi-feather::before { content: "\f7bf"; } +.bi-feather2::before { content: "\f7c4"; } +.bi-floppy-fill::before { content: "\f7c5"; } +.bi-floppy::before { content: "\f7d8"; } +.bi-floppy2-fill::before { content: "\f7d9"; } +.bi-floppy2::before { content: "\f7e4"; } +.bi-gitlab::before { content: "\f7e5"; } +.bi-highlighter::before { content: "\f7f8"; } +.bi-marker-tip::before { content: "\f802"; } +.bi-nvme-fill::before { content: "\f803"; } +.bi-nvme::before { content: "\f80c"; } +.bi-opencollective::before { content: "\f80d"; } +.bi-pci-card-network::before { content: "\f8cd"; } +.bi-pci-card-sound::before { content: "\f8ce"; } +.bi-radar::before { content: "\f8cf"; } +.bi-send-arrow-down-fill::before { content: "\f8d0"; } +.bi-send-arrow-down::before { content: "\f8d1"; } +.bi-send-arrow-up-fill::before { content: "\f8d2"; } +.bi-send-arrow-up::before { content: "\f8d3"; } +.bi-sim-slash-fill::before { content: "\f8d4"; } +.bi-sim-slash::before { content: "\f8d5"; } +.bi-sourceforge::before { content: "\f8d6"; } +.bi-substack::before { content: "\f8d7"; } +.bi-threads-fill::before { content: "\f8d8"; } +.bi-threads::before { content: "\f8d9"; } +.bi-transparency::before { content: "\f8da"; } +.bi-twitter-x::before { content: "\f8db"; } +.bi-type-h4::before { content: "\f8dc"; } +.bi-type-h5::before { content: "\f8dd"; } +.bi-type-h6::before { content: "\f8de"; } +.bi-backpack-fill::before { content: "\f8df"; } +.bi-backpack::before { content: "\f8e0"; } +.bi-backpack2-fill::before { content: "\f8e1"; } +.bi-backpack2::before { content: "\f8e2"; } +.bi-backpack3-fill::before { content: "\f8e3"; } +.bi-backpack3::before { content: "\f8e4"; } +.bi-backpack4-fill::before { content: "\f8e5"; } +.bi-backpack4::before { content: "\f8e6"; } +.bi-brilliance::before { content: "\f8e7"; } +.bi-cake-fill::before { content: "\f8e8"; } +.bi-cake2-fill::before { content: "\f8e9"; } +.bi-duffle-fill::before { content: "\f8ea"; } +.bi-duffle::before { content: "\f8eb"; } +.bi-exposure::before { content: "\f8ec"; } +.bi-gender-neuter::before { content: "\f8ed"; } +.bi-highlights::before { content: "\f8ee"; } +.bi-luggage-fill::before { content: "\f8ef"; } +.bi-luggage::before { content: "\f8f0"; } +.bi-mailbox-flag::before { content: "\f8f1"; } +.bi-mailbox2-flag::before { content: "\f8f2"; } +.bi-noise-reduction::before { content: "\f8f3"; } +.bi-passport-fill::before { content: "\f8f4"; } +.bi-passport::before { content: "\f8f5"; } +.bi-person-arms-up::before { content: "\f8f6"; } +.bi-person-raised-hand::before { content: "\f8f7"; } +.bi-person-standing-dress::before { content: "\f8f8"; } +.bi-person-standing::before { content: "\f8f9"; } +.bi-person-walking::before { content: "\f8fa"; } +.bi-person-wheelchair::before { content: "\f8fb"; } +.bi-shadows::before { content: "\f8fc"; } +.bi-suitcase-fill::before { content: "\f8fd"; } +.bi-suitcase-lg-fill::before { content: "\f8fe"; } +.bi-suitcase-lg::before { content: "\f8ff"; } +.bi-suitcase::before { content: "\f900"; } +.bi-suitcase2-fill::before { content: "\f901"; } +.bi-suitcase2::before { content: "\f902"; } +.bi-vignette::before { content: "\f903"; } +.bi-bluesky::before { content: "\f7f9"; } +.bi-tux::before { content: "\f904"; } +.bi-beaker-fill::before { content: "\f905"; } +.bi-beaker::before { content: "\f906"; } +.bi-flask-fill::before { content: "\f907"; } +.bi-flask-florence-fill::before { content: "\f908"; } +.bi-flask-florence::before { content: "\f909"; } +.bi-flask::before { content: "\f90a"; } +.bi-leaf-fill::before { content: "\f90b"; } +.bi-leaf::before { content: "\f90c"; } +.bi-measuring-cup-fill::before { content: "\f90d"; } +.bi-measuring-cup::before { content: "\f90e"; } +.bi-unlock2-fill::before { content: "\f90f"; } +.bi-unlock2::before { content: "\f910"; } +.bi-battery-low::before { content: "\f911"; } +.bi-anthropic::before { content: "\f912"; } +.bi-apple-music::before { content: "\f913"; } +.bi-claude::before { content: "\f914"; } +.bi-openai::before { content: "\f915"; } +.bi-perplexity::before { content: "\f916"; } +.bi-css::before { content: "\f917"; } +.bi-javascript::before { content: "\f918"; } +.bi-typescript::before { content: "\f919"; } +.bi-fork-knife::before { content: "\f91a"; } +.bi-globe-americas-fill::before { content: "\f91b"; } +.bi-globe-asia-australia-fill::before { content: "\f91c"; } +.bi-globe-central-south-asia-fill::before { content: "\f91d"; } +.bi-globe-europe-africa-fill::before { content: "\f91e"; } diff --git a/docs/site_libs/bootstrap/bootstrap-icons.woff b/docs/site_libs/bootstrap/bootstrap-icons.woff new file mode 100644 index 0000000..a4fa4f0 Binary files /dev/null and b/docs/site_libs/bootstrap/bootstrap-icons.woff differ diff --git a/docs/site_libs/bootstrap/bootstrap.min.js b/docs/site_libs/bootstrap/bootstrap.min.js new file mode 100644 index 0000000..e8f21f7 --- /dev/null +++ b/docs/site_libs/bootstrap/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.1 (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function j(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${j(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${j(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${j(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.1"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return n(e)},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",Mt="collapsing",jt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(Mt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Mt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(jt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Me(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const je={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Me(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:Me(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==P(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],M=f?-T[$]/2:0,j=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-M-q-z-O.mainAxis:j-q-z-O.mainAxis,K=v?-E[$]/2+M+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,Mn=`hide${xn}`,jn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Mn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,jn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,jn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",Ms="Home",js="End",Fs="active",Hs="fade",Ws="show",Bs=":not(.dropdown-toggle)",zs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Rs=`.nav-link${Bs}, .list-group-item${Bs}, [role="tab"]${Bs}, ${zs}`,qs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Vs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,Ms,js].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Ms,js].includes(t.key))i=e[t.key===Ms?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Vs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Rs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(".dropdown-toggle",Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(Rs)?t:z.findOne(Rs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Vs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,zs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Vs.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(qs))Vs.getOrCreateInstance(t)})),m(Vs);const Ks=".bs.toast",Qs=`mouseover${Ks}`,Xs=`mouseout${Ks}`,Ys=`focusin${Ks}`,Us=`focusout${Ks}`,Gs=`hide${Ks}`,Js=`hidden${Ks}`,Zs=`show${Ks}`,to=`shown${Ks}`,eo="hide",io="show",no="showing",so={animation:"boolean",autohide:"boolean",delay:"number"},oo={animation:!0,autohide:!0,delay:5e3};class ro extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return oo}static get DefaultType(){return so}static get NAME(){return"toast"}show(){N.trigger(this._element,Zs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(eo),d(this._element),this._element.classList.add(io,no),this._queueCallback((()=>{this._element.classList.remove(no),N.trigger(this._element,to),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Gs).defaultPrevented||(this._element.classList.add(no),this._queueCallback((()=>{this._element.classList.add(eo),this._element.classList.remove(no,io),N.trigger(this._element,Js)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(io),super.dispose()}isShown(){return this._element.classList.contains(io)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Qs,(t=>this._onInteraction(t,!0))),N.on(this._element,Xs,(t=>this._onInteraction(t,!1))),N.on(this._element,Ys,(t=>this._onInteraction(t,!0))),N.on(this._element,Us,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ro.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ro),m(ro),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Vs,Toast:ro,Tooltip:cs}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/docs/site_libs/clipboard/clipboard.min.js b/docs/site_libs/clipboard/clipboard.min.js new file mode 100644 index 0000000..1103f81 --- /dev/null +++ b/docs/site_libs/clipboard/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",A.sheet.cssRules.length),A.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",A.sheet.cssRules.length),A.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',A.sheet.cssRules.length)),h=document.querySelectorAll("[id]"),t=[].map.call(h,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); +// @license-end \ No newline at end of file diff --git a/docs/site_libs/quarto-html/axe/axe-check.js b/docs/site_libs/quarto-html/axe/axe-check.js new file mode 100644 index 0000000..8808085 --- /dev/null +++ b/docs/site_libs/quarto-html/axe/axe-check.js @@ -0,0 +1,145 @@ +class QuartoAxeReporter { + constructor(axeResult, options) { + this.axeResult = axeResult; + this.options = options; + } + + report() { + throw new Error("report() is an abstract method"); + } +} + +class QuartoAxeJsonReporter extends QuartoAxeReporter { + constructor(axeResult, options) { + super(axeResult, options); + } + + report() { + console.log(JSON.stringify(this.axeResult, null, 2)); + } +} + +class QuartoAxeConsoleReporter extends QuartoAxeReporter { + constructor(axeResult, options) { + super(axeResult, options); + } + + report() { + for (const violation of this.axeResult.violations) { + console.log(violation.description); + for (const node of violation.nodes) { + for (const target of node.target) { + console.log(target); + console.log(document.querySelector(target)); + } + } + } + } +} + +class QuartoAxeDocumentReporter extends QuartoAxeReporter { + constructor(axeResult, options) { + super(axeResult, options); + } + + createViolationElement(violation) { + const violationElement = document.createElement("div"); + + const descriptionElement = document.createElement("div"); + descriptionElement.className = "quarto-axe-violation-description"; + descriptionElement.innerText = `${violation.impact.replace(/^[a-z]/, match => match.toLocaleUpperCase())}: ${violation.description}`; + violationElement.appendChild(descriptionElement); + + const helpElement = document.createElement("div"); + helpElement.className = "quarto-axe-violation-help"; + helpElement.innerText = violation.help; + violationElement.appendChild(helpElement); + + const nodesElement = document.createElement("div"); + nodesElement.className = "quarto-axe-violation-nodes"; + violationElement.appendChild(nodesElement); + const nodeElement = document.createElement("div"); + nodeElement.className = "quarto-axe-violation-selector"; + for (const node of violation.nodes) { + for (const target of node.target) { + const targetElement = document.createElement("span"); + targetElement.className = "quarto-axe-violation-target"; + targetElement.innerText = target; + nodeElement.appendChild(targetElement); + nodeElement.addEventListener("mouseenter", () => { + const element = document.querySelector(target); + if (element) { + element.scrollIntoView({ behavior: "smooth", block: "center" }); + element.classList.add("quarto-axe-hover-highlight"); + setTimeout(() => { + element.style.border = ""; + }, 2000); + } + }); + nodeElement.addEventListener("mouseleave", () => { + const element = document.querySelector(target); + if (element) { + element.classList.remove("quarto-axe-hover-highlight"); + } + }); + nodeElement.addEventListener("click", () => { + console.log(document.querySelector(target)); + }); + nodeElement.appendChild(targetElement); + } + nodesElement.appendChild(nodeElement); + } + return violationElement; + } + + report() { + const violations = this.axeResult.violations; + const reportElement = document.createElement("div"); + reportElement.className = "quarto-axe-report"; + if (violations.length === 0) { + const noViolationsElement = document.createElement("div"); + noViolationsElement.className = "quarto-axe-no-violations"; + noViolationsElement.innerText = "No axe-core violations found."; + reportElement.appendChild(noViolationsElement); + } + violations.forEach((violation) => { + reportElement.appendChild(this.createViolationElement(violation)); + }); + document.querySelector("main").appendChild(reportElement); + } +} + +const reporters = { + json: QuartoAxeJsonReporter, + console: QuartoAxeConsoleReporter, + document: QuartoAxeDocumentReporter, +}; + +class QuartoAxeChecker { + constructor(opts) { + this.options = opts; + } + async init() { + const axe = (await import("https://cdn.skypack.dev/pin/axe-core@v4.10.3-aVOFXWsJaCpVrtv89pCa/mode=imports,min/optimized/axe-core.js")).default; + const result = await axe.run({ + exclude: [ + // https://github.com/microsoft/tabster/issues/288 + // MS has claimed they won't fix this, so we need to add an exclusion to + // all tabster elements + "[data-tabster-dummy]" + ], + preload: { assets: ['cssom'], timeout: 50000 } + }); + const reporter = this.options === true ? new QuartoAxeConsoleReporter(result) : new reporters[this.options.output](result, this.options); + reporter.report(); + } +} + +export async function init() { + const opts = document.querySelector("#quarto-axe-checker-options"); + if (opts) { + const jsonOptions = JSON.parse(atob(opts.textContent)); + const checker = new QuartoAxeChecker(jsonOptions); + await checker.init(); + } +} \ No newline at end of file diff --git a/docs/site_libs/quarto-html/popper.min.js b/docs/site_libs/quarto-html/popper.min.js new file mode 100644 index 0000000..e3726d7 --- /dev/null +++ b/docs/site_libs/quarto-html/popper.min.js @@ -0,0 +1,6 @@ +/** + * @popperjs/core v2.11.7 - MIT License + */ + +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(){var e=navigator.userAgentData;return null!=e&&e.brands&&Array.isArray(e.brands)?e.brands.map((function(e){return e.brand+"/"+e.version})).join(" "):navigator.userAgent}function c(){return!/^((?!chrome|android).)*safari/i.test(f())}function p(e,o,i){void 0===o&&(o=!1),void 0===i&&(i=!1);var a=e.getBoundingClientRect(),f=1,p=1;o&&r(e)&&(f=e.offsetWidth>0&&s(a.width)/e.offsetWidth||1,p=e.offsetHeight>0&&s(a.height)/e.offsetHeight||1);var u=(n(e)?t(e):window).visualViewport,l=!c()&&i,d=(a.left+(l&&u?u.offsetLeft:0))/f,h=(a.top+(l&&u?u.offsetTop:0))/p,m=a.width/f,v=a.height/p;return{width:m,height:v,top:h,right:d+m,bottom:h+v,left:d,x:d,y:h}}function u(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function l(e){return e?(e.nodeName||"").toLowerCase():null}function d(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function h(e){return p(d(e)).left+u(e).scrollLeft}function m(e){return t(e).getComputedStyle(e)}function v(e){var t=m(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function y(e,n,o){void 0===o&&(o=!1);var i,a,f=r(n),c=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),m=d(n),y=p(e,c,o),g={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(f||!f&&!o)&&(("body"!==l(n)||v(m))&&(g=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:u(i)),r(n)?((b=p(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):m&&(b.x=h(m))),{x:y.left+g.scrollLeft-b.x,y:y.top+g.scrollTop-b.y,width:y.width,height:y.height}}function g(e){var t=p(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function b(e){return"html"===l(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||d(e)}function x(e){return["html","body","#document"].indexOf(l(e))>=0?e.ownerDocument.body:r(e)&&v(e)?e:x(b(e))}function w(e,n){var r;void 0===n&&(n=[]);var o=x(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],v(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(w(b(s)))}function O(e){return["table","td","th"].indexOf(l(e))>=0}function j(e){return r(e)&&"fixed"!==m(e).position?e.offsetParent:null}function E(e){for(var n=t(e),i=j(e);i&&O(i)&&"static"===m(i).position;)i=j(i);return i&&("html"===l(i)||"body"===l(i)&&"static"===m(i).position)?n:i||function(e){var t=/firefox/i.test(f());if(/Trident/i.test(f())&&r(e)&&"fixed"===m(e).position)return null;var n=b(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(l(n))<0;){var i=m(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var D="top",A="bottom",L="right",P="left",M="auto",k=[D,A,L,P],W="start",B="end",H="viewport",T="popper",R=k.reduce((function(e,t){return e.concat([t+"-"+W,t+"-"+B])}),[]),S=[].concat(k,[M]).reduce((function(e,t){return e.concat([t,t+"-"+W,t+"-"+B])}),[]),V=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function q(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function N(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function I(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function _(e,r,o){return r===H?I(function(e,n){var r=t(e),o=d(e),i=r.visualViewport,a=o.clientWidth,s=o.clientHeight,f=0,p=0;if(i){a=i.width,s=i.height;var u=c();(u||!u&&"fixed"===n)&&(f=i.offsetLeft,p=i.offsetTop)}return{width:a,height:s,x:f+h(e),y:p}}(e,o)):n(r)?function(e,t){var n=p(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(r,o):I(function(e){var t,n=d(e),r=u(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+h(e),c=-r.scrollTop;return"rtl"===m(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:c}}(d(e)))}function F(e,t,o,s){var f="clippingParents"===t?function(e){var t=w(b(e)),o=["absolute","fixed"].indexOf(m(e).position)>=0&&r(e)?E(e):e;return n(o)?t.filter((function(e){return n(e)&&N(e,o)&&"body"!==l(e)})):[]}(e):[].concat(t),c=[].concat(f,[o]),p=c[0],u=c.reduce((function(t,n){var r=_(e,n,s);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),_(e,p,s));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function U(e){return e.split("-")[1]}function z(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function X(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?U(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case D:t={x:s,y:n.y-r.height};break;case A:t={x:s,y:n.y+n.height};break;case L:t={x:n.x+n.width,y:f};break;case P:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?z(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case W:t[c]=t[c]-(n[p]/2-r[p]/2);break;case B:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function Y(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function G(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function J(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.strategy,s=void 0===a?e.strategy:a,f=r.boundary,c=void 0===f?"clippingParents":f,u=r.rootBoundary,l=void 0===u?H:u,h=r.elementContext,m=void 0===h?T:h,v=r.altBoundary,y=void 0!==v&&v,g=r.padding,b=void 0===g?0:g,x=Y("number"!=typeof b?b:G(b,k)),w=m===T?"reference":T,O=e.rects.popper,j=e.elements[y?w:m],E=F(n(j)?j:j.contextElement||d(e.elements.popper),c,l,s),P=p(e.elements.reference),M=X({reference:P,element:O,strategy:"absolute",placement:i}),W=I(Object.assign({},O,M)),B=m===T?W:P,R={top:E.top-B.top+x.top,bottom:B.bottom-E.bottom+x.bottom,left:E.left-B.left+x.left,right:B.right-E.right+x.right},S=e.modifiersData.offset;if(m===T&&S){var V=S[i];Object.keys(R).forEach((function(e){var t=[L,A].indexOf(e)>=0?1:-1,n=[D,A].indexOf(e)>=0?"y":"x";R[e]+=V[n]*t}))}return R}var K={placement:"bottom",modifiers:[],strategy:"absolute"};function Q(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[P,L].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},se={left:"right",right:"left",bottom:"top",top:"bottom"};function fe(e){return e.replace(/left|right|bottom|top/g,(function(e){return se[e]}))}var ce={start:"end",end:"start"};function pe(e){return e.replace(/start|end/g,(function(e){return ce[e]}))}function ue(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?S:f,p=U(r),u=p?s?R:R.filter((function(e){return U(e)===p})):k,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=J(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var le={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,y=C(v),g=f||(y===v||!h?[fe(v)]:function(e){if(C(e)===M)return[];var t=fe(e);return[pe(e),t,pe(t)]}(v)),b=[v].concat(g).reduce((function(e,n){return e.concat(C(n)===M?ue(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,j=!0,E=b[0],k=0;k=0,S=R?"width":"height",V=J(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),q=R?T?L:P:T?A:D;x[S]>w[S]&&(q=fe(q));var N=fe(q),I=[];if(i&&I.push(V[H]<=0),s&&I.push(V[q]<=0,V[N]<=0),I.every((function(e){return e}))){E=B,j=!1;break}O.set(B,I)}if(j)for(var _=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return E=t,"break"},F=h?3:1;F>0;F--){if("break"===_(F))break}t.placement!==E&&(t.modifiersData[r]._skip=!0,t.placement=E,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function de(e,t,n){return i(e,a(t,n))}var he={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,v=n.tetherOffset,y=void 0===v?0:v,b=J(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=U(t.placement),O=!w,j=z(x),M="x"===j?"y":"x",k=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,V={x:0,y:0};if(k){if(s){var q,N="y"===j?D:P,I="y"===j?A:L,_="y"===j?"height":"width",F=k[j],X=F+b[N],Y=F-b[I],G=m?-H[_]/2:0,K=w===W?B[_]:H[_],Q=w===W?-H[_]:-B[_],Z=t.elements.arrow,$=m&&Z?g(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=de(0,B[_],$[_]),oe=O?B[_]/2-G-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=O?-B[_]/2+G+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&E(t.elements.arrow),se=ae?"y"===j?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(q=null==S?void 0:S[j])?q:0,ce=F+ie-fe,pe=de(m?a(X,F+oe-fe-se):X,F,m?i(Y,ce):Y);k[j]=pe,V[j]=pe-F}if(c){var ue,le="x"===j?D:P,he="x"===j?A:L,me=k[M],ve="y"===M?"height":"width",ye=me+b[le],ge=me-b[he],be=-1!==[D,P].indexOf(x),xe=null!=(ue=null==S?void 0:S[M])?ue:0,we=be?ye:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ge,je=m&&be?function(e,t,n){var r=de(e,t,n);return r>n?n:r}(we,me,Oe):de(m?we:ye,me,m?Oe:ge);k[M]=je,V[M]=je-me}t.modifiersData[r]=V}},requiresIfExists:["offset"]};var me={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=z(s),c=[P,L].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return Y("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:G(e,k))}(o.padding,n),u=g(i),l="y"===f?D:P,d="y"===f?A:L,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],v=E(i),y=v?"y"===f?v.clientHeight||0:v.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],O=y/2-u[c]/2+b,j=de(x,O,w),M=f;n.modifiersData[r]=((t={})[M]=j,t.centerOffset=j-O,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&N(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ve(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function ye(e){return[D,L,A,P].some((function(t){return e[t]>=0}))}var ge={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=J(t,{elementContext:"reference"}),s=J(t,{altBoundary:!0}),f=ve(a,r),c=ve(s,o,i),p=ye(f),u=ye(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},be=Z({defaultModifiers:[ee,te,oe,ie]}),xe=[ee,te,oe,ie,ae,le,he,me,ge],we=Z({defaultModifiers:xe});e.applyStyles=ie,e.arrow=me,e.computeStyles=oe,e.createPopper=we,e.createPopperLite=be,e.defaultModifiers=xe,e.detectOverflow=J,e.eventListeners=ee,e.flip=le,e.hide=ge,e.offset=ae,e.popperGenerator=Z,e.popperOffsets=te,e.preventOverflow=he,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/docs/site_libs/quarto-html/quarto-syntax-highlighting-ed96de9b727972fe78a7b5d16c58bf87.css b/docs/site_libs/quarto-html/quarto-syntax-highlighting-ed96de9b727972fe78a7b5d16c58bf87.css new file mode 100644 index 0000000..7bb4f73 --- /dev/null +++ b/docs/site_libs/quarto-html/quarto-syntax-highlighting-ed96de9b727972fe78a7b5d16c58bf87.css @@ -0,0 +1,236 @@ +/* quarto syntax highlight colors */ +:root { + --quarto-hl-ot-color: #003B4F; + --quarto-hl-at-color: #657422; + --quarto-hl-ss-color: #20794D; + --quarto-hl-an-color: #5E5E5E; + --quarto-hl-fu-color: #4758AB; + --quarto-hl-st-color: #20794D; + --quarto-hl-cf-color: #003B4F; + --quarto-hl-op-color: #5E5E5E; + --quarto-hl-er-color: #AD0000; + --quarto-hl-bn-color: #AD0000; + --quarto-hl-al-color: #AD0000; + --quarto-hl-va-color: #111111; + --quarto-hl-bu-color: inherit; + --quarto-hl-ex-color: inherit; + --quarto-hl-pp-color: #AD0000; + --quarto-hl-in-color: #5E5E5E; + --quarto-hl-vs-color: #20794D; + --quarto-hl-wa-color: #5E5E5E; + --quarto-hl-do-color: #5E5E5E; + --quarto-hl-im-color: #00769E; + --quarto-hl-ch-color: #20794D; + --quarto-hl-dt-color: #AD0000; + --quarto-hl-fl-color: #AD0000; + --quarto-hl-co-color: #5E5E5E; + --quarto-hl-cv-color: #5E5E5E; + --quarto-hl-cn-color: #8f5902; + --quarto-hl-sc-color: #5E5E5E; + --quarto-hl-dv-color: #AD0000; + --quarto-hl-kw-color: #003B4F; +} + +/* other quarto variables */ +:root { + --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +/* syntax highlight based on Pandoc's rules */ +pre > code.sourceCode > span { + color: #003B4F; +} + +code.sourceCode > span { + color: #003B4F; +} + +div.sourceCode, +div.sourceCode pre.sourceCode { + color: #003B4F; +} + +/* Normal */ +code span { + color: #003B4F; +} + +/* Alert */ +code span.al { + color: #AD0000; + font-style: inherit; +} + +/* Annotation */ +code span.an { + color: #5E5E5E; + font-style: inherit; +} + +/* Attribute */ +code span.at { + color: #657422; + font-style: inherit; +} + +/* BaseN */ +code span.bn { + color: #AD0000; + font-style: inherit; +} + +/* BuiltIn */ +code span.bu { + font-style: inherit; +} + +/* ControlFlow */ +code span.cf { + color: #003B4F; + font-weight: bold; + font-style: inherit; +} + +/* Char */ +code span.ch { + color: #20794D; + font-style: inherit; +} + +/* Constant */ +code span.cn { + color: #8f5902; + font-style: inherit; +} + +/* Comment */ +code span.co { + color: #5E5E5E; + font-style: inherit; +} + +/* CommentVar */ +code span.cv { + color: #5E5E5E; + font-style: italic; +} + +/* Documentation */ +code span.do { + color: #5E5E5E; + font-style: italic; +} + +/* DataType */ +code span.dt { + color: #AD0000; + font-style: inherit; +} + +/* DecVal */ +code span.dv { + color: #AD0000; + font-style: inherit; +} + +/* Error */ +code span.er { + color: #AD0000; + font-style: inherit; +} + +/* Extension */ +code span.ex { + font-style: inherit; +} + +/* Float */ +code span.fl { + color: #AD0000; + font-style: inherit; +} + +/* Function */ +code span.fu { + color: #4758AB; + font-style: inherit; +} + +/* Import */ +code span.im { + color: #00769E; + font-style: inherit; +} + +/* Information */ +code span.in { + color: #5E5E5E; + font-style: inherit; +} + +/* Keyword */ +code span.kw { + color: #003B4F; + font-weight: bold; + font-style: inherit; +} + +/* Operator */ +code span.op { + color: #5E5E5E; + font-style: inherit; +} + +/* Other */ +code span.ot { + color: #003B4F; + font-style: inherit; +} + +/* Preprocessor */ +code span.pp { + color: #AD0000; + font-style: inherit; +} + +/* SpecialChar */ +code span.sc { + color: #5E5E5E; + font-style: inherit; +} + +/* SpecialString */ +code span.ss { + color: #20794D; + font-style: inherit; +} + +/* String */ +code span.st { + color: #20794D; + font-style: inherit; +} + +/* Variable */ +code span.va { + color: #111111; + font-style: inherit; +} + +/* VerbatimString */ +code span.vs { + color: #20794D; + font-style: inherit; +} + +/* Warning */ +code span.wa { + color: #5E5E5E; + font-style: italic; +} + +.prevent-inlining { + content: " { + // Find any conflicting margin elements and add margins to the + // top to prevent overlap + const marginChildren = window.document.querySelectorAll( + ".column-margin.column-container > *, .margin-caption, .aside" + ); + + let lastBottom = 0; + for (const marginChild of marginChildren) { + if (marginChild.offsetParent !== null) { + // clear the top margin so we recompute it + marginChild.style.marginTop = null; + const top = marginChild.getBoundingClientRect().top + window.scrollY; + if (top < lastBottom) { + const marginChildStyle = window.getComputedStyle(marginChild); + const marginBottom = parseFloat(marginChildStyle["marginBottom"]); + const margin = lastBottom - top + marginBottom; + marginChild.style.marginTop = `${margin}px`; + } + const styles = window.getComputedStyle(marginChild); + const marginTop = parseFloat(styles["marginTop"]); + lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; + } + } +}; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Recompute the position of margin elements anytime the body size changes + if (window.ResizeObserver) { + const resizeObserver = new window.ResizeObserver( + throttle(() => { + layoutMarginEls(); + if ( + window.document.body.getBoundingClientRect().width < 990 && + isReaderMode() + ) { + quartoToggleReader(); + } + }, 50) + ); + resizeObserver.observe(window.document.body); + } + + const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); + const sidebarEl = window.document.getElementById("quarto-sidebar"); + const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); + const marginSidebarEl = window.document.getElementById( + "quarto-margin-sidebar" + ); + // function to determine whether the element has a previous sibling that is active + const prevSiblingIsActiveLink = (el) => { + const sibling = el.previousElementSibling; + if (sibling && sibling.tagName === "A") { + return sibling.classList.contains("active"); + } else { + return false; + } + }; + + // dispatch for htmlwidgets + // they use slideenter event to trigger resize + function fireSlideEnter() { + const event = window.document.createEvent("Event"); + event.initEvent("slideenter", true, true); + window.document.dispatchEvent(event); + } + + const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); + tabs.forEach((tab) => { + tab.addEventListener("shown.bs.tab", fireSlideEnter); + }); + + // dispatch for shiny + // they use BS shown and hidden events to trigger rendering + function distpatchShinyEvents(previous, current) { + if (window.jQuery) { + if (previous) { + window.jQuery(previous).trigger("hidden"); + } + if (current) { + window.jQuery(current).trigger("shown"); + } + } + } + + // tabby.js listener: Trigger event for htmlwidget and shiny + document.addEventListener( + "tabby", + function (event) { + fireSlideEnter(); + distpatchShinyEvents(event.detail.previousTab, event.detail.tab); + }, + false + ); + + // Track scrolling and mark TOC links as active + // get table of contents and sidebar (bail if we don't have at least one) + const tocLinks = tocEl + ? [...tocEl.querySelectorAll("a[data-scroll-target]")] + : []; + const makeActive = (link) => tocLinks[link].classList.add("active"); + const removeActive = (link) => tocLinks[link].classList.remove("active"); + const removeAllActive = () => + [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); + + // activate the anchor for a section associated with this TOC entry + tocLinks.forEach((link) => { + link.addEventListener("click", () => { + if (link.href.indexOf("#") !== -1) { + const anchor = link.href.split("#")[1]; + const heading = window.document.querySelector( + `[data-anchor-id="${anchor}"]` + ); + if (heading) { + // Add the class + heading.classList.add("reveal-anchorjs-link"); + + // function to show the anchor + const handleMouseout = () => { + heading.classList.remove("reveal-anchorjs-link"); + heading.removeEventListener("mouseout", handleMouseout); + }; + + // add a function to clear the anchor when the user mouses out of it + heading.addEventListener("mouseout", handleMouseout); + } + } + }); + }); + + const sections = tocLinks.map((link) => { + const target = link.getAttribute("data-scroll-target"); + if (target.startsWith("#")) { + return window.document.getElementById(decodeURI(`${target.slice(1)}`)); + } else { + return window.document.querySelector(decodeURI(`${target}`)); + } + }); + + const sectionMargin = 200; + let currentActive = 0; + // track whether we've initialized state the first time + let init = false; + + const updateActiveLink = () => { + // The index from bottom to top (e.g. reversed list) + let sectionIndex = -1; + if ( + window.innerHeight + window.pageYOffset >= + window.document.body.offsetHeight + ) { + // This is the no-scroll case where last section should be the active one + sectionIndex = 0; + } else { + // This finds the last section visible on screen that should be made active + sectionIndex = [...sections].reverse().findIndex((section) => { + if (section) { + return window.pageYOffset >= section.offsetTop - sectionMargin; + } else { + return false; + } + }); + } + if (sectionIndex > -1) { + const current = sections.length - sectionIndex - 1; + if (current !== currentActive) { + removeAllActive(); + currentActive = current; + makeActive(current); + if (init) { + window.dispatchEvent(sectionChanged); + } + init = true; + } + } + }; + + const inHiddenRegion = (top, bottom, hiddenRegions) => { + for (const region of hiddenRegions) { + if (top <= region.bottom && bottom >= region.top) { + return true; + } + } + return false; + }; + + const categorySelector = "header.quarto-title-block .quarto-category"; + const activateCategories = (href) => { + // Find any categories + // Surround them with a link pointing back to: + // #category=Authoring + try { + const categoryEls = window.document.querySelectorAll(categorySelector); + for (const categoryEl of categoryEls) { + const categoryText = categoryEl.textContent; + if (categoryText) { + const link = `${href}#category=${encodeURIComponent(categoryText)}`; + const linkEl = window.document.createElement("a"); + linkEl.setAttribute("href", link); + for (const child of categoryEl.childNodes) { + linkEl.append(child); + } + categoryEl.appendChild(linkEl); + } + } + } catch { + // Ignore errors + } + }; + function hasTitleCategories() { + return window.document.querySelector(categorySelector) !== null; + } + + function offsetRelativeUrl(url) { + const offset = getMeta("quarto:offset"); + return offset ? offset + url : url; + } + + function offsetAbsoluteUrl(url) { + const offset = getMeta("quarto:offset"); + const baseUrl = new URL(offset, window.location); + + const projRelativeUrl = url.replace(baseUrl, ""); + if (projRelativeUrl.startsWith("/")) { + return projRelativeUrl; + } else { + return "/" + projRelativeUrl; + } + } + + // read a meta tag value + function getMeta(metaName) { + const metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; + } + + async function findAndActivateCategories() { + // Categories search with listing only use path without query + const currentPagePath = offsetAbsoluteUrl( + window.location.origin + window.location.pathname + ); + const response = await fetch(offsetRelativeUrl("listings.json")); + if (response.status == 200) { + return response.json().then(function (listingPaths) { + const listingHrefs = []; + for (const listingPath of listingPaths) { + const pathWithoutLeadingSlash = listingPath.listing.substring(1); + for (const item of listingPath.items) { + const encodedItem = encodeURI(item); + if ( + encodedItem === currentPagePath || + encodedItem === currentPagePath + "index.html" + ) { + // Resolve this path against the offset to be sure + // we already are using the correct path to the listing + // (this adjusts the listing urls to be rooted against + // whatever root the page is actually running against) + const relative = offsetRelativeUrl(pathWithoutLeadingSlash); + const baseUrl = window.location; + const resolvedPath = new URL(relative, baseUrl); + listingHrefs.push(resolvedPath.pathname); + break; + } + } + } + + // Look up the tree for a nearby linting and use that if we find one + const nearestListing = findNearestParentListing( + offsetAbsoluteUrl(window.location.pathname), + listingHrefs + ); + if (nearestListing) { + activateCategories(nearestListing); + } else { + // See if the referrer is a listing page for this item + const referredRelativePath = offsetAbsoluteUrl(document.referrer); + const referrerListing = listingHrefs.find((listingHref) => { + const isListingReferrer = + listingHref === referredRelativePath || + listingHref === referredRelativePath + "index.html"; + return isListingReferrer; + }); + + if (referrerListing) { + // Try to use the referrer if possible + activateCategories(referrerListing); + } else if (listingHrefs.length > 0) { + // Otherwise, just fall back to the first listing + activateCategories(listingHrefs[0]); + } + } + }); + } + } + if (hasTitleCategories()) { + findAndActivateCategories(); + } + + const findNearestParentListing = (href, listingHrefs) => { + if (!href || !listingHrefs) { + return undefined; + } + // Look up the tree for a nearby linting and use that if we find one + const relativeParts = href.substring(1).split("/"); + while (relativeParts.length > 0) { + const path = relativeParts.join("/"); + for (const listingHref of listingHrefs) { + if (listingHref.startsWith(path)) { + return listingHref; + } + } + relativeParts.pop(); + } + + return undefined; + }; + + const manageSidebarVisiblity = (el, placeholderDescriptor) => { + let isVisible = true; + let elRect; + + return (hiddenRegions) => { + if (el === null) { + return; + } + + // Find the last element of the TOC + const lastChildEl = el.lastElementChild; + + if (lastChildEl) { + // Converts the sidebar to a menu + const convertToMenu = () => { + for (const child of el.children) { + child.style.opacity = 0; + child.style.overflow = "hidden"; + child.style.pointerEvents = "none"; + } + + nexttick(() => { + const toggleContainer = window.document.createElement("div"); + toggleContainer.style.width = "100%"; + toggleContainer.classList.add("zindex-over-content"); + toggleContainer.classList.add("quarto-sidebar-toggle"); + toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom + toggleContainer.id = placeholderDescriptor.id; + toggleContainer.style.position = "fixed"; + + const toggleIcon = window.document.createElement("i"); + toggleIcon.classList.add("quarto-sidebar-toggle-icon"); + toggleIcon.classList.add("bi"); + toggleIcon.classList.add("bi-caret-down-fill"); + + const toggleTitle = window.document.createElement("div"); + const titleEl = window.document.body.querySelector( + placeholderDescriptor.titleSelector + ); + if (titleEl) { + toggleTitle.append( + titleEl.textContent || titleEl.innerText, + toggleIcon + ); + } + toggleTitle.classList.add("zindex-over-content"); + toggleTitle.classList.add("quarto-sidebar-toggle-title"); + toggleContainer.append(toggleTitle); + + const toggleContents = window.document.createElement("div"); + toggleContents.classList = el.classList; + toggleContents.classList.add("zindex-over-content"); + toggleContents.classList.add("quarto-sidebar-toggle-contents"); + for (const child of el.children) { + if (child.id === "toc-title") { + continue; + } + + const clone = child.cloneNode(true); + clone.style.opacity = 1; + clone.style.pointerEvents = null; + clone.style.display = null; + toggleContents.append(clone); + } + toggleContents.style.height = "0px"; + const positionToggle = () => { + // position the element (top left of parent, same width as parent) + if (!elRect) { + elRect = el.getBoundingClientRect(); + } + toggleContainer.style.left = `${elRect.left}px`; + toggleContainer.style.top = `${elRect.top}px`; + toggleContainer.style.width = `${elRect.width}px`; + }; + positionToggle(); + + toggleContainer.append(toggleContents); + el.parentElement.prepend(toggleContainer); + + // Process clicks + let tocShowing = false; + // Allow the caller to control whether this is dismissed + // when it is clicked (e.g. sidebar navigation supports + // opening and closing the nav tree, so don't dismiss on click) + const clickEl = placeholderDescriptor.dismissOnClick + ? toggleContainer + : toggleTitle; + + const closeToggle = () => { + if (tocShowing) { + toggleContainer.classList.remove("expanded"); + toggleContents.style.height = "0px"; + tocShowing = false; + } + }; + + // Get rid of any expanded toggle if the user scrolls + window.document.addEventListener( + "scroll", + throttle(() => { + closeToggle(); + }, 50) + ); + + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + positionToggle(); + }, 50) + ); + + window.addEventListener("quarto-hrChanged", () => { + elRect = undefined; + }); + + // Process the click + clickEl.onclick = () => { + if (!tocShowing) { + toggleContainer.classList.add("expanded"); + toggleContents.style.height = null; + tocShowing = true; + } else { + closeToggle(); + } + }; + }); + }; + + // Converts a sidebar from a menu back to a sidebar + const convertToSidebar = () => { + for (const child of el.children) { + child.style.opacity = 1; + child.style.overflow = null; + child.style.pointerEvents = null; + } + + const placeholderEl = window.document.getElementById( + placeholderDescriptor.id + ); + if (placeholderEl) { + placeholderEl.remove(); + } + + el.classList.remove("rollup"); + }; + + if (isReaderMode()) { + convertToMenu(); + isVisible = false; + } else { + // Find the top and bottom o the element that is being managed + const elTop = el.offsetTop; + const elBottom = + elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; + + if (!isVisible) { + // If the element is current not visible reveal if there are + // no conflicts with overlay regions + if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToSidebar(); + isVisible = true; + } + } else { + // If the element is visible, hide it if it conflicts with overlay regions + // and insert a placeholder toggle (or if we're in reader mode) + if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToMenu(); + isVisible = false; + } + } + } + } + }; + }; + + const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); + for (const tabEl of tabEls) { + const id = tabEl.getAttribute("data-bs-target"); + if (id) { + const columnEl = document.querySelector( + `${id} .column-margin, .tabset-margin-content` + ); + if (columnEl) + tabEl.addEventListener("shown.bs.tab", function (event) { + const el = event.srcElement; + if (el) { + const visibleCls = `${el.id}-margin-content`; + // walk up until we find a parent tabset + let panelTabsetEl = el.parentElement; + while (panelTabsetEl) { + if (panelTabsetEl.classList.contains("panel-tabset")) { + break; + } + panelTabsetEl = panelTabsetEl.parentElement; + } + + if (panelTabsetEl) { + const prevSib = panelTabsetEl.previousElementSibling; + if ( + prevSib && + prevSib.classList.contains("tabset-margin-container") + ) { + const childNodes = prevSib.querySelectorAll( + ".tabset-margin-content" + ); + for (const childEl of childNodes) { + if (childEl.classList.contains(visibleCls)) { + childEl.classList.remove("collapse"); + } else { + childEl.classList.add("collapse"); + } + } + } + } + } + + layoutMarginEls(); + }); + } + } + + // Manage the visibility of the toc and the sidebar + const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { + id: "quarto-toc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { + id: "quarto-sidebarnav-toggle", + titleSelector: ".title", + dismissOnClick: false, + }); + let tocLeftScrollVisibility; + if (leftTocEl) { + tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { + id: "quarto-lefttoc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + } + + // Find the first element that uses formatting in special columns + const conflictingEls = window.document.body.querySelectorAll( + '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' + ); + + // Filter all the possibly conflicting elements into ones + // the do conflict on the left or ride side + const arrConflictingEls = Array.from(conflictingEls); + const leftSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return false; + } + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + className.startsWith("column-") && + !className.endsWith("right") && + !className.endsWith("container") && + className !== "column-margin" + ); + }); + }); + const rightSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return true; + } + + const hasMarginCaption = Array.from(el.classList).find((className) => { + return className == "margin-caption"; + }); + if (hasMarginCaption) { + return true; + } + + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + !className.endsWith("container") && + className.startsWith("column-") && + !className.endsWith("left") + ); + }); + }); + + const kOverlapPaddingSize = 10; + function toRegions(els) { + return els.map((el) => { + const boundRect = el.getBoundingClientRect(); + const top = + boundRect.top + + document.documentElement.scrollTop - + kOverlapPaddingSize; + return { + top, + bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, + }; + }); + } + + let hasObserved = false; + const visibleItemObserver = (els) => { + let visibleElements = [...els]; + const intersectionObserver = new IntersectionObserver( + (entries, _observer) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + if (visibleElements.indexOf(entry.target) === -1) { + visibleElements.push(entry.target); + } + } else { + visibleElements = visibleElements.filter((visibleEntry) => { + return visibleEntry !== entry; + }); + } + }); + + if (!hasObserved) { + hideOverlappedSidebars(); + } + hasObserved = true; + }, + {} + ); + els.forEach((el) => { + intersectionObserver.observe(el); + }); + + return { + getVisibleEntries: () => { + return visibleElements; + }, + }; + }; + + const rightElementObserver = visibleItemObserver(rightSideConflictEls); + const leftElementObserver = visibleItemObserver(leftSideConflictEls); + + const hideOverlappedSidebars = () => { + marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); + sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); + if (tocLeftScrollVisibility) { + tocLeftScrollVisibility( + toRegions(leftElementObserver.getVisibleEntries()) + ); + } + }; + + window.quartoToggleReader = () => { + // Applies a slow class (or removes it) + // to update the transition speed + const slowTransition = (slow) => { + const manageTransition = (id, slow) => { + const el = document.getElementById(id); + if (el) { + if (slow) { + el.classList.add("slow"); + } else { + el.classList.remove("slow"); + } + } + }; + + manageTransition("TOC", slow); + manageTransition("quarto-sidebar", slow); + }; + const readerMode = !isReaderMode(); + setReaderModeValue(readerMode); + + // If we're entering reader mode, slow the transition + if (readerMode) { + slowTransition(readerMode); + } + highlightReaderToggle(readerMode); + hideOverlappedSidebars(); + + // If we're exiting reader mode, restore the non-slow transition + if (!readerMode) { + slowTransition(!readerMode); + } + }; + + const highlightReaderToggle = (readerMode) => { + const els = document.querySelectorAll(".quarto-reader-toggle"); + if (els) { + els.forEach((el) => { + if (readerMode) { + el.classList.add("reader"); + } else { + el.classList.remove("reader"); + } + }); + } + }; + + const setReaderModeValue = (val) => { + if (window.location.protocol !== "file:") { + window.localStorage.setItem("quarto-reader-mode", val); + } else { + localReaderMode = val; + } + }; + + const isReaderMode = () => { + if (window.location.protocol !== "file:") { + return window.localStorage.getItem("quarto-reader-mode") === "true"; + } else { + return localReaderMode; + } + }; + let localReaderMode = null; + + const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); + const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; + + // Walk the TOC and collapse/expand nodes + // Nodes are expanded if: + // - they are top level + // - they have children that are 'active' links + // - they are directly below an link that is 'active' + const walk = (el, depth) => { + // Tick depth when we enter a UL + if (el.tagName === "UL") { + depth = depth + 1; + } + + // It this is active link + let isActiveNode = false; + if (el.tagName === "A" && el.classList.contains("active")) { + isActiveNode = true; + } + + // See if there is an active child to this element + let hasActiveChild = false; + for (const child of el.children) { + hasActiveChild = walk(child, depth) || hasActiveChild; + } + + // Process the collapse state if this is an UL + if (el.tagName === "UL") { + if (tocOpenDepth === -1 && depth > 1) { + // toc-expand: false + el.classList.add("collapse"); + } else if ( + depth <= tocOpenDepth || + hasActiveChild || + prevSiblingIsActiveLink(el) + ) { + el.classList.remove("collapse"); + } else { + el.classList.add("collapse"); + } + + // untick depth when we leave a UL + depth = depth - 1; + } + return hasActiveChild || isActiveNode; + }; + + // walk the TOC and expand / collapse any items that should be shown + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + + // Throttle the scroll event and walk peridiocally + window.document.addEventListener( + "scroll", + throttle(() => { + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 5) + ); + window.addEventListener( + "resize", + throttle(() => { + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 10) + ); + hideOverlappedSidebars(); + highlightReaderToggle(isReaderMode()); +}); + +tabsets.init(); +axe.init(); + +function throttle(func, wait) { + let waiting = false; + return function () { + if (!waiting) { + func.apply(this, arguments); + waiting = true; + setTimeout(function () { + waiting = false; + }, wait); + } + }; +} + +function nexttick(func) { + return setTimeout(func, 0); +} diff --git a/docs/site_libs/quarto-html/tabsets/tabsets.js b/docs/site_libs/quarto-html/tabsets/tabsets.js new file mode 100644 index 0000000..51345d0 --- /dev/null +++ b/docs/site_libs/quarto-html/tabsets/tabsets.js @@ -0,0 +1,95 @@ +// grouped tabsets + +export function init() { + window.addEventListener("pageshow", (_event) => { + function getTabSettings() { + const data = localStorage.getItem("quarto-persistent-tabsets-data"); + if (!data) { + localStorage.setItem("quarto-persistent-tabsets-data", "{}"); + return {}; + } + if (data) { + return JSON.parse(data); + } + } + + function setTabSettings(data) { + localStorage.setItem( + "quarto-persistent-tabsets-data", + JSON.stringify(data) + ); + } + + function setTabState(groupName, groupValue) { + const data = getTabSettings(); + data[groupName] = groupValue; + setTabSettings(data); + } + + function toggleTab(tab, active) { + const tabPanelId = tab.getAttribute("aria-controls"); + const tabPanel = document.getElementById(tabPanelId); + if (active) { + tab.classList.add("active"); + tabPanel.classList.add("active"); + } else { + tab.classList.remove("active"); + tabPanel.classList.remove("active"); + } + } + + function toggleAll(selectedGroup, selectorsToSync) { + for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { + const active = selectedGroup === thisGroup; + for (const tab of tabs) { + toggleTab(tab, active); + } + } + } + + function findSelectorsToSyncByLanguage() { + const result = {}; + const tabs = Array.from( + document.querySelectorAll(`div[data-group] a[id^='tabset-']`) + ); + for (const item of tabs) { + const div = item.parentElement.parentElement.parentElement; + const group = div.getAttribute("data-group"); + if (!result[group]) { + result[group] = {}; + } + const selectorsToSync = result[group]; + const value = item.innerHTML; + if (!selectorsToSync[value]) { + selectorsToSync[value] = []; + } + selectorsToSync[value].push(item); + } + return result; + } + + function setupSelectorSync() { + const selectorsToSync = findSelectorsToSyncByLanguage(); + Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { + Object.entries(tabSetsByValue).forEach(([value, items]) => { + items.forEach((item) => { + item.addEventListener("click", (_event) => { + setTabState(group, value); + toggleAll(value, selectorsToSync[group]); + }); + }); + }); + }); + return selectorsToSync; + } + + const selectorsToSync = setupSelectorSync(); + for (const [group, selectedName] of Object.entries(getTabSettings())) { + const selectors = selectorsToSync[group]; + // it's possible that stale state gives us empty selections, so we explicitly check here. + if (selectors) { + toggleAll(selectedName, selectors); + } + } + }); +} diff --git a/docs/site_libs/quarto-html/tippy.css b/docs/site_libs/quarto-html/tippy.css new file mode 100644 index 0000000..e6ae635 --- /dev/null +++ b/docs/site_libs/quarto-html/tippy.css @@ -0,0 +1 @@ +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/docs/site_libs/quarto-html/tippy.umd.min.js b/docs/site_libs/quarto-html/tippy.umd.min.js new file mode 100644 index 0000000..ca292be --- /dev/null +++ b/docs/site_libs/quarto-html/tippy.umd.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); + diff --git a/docs/site_libs/quarto-nav/headroom.min.js b/docs/site_libs/quarto-nav/headroom.min.js new file mode 100644 index 0000000..b08f1df --- /dev/null +++ b/docs/site_libs/quarto-nav/headroom.min.js @@ -0,0 +1,7 @@ +/*! + * headroom.js v0.12.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t){return t===Object(t)?t:{down:t,up:t}}function s(t,n){n=n||{},Object.assign(this,s.options,n),this.classes=Object.assign({},s.options.classes,n.classes),this.elem=t,this.tolerance=o(this.tolerance),this.offset=o(this.offset),this.initialised=!1,this.frozen=!1}return s.prototype={constructor:s,init:function(){return s.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},s.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},s.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),s}); diff --git a/docs/site_libs/quarto-nav/quarto-nav.js b/docs/site_libs/quarto-nav/quarto-nav.js new file mode 100644 index 0000000..38cc430 --- /dev/null +++ b/docs/site_libs/quarto-nav/quarto-nav.js @@ -0,0 +1,325 @@ +const headroomChanged = new CustomEvent("quarto-hrChanged", { + detail: {}, + bubbles: true, + cancelable: false, + composed: false, +}); + +const announceDismiss = () => { + const annEl = window.document.getElementById("quarto-announcement"); + if (annEl) { + annEl.remove(); + + const annId = annEl.getAttribute("data-announcement-id"); + window.localStorage.setItem(`quarto-announce-${annId}`, "true"); + } +}; + +const announceRegister = () => { + const annEl = window.document.getElementById("quarto-announcement"); + if (annEl) { + const annId = annEl.getAttribute("data-announcement-id"); + const isDismissed = + window.localStorage.getItem(`quarto-announce-${annId}`) || false; + if (isDismissed) { + announceDismiss(); + return; + } else { + annEl.classList.remove("hidden"); + } + + const actionEl = annEl.querySelector(".quarto-announcement-action"); + if (actionEl) { + actionEl.addEventListener("click", function (e) { + e.preventDefault(); + // Hide the bar immediately + announceDismiss(); + }); + } + } +}; + +window.document.addEventListener("DOMContentLoaded", function () { + let init = false; + + announceRegister(); + + // Manage the back to top button, if one is present. + let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop; + const scrollDownBuffer = 5; + const scrollUpBuffer = 35; + const btn = document.getElementById("quarto-back-to-top"); + const hideBackToTop = () => { + btn.style.display = "none"; + }; + const showBackToTop = () => { + btn.style.display = "inline-block"; + }; + if (btn) { + window.document.addEventListener( + "scroll", + function () { + const currentScrollTop = + window.pageYOffset || document.documentElement.scrollTop; + + // Shows and hides the button 'intelligently' as the user scrolls + if (currentScrollTop - scrollDownBuffer > lastScrollTop) { + hideBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } else if (currentScrollTop < lastScrollTop - scrollUpBuffer) { + showBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } + + // Show the button at the bottom, hides it at the top + if (currentScrollTop <= 0) { + hideBackToTop(); + } else if ( + window.innerHeight + currentScrollTop >= + document.body.offsetHeight + ) { + showBackToTop(); + } + }, + false + ); + } + + function throttle(func, wait) { + var timeout; + return function () { + const context = this; + const args = arguments; + const later = function () { + clearTimeout(timeout); + timeout = null; + func.apply(context, args); + }; + + if (!timeout) { + timeout = setTimeout(later, wait); + } + }; + } + + function headerOffset() { + // Set an offset if there is are fixed top navbar + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl) { + return headerEl.clientHeight; + } else { + return 0; + } + } + + function footerOffset() { + const footerEl = window.document.querySelector("footer.footer"); + if (footerEl) { + return footerEl.clientHeight; + } else { + return 0; + } + } + + function dashboardOffset() { + const dashboardNavEl = window.document.getElementById( + "quarto-dashboard-header" + ); + if (dashboardNavEl !== null) { + return dashboardNavEl.clientHeight; + } else { + return 0; + } + } + + function updateDocumentOffsetWithoutAnimation() { + updateDocumentOffset(false); + } + + function updateDocumentOffset(animated) { + // set body offset + const topOffset = headerOffset(); + const bodyOffset = topOffset + footerOffset() + dashboardOffset(); + const bodyEl = window.document.body; + bodyEl.setAttribute("data-bs-offset", topOffset); + bodyEl.style.paddingTop = topOffset + "px"; + + // deal with sidebar offsets + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + if (!animated) { + sidebar.classList.add("notransition"); + // Remove the no transition class after the animation has time to complete + setTimeout(function () { + sidebar.classList.remove("notransition"); + }, 201); + } + + if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) { + sidebar.style.top = "0"; + sidebar.style.maxHeight = "100vh"; + } else { + sidebar.style.top = topOffset + "px"; + sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)"; + } + }); + + // allow space for footer + const mainContainer = window.document.querySelector(".quarto-container"); + if (mainContainer) { + mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)"; + } + + // link offset + let linkStyle = window.document.querySelector("#quarto-target-style"); + if (!linkStyle) { + linkStyle = window.document.createElement("style"); + linkStyle.setAttribute("id", "quarto-target-style"); + window.document.head.appendChild(linkStyle); + } + while (linkStyle.firstChild) { + linkStyle.removeChild(linkStyle.firstChild); + } + if (topOffset > 0) { + linkStyle.appendChild( + window.document.createTextNode(` + section:target::before { + content: ""; + display: block; + height: ${topOffset}px; + margin: -${topOffset}px 0 0; + }`) + ); + } + if (init) { + window.dispatchEvent(headroomChanged); + } + init = true; + } + + // initialize headroom + var header = window.document.querySelector("#quarto-header"); + if (header && window.Headroom) { + const headroom = new window.Headroom(header, { + tolerance: 5, + onPin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.remove("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + onUnpin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.add("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + }); + headroom.init(); + + let frozen = false; + window.quartoToggleHeadroom = function () { + if (frozen) { + headroom.unfreeze(); + frozen = false; + } else { + headroom.freeze(); + frozen = true; + } + }; + } + + window.addEventListener( + "hashchange", + function (e) { + if ( + getComputedStyle(document.documentElement).scrollBehavior !== "smooth" + ) { + window.scrollTo(0, window.pageYOffset - headerOffset()); + } + }, + false + ); + + // Observe size changed for the header + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl && window.ResizeObserver) { + const observer = new window.ResizeObserver(() => { + setTimeout(updateDocumentOffsetWithoutAnimation, 0); + }); + observer.observe(headerEl, { + attributes: true, + childList: true, + characterData: true, + }); + } else { + window.addEventListener( + "resize", + throttle(updateDocumentOffsetWithoutAnimation, 50) + ); + } + setTimeout(updateDocumentOffsetWithoutAnimation, 250); + + // fixup index.html links if we aren't on the filesystem + if (window.location.protocol !== "file:") { + const links = window.document.querySelectorAll("a"); + for (let i = 0; i < links.length; i++) { + if (links[i].href) { + links[i].dataset.originalHref = links[i].href; + links[i].href = links[i].href.replace(/\/index\.html/, "/"); + } + } + + // Fixup any sharing links that require urls + // Append url to any sharing urls + const sharingLinks = window.document.querySelectorAll( + "a.sidebar-tools-main-item, a.quarto-navigation-tool, a.quarto-navbar-tools, a.quarto-navbar-tools-item" + ); + for (let i = 0; i < sharingLinks.length; i++) { + const sharingLink = sharingLinks[i]; + const href = sharingLink.getAttribute("href"); + if (href) { + sharingLink.setAttribute( + "href", + href.replace("|url|", window.location.href) + ); + } + } + + // Scroll the active navigation item into view, if necessary + const navSidebar = window.document.querySelector("nav#quarto-sidebar"); + if (navSidebar) { + // Find the active item + const activeItem = navSidebar.querySelector("li.sidebar-item a.active"); + if (activeItem) { + // Wait for the scroll height and height to resolve by observing size changes on the + // nav element that is scrollable + const resizeObserver = new ResizeObserver((_entries) => { + // The bottom of the element + const elBottom = activeItem.offsetTop; + const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight; + + // The element height and scroll height are the same, then we are still loading + if (viewBottom !== navSidebar.scrollHeight) { + // Determine if the item isn't visible and scroll to it + if (elBottom >= viewBottom) { + navSidebar.scrollTop = elBottom; + } + + // stop observing now since we've completed the scroll + resizeObserver.unobserve(navSidebar); + } + }); + resizeObserver.observe(navSidebar); + } + } + } +}); diff --git a/docs/site_libs/quarto-search/autocomplete.umd.js b/docs/site_libs/quarto-search/autocomplete.umd.js new file mode 100644 index 0000000..6090a55 --- /dev/null +++ b/docs/site_libs/quarto-search/autocomplete.umd.js @@ -0,0 +1,3 @@ +/*! @algolia/autocomplete-js 1.19.1 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["@algolia/autocomplete-js"]={})}(this,(function(e){"use strict";function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function n(e){for(var n=1;n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function a(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,i,u,a=[],l=!0,c=!1;try{if(i=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;l=!1}else for(;!(l=(r=i.call(n)).done)&&(a.push(r.value),a.length!==t);l=!0);}catch(e){c=!0,o=e}finally{try{if(!l&&null!=n.return&&(u=n.return(),Object(u)!==u))return}finally{if(c)throw o}}return a}}(e,t)||c(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(e){return function(e){if(Array.isArray(e))return s(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||c(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function c(e,t){if(e){if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?s(e,t):void 0}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function x(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function N(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:20,n=[],r=0;r=3||2===n&&r>=4||1===n&&r>=10);function i(t,n,r){if(o&&void 0!==r){var i=r[0].__autocomplete_algoliaCredentials,u={"X-Algolia-Application-Id":i.appId,"X-Algolia-API-Key":i.apiKey};e.apply(void 0,[t].concat(D(n),[{headers:u}]))}else e.apply(void 0,[t].concat(D(n)))}return{init:function(t,n){e("init",{appId:t,apiKey:n})},setAuthenticatedUserToken:function(t){e("setAuthenticatedUserToken",t)},setUserToken:function(t){e("setUserToken",t)},clickedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&i("clickedObjectIDsAfterSearch",B(t),t[0].items)},clickedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&i("clickedObjectIDs",B(t),t[0].items)},clickedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r0&&e.apply(void 0,["clickedFilters"].concat(n))},convertedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&i("convertedObjectIDsAfterSearch",B(t),t[0].items)},convertedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&i("convertedObjectIDs",B(t),t[0].items)},convertedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r0&&e.apply(void 0,["convertedFilters"].concat(n))},viewedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&t.reduce((function(e,t){var n=t.items,r=k(t,A);return[].concat(D(e),D(q(N(N({},r),{},{objectIDs:(null==n?void 0:n.map((function(e){return e.objectID})))||r.objectIDs})).map((function(e){return{items:n,payload:e}}))))}),[]).forEach((function(e){var t=e.items;return i("viewedObjectIDs",[e.payload],t)}))},viewedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r0&&e.apply(void 0,["viewedFilters"].concat(n))}}}function L(e){var t=e.items.reduce((function(e,t){var n;return e[t.__autocomplete_indexName]=(null!==(n=e[t.__autocomplete_indexName])&&void 0!==n?n:[]).concat(t),e}),{});return Object.keys(t).map((function(e){return{index:e,items:t[e],algoliaSource:["autocomplete"]}}))}function F(e){return e.objectID&&e.__autocomplete_indexName&&e.__autocomplete_queryID}function U(e){return U="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},U(e)}function M(e){return function(e){if(Array.isArray(e))return H(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return H(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return H(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function H(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&z({onItemsChange:o,items:n,insights:c,state:t}))}}),0);return{name:"aa.algoliaInsightsPlugin",subscribe:function(e){var t=e.setContext,n=e.onSelect,r=e.onActive;function o(e){t({algoliaInsightsPlugin:{__algoliaSearchParameters:W(W({},a?{clickAnalytics:!0}:{}),e?{userToken:X(e)}:{}),insights:c}})}l("addAlgoliaAgent","insights-plugin"),o(),l("onUserTokenChange",(function(e){o(e)})),l("getUserToken",null,(function(e,t){o(t)})),n((function(e){var t=e.item,n=e.state,r=e.event,o=e.source;F(t)&&i({state:n,event:r,insights:c,item:t,insightsEvents:[W({eventName:"Item Selected"},j({item:t,items:o.getItems().filter(F)}))]})})),r((function(e){var t=e.item,n=e.source,r=e.state,o=e.event;F(t)&&u({state:r,event:o,insights:c,item:t,insightsEvents:[W({eventName:"Item Active"},j({item:t,items:n.getItems().filter(F)}))]})}))},onStateChange:function(e){var t=e.state;m({state:t})},__autocomplete_pluginOptions:e}}function J(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length>1?arguments[1]:void 0;return[].concat(M(t),["autocomplete-internal"],M(null!==(e=n.algoliaInsightsPlugin)&&void 0!==e&&e.__automaticInsights?["autocomplete-automatic"]:[]))}function X(e){return"number"==typeof e?e.toString():e}function Y(e,t){var n=t;return{then:function(t,r){return Y(e.then(ee(t,n,e),ee(r,n,e)),n)},catch:function(t){return Y(e.catch(ee(t,n,e)),n)},finally:function(t){return t&&n.onCancelList.push(t),Y(e.finally(ee(t&&function(){return n.onCancelList=[],t()},n,e)),n)},cancel:function(){n.isCanceled=!0;var e=n.onCancelList;n.onCancelList=[],e.forEach((function(e){e()}))},isCanceled:function(){return!0===n.isCanceled}}}function Z(e){return Y(e,{isCanceled:!1,onCancelList:[]})}function ee(e,t,n){return e?function(n){return t.isCanceled?n:e(n)}:n}var te,ne=!0;function re(e,t,n,r){if(!n)return null;if(e<0&&(null===t||null!==r&&0===t))return n+e;var o=(null===t?-1:t)+e;return o<=-1||o>=n?null===r?null:0:o}function oe(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function ie(e){for(var t=1;t=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,u=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return u=e.done,e},e:function(e){a=!0,i=e},f:function(){try{u||null==n.return||n.return()}finally{if(a)throw i}}}}function ce(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0?t.wait(Math.max.apply(Math,o)):void 0};function fe(e){var t=function(e){var t=e.collections.map((function(e){return e.items.length})).reduce((function(e,t,n){var r=(e[n-1]||0)+t;return e.push(r),e}),[]).reduce((function(t,n){return n<=e.activeItemId?t+1:t}),0);return e.collections[t]}(e);if(!t)return null;var n=t.items[function(e){for(var t=e.state,n=e.collection,r=!1,o=0,i=0;!1===r;){var u=t.collections[o];if(u===n){r=!0;break}i+=u.items.length,o++}return t.activeItemId-i}({state:e,collection:t})],r=t.source;return{item:n,itemInputValue:r.getItemInputValue({item:n,state:e}),itemUrl:r.getItemUrl({item:n,state:e}),source:r}}function pe(e,t,n){return[e,null==n?void 0:n.sourceId,t].filter(Boolean).join("-").replace(/\s/g,"")}var me=/((gt|sm)-|galaxy nexus)|samsung[- ]|samsungbrowser/i;function ve(e){return e.nativeEvent||e}function de(e){return de="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},de(e)}function ye(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function be(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==de(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==de(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===de(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ge(e,t,n){var r,o=t.initialState;return{getState:function(){return o},dispatch:function(r,i){var u=function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n0},reshape:function(e){return e.sources}},e),{},{id:null!==(n=e.id)&&void 0!==n?n:d(),plugins:o,initialState:Ae({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var n;null===(n=e.onStateChange)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onStateChange)||void 0===n?void 0:n.call(e,t)}))},onSubmit:function(t){var n;null===(n=e.onSubmit)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onSubmit)||void 0===n?void 0:n.call(e,t)}))},onReset:function(t){var n;null===(n=e.onReset)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onReset)||void 0===n?void 0:n.call(e,t)}))},getSources:function(n){return Promise.all([].concat(Pe(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return function(e,t){var n=[];return Promise.resolve(e(t)).then((function(e){return Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,n.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));n.push(e.sourceId);var t={getItemInputValue:function(e){return e.state.query},getItemUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onActive:_,onResolve:_};Object.keys(t).forEach((function(e){t[e].__default=!0}));var r=ie(ie({},t),e);return Promise.resolve(r)})))}))}(e,n)}))).then((function(e){return m(e)})).then((function(e){return e.map((function(e){return Ae(Ae({},e),{},{onSelect:function(n){e.onSelect(n),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,n)}))},onActive:function(n){e.onActive(n),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,n)}))},onResolve:function(n){e.onResolve(n),t.forEach((function(e){var t;return null===(t=e.onResolve)||void 0===t?void 0:t.call(e,n)}))}})}))}))},navigator:Ae({navigate:function(e){var t=e.itemUrl;r.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,n=r.open(t,"_blank","noopener");null==n||n.focus()},navigateNewWindow:function(e){var t=e.itemUrl;r.open(t,"_blank","noopener")}},e.navigator)})}function Ce(e){return Ce="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Ce(e)}function ke(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function xe(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var Je,Xe,Ye,Ze=null,et=(Je=-1,Xe=-1,Ye=void 0,function(e){var t=++Je;return Promise.resolve(e).then((function(e){return Ye&&t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function lt(e){return lt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},lt(e)}var ct=["props","refresh","store"],st=["inputElement","formElement","panelElement"],ft=["inputElement"],pt=["inputElement","maxLength"],mt=["source"],vt=["item","source"];function dt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function yt(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function ht(e){var t=e.props,n=e.refresh,r=e.store,o=gt(e,ct);return{getEnvironmentProps:function(e){var n=e.inputElement,o=e.formElement,i=e.panelElement;function u(e){!r.getState().isOpen&&r.pendingRequests.isEmpty()||e.target===n||!1===[o,i].some((function(t){return n=t,r=e.target,n===r||n.contains(r);var n,r}))&&(r.dispatch("blur",null),t.debug||r.pendingRequests.cancelAll())}return yt({onTouchStart:u,onMouseDown:u,onTouchMove:function(e){!1!==r.getState().isOpen&&n===t.environment.document.activeElement&&e.target!==n&&n.blur()}},gt(e,st))},getRootProps:function(e){return yt({role:"combobox","aria-expanded":r.getState().isOpen,"aria-haspopup":"listbox","aria-controls":r.getState().isOpen?r.getState().collections.map((function(e){var n=e.source;return pe(t.id,"list",n)})).join(" "):void 0,"aria-labelledby":pe(t.id,"label")},e)},getFormProps:function(e){e.inputElement;var i=gt(e,ft),u=function(i){var u;t.onSubmit(yt({event:i,refresh:n,state:r.getState()},o)),r.dispatch("submit",null),null===(u=e.inputElement)||void 0===u||u.blur()};return yt({action:"",noValidate:!0,role:"search",onSubmit:function(e){e.preventDefault();var n=se(t.plugins,r.pendingRequests);void 0!==n?n.then((function(){return u(e)})):u(e)},onReset:function(i){var u;i.preventDefault(),t.onReset(yt({event:i,refresh:n,state:r.getState()},o)),r.dispatch("reset",null),null===(u=e.inputElement)||void 0===u||u.focus()}},i)},getLabelProps:function(e){return yt({htmlFor:pe(t.id,"input"),id:pe(t.id,"label")},e)},getInputProps:function(e){var i;function u(e){(t.openOnFocus||Boolean(r.getState().query))&&tt(yt({event:e,props:t,query:r.getState().completion||r.getState().query,refresh:n,store:r},o)),r.dispatch("focus",null)}var a=e||{};a.inputElement;var l=a.maxLength,c=void 0===l?512:l,s=gt(a,pt),f=fe(r.getState()),p=function(e){return Boolean(e&&e.match(me))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),m=t.enterKeyHint||(null!=f&&f.itemUrl&&!p?"go":"search");return yt({"aria-autocomplete":"both","aria-activedescendant":r.getState().isOpen&&null!==r.getState().activeItemId?pe(t.id,"item-".concat(r.getState().activeItemId),null==f?void 0:f.source):void 0,"aria-controls":r.getState().isOpen?r.getState().collections.filter((function(e){return e.items.length>0})).map((function(e){var n=e.source;return pe(t.id,"list",n)})).join(" "):void 0,"aria-labelledby":pe(t.id,"label"),value:r.getState().completion||r.getState().query,id:pe(t.id,"input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:m,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:c,type:"search",onChange:function(e){var i=e.currentTarget.value;t.ignoreCompositionEvents&&ve(e).isComposing?o.setQuery(i):tt(yt({event:e,props:t,query:i.slice(0,c),refresh:n,store:r},o))},onCompositionEnd:function(e){tt(yt({event:e,props:t,query:e.currentTarget.value.slice(0,c),refresh:n,store:r},o))},onKeyDown:function(e){ve(e).isComposing||function(e){var t=e.event,n=e.props,r=e.refresh,o=e.store,i=at(e,rt);if("ArrowUp"===t.key||"ArrowDown"===t.key){var u=function(){var e=fe(o.getState()),t=n.environment.document.getElementById(pe(n.id,"item-".concat(o.getState().activeItemId),null==e?void 0:e.source));t&&(t.scrollIntoViewIfNeeded?t.scrollIntoViewIfNeeded(!1):t.scrollIntoView(!1))},a=function(){var e=fe(o.getState());if(null!==o.getState().activeItemId&&e){var n=e.item,u=e.itemInputValue,a=e.itemUrl,l=e.source;l.onActive(it({event:t,item:n,itemInputValue:u,itemUrl:a,refresh:r,source:l,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(n.openOnFocus||Boolean(o.getState().query))?tt(it({event:t,props:n,query:o.getState().query,refresh:r,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:n.defaultActiveItemId}),a(),setTimeout(u,0)})):(o.dispatch(t.key,{}),a(),u())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length}))){var l=se(n.plugins,o.pendingRequests);return void(void 0!==l?l.then(o.pendingRequests.cancelAll):n.debug||o.pendingRequests.cancelAll())}t.preventDefault();var c=fe(o.getState()),s=c.item,f=c.itemInputValue,p=c.itemUrl,m=c.source;if(t.metaKey||t.ctrlKey)void 0!==p&&(m.onSelect(it({event:t,item:s,itemInputValue:f,itemUrl:p,refresh:r,source:m,state:o.getState()},i)),n.navigator.navigateNewTab({itemUrl:p,item:s,state:o.getState()}));else if(t.shiftKey)void 0!==p&&(m.onSelect(it({event:t,item:s,itemInputValue:f,itemUrl:p,refresh:r,source:m,state:o.getState()},i)),n.navigator.navigateNewWindow({itemUrl:p,item:s,state:o.getState()}));else if(t.altKey);else{if(void 0!==p)return m.onSelect(it({event:t,item:s,itemInputValue:f,itemUrl:p,refresh:r,source:m,state:o.getState()},i)),void n.navigator.navigate({itemUrl:p,item:s,state:o.getState()});tt(it({event:t,nextState:{isOpen:!1},props:n,query:f,refresh:r,store:o},i)).then((function(){m.onSelect(it({event:t,item:s,itemInputValue:f,itemUrl:p,refresh:r,source:m,state:o.getState()},i))}))}}}(yt({event:e,props:t,refresh:n,store:r},o))},onFocus:u,onBlur:_,onClick:function(n){e.inputElement!==t.environment.document.activeElement||r.getState().isOpen||u(n)}},s)},getPanelProps:function(e){return yt({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){r.dispatch("mouseleave",null)}},e)},getListProps:function(e){var n=e||{},r=n.source,o=gt(n,mt);return yt({role:"listbox","aria-labelledby":pe(t.id,"label"),id:pe(t.id,"list",r)},o)},getItemProps:function(e){var i=e.item,u=e.source,a=gt(e,vt);return yt({id:pe(t.id,"item-".concat(i.__autocomplete_id),u),role:"option","aria-selected":r.getState().activeItemId===i.__autocomplete_id,onMouseMove:function(e){if(i.__autocomplete_id!==r.getState().activeItemId){r.dispatch("mousemove",i.__autocomplete_id);var t=fe(r.getState());if(null!==r.getState().activeItemId&&t){var u=t.item,a=t.itemInputValue,l=t.itemUrl,c=t.source;c.onActive(yt({event:e,item:u,itemInputValue:a,itemUrl:l,refresh:n,source:c,state:r.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var a=u.getItemInputValue({item:i,state:r.getState()}),l=u.getItemUrl({item:i,state:r.getState()});(l?Promise.resolve():tt(yt({event:e,nextState:{isOpen:!1},props:t,query:a,refresh:n,store:r},o))).then((function(){u.onSelect(yt({event:e,item:i,itemInputValue:a,itemUrl:l,refresh:n,source:u,state:r.getState()},o))}))}},a)}}}function _t(e){return _t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},_t(e)}function Ot(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function St(e){for(var t=1;t=5&&((o||!e&&5===r)&&(u.push(r,0,o,n),r=6),e&&(u.push(r,e,0,n),r=6)),o=""},l=0;l"===t?(r=1,o=""):o=t+o[0]:i?t===i?i="":o+=t:'"'===t||"'"===t?i=t:">"===t?(a(),r=1):r&&("="===t?(r=5,n=o,o=""):"/"===t&&(r<5||">"===e[l][c+1])?(a(),3===r&&(u=u[0]),r=u,(u=u[0]).push(2,0,r),r=0):" "===t||"\t"===t||"\n"===t||"\r"===t?(a(),r=2):o+=t),3===r&&"!--"===o&&(r=4,u=u[0])}return a(),u}(e)),t),arguments,[])).length>1?t:t[0]}var Ft=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-ClearIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","18"),n.setAttribute("height","18"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M5.293 6.707l5.293 5.293-5.293 5.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5.293-5.293 5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-5.293-5.293 5.293-5.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"),n.appendChild(r),n};function Ut(e,t){if("string"==typeof t){var n=e.document.querySelector(t);return"The element ".concat(JSON.stringify(t)," is not in the document."),n}return t}function Mt(){for(var e=arguments.length,t=new Array(e),n=0;n2&&(u.children=arguments.length>3?on.call(arguments,2):n),"function"==typeof e&&null!=e.defaultProps)for(i in e.defaultProps)void 0===u[i]&&(u[i]=e.defaultProps[i]);return gn(e,u,r,o,null)}function gn(e,t,n,r,o){var i={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==o?++an:o};return null==o&&null!=un.vnode&&un.vnode(i),i}function hn(e){return e.children}function _n(e,t){this.props=e,this.context=t}function On(e,t){if(null==t)return e.__?On(e.__,e.__.__k.indexOf(e)+1):null;for(var n;tt&&ln.sort(fn));Pn.__r=0}function wn(e,t,n,r,o,i,u,a,l,c){var s,f,p,m,v,d,y,b=r&&r.__k||mn,g=b.length;for(n.__k=[],s=0;s0?gn(m.type,m.props,m.key,m.ref?m.ref:null,m.__v):m)){if(m.__=n,m.__b=n.__b+1,null===(p=b[s])||p&&m.key==p.key&&m.type===p.type)b[s]=void 0;else for(f=0;f=0;t--)if((n=e.__k[t])&&(r=En(n)))return r;return null}function Dn(e,t,n){"-"===t[0]?e.setProperty(t,null==n?"":n):e[t]=null==n?"":"number"!=typeof n||vn.test(t)?n:n+"px"}function Cn(e,t,n,r,o){var i;e:if("style"===t)if("string"==typeof n)e.style.cssText=n;else{if("string"==typeof r&&(e.style.cssText=r=""),r)for(t in r)n&&t in n||Dn(e.style,t,"");if(n)for(t in n)r&&n[t]===r[t]||Dn(e.style,t,n[t])}else if("o"===t[0]&&"n"===t[1])i=t!==(t=t.replace(/Capture$/,"")),t=t.toLowerCase()in e?t.toLowerCase().slice(2):t.slice(2),e.l||(e.l={}),e.l[t+i]=n,n?r||e.addEventListener(t,i?xn:kn,i):e.removeEventListener(t,i?xn:kn,i);else if("dangerouslySetInnerHTML"!==t){if(o)t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!==t&&"height"!==t&&"href"!==t&&"list"!==t&&"form"!==t&&"tabIndex"!==t&&"download"!==t&&t in e)try{e[t]=null==n?"":n;break e}catch(e){}"function"==typeof n||(null==n||!1===n&&"-"!==t[4]?e.removeAttribute(t):e.setAttribute(t,n))}}function kn(e){return this.l[e.type+!1](un.event?un.event(e):e)}function xn(e){return this.l[e.type+!0](un.event?un.event(e):e)}function Nn(e,t,n,r,o,i,u,a,l){var c,s,f,p,m,v,d,y,b,g,h,_,O,S,j,P=t.type;if(void 0!==t.constructor)return null;null!=n.__h&&(l=n.__h,a=t.__e=n.__e,t.__h=null,i=[a]),(c=un.__b)&&c(t);try{e:if("function"==typeof P){if(y=t.props,b=(c=P.contextType)&&r[c.__c],g=c?b?b.props.value:c.__:r,n.__c?d=(s=t.__c=n.__c).__=s.__E:("prototype"in P&&P.prototype.render?t.__c=s=new P(y,g):(t.__c=s=new _n(y,g),s.constructor=P,s.render=Ln),b&&b.sub(s),s.props=y,s.state||(s.state={}),s.context=g,s.__n=r,f=s.__d=!0,s.__h=[],s._sb=[]),null==s.__s&&(s.__s=s.state),null!=P.getDerivedStateFromProps&&(s.__s==s.state&&(s.__s=dn({},s.__s)),dn(s.__s,P.getDerivedStateFromProps(y,s.__s))),p=s.props,m=s.state,s.__v=t,f)null==P.getDerivedStateFromProps&&null!=s.componentWillMount&&s.componentWillMount(),null!=s.componentDidMount&&s.__h.push(s.componentDidMount);else{if(null==P.getDerivedStateFromProps&&y!==p&&null!=s.componentWillReceiveProps&&s.componentWillReceiveProps(y,g),!s.__e&&null!=s.shouldComponentUpdate&&!1===s.shouldComponentUpdate(y,s.__s,g)||t.__v===n.__v){for(t.__v!==n.__v&&(s.props=y,s.state=s.__s,s.__d=!1),s.__e=!1,t.__e=n.__e,t.__k=n.__k,t.__k.forEach((function(e){e&&(e.__=t)})),h=0;h0&&void 0!==arguments[0]?arguments[0]:[];return{get:function(){return e},add:function(t){var n=e[e.length-1];(null==n?void 0:n.isHighlighted)===t.isHighlighted?e[e.length-1]={value:n.value+t.value,isHighlighted:n.isHighlighted}:e.push(t)}}}(n?[{value:n,isHighlighted:!1}]:[]);return t.forEach((function(e){var t=e.split(Un);r.add({value:t[0],isHighlighted:!0}),""!==t[1]&&r.add({value:t[1],isHighlighted:!1})})),r.get()}function Hn(e){return function(e){if(Array.isArray(e))return Vn(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Vn(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Vn(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Vn(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n",""":'"',"'":"'"},Kn=new RegExp(/\w/i),$n=/&(amp|quot|lt|gt|#39);/g,zn=RegExp($n.source);function Gn(e,t){var n,r,o,i=e[t],u=(null===(n=e[t+1])||void 0===n?void 0:n.isHighlighted)||!0,a=(null===(r=e[t-1])||void 0===r?void 0:r.isHighlighted)||!0;return Kn.test((o=i.value)&&zn.test(o)?o.replace($n,(function(e){return Qn[e]})):o)||a!==u?i.isHighlighted:a}function Jn(e){return Jn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Jn(e)}function Xn(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Yn(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function vr(e){return function(e){if(Array.isArray(e))return dr(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return dr(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return dr(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function dr(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;if(!_.value.core.openOnFocus&&!t.query)return n;var r=Boolean(y.current||_.value.renderer.renderNoResults);return!n&&r||n},__autocomplete_metadata:{userAgents:wr,options:e}}))})),j=f(n({collections:[],completion:null,context:{},isOpen:!1,query:"",activeItemId:null,status:"idle"},_.value.core.initialState)),P={getEnvironmentProps:_.value.renderer.getEnvironmentProps,getFormProps:_.value.renderer.getFormProps,getInputProps:_.value.renderer.getInputProps,getItemProps:_.value.renderer.getItemProps,getLabelProps:_.value.renderer.getLabelProps,getListProps:_.value.renderer.getListProps,getPanelProps:_.value.renderer.getPanelProps,getRootProps:_.value.renderer.getRootProps},w={setActiveItemId:S.value.setActiveItemId,setQuery:S.value.setQuery,setCollections:S.value.setCollections,setIsOpen:S.value.setIsOpen,setStatus:S.value.setStatus,setContext:S.value.setContext,refresh:S.value.refresh,navigator:S.value.navigator},I=m((function(){return Lt.bind(_.value.renderer.renderer.createElement)})),A=m((function(){return rn({autocomplete:S.value,autocompleteScopeApi:w,classNames:_.value.renderer.classNames,environment:_.value.core.environment,isDetached:O.value,placeholder:_.value.core.placeholder,propGetters:P,setIsModalOpen:k,state:j.current,translations:_.value.renderer.translations})}));function E(){Jt(A.value.panel,{style:O.value?{}:Pr({panelPlacement:_.value.renderer.panelPlacement,container:A.value.root,form:A.value.form,environment:_.value.core.environment})})}function D(e){j.current=e;var t={autocomplete:S.value,autocompleteScopeApi:w,classNames:_.value.renderer.classNames,components:_.value.renderer.components,container:_.value.renderer.container,html:I.value,dom:A.value,panelContainer:O.value?A.value.detachedContainer:_.value.renderer.panelContainer,propGetters:P,state:j.current,renderer:_.value.renderer.renderer},r=!b(e)&&!y.current&&_.value.renderer.renderNoResults||_.value.renderer.render;!function(e){var t=e.autocomplete,r=e.autocompleteScopeApi,o=e.dom,i=e.propGetters,u=e.state;Xt(o.root,i.getRootProps(n({state:u,props:t.getRootProps({})},r))),Xt(o.input,i.getInputProps(n({state:u,props:t.getInputProps({inputElement:o.input}),inputElement:o.input},r))),Jt(o.label,{hidden:"stalled"===u.status}),Jt(o.loadingIndicator,{hidden:"stalled"!==u.status}),Jt(o.clearButton,{hidden:!u.query}),Jt(o.detachedSearchButtonQuery,{textContent:u.query}),Jt(o.detachedSearchButtonPlaceholder,{hidden:Boolean(u.query)})}(t),function(e,t){var r=t.autocomplete,o=t.autocompleteScopeApi,u=t.classNames,a=t.html,l=t.dom,c=t.panelContainer,s=t.propGetters,f=t.state,p=t.components,m=t.renderer;if(f.isOpen){c.contains(l.panel)||"loading"===f.status||c.appendChild(l.panel),l.panel.classList.toggle("aa-Panel--stalled","stalled"===f.status);var v=f.collections.filter((function(e){var t=e.source,n=e.items;return t.templates.noResults||n.length>0})).map((function(e,t){var l=e.source,c=e.items;return m.createElement("section",{key:t,className:u.source,"data-autocomplete-source-id":l.sourceId},l.templates.header&&m.createElement("div",{className:u.sourceHeader},l.templates.header({components:p,createElement:m.createElement,Fragment:m.Fragment,items:c,source:l,state:f,html:a})),l.templates.noResults&&0===c.length?m.createElement("div",{className:u.sourceNoResults},l.templates.noResults({components:p,createElement:m.createElement,Fragment:m.Fragment,source:l,state:f,html:a})):m.createElement("ul",i({className:u.list},s.getListProps(n({state:f,props:r.getListProps({source:l})},o))),c.map((function(e){var t=r.getItemProps({item:e,source:l});return m.createElement("li",i({key:t.id,className:u.item},s.getItemProps(n({state:f,props:t},o))),l.templates.item({components:p,createElement:m.createElement,Fragment:m.Fragment,item:e,state:f,html:a}))}))),l.templates.footer&&m.createElement("div",{className:u.sourceFooter},l.templates.footer({components:p,createElement:m.createElement,Fragment:m.Fragment,items:c,source:l,state:f,html:a})))})),d=m.createElement(m.Fragment,null,m.createElement("div",{className:u.panelLayout},v),m.createElement("div",{className:"aa-GradientBottom"})),y=v.reduce((function(e,t){return e[t.props["data-autocomplete-source-id"]]=t,e}),{});e(n(n({children:d,state:f,sections:v,elements:y},m),{},{components:p,html:a},o),l.panel)}else c.contains(l.panel)&&c.removeChild(l.panel)}(r,t)}function C(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};l();var t=_.value.renderer,n=t.components,r=u(t,Ir);g.current=Vt(r,_.value.core,{components:Wt(n,(function(e){return!e.value.hasOwnProperty("__autocomplete_componentName")})),initialState:j.current},e),v(),c(),S.value.refresh().then((function(){D(j.current)}))}function k(e){e!==_.value.core.environment.document.body.contains(A.value.detachedOverlay)&&(e?(_.value.core.environment.document.body.appendChild(A.value.detachedOverlay),_.value.core.environment.document.body.classList.add("aa-Detached"),A.value.input.focus()):(_.value.core.environment.document.body.removeChild(A.value.detachedOverlay),_.value.core.environment.document.body.classList.remove("aa-Detached")))}return a((function(){var e=S.value.getEnvironmentProps({formElement:A.value.form,panelElement:A.value.panel,inputElement:A.value.input});return Jt(_.value.core.environment,e),function(){Jt(_.value.core.environment,Object.keys(e).reduce((function(e,t){return n(n({},e),{},o({},t,void 0))}),{}))}})),a((function(){var e=O.value?_.value.core.environment.document.body:_.value.renderer.panelContainer,t=O.value?A.value.detachedOverlay:A.value.panel;return O.value&&j.current.isOpen&&k(!0),D(j.current),function(){e.contains(t)&&(e.removeChild(t),e.classList.remove("aa-Detached"))}})),a((function(){var e=_.value.renderer.container;return e.appendChild(A.value.root),function(){e.removeChild(A.value.root)}})),a((function(){var e=p((function(e){D(e.state)}),0);return h.current=function(t){var n=t.state,r=t.prevState;(O.value&&r.isOpen!==n.isOpen&&k(n.isOpen),O.value||!n.isOpen||r.isOpen||E(),n.query!==r.query)&&_.value.core.environment.document.querySelectorAll(".aa-Panel--scrollable").forEach((function(e){0!==e.scrollTop&&(e.scrollTop=0)}));e({state:n})},function(){h.current=void 0}})),a((function(){var e=p((function(){var e=O.value;O.value=_.value.core.environment.matchMedia(_.value.renderer.detachedMediaQuery).matches,e!==O.value?C({}):requestAnimationFrame(E)}),20);return _.value.core.environment.addEventListener("resize",e),function(){_.value.core.environment.removeEventListener("resize",e)}})),a((function(){if(!O.value)return function(){};function e(e){A.value.detachedContainer.classList.toggle("aa-DetachedContainer--modal",e)}function t(t){e(t.matches)}var n=_.value.core.environment.matchMedia(getComputedStyle(_.value.core.environment.document.documentElement).getPropertyValue("--aa-detached-modal-media-query"));e(n.matches);var r=Boolean(n.addEventListener);return r?n.addEventListener("change",t):n.addListener(t),function(){r?n.removeEventListener("change",t):n.removeListener(t)}})),a((function(){return requestAnimationFrame(E),function(){}})),n(n({},w),{},{update:C,destroy:function(){l()}})},e.getAlgoliaFacets=function(e){var t=Ar({transformResponse:function(e){return e.facetHits}}),r=e.queries.map((function(e){return n(n({},e),{},{type:"facet"})}));return t(n(n({},e),{},{queries:r}))},e.getAlgoliaResults=Er,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/docs/site_libs/quarto-search/fuse.min.js b/docs/site_libs/quarto-search/fuse.min.js new file mode 100644 index 0000000..adc2835 --- /dev/null +++ b/docs/site_libs/quarto-search/fuse.min.js @@ -0,0 +1,9 @@ +/** + * Fuse.js v6.6.2 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2022 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(C).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),c=parseFloat(Math.round(o*r)/r);return n.set(i,c),c},clear:function(){n.clear()}}}var $=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?I.getFn:n,o=t.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o;r(this,e),this.norm=E(c,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,g(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();g(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?I.getFn:r,o=n.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o,a=new $({getFn:i,fieldNormWeight:c});return a.setKeys(e.map(_)),a.setSources(t),a.create(),a}function R(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,c=t.expectedLocation,a=void 0===c?0:c,s=t.distance,u=void 0===s?I.distance:s,h=t.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=r/e.length;if(l)return f;var d=Math.abs(a-o);return u?f+d/u:d?1:f}function N(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:I.minMatchCharLength,n=[],r=-1,i=-1,o=0,c=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}var P=32;function W(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,c=void 0===o?I.location:o,a=i.threshold,s=void 0===a?I.threshold:a,u=i.distance,h=void 0===u?I.distance:u,l=i.includeMatches,f=void 0===l?I.includeMatches:l,d=i.findAllMatches,v=void 0===d?I.findAllMatches:d,g=i.minMatchCharLength,y=void 0===g?I.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?I.isCaseSensitive:p,k=i.ignoreLocation,M=void 0===k?I.ignoreLocation:k;if(r(this,e),this.options={location:c,threshold:s,distance:h,includeMatches:f,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:M},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var b=function(e,t){n.chunks.push({pattern:e,alphabet:W(e),startIndex:t})},x=this.pattern.length;if(x>P){for(var w=0,L=x%P,S=x-L;w3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?I.location:i,c=r.distance,a=void 0===c?I.distance:c,s=r.threshold,u=void 0===s?I.threshold:s,h=r.findAllMatches,l=void 0===h?I.findAllMatches:h,f=r.minMatchCharLength,d=void 0===f?I.minMatchCharLength:f,v=r.includeMatches,g=void 0===v?I.includeMatches:v,y=r.ignoreLocation,p=void 0===y?I.ignoreLocation:y;if(t.length>P)throw new Error(w(P));for(var m,k=t.length,M=e.length,b=Math.max(0,Math.min(o,M)),x=u,L=b,S=d>1||g,_=S?Array(M):[];(m=e.indexOf(t,L))>-1;){var O=R(t,{currentLocation:m,expectedLocation:b,distance:a,ignoreLocation:p});if(x=Math.min(O,x),L=m+k,S)for(var j=0;j=z;q-=1){var B=q-1,J=n[e.charAt(B)];if(S&&(_[B]=+!!J),K[q]=(K[q+1]<<1|1)&J,F&&(K[q]|=(A[q+1]|A[q])<<1|1|A[q+1]),K[q]&$&&(C=R(t,{errors:F,currentLocation:B,expectedLocation:b,distance:a,ignoreLocation:p}))<=x){if(x=C,(L=B)<=b)break;z=Math.max(1,2*b-L)}}if(R(t,{errors:F+1,currentLocation:b,expectedLocation:b,distance:a,ignoreLocation:p})>x)break;A=K}var U={isMatch:L>=0,score:Math.max(.001,C)};if(S){var V=N(_,d);V.length?g&&(U.indices=V):U.isMatch=!1}return U}(e,n,i,{location:c+o,distance:a,threshold:s,findAllMatches:u,minMatchCharLength:h,includeMatches:r,ignoreLocation:l}),p=y.isMatch,m=y.score,k=y.indices;p&&(g=!0),v+=m,p&&k&&(d=[].concat(f(d),f(k)))}));var y={isMatch:g,score:g?v/this.chunks.length:1};return g&&r&&(y.indices=d),y}}]),e}(),z=function(){function e(t){r(this,e),this.pattern=t}return o(e,[{key:"search",value:function(){}}],[{key:"isMultiMatch",value:function(e){return D(e,this.multiRegex)}},{key:"isSingleMatch",value:function(e){return D(e,this.singleRegex)}}]),e}();function D(e,t){var n=e.match(t);return n?n[1]:null}var K=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"exact"}},{key:"multiRegex",get:function(){return/^="(.*)"$/}},{key:"singleRegex",get:function(){return/^=(.*)$/}}]),n}(z),q=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=-1===e.indexOf(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"$/}},{key:"singleRegex",get:function(){return/^!(.*)$/}}]),n}(z),B=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"prefix-exact"}},{key:"multiRegex",get:function(){return/^\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^\^(.*)$/}}]),n}(z),J=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-prefix-exact"}},{key:"multiRegex",get:function(){return/^!\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^!\^(.*)$/}}]),n}(z),U=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[e.length-this.pattern.length,e.length-1]}}}],[{key:"type",get:function(){return"suffix-exact"}},{key:"multiRegex",get:function(){return/^"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^(.*)\$$/}}]),n}(z),V=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-suffix-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^!(.*)\$$/}}]),n}(z),G=function(e){a(n,e);var t=l(n);function n(e){var i,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},c=o.location,a=void 0===c?I.location:c,s=o.threshold,u=void 0===s?I.threshold:s,h=o.distance,l=void 0===h?I.distance:h,f=o.includeMatches,d=void 0===f?I.includeMatches:f,v=o.findAllMatches,g=void 0===v?I.findAllMatches:v,y=o.minMatchCharLength,p=void 0===y?I.minMatchCharLength:y,m=o.isCaseSensitive,k=void 0===m?I.isCaseSensitive:m,M=o.ignoreLocation,b=void 0===M?I.ignoreLocation:M;return r(this,n),(i=t.call(this,e))._bitapSearch=new T(e,{location:a,threshold:u,distance:l,includeMatches:d,findAllMatches:g,minMatchCharLength:p,isCaseSensitive:k,ignoreLocation:b}),i}return o(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(z),H=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){for(var t,n=0,r=[],i=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+i,r.push([t,n-1]);var o=!!r.length;return{isMatch:o,score:o?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(z),Q=[K,H,B,J,V,U,q,G],X=Q.length,Y=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;function Z(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(Y).filter((function(e){return e&&!!e.trim()})),r=[],i=0,o=n.length;i1&&void 0!==arguments[1]?arguments[1]:{},i=n.isCaseSensitive,o=void 0===i?I.isCaseSensitive:i,c=n.includeMatches,a=void 0===c?I.includeMatches:c,s=n.minMatchCharLength,u=void 0===s?I.minMatchCharLength:s,h=n.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=n.findAllMatches,d=void 0===f?I.findAllMatches:f,v=n.location,g=void 0===v?I.location:v,y=n.threshold,p=void 0===y?I.threshold:y,m=n.distance,k=void 0===m?I.distance:m;r(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:u,findAllMatches:d,ignoreLocation:l,location:g,threshold:p,distance:k},this.pattern=o?t:t.toLowerCase(),this.query=Z(this.pattern,this.options)}return o(e,[{key:"searchIn",value:function(e){var t=this.query;if(!t)return{isMatch:!1,score:1};var n=this.options,r=n.includeMatches;e=n.isCaseSensitive?e:e.toLowerCase();for(var i=0,o=[],c=0,a=0,s=t.length;a-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function ve(e,t){t.score=e.score}function ge(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?I.includeMatches:r,o=n.includeScore,c=void 0===o?I.includeScore:o,a=[];return i&&a.push(de),c&&a.push(ve),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return a.length&&a.forEach((function(t){t(e,r)})),r}))}var ye=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;r(this,e),this.options=t(t({},I),i),this.options.useExtendedSearch,this._keyStore=new S(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof $))throw new Error("Incorrect 'index' type");this._myIndex=t||F(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){k(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.limit,r=void 0===n?-1:n,i=this.options,o=i.includeMatches,c=i.includeScore,a=i.shouldSort,s=i.sortFn,u=i.ignoreFieldNorm,h=g(e)?g(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return fe(h,{ignoreFieldNorm:u}),a&&h.sort(s),y(r)&&r>-1&&(h=h.slice(0,r)),ge(h,this._docs,{includeMatches:o,includeScore:c})}},{key:"_searchStringList",value:function(e){var t=re(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(k(n)){var c=t.searchIn(n),a=c.isMatch,s=c.score,u=c.indices;a&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:u}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=function(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).auto,r=void 0===n||n,i=function e(n){var i=Object.keys(n),o=ue(n);if(!o&&i.length>1&&!se(n))return e(le(n));if(he(n)){var c=o?n[ce]:i[0],a=o?n[ae]:n[c];if(!g(a))throw new Error(x(c));var s={keyId:j(c),pattern:a};return r&&(s.searcher=re(a,t)),s}var u={children:[],operator:i[0]};return i.forEach((function(t){var r=n[t];v(r)&&r.forEach((function(t){u.children.push(e(t))}))})),u};return se(e)||(e=le(e)),i(e)}(e,this.options),r=function e(n,r,i){if(!n.children){var o=n.keyId,c=n.searcher,a=t._findMatches({key:t._keyStore.get(o),value:t._myIndex.getValueForItemAtKeyId(r,o),searcher:c});return a&&a.length?[{idx:i,item:r,matches:a}]:[]}for(var s=[],u=0,h=n.children.length;u1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?I.getFn:n,i=t.fieldNormWeight,o=void 0===i?I.fieldNormWeight:i,c=e.keys,a=e.records,s=new $({getFn:r,fieldNormWeight:o});return s.setKeys(c),s.setIndexRecords(a),s},ye.config=I,function(){ne.push.apply(ne,arguments)}(te),ye},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/docs/site_libs/quarto-search/quarto-search.js b/docs/site_libs/quarto-search/quarto-search.js new file mode 100644 index 0000000..d788a95 --- /dev/null +++ b/docs/site_libs/quarto-search/quarto-search.js @@ -0,0 +1,1290 @@ +const kQueryArg = "q"; +const kResultsArg = "show-results"; + +// If items don't provide a URL, then both the navigator and the onSelect +// function aren't called (and therefore, the default implementation is used) +// +// We're using this sentinel URL to signal to those handlers that this +// item is a more item (along with the type) and can be handled appropriately +const kItemTypeMoreHref = "0767FDFD-0422-4E5A-BC8A-3BE11E5BBA05"; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Ensure that search is available on this page. If it isn't, + // should return early and not do anything + var searchEl = window.document.getElementById("quarto-search"); + if (!searchEl) return; + + const { autocomplete } = window["@algolia/autocomplete-js"]; + + let quartoSearchOptions = {}; + let language = {}; + const searchOptionEl = window.document.getElementById( + "quarto-search-options" + ); + if (searchOptionEl) { + const jsonStr = searchOptionEl.textContent; + quartoSearchOptions = JSON.parse(jsonStr); + language = quartoSearchOptions.language; + } + + // note the search mode + if (quartoSearchOptions.type === "overlay") { + searchEl.classList.add("type-overlay"); + } else { + searchEl.classList.add("type-textbox"); + } + + // Used to determine highlighting behavior for this page + // A `q` query param is expected when the user follows a search + // to this page + const currentUrl = new URL(window.location); + const query = currentUrl.searchParams.get(kQueryArg); + const showSearchResults = currentUrl.searchParams.get(kResultsArg); + const mainEl = window.document.querySelector("main"); + + // highlight matches on the page + if (query && mainEl) { + // perform any highlighting + highlight(escapeRegExp(query), mainEl); + + // fix up the URL to remove the q query param + const replacementUrl = new URL(window.location); + replacementUrl.searchParams.delete(kQueryArg); + window.history.replaceState({}, "", replacementUrl); + } + + // function to clear highlighting on the page when the search query changes + // (e.g. if the user edits the query or clears it) + let highlighting = true; + const resetHighlighting = (searchTerm) => { + if (mainEl && highlighting && query && searchTerm !== query) { + clearHighlight(query, mainEl); + highlighting = false; + } + }; + + // Clear search highlighting when the user scrolls sufficiently + const resetFn = () => { + resetHighlighting(""); + window.removeEventListener("quarto-hrChanged", resetFn); + window.removeEventListener("quarto-sectionChanged", resetFn); + }; + + // Register this event after the initial scrolling and settling of events + // on the page + window.addEventListener("quarto-hrChanged", resetFn); + window.addEventListener("quarto-sectionChanged", resetFn); + + // Responsively switch to overlay mode if the search is present on the navbar + // Note that switching the sidebar to overlay mode requires more coordinate (not just + // the media query since we generate different HTML for sidebar overlays than we do + // for sidebar input UI) + const detachedMediaQuery = + quartoSearchOptions.type === "overlay" ? "all" : "(max-width: 991px)"; + + // If configured, include the analytics client to send insights + const plugins = configurePlugins(quartoSearchOptions); + + let lastState = null; + const { setIsOpen, setQuery, setCollections } = autocomplete({ + container: searchEl, + detachedMediaQuery: detachedMediaQuery, + defaultActiveItemId: 0, + panelContainer: "#quarto-search-results", + panelPlacement: quartoSearchOptions["panel-placement"], + debug: false, + openOnFocus: true, + plugins, + classNames: { + form: "d-flex", + }, + placeholder: language["search-text-placeholder"], + translations: { + clearButtonTitle: language["search-clear-button-title"], + detachedCancelButtonText: language["search-detached-cancel-button-title"], + submitButtonTitle: language["search-submit-button-title"], + }, + initialState: { + query, + }, + getItemUrl({ item }) { + return item.href; + }, + onStateChange({ state }) { + // If this is a file URL, note that + + // Perhaps reset highlighting + resetHighlighting(state.query); + + // If the panel just opened, ensure the panel is positioned properly + if (state.isOpen) { + if (lastState && !lastState.isOpen) { + setTimeout(() => { + positionPanel(quartoSearchOptions["panel-placement"]); + }, 150); + } + } + + // Perhaps show the copy link + showCopyLink(state.query, quartoSearchOptions); + + lastState = state; + }, + reshape({ sources, state }) { + return sources.map((source) => { + try { + const items = source.getItems(); + + // Validate the items + validateItems(items); + + // group the items by document + const groupedItems = new Map(); + items.forEach((item) => { + const hrefParts = item.href.split("#"); + const baseHref = hrefParts[0]; + const isDocumentItem = hrefParts.length === 1; + + const items = groupedItems.get(baseHref); + if (!items) { + groupedItems.set(baseHref, [item]); + } else { + // If the href for this item matches the document + // exactly, place this item first as it is the item that represents + // the document itself + if (isDocumentItem) { + items.unshift(item); + } else { + items.push(item); + } + groupedItems.set(baseHref, items); + } + }); + + const reshapedItems = []; + let count = 1; + for (const [_key, value] of groupedItems) { + const firstItem = value[0]; + reshapedItems.push({ + ...firstItem, + type: kItemTypeDoc, + }); + + const collapseMatches = quartoSearchOptions["collapse-after"]; + const collapseCount = + typeof collapseMatches === "number" ? collapseMatches : 1; + + if (value.length > 1) { + const target = `search-more-${count}`; + const isExpanded = + state.context.expanded && + state.context.expanded.includes(target); + + const remainingCount = value.length - collapseCount; + + for (let i = 1; i < value.length; i++) { + if (collapseMatches && i === collapseCount) { + reshapedItems.push({ + target, + title: isExpanded + ? language["search-hide-matches-text"] + : remainingCount === 1 + ? `${remainingCount} ${language["search-more-match-text"]}` + : `${remainingCount} ${language["search-more-matches-text"]}`, + type: kItemTypeMore, + href: kItemTypeMoreHref, + }); + } + + if (isExpanded || !collapseMatches || i < collapseCount) { + reshapedItems.push({ + ...value[i], + type: kItemTypeItem, + target, + }); + } + } + } + count += 1; + } + + return { + ...source, + getItems() { + return reshapedItems; + }, + }; + } catch (error) { + // Some form of error occurred + return { + ...source, + getItems() { + return [ + { + title: error.name || "An Error Occurred While Searching", + text: + error.message || + "An unknown error occurred while attempting to perform the requested search.", + type: kItemTypeError, + }, + ]; + }, + }; + } + }); + }, + navigator: { + navigate({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.location.assign(itemUrl); + } + }, + navigateNewTab({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + const windowReference = window.open(itemUrl, "_blank", "noopener"); + if (windowReference) { + windowReference.focus(); + } + } + }, + navigateNewWindow({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.open(itemUrl, "_blank", "noopener"); + } + }, + }, + getSources({ state, setContext, setActiveItemId, refresh }) { + return [ + { + sourceId: "documents", + getItemUrl({ item }) { + if (item.href) { + return offsetURL(item.href); + } else { + return undefined; + } + }, + onSelect({ + item, + state, + setContext, + setIsOpen, + setActiveItemId, + refresh, + }) { + if (item.type === kItemTypeMore) { + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + + // Toggle more + setIsOpen(true); + } + }, + getItems({ query }) { + if (query === null || query === "") { + return []; + } + + const limit = quartoSearchOptions.limit; + if (quartoSearchOptions.algolia) { + return algoliaSearch(query, limit, quartoSearchOptions.algolia); + } else { + // Fuse search options + const fuseSearchOptions = { + isCaseSensitive: false, + shouldSort: true, + minMatchCharLength: 2, + limit: limit, + }; + + return readSearchData().then(function (fuse) { + return fuseSearch(query, fuse, fuseSearchOptions); + }); + } + }, + templates: { + noResults({ createElement }) { + const hasQuery = lastState.query; + + return createElement( + "div", + { + class: `quarto-search-no-results${ + hasQuery ? "" : " no-query" + }`, + }, + language["search-no-results-text"] + ); + }, + header({ items, createElement }) { + // count the documents + const count = items.filter((item) => { + return item.type === kItemTypeDoc; + }).length; + + if (count > 0) { + return createElement( + "div", + { class: "search-result-header" }, + `${count} ${language["search-matching-documents-text"]}` + ); + } else { + return createElement( + "div", + { class: "search-result-header-no-results" }, + `` + ); + } + }, + footer({ _items, createElement }) { + if ( + quartoSearchOptions.algolia && + quartoSearchOptions.algolia["show-logo"] + ) { + const libDir = quartoSearchOptions.algolia["libDir"]; + const logo = createElement("img", { + src: offsetURL( + `${libDir}/quarto-search/search-by-algolia.svg` + ), + class: "algolia-search-logo", + }); + return createElement( + "a", + { href: "http://www.algolia.com/" }, + logo + ); + } + }, + + item({ item, createElement }) { + return renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh, + quartoSearchOptions + ); + }, + }, + }, + ]; + }, + }); + + window.quartoOpenSearch = () => { + setIsOpen(false); + setIsOpen(true); + focusSearchInput(); + }; + + document.addEventListener("keyup", (event) => { + const { key } = event; + const kbds = quartoSearchOptions["keyboard-shortcut"]; + const focusedEl = document.activeElement; + + const isFormElFocused = [ + "input", + "select", + "textarea", + "button", + "option", + ].find((tag) => { + return focusedEl.tagName.toLowerCase() === tag; + }); + + if ( + kbds && + kbds.includes(key) && + !isFormElFocused && + !document.activeElement.isContentEditable + ) { + event.preventDefault(); + window.quartoOpenSearch(); + } + }); + + // Remove the labeleledby attribute since it is pointing + // to a non-existent label + if (quartoSearchOptions.type === "overlay") { + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + if (inputEl) { + inputEl.removeAttribute("aria-labelledby"); + } + } + + function throttle(func, wait) { + let waiting = false; + return function () { + if (!waiting) { + func.apply(this, arguments); + waiting = true; + setTimeout(function () { + waiting = false; + }, wait); + } + }; + } + + // If the main document scrolls dismiss the search results + // (otherwise, since they're floating in the document they can scroll with the document) + window.document.body.onscroll = throttle(() => { + // Only do this if we're not detached + // Bug #7117 + // This will happen when the keyboard is shown on ios (resulting in a scroll) + // which then closed the search UI + if (!window.matchMedia(detachedMediaQuery).matches) { + setIsOpen(false); + } + }, 50); + + if (showSearchResults) { + setIsOpen(true); + focusSearchInput(); + } +}); + +function configurePlugins(quartoSearchOptions) { + const autocompletePlugins = []; + const algoliaOptions = quartoSearchOptions.algolia; + if ( + algoliaOptions && + algoliaOptions["analytics-events"] && + algoliaOptions["search-only-api-key"] && + algoliaOptions["application-id"] + ) { + const apiKey = algoliaOptions["search-only-api-key"]; + const appId = algoliaOptions["application-id"]; + + // Aloglia insights may not be loaded because they require cookie consent + // Use deferred loading so events will start being recorded when/if consent + // is granted. + const algoliaInsightsDeferredPlugin = deferredLoadPlugin(() => { + if ( + window.aa && + window["@algolia/autocomplete-plugin-algolia-insights"] + ) { + window.aa("init", { + appId, + apiKey, + useCookie: true, + }); + + const { createAlgoliaInsightsPlugin } = + window["@algolia/autocomplete-plugin-algolia-insights"]; + // Register the insights client + const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({ + insightsClient: window.aa, + onItemsChange({ insights, insightsEvents }) { + const events = insightsEvents.flatMap((event) => { + // This API limits the number of items per event to 20 + const chunkSize = 20; + const itemChunks = []; + const eventItems = event.items; + for (let i = 0; i < eventItems.length; i += chunkSize) { + itemChunks.push(eventItems.slice(i, i + chunkSize)); + } + // Split the items into multiple events that can be sent + const events = itemChunks.map((items) => { + return { + ...event, + items, + }; + }); + return events; + }); + + for (const event of events) { + insights.viewedObjectIDs(event); + } + }, + }); + return algoliaInsightsPlugin; + } + }); + + // Add the plugin + autocompletePlugins.push(algoliaInsightsDeferredPlugin); + return autocompletePlugins; + } +} + +// For plugins that may not load immediately, create a wrapper +// plugin and forward events and plugin data once the plugin +// is initialized. This is useful for cases like cookie consent +// which may prevent the analytics insights event plugin from initializing +// immediately. +function deferredLoadPlugin(createPlugin) { + let plugin = undefined; + let subscribeObj = undefined; + const wrappedPlugin = () => { + if (!plugin && subscribeObj) { + plugin = createPlugin(); + if (plugin && plugin.subscribe) { + plugin.subscribe(subscribeObj); + } + } + return plugin; + }; + + return { + subscribe: (obj) => { + subscribeObj = obj; + }, + onStateChange: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onStateChange) { + plugin.onStateChange(obj); + } + }, + onSubmit: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onSubmit) { + plugin.onSubmit(obj); + } + }, + onReset: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onReset) { + plugin.onReset(obj); + } + }, + getSources: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.getSources) { + return plugin.getSources(obj); + } else { + return Promise.resolve([]); + } + }, + data: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.data) { + plugin.data(obj); + } + }, + }; +} + +function validateItems(items) { + // Validate the first item + if (items.length > 0) { + const item = items[0]; + const missingFields = []; + if (item.href == undefined) { + missingFields.push("href"); + } + if (!item.title == undefined) { + missingFields.push("title"); + } + if (!item.text == undefined) { + missingFields.push("text"); + } + + if (missingFields.length === 1) { + throw { + name: `Error: Search index is missing the ${missingFields[0]} field.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items include the ${missingFields[0]} field or use index-fields in your _quarto.yml file to specify the field names.`, + }; + } else if (missingFields.length > 1) { + const missingFieldList = missingFields + .map((field) => { + return `${field}`; + }) + .join(", "); + + throw { + name: `Error: Search index is missing the following fields: ${missingFieldList}.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items includes the following fields: ${missingFieldList}, or use index-fields in your _quarto.yml file to specify the field names.`, + }; + } + } +} + +let lastQuery = null; +function showCopyLink(query, options) { + const language = options.language; + lastQuery = query; + // Insert share icon + const inputSuffixEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix" + ); + + if (inputSuffixEl) { + let copyButtonEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix .aa-CopyButton" + ); + + if (copyButtonEl === null) { + copyButtonEl = window.document.createElement("button"); + copyButtonEl.setAttribute("class", "aa-CopyButton"); + copyButtonEl.setAttribute("type", "button"); + copyButtonEl.setAttribute("title", language["search-copy-link-title"]); + copyButtonEl.onmousedown = (e) => { + e.preventDefault(); + e.stopPropagation(); + }; + + const linkIcon = "bi-clipboard"; + const checkIcon = "bi-check2"; + + const shareIconEl = window.document.createElement("i"); + shareIconEl.setAttribute("class", `bi ${linkIcon}`); + copyButtonEl.appendChild(shareIconEl); + inputSuffixEl.prepend(copyButtonEl); + + const clipboard = new window.ClipboardJS(".aa-CopyButton", { + text: function (_trigger) { + const copyUrl = new URL(window.location); + copyUrl.searchParams.set(kQueryArg, lastQuery); + copyUrl.searchParams.set(kResultsArg, "1"); + return copyUrl.toString(); + }, + }); + clipboard.on("success", function (e) { + // Focus the input + + // button target + const button = e.trigger; + const icon = button.querySelector("i.bi"); + + // flash "checked" + icon.classList.add(checkIcon); + icon.classList.remove(linkIcon); + setTimeout(function () { + icon.classList.remove(checkIcon); + icon.classList.add(linkIcon); + }, 1000); + }); + } + + // If there is a query, show the link icon + if (copyButtonEl) { + if (lastQuery && options["copy-button"]) { + copyButtonEl.style.display = "flex"; + } else { + copyButtonEl.style.display = "none"; + } + } + } +} + +/* Search Index Handling */ +// create the index +var fuseIndex = undefined; +var shownWarning = false; + +// fuse index options +const kFuseIndexOptions = { + keys: [ + { name: "title", weight: 20 }, + { name: "section", weight: 20 }, + { name: "text", weight: 10 }, + ], + ignoreLocation: true, + threshold: 0.1, +}; + +async function readSearchData() { + // Initialize the search index on demand + if (fuseIndex === undefined) { + if (window.location.protocol === "file:" && !shownWarning) { + window.alert( + "Search requires JavaScript features disabled when running in file://... URLs. In order to use search, please run this document in a web server." + ); + shownWarning = true; + return; + } + const fuse = new window.Fuse([], kFuseIndexOptions); + + // fetch the main search.json + const response = await fetch(offsetURL("search.json")); + if (response.status == 200) { + return response.json().then(function (searchDocs) { + searchDocs.forEach(function (searchDoc) { + fuse.add(searchDoc); + }); + fuseIndex = fuse; + return fuseIndex; + }); + } else { + return Promise.reject( + new Error( + "Unexpected status from search index request: " + response.status + ) + ); + } + } + + return fuseIndex; +} + +function inputElement() { + return window.document.body.querySelector(".aa-Form .aa-Input"); +} + +function focusSearchInput() { + setTimeout(() => { + const inputEl = inputElement(); + if (inputEl) { + inputEl.focus(); + } + }, 50); +} + +/* Panels */ +const kItemTypeDoc = "document"; +const kItemTypeMore = "document-more"; +const kItemTypeItem = "document-item"; +const kItemTypeError = "error"; + +function renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh, + quartoSearchOptions +) { + switch (item.type) { + case kItemTypeDoc: + return createDocumentCard( + createElement, + "file-richtext", + item.title, + item.section, + item.text, + item.href, + item.crumbs, + quartoSearchOptions + ); + case kItemTypeMore: + return createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh + ); + case kItemTypeItem: + return createSectionCard( + createElement, + item.section, + item.text, + item.href + ); + case kItemTypeError: + return createErrorCard(createElement, item.title, item.text); + default: + return undefined; + } +} + +function createDocumentCard( + createElement, + icon, + title, + section, + text, + href, + crumbs, + quartoSearchOptions +) { + const iconEl = createElement("i", { + class: `bi bi-${icon} search-result-icon`, + }); + const titleEl = createElement("p", { class: "search-result-title" }, title); + const titleContents = [iconEl, titleEl]; + const showParent = quartoSearchOptions["show-item-context"]; + if (crumbs && showParent) { + let crumbsOut = undefined; + const crumbClz = ["search-result-crumbs"]; + if (showParent === "root") { + crumbsOut = crumbs.length > 1 ? crumbs[0] : undefined; + } else if (showParent === "parent") { + crumbsOut = crumbs.length > 1 ? crumbs[crumbs.length - 2] : undefined; + } else { + crumbsOut = crumbs.length > 1 ? crumbs.join(" > ") : undefined; + crumbClz.push("search-result-crumbs-wrap"); + } + + const crumbEl = createElement( + "p", + { class: crumbClz.join(" ") }, + crumbsOut + ); + titleContents.push(crumbEl); + } + + const titleContainerEl = createElement( + "div", + { class: "search-result-title-container" }, + titleContents + ); + + const textEls = []; + if (section) { + const sectionEl = createElement( + "p", + { class: "search-result-section" }, + section + ); + textEls.push(sectionEl); + } + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + textEls.push(descEl); + + const textContainerEl = createElement( + "div", + { class: "search-result-text-container" }, + textEls + ); + + const containerEl = createElement( + "div", + { + class: "search-result-container", + }, + [titleContainerEl, textContainerEl] + ); + + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + containerEl + ); + + const classes = ["search-result-doc", "search-item"]; + if (!section) { + classes.push("document-selectable"); + } + + return createElement( + "div", + { + class: classes.join(" "), + }, + linkEl + ); +} + +function createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh +) { + const moreCardEl = createElement( + "div", + { + class: "search-result-more search-item", + onClick: (e) => { + // Handle expanding the sections by adding the expanded + // section to the list of expanded sections + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + e.stopPropagation(); + }, + }, + item.title + ); + + return moreCardEl; +} + +function toggleExpanded(item, state, setContext, setActiveItemId, refresh) { + const expanded = state.context.expanded || []; + if (expanded.includes(item.target)) { + setContext({ + expanded: expanded.filter((target) => target !== item.target), + }); + } else { + setContext({ expanded: [...expanded, item.target] }); + } + + refresh(); + setActiveItemId(item.__autocomplete_id); +} + +function createSectionCard(createElement, section, text, href) { + const sectionEl = createSection(createElement, section, text, href); + return createElement( + "div", + { + class: "search-result-doc-section search-item", + }, + sectionEl + ); +} + +function createSection(createElement, title, text, href) { + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { class: "search-result-section" }, title); + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + [titleEl, descEl] + ); + return linkEl; +} + +function createErrorCard(createElement, title, text) { + const descEl = createElement("p", { + class: "search-error-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { + class: "search-error-title", + dangerouslySetInnerHTML: { + __html: ` ${title}`, + }, + }); + const errorEl = createElement("div", { class: "search-error" }, [ + titleEl, + descEl, + ]); + return errorEl; +} + +function positionPanel(pos) { + const panelEl = window.document.querySelector( + "#quarto-search-results .aa-Panel" + ); + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + + if (panelEl && inputEl) { + panelEl.style.top = `${Math.round(panelEl.offsetTop)}px`; + if (pos === "start") { + panelEl.style.left = `${Math.round(inputEl.left)}px`; + } else { + panelEl.style.right = `${Math.round(inputEl.offsetRight)}px`; + } + } +} + +/* Highlighting */ +// highlighting functions +function highlightMatch(query, text) { + if (text) { + const start = text.toLowerCase().indexOf(query.toLowerCase()); + if (start !== -1) { + const startMark = ""; + const endMark = ""; + + const end = start + query.length; + text = + text.slice(0, start) + + startMark + + text.slice(start, end) + + endMark + + text.slice(end); + const startInfo = clipStart(text, start); + const endInfo = clipEnd( + text, + startInfo.position + startMark.length + endMark.length + ); + text = + startInfo.prefix + + text.slice(startInfo.position, endInfo.position) + + endInfo.suffix; + + return text; + } else { + return text; + } + } else { + return text; + } +} + +function clipStart(text, pos) { + const clipStart = pos - 50; + if (clipStart < 0) { + // This will just return the start of the string + return { + position: 0, + prefix: "", + }; + } else { + // We're clipping before the start of the string, walk backwards to the first space. + const spacePos = findSpace(text, pos, -1); + return { + position: spacePos.position, + prefix: "", + }; + } +} + +function clipEnd(text, pos) { + const clipEnd = pos + 200; + if (clipEnd > text.length) { + return { + position: text.length, + suffix: "", + }; + } else { + const spacePos = findSpace(text, clipEnd, 1); + return { + position: spacePos.position, + suffix: spacePos.clipped ? "…" : "", + }; + } +} + +function findSpace(text, start, step) { + let stepPos = start; + while (stepPos > -1 && stepPos < text.length) { + const char = text[stepPos]; + if (char === " " || char === "," || char === ":") { + return { + position: step === 1 ? stepPos : stepPos - step, + clipped: stepPos > 1 && stepPos < text.length, + }; + } + stepPos = stepPos + step; + } + + return { + position: stepPos - step, + clipped: false, + }; +} + +// removes highlighting as implemented by the mark tag +function clearHighlight(searchterm, el) { + const childNodes = el.childNodes; + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + if (node.nodeType === Node.ELEMENT_NODE) { + if ( + node.tagName === "MARK" && + node.innerText.toLowerCase() === searchterm.toLowerCase() + ) { + el.replaceChild(document.createTextNode(node.innerText), node); + } else { + clearHighlight(searchterm, node); + } + } + } +} + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} + +// highlight matches +function highlight(term, el) { + const termRegex = new RegExp(term, "ig"); + const childNodes = el.childNodes; + + // walk back to front avoid mutating elements in front of us + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + + if (node.nodeType === Node.TEXT_NODE) { + // Search text nodes for text to highlight + const text = node.nodeValue; + + let startIndex = 0; + let matchIndex = text.search(termRegex); + if (matchIndex > -1) { + const markFragment = document.createDocumentFragment(); + while (matchIndex > -1) { + const prefix = text.slice(startIndex, matchIndex); + markFragment.appendChild(document.createTextNode(prefix)); + + const mark = document.createElement("mark"); + mark.appendChild( + document.createTextNode( + text.slice(matchIndex, matchIndex + term.length) + ) + ); + markFragment.appendChild(mark); + + startIndex = matchIndex + term.length; + matchIndex = text.slice(startIndex).search(new RegExp(term, "ig")); + if (matchIndex > -1) { + matchIndex = startIndex + matchIndex; + } + } + if (startIndex < text.length) { + markFragment.appendChild( + document.createTextNode(text.slice(startIndex, text.length)) + ); + } + + el.replaceChild(markFragment, node); + } + } else if (node.nodeType === Node.ELEMENT_NODE) { + // recurse through elements + highlight(term, node); + } + } +} + +/* Link Handling */ +// get the offset from this page for a given site root relative url +function offsetURL(url) { + var offset = getMeta("quarto:offset"); + return offset ? offset + url : url; +} + +// read a meta tag value +function getMeta(metaName) { + var metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; +} + +function algoliaSearch(query, limit, algoliaOptions) { + const { getAlgoliaResults } = window["@algolia/autocomplete-preset-algolia"]; + + const applicationId = algoliaOptions["application-id"]; + const searchOnlyApiKey = algoliaOptions["search-only-api-key"]; + const indexName = algoliaOptions["index-name"]; + const indexFields = algoliaOptions["index-fields"]; + const searchClient = window.algoliasearch(applicationId, searchOnlyApiKey); + const searchParams = algoliaOptions["params"]; + const searchAnalytics = !!algoliaOptions["analytics-events"]; + + return getAlgoliaResults({ + searchClient, + queries: [ + { + indexName: indexName, + query, + params: { + hitsPerPage: limit, + clickAnalytics: searchAnalytics, + ...searchParams, + }, + }, + ], + transformResponse: (response) => { + if (!indexFields) { + return response.hits.map((hit) => { + return hit.map((item) => { + return { + ...item, + text: highlightMatch(query, item.text), + }; + }); + }); + } else { + const remappedHits = response.hits.map((hit) => { + return hit.map((item) => { + const newItem = { ...item }; + ["href", "section", "title", "text", "crumbs"].forEach( + (keyName) => { + const mappedName = indexFields[keyName]; + if ( + mappedName && + item[mappedName] !== undefined && + mappedName !== keyName + ) { + newItem[keyName] = item[mappedName]; + delete newItem[mappedName]; + } + } + ); + newItem.text = highlightMatch(query, newItem.text); + return newItem; + }); + }); + return remappedHits; + } + }, + }); +} + +let subSearchTerm = undefined; +let subSearchFuse = undefined; +const kFuseMaxWait = 125; + +async function fuseSearch(query, fuse, fuseOptions) { + let index = fuse; + // Fuse.js using the Bitap algorithm for text matching which runs in + // O(nm) time (no matter the structure of the text). In our case this + // means that long search terms mixed with large index gets very slow + // + // This injects a subIndex that will be used once the terms get long enough + // Usually making this subindex is cheap since there will typically be + // a subset of results matching the existing query + if (subSearchFuse !== undefined && query.startsWith(subSearchTerm)) { + // Use the existing subSearchFuse + index = subSearchFuse; + } else if (subSearchFuse !== undefined) { + // The term changed, discard the existing fuse + subSearchFuse = undefined; + subSearchTerm = undefined; + } + + // Search using the active fuse + const then = performance.now(); + const resultsRaw = await index.search(query, fuseOptions); + const now = performance.now(); + + const results = resultsRaw.map((result) => { + const addParam = (url, name, value) => { + const anchorParts = url.split("#"); + const baseUrl = anchorParts[0]; + const sep = baseUrl.search("\\?") > 0 ? "&" : "?"; + anchorParts[0] = baseUrl + sep + name + "=" + value; + return anchorParts.join("#"); + }; + + return { + title: result.item.title, + section: result.item.section, + href: addParam(result.item.href, kQueryArg, query), + text: highlightMatch(query, result.item.text), + crumbs: result.item.crumbs, + }; + }); + + // If we don't have a subfuse and the query is long enough, go ahead + // and create a subfuse to use for subsequent queries + if ( + now - then > kFuseMaxWait && + subSearchFuse === undefined && + resultsRaw.length < fuseOptions.limit + ) { + subSearchTerm = query; + subSearchFuse = new window.Fuse([], kFuseIndexOptions); + resultsRaw.forEach((rr) => { + subSearchFuse.add(rr.item); + }); + } + return results; +} diff --git a/docs/sitemap.xml b/docs/sitemap.xml new file mode 100644 index 0000000..86fa81d --- /dev/null +++ b/docs/sitemap.xml @@ -0,0 +1,171 @@ + + + + https://github.com/Hirototensho/Py4Stats/index.html + 2026-01-24T07:58:29.219Z + + + https://github.com/Hirototensho/Py4Stats/introduction.html + 2026-01-24T08:05:47.646Z + + + https://github.com/Hirototensho/Py4Stats/reference.html + 2026-01-24T07:50:33.704Z + + + https://github.com/Hirototensho/Py4Stats/man/diagnose.html + 2026-01-24T07:44:21.116Z + + + https://github.com/Hirototensho/Py4Stats/man/tabyl.html + 2026-01-24T08:06:30.723Z + + + https://github.com/Hirototensho/Py4Stats/man/freq_table.html + 2026-01-24T07:43:33.450Z + + + https://github.com/Hirototensho/Py4Stats/man/Pareto_plot.html + 2026-01-24T07:43:33.434Z + + + https://github.com/Hirototensho/Py4Stats/man/plot_category.html + 2026-01-24T07:43:33.458Z + + + https://github.com/Hirototensho/Py4Stats/man/diagnose_category.html + 2026-01-24T07:43:33.448Z + + + https://github.com/Hirototensho/Py4Stats/man/point_range.html + 2026-01-24T07:43:33.460Z + + + https://github.com/Hirototensho/Py4Stats/man/remove_empty_constant.html + 2026-01-24T07:43:33.465Z + + + https://github.com/Hirototensho/Py4Stats/man/filtering_out.html + 2026-01-24T07:43:33.449Z + + + https://github.com/Hirototensho/Py4Stats/man/relocate.html + 2026-01-24T08:08:13.737Z + + + https://github.com/Hirototensho/Py4Stats/man/compare_df_cols.html + 2026-01-24T07:43:33.440Z + + + https://github.com/Hirototensho/Py4Stats/man/compare_group_stats.html + 2026-01-24T07:43:33.441Z + + + https://github.com/Hirototensho/Py4Stats/man/plot_miss_var.html + 2026-01-24T07:43:33.459Z + + + https://github.com/Hirototensho/Py4Stats/man/set_miss.html + 2026-01-24T07:53:22.544Z + + + https://github.com/Hirototensho/Py4Stats/man/scale_wmean.html + 2026-01-24T07:43:33.466Z + + + https://github.com/Hirototensho/Py4Stats/man/predicate_str.html + 2026-01-24T07:43:33.461Z + + + https://github.com/Hirototensho/Py4Stats/man/is_dummy.html + 2026-01-24T07:43:33.455Z + + + https://github.com/Hirototensho/Py4Stats/man/varidate.html + 2026-01-24T07:43:33.481Z + + + https://github.com/Hirototensho/Py4Stats/man/compare_ols.html + 2026-01-24T07:43:33.446Z + + + https://github.com/Hirototensho/Py4Stats/man/compare_mfx.html + 2026-01-24T07:43:33.443Z + + + https://github.com/Hirototensho/Py4Stats/man/coefplot.html + 2026-01-24T07:43:33.439Z + + + https://github.com/Hirototensho/Py4Stats/man/tidy.html + 2026-01-24T07:43:33.475Z + + + https://github.com/Hirototensho/Py4Stats/man/tidy_test.html + 2026-01-24T07:43:33.478Z + + + https://github.com/Hirototensho/Py4Stats/man/glance.html + 2026-01-24T07:43:33.451Z + + + https://github.com/Hirototensho/Py4Stats/man/Blinder_Oaxaca.html + 2026-01-24T07:53:22.548Z + + + https://github.com/Hirototensho/Py4Stats/man/tidy_heckit.html + 2026-01-24T07:43:33.477Z + + + https://github.com/Hirototensho/Py4Stats/man/Heckit_from_formula.html + 2026-01-24T07:43:33.433Z + + + https://github.com/Hirototensho/Py4Stats/man/heckitmfx_compute.html + 2026-01-24T07:43:33.453Z + + + https://github.com/Hirototensho/Py4Stats/man/arg_match.html + 2026-01-24T07:43:33.435Z + + + https://github.com/Hirototensho/Py4Stats/man/assert_dtype.html + 2026-01-24T07:43:33.437Z + + + https://github.com/Hirototensho/Py4Stats/man/is_dtype.html + 2026-01-24T07:43:33.454Z + + + https://github.com/Hirototensho/Py4Stats/man/miscellaneous.html + 2026-01-24T07:43:33.455Z + + + https://github.com/Hirototensho/Py4Stats/man/style_pvalue.html + 2026-01-24T07:43:33.468Z + + + https://github.com/Hirototensho/Py4Stats/man/oxford_comma.html + 2026-01-24T07:43:33.456Z + + + https://github.com/Hirototensho/Py4Stats/articles/release_notes.html + 2026-01-24T07:51:08.983Z + + + https://github.com/Hirototensho/Py4Stats/articles/scaling_up_regression.html + 2026-01-24T07:53:22.548Z + + + https://github.com/Hirototensho/Py4Stats/articles/narwhals_in_py4stats.html + 2026-01-23T15:04:30.708Z + + + https://github.com/Hirototensho/Py4Stats/articles/eda_tools_development_status.html + 2026-01-24T07:56:44.925Z + + + https://github.com/Hirototensho/Py4Stats/articles/narwhalsについての考察.html + 2026-01-23T15:32:31.770Z + + diff --git a/docs/theme.scss b/docs/theme.scss new file mode 100644 index 0000000..30df0d3 --- /dev/null +++ b/docs/theme.scss @@ -0,0 +1,31 @@ +/*-- scss:defaults --*/ +$primary: #39729E !default; +$link-color: #39729E !default; + +/*-- scss:rules --*/ + +.sidebar-title { + color: #39729E; +} + +div.sidebar-item-container .active { + font-weight: bold; +} + +.sidebar nav[role=doc-toc] ul>li>a.active, .sidebar nav[role=doc-toc] ul>li>ul>li>a.active{ + font-weight: bold; +} + +/* Code ------------------------------------------------ */ + +code { + color: #373a3c; +} + +code a:any-link { + text-decoration: underline; + text-decoration-color: #ccc; +} + + + diff --git a/index.qmd b/index.qmd new file mode 100644 index 0000000..5a3ba1a --- /dev/null +++ b/index.qmd @@ -0,0 +1,94 @@ +--- +date: today +date-format: "YYYY-MM-DD" +--- + +# Readme + +`Py4Stats` は、主に実証研究で用いられる、探索的データ分析および回帰結果レポート用のユーティリティライブラリです。回帰分析を中心とする分析でよく使われるR言語の機能を Python で実装しています。 + +- [🚀 **Get Started**](./introduction.qmd) +- [📖 **API Reference**](./reference.qmd) + +本ライブラリの主な機能は [Get Started](./introduction.qmd) を、実装されている関数の一覧は [Function reference](./reference.qmd) を参照してください。 + +## Installation + +[`uv`](https://github.com/astral-sh/uv) をお使いの場合、次のコードで `py4stats` をインストールできます。 + +``` python +! uv add git+https://github.com/Hirototensho/py4stats.git +``` + +一方で、`pip` をお使いの場合には、次のコードで `py4stats` をインストールできます。 + +``` python +! pip install git+https://github.com/Hirototensho/py4stats.git +``` + +## 使用例 + +``` python +import py4stats as py4st +``` + +[`py4stats.diagnose()`](man/diagnose.qmd) 関数はデータの全般的な状態についての要約を提供します。 + +``` python +import pandas as pd +from palmerpenguins import load_penguins +penguins = load_penguins() # サンプルデータの読み込み + +print(py4st.diagnose(penguins).round(4)) +#> columns dtype missing_count missing_percent unique_count unique_rate +#> 0 species object 0 0.0000 3 0.8721 +#> 1 island object 0 0.0000 3 0.8721 +#> 2 bill_length_mm float64 2 0.5814 165 47.9651 +#> 3 bill_depth_mm float64 2 0.5814 81 23.5465 +#> 4 flipper_length_mm float64 2 0.5814 56 16.2791 +#> 5 body_mass_g float64 2 0.5814 95 27.6163 +#> 6 sex object 11 3.1977 3 0.8721 +#> 7 year int64 0 0.0000 3 0.8721 +``` + +[`py4stats.compare_ols()`](man/compare_ols.qmd) 関数は、計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。 + + +``` python +import statsmodels.formula.api as smf + +# 回帰分析の実行 +fit1 = smf.ols('body_mass_g ~ bill_length_mm + species', data = penguins).fit() +fit2 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species', data = penguins).fit() +fit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', data = penguins).fit() + +compare_tab1 = py4st.compare_ols(list_models = [fit1, fit2, fit3]) # 表の作成 +compare_tab1 +``` + +| term | model 1 | model 2 | model 3 | +|:---------------------|:---------------|:-----------------|:----------------| +| Intercept | 153.7397 | -1,742.7202 *** | 843.9812 ** | +| | (268.9012) | (313.7697) | (403.5956) | +| species[T.Chinstrap] | -885.8121 *** | -539.6864 *** | -245.1516 *** | +| | (88.2502) | (86.9425) | (84.5952) | +| species[T.Gentoo] | 578.6292 *** | 1,492.8283 *** | 1,443.3525 *** | +| | (75.3623) | (118.4442) | (107.7844) | +| bill_length_mm | 91.4358 *** | 55.6461 *** | 26.5366 *** | +| | (6.8871) | (7.2326) | (7.2436) | +| bill_depth_mm | | 179.0434 *** | 87.9328 *** | +| | | (19.0997) | (20.2192) | +| sex[T.male] | | | 437.2007 *** | +| | | | (49.1098) | +| rsquared_adj | 0.7810 | 0.8258 | 0.8613 | +| nobs | 342 | 342 | 333 | +| df | 3 | 4 | 5 | + + +詳細は、[`py4stats.compare_ols()`](man/compare_ols.qmd) を参照してください。  + +*** +[Jump to **Get Started**.](./introduction.qmd) +[Jump to **Function reference**.](./reference.qmd) + + diff --git a/INTRODUCTION.md b/introduction.qmd similarity index 75% rename from INTRODUCTION.md rename to introduction.qmd index 5e351f8..f26fdde 100644 --- a/INTRODUCTION.md +++ b/introduction.qmd @@ -1,16 +1,16 @@ -# `Introduction to Py4Stats` +# Introduction to Py4Stats ``` python import py4stats as py4st ``` -ここでは `Py4Stats` の主な機能を紹介します。実装されている関数の一覧は [Function reference](./reference.md) を参照してください。 +ここでは `Py4Stats` の主な機能を紹介します。実装されている関数の一覧は [Function reference](./reference.qmd) を参照してください。 ## `py4stats.eda_tools` - 探索的データ解析と前処理に関する機能を提供するモジュールです。このモジュールは、複数の DataFrame バックエンドに対して共通の API を提供することを目的として、[`narwhals`](https://narwhals-dev.github.io/narwhals/) ライブラリを用いて実装されています。詳細は [Technical Notes: py4stats.eda_tools における narwhals ベースの実装](articles/narwhals_in_py4stats.md) を参照してください。 + 探索的データ解析と前処理に関する機能を提供するモジュールです。このモジュールは、複数の DataFrame バックエンドに対して共通の API を提供することを目的として、[`narwhals`](https://narwhals-dev.github.io/narwhals/) ライブラリを用いて実装されています。詳細は [Technical Notes: py4stats.eda_tools における narwhals ベースの実装](articles/narwhals_in_py4stats.qmd) を参照してください。 - [`py4stats.diagnose()`](man/diagnose.md):R言語の[`dlookr::diagnose()`](https://choonghyunryu.github.io/dlookr/reference/diagnose.data.frame.html)を再現した関数で、データの全般的な状態についての要約を提供します。 + [`py4stats.diagnose()`](man/diagnose.qmd):R言語の[`dlookr::diagnose()`](https://choonghyunryu.github.io/dlookr/reference/diagnose.data.frame.html)を再現した関数で、データの全般的な状態についての要約を提供します。 ``` python import pandas as pd @@ -30,7 +30,7 @@ print(py4st.diagnose(penguins).round(4)) #> year int64 0 0.0000 3 0.8721 ``` -[`py4stats.tabyl()`](man/tabyl.md):R言語の [`janitor::tabyl()`](https://sfirke.github.io/janitor/reference/tabyl.html)を参考にした、クロス集計表を作成する関数です。 +[`py4stats.tabyl()`](man/tabyl.qmd):R言語の [`janitor::tabyl()`](https://sfirke.github.io/janitor/reference/tabyl.html)を参考にした、クロス集計表を作成する関数です。 ``` python print(py4st.tabyl(penguins, 'island', 'species')) @@ -41,7 +41,7 @@ print(py4st.tabyl(penguins, 'island', 'species')) #> Torgersen 52 (100.0%) 0 (0.0%) 0 (0.0%) 52 #> All 152 (44.2%) 68 (19.8%) 124 (36.0%) 344 ``` - [`py4stats.freq_table()`](man/freq_table.md):R言語の[`DescTools::Freq()`](https://cran.r-project.org/web/packages/DescTools/DescTools.pdf)をオマージュした、1変数の度数分布表を計算する関数。度数 `freq` と相対度数 `perc` に加えて、それぞれの累積値を計算します。 + [`py4stats.freq_table()`](man/freq_table.qmd):R言語の[`DescTools::Freq()`](https://cran.r-project.org/web/packages/DescTools/DescTools.pdf)をオマージュした、1変数の度数分布表を計算する関数。度数 `freq` と相対度数 `perc` に加えて、それぞれの累積値を計算します。 ``` python print(py4st.freq_table(penguins, 'species')) @@ -76,7 +76,7 @@ print( #> (52.725, 59.6] 5 0.040650 123 1.000000 ``` - [`py4stats.remove_empty()`](man/remove_empty_constant.md):完全に空白な列や行の削除する関数。R言語の [`janitor::remove_empty()`](https://sfirke.github.io/janitor/reference/remove_empty.html) をオマージュした関数で、全ての要素が `NaN` である列や行をデータフレームから除外します。 + [`py4stats.remove_empty()`](man/remove_empty_constant.qmd):完全に空白な列や行の削除する関数。R言語の [`janitor::remove_empty()`](https://sfirke.github.io/janitor/reference/remove_empty.html) をオマージュした関数で、全ての要素が `NaN` である列や行をデータフレームから除外します。 ``` python penguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy() @@ -115,7 +115,7 @@ print(py4st.remove_empty(penguins2, cols = False, quiet = False).tail(3)) #> 343 Chinstrap 3775.0 NaN ``` - [`py4stats.remove_constant()`](man/remove_empty_constant.md):定数列の削除。R言語の [`janitor::remove_constant()`](https://sfirke.github.io/janitor/reference/remove_constant.html) をオマージュした関数で、1種類だけの要素からなる列をデータフレームから除外します。 + [`py4stats.remove_constant()`](man/remove_empty_constant.qmd):定数列の削除。R言語の [`janitor::remove_constant()`](https://sfirke.github.io/janitor/reference/remove_constant.html) をオマージュした関数で、1種類だけの要素からなる列をデータフレームから除外します。 ``` python penguins2 = penguins.loc[:, ['species', 'body_mass_g']].copy() penguins2.loc[:, 'constant'] = 'c' @@ -134,7 +134,7 @@ print(py4st.remove_constant(penguins2, quiet = False).head(3)) #> 2 Adelie 3250.0 ``` - [`py4stats.filtering_out()`](man/filtering_out.md):`pandas` の [`DataFrame.filter()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.filter.html) メソッドでは引数 `like` に文字列を指定することで、列名に特定の文字列を含む列を選択できますが、反対に `py4stats.filtering_out()` では列名に特定の文字列を含む列を除外します。実装の一部はR言語の [`dplyr::select()`](https://dplyr.tidyverse.org/reference/select.html) を参考にしました。 + [`py4stats.filtering_out()`](man/filtering_out.qmd):`pandas` の [`DataFrame.filter()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.filter.html) メソッドでは引数 `like` に文字列を指定することで、列名に特定の文字列を含む列を選択できますが、反対に `py4stats.filtering_out()` では列名に特定の文字列を含む列を除外します。実装の一部はR言語の [`dplyr::select()`](https://dplyr.tidyverse.org/reference/select.html) を参考にしました。 ```python # 列名に 'length' を含む列を除外 @@ -163,7 +163,7 @@ print(py4st.filtering_out(penguins, ends_with = '_mm').head(3))  `py4stats.regression_tools` は [`statsmodels`](https://www.statsmodels.org/stable/index.html)ライブラリで作成された回帰分析の結果についての表作成と可視化を補助する機能を提供するモジュールです。 - [`py4stats.compare_ols()`](man/compare_ols.md) :計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。表のフォーマットについてはR言語の[`texreg::screenreg()`](https://cran.r-project.org/web/packages/texreg/index.html)や[`modelsummary::modelsummary()`](https://modelsummary.com/man/modelsummary.html)を参考にしています。同種の機能を提供する Python ライブラリーとしては、R言語の [`stargazer`](https://cran.r-project.org/web/packages/stargazer/index.html) パッケージをもとにした [`stargazer`](https://pypi.org/project/stargazer/) ライブラリがあります。 + [`py4stats.compare_ols()`](man/compare_ols.qmd) :計量経済学の実証論文でよく用いられる、回帰分析の結果を列方向に並べて比較する表を作成します。表のフォーマットについてはR言語の[`texreg::screenreg()`](https://cran.r-project.org/web/packages/texreg/index.html)や[`modelsummary::modelsummary()`](https://modelsummary.com/man/modelsummary.html)を参考にしています。同種の機能を提供する Python ライブラリーとしては、R言語の [`stargazer`](https://cran.r-project.org/web/packages/stargazer/index.html) パッケージをもとにした [`stargazer`](https://pypi.org/project/stargazer/) ライブラリがあります。 ``` python import statsmodels.formula.api as smf @@ -196,7 +196,7 @@ compare_tab1 | df | 3 | 4 | 5 | -`py4stats.compare_ols()` の実行結果は `Pandas` の `DataFrame` として出力されるため、`.xlsx`. ファイルなどに変換することができます。また、用途に応じて表の体裁を調整できるようにしています。詳細については [「回帰分析の比較」](man/compare_ols.md) を参照してください。 +`py4stats.compare_ols()` の実行結果は `Pandas` の `DataFrame` として出力されるため、`.xlsx`. ファイルなどに変換することができます。また、用途に応じて表の体裁を調整できるようにしています。詳細については [「回帰分析の比較」](man/compare_ols.qmd) を参照してください。 ``` python compare_tab2 = py4st.compare_ols( @@ -222,13 +222,13 @@ compare_tab2 | nobs | 342 | 342 | 333 | | df | 3 | 4 | 5 | -[`py4stats.coefplot()`](man/coefplot.md):回帰係数の可視化。R言語の [`coefplot::coefplot()`](https://cran.r-project.org/web/packages/coefplot/index.html) を参考にしました。 +[`py4stats.coefplot()`](man/coefplot.qmd):回帰係数の可視化。R言語の [`coefplot::coefplot()`](https://cran.r-project.org/web/packages/coefplot/index.html) を参考にしました。 ```python import matplotlib.pyplot as plt py4st.coefplot(fit3) ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/637437c3-f943-4817-a1ad-21bbd538e97d) +![coefplot1](man/image/coefplot1.png) ```python plt.rcParams["figure.autolayout"] = True @@ -242,10 +242,10 @@ py4st.coefplot(fit3, ax = ax[1], palette = ['#FF6F91', '#F2E5EB']) ax[1].set_xlim(-900, 1800); ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/4c2dbfda-c67d-45c5-ba28-0f7fc72bd7d3) +![coefplot2](man/image/coefplot2.png) - [`py4stats.compare_mfx()`](man/compare_mfx.md) - と [`py4stats.mfxplot()`](man/compare_mfx.md) は、それぞれ `py4stats.compare_ols()` と `py4stats.coefplot()` の一般化線型モデルバージョンです。`statsmodels` ライブラリの[`.get_margeff()`](https://www.statsmodels.org/dev/generated/statsmodels.discrete.discrete_model.DiscreteResults.get_margeff.html) メソッドから得られた限界効果の推定値を表示します。 + [`py4stats.compare_mfx()`](man/compare_mfx.qmd) + と [`py4stats.mfxplot()`](man/compare_mfx.qmd) は、それぞれ `py4stats.compare_ols()` と `py4stats.coefplot()` の一般化線型モデルバージョンです。`statsmodels` ライブラリの[`.get_margeff()`](https://www.statsmodels.org/dev/generated/statsmodels.discrete.discrete_model.DiscreteResults.get_margeff.html) メソッドから得られた限界効果の推定値を表示します。 ```python penguins['female'] = np.where(penguins['sex'] == 'female', 1, 0) @@ -285,7 +285,7 @@ py4st.mfxplot(fit_logit2, ax = ax[1], palette = ['#FF6F91', '#F2E5EB']) ax[1].set_xlim(-0.2, 0.85); ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/f62e934a-91da-4ca8-9272-3006df2383f0) +![coefplot3](man/image/coefplot3.png) *** -[Jump to **Function reference**.](./reference.md) +[Jump to **Function reference**.](./reference.qmd) diff --git a/man/Blinder_Oaxaca.md b/man/Blinder_Oaxaca.qmd similarity index 94% rename from man/Blinder_Oaxaca.md rename to man/Blinder_Oaxaca.qmd index e348db0..9f0210b 100644 --- a/man/Blinder_Oaxaca.md +++ b/man/Blinder_Oaxaca.qmd @@ -1,4 +1,4 @@ -# `py4stats.Blinder_Oaxaca()`, `py4stats.plot_Blinder_Oaxaca()` +# Blinder_Oaxaca, plot_Blinder_Oaxaca ## 概要 @@ -114,7 +114,7 @@ py4st.plot_Blinder_Oaxaca( ) ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/a0b8e389-5d17-4476-8626-755ad51d0018) +![plot_Blinder_Oaxaca1](image/plot_Blinder_Oaxaca1.png) `diff_type` を指定することで、一方の統計量だけを表示することもできます。 @@ -125,7 +125,7 @@ py4st.plot_Blinder_Oaxaca( diff_type = 'unobserved_diff' ) ``` -![Unknown-2](https://github.com/Hirototensho/Py4Stats/assets/55335752/36516540-82c0-462b-b122-880959cfd9f1) +![plot_Blinder_Oaxaca2](image/plot_Blinder_Oaxaca2.png) グラフのサイズや解像度を指定するには、次のように行います。 @@ -145,5 +145,5 @@ fig.tight_layout() - 朝井 友紀子 (2014) 「労働市場における男女差の30年― 就業のサンプルセレクションと男女間賃金格差」『日本労働研究雑誌』, No.648, pp.6–16 *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/Heckit_from_formula.md b/man/Heckit_from_formula.qmd similarity index 98% rename from man/Heckit_from_formula.md rename to man/Heckit_from_formula.qmd index c22aee8..886c9ce 100644 --- a/man/Heckit_from_formula.md +++ b/man/Heckit_from_formula.qmd @@ -1,4 +1,4 @@ -# `heckit_helper.Heckit_from_formula()` +# heckit_helper.Heckit_from_formula ## 概要 @@ -107,4 +107,4 @@ print(res_heckit.summary()) - 春山鉄源(2023) 『Pythonで学ぶ入門計量経済学』 https://py4etrics.github.io/index.html *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/Pareto_plot.md b/man/Pareto_plot.qmd similarity index 96% rename from man/Pareto_plot.md rename to man/Pareto_plot.qmd index 771d194..f3cc43f 100644 --- a/man/Pareto_plot.md +++ b/man/Pareto_plot.qmd @@ -1,4 +1,6 @@ -# `py4stats.Pareto_plot()`: パレート図の作成 +# Pareto_plot + +パレート図の作成 ## 概要 @@ -76,4 +78,4 @@ py4st.Pareto_plot( ![Pareto_plot3](image/Pareto_plot3.png) *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/arg_match.md b/man/arg_match.qmd similarity index 91% rename from man/arg_match.md rename to man/arg_match.qmd index fcaeda2..536fcfd 100644 --- a/man/arg_match.md +++ b/man/arg_match.qmd @@ -1,4 +1,6 @@ -# 引数のアサーション `building_block.arg_match()` +# building_block.arg_match + +引数のアサーション ## 概要 @@ -86,7 +88,7 @@ my_faivarit2(['apple', 'orang']) #> Did you mean 'orange'? ``` - `Py4Stats` では [`eda_tools.tabyl()`](./tabyl.md)や [`regression_tools.compare_ols()`](./compare_ols.md) など、文字列で指定する引数をもつ関数で、引数のアサーションに `build.arg_match()` を使用しています。 + `Py4Stats` では [`eda_tools.tabyl()`](./tabyl.qmd)や [`regression_tools.compare_ols()`](./compare_ols.qmd) など、文字列で指定する引数をもつ関数で、引数のアサーションに `build.arg_match()` を使用しています。 ```python import py4stats as py4st @@ -99,5 +101,5 @@ py4st.tabyl(penguins, 'island', 'species', normalize = 'ind') #> Did you mean 'index'? ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/assert_dtype.md b/man/assert_dtype.qmd similarity index 96% rename from man/assert_dtype.md rename to man/assert_dtype.qmd index 0e547ed..2297eca 100644 --- a/man/assert_dtype.md +++ b/man/assert_dtype.qmd @@ -1,4 +1,6 @@ -# データ型による引数のアサーション +# building_block.assert_dtypes + +データ型による引数のアサーション ## 概要 @@ -170,7 +172,7 @@ build.assert_numeric( ## 参照 - データ型の判定には[こちらの関数](./is_dtype.md)を使用しています。 + データ型の判定には[こちらの関数](./is_dtype.qmd)を使用しています。 *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/coefplot.md b/man/coefplot.qmd similarity index 89% rename from man/coefplot.md rename to man/coefplot.qmd index 7a14498..6d0757a 100644 --- a/man/coefplot.md +++ b/man/coefplot.qmd @@ -1,8 +1,10 @@ -# 回帰分析による推定値の視覚化:`py4stats.coefplot()`, `py4stats.mfxplot()` +# coefplot, mfxplot + + 回帰分析による推定値の視覚化 ## 概要 - グラフ上の縦軸が説明変数、横軸回帰係数の値です。点が回帰係数の推定値を、エラーバー(横棒)が信頼区間を表します。 +グラフ上の縦軸が説明変数、横軸回帰係数の値です。点が回帰係数の推定値を、エラーバー(横棒)が信頼区間を表します。 ```python coefplot( @@ -75,7 +77,8 @@ fit3 = smf.ols('body_mass_g ~ bill_length_mm + bill_depth_mm + species + sex', d py4st.coefplot(fit3) ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/637437c3-f943-4817-a1ad-21bbd538e97d) + +![coefplot1](image/coefplot1.png) ```python plt.rcParams["figure.autolayout"] = True @@ -89,7 +92,7 @@ py4st.coefplot(fit3, ax = ax[1], palette = ['#FF6F91', '#F2E5EB']) ax[1].set_xlim(-900, 1800); ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/4c2dbfda-c67d-45c5-ba28-0f7fc72bd7d3) +![coefplot2](image/coefplot2.png) ```python penguins['female'] = np.where(penguins['sex'] == 'female', 1, 0) @@ -111,8 +114,7 @@ py4st.mfxplot(fit_logit2, ax = ax[1], palette = ['#FF6F91', '#F2E5EB']) ax[1].set_xlim(-0.2, 0.85); ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/f62e934a-91da-4ca8-9272-3006df2383f0) - +![coefplot3](image/coefplot3.png) *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/compare_df_cols.md b/man/compare_df_cols.qmd similarity index 87% rename from man/compare_df_cols.md rename to man/compare_df_cols.qmd index 14fb9b1..b5ca097 100644 --- a/man/compare_df_cols.md +++ b/man/compare_df_cols.qmd @@ -1,8 +1,10 @@ -# `py4stats.compare_df_cols()`, `py4stats.compare_df_stats()` +# compare_df_cols, compare_df_stats + +データ型と統計値によるデータフレームの比較 ## 概要 - R言語の [`janitor::compare_df_cols()`](https://sfirke.github.io/janitor/reference/compare_df_cols.html) をオマージュした関数で、`compare_df_cols()` は複数の pandas.DataFrame に含まれる同じ名前を持つ列同士のデータ型 `dtype` を比較し、`compare_df_stats()` は同じ名前を持つ列同士の記述統計量を比較します。 +R言語の [`janitor::compare_df_cols()`](https://sfirke.github.io/janitor/reference/compare_df_cols.html) をオマージュした関数で、`compare_df_cols()` は複数の pandas.DataFrame に含まれる同じ名前を持つ列同士のデータ型 `dtype` を比較し、`compare_df_stats()` は同じ名前を持つ列同士の記述統計量を比較します。 ```python compare_df_cols( @@ -88,4 +90,4 @@ print( #> 4 year 2008.03 2008.03 True ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/compare_group_stats.md b/man/compare_group_stats.qmd similarity index 93% rename from man/compare_group_stats.md rename to man/compare_group_stats.qmd index a98959e..de17fa0 100644 --- a/man/compare_group_stats.md +++ b/man/compare_group_stats.qmd @@ -1,4 +1,6 @@ -# 統計量に基づくグループ間比較 +# compare_group_means, compare_group_median, plot_mean_diff, plot_median_diff + +統計量に基づく2グループの比較と差分の可視化 ## 概要 @@ -124,7 +126,7 @@ py4st.plot_mean_diff( ) ``` -![Unknown](https://github.com/Hirototensho/Py4Stats/assets/55335752/696cbbe0-2c0c-435c-bb9c-71a59a3742f9) +![plot_mean_diff1](image/plot_mean_diff1.png) ```python py4st.plot_mean_diff( @@ -134,7 +136,7 @@ py4st.plot_mean_diff( ) ``` -![Unknown-2](https://github.com/Hirototensho/Py4Stats/assets/55335752/735866a9-aed2-4e10-bac1-6fc7004fba8f) +![plot_mean_diff2](image/plot_mean_diff2.png) ```python py4st.plot_median_diff( @@ -143,6 +145,7 @@ py4st.plot_median_diff( stats_diff = 'rel_diff' ) ``` -![Unknown-3](https://github.com/Hirototensho/Py4Stats/assets/55335752/7a496916-e828-44e1-a0e0-d50bb22ecc12) +![plot_median_diff1](image/plot_median_diff1.png) + *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/compare_mfx.md b/man/compare_mfx.qmd similarity index 94% rename from man/compare_mfx.md rename to man/compare_mfx.qmd index 1a4b118..6da115d 100644 --- a/man/compare_mfx.md +++ b/man/compare_mfx.qmd @@ -1,4 +1,6 @@ -# 限界効果の比較:`py4stats.compare_mfx()` +# compare_mfx + +限界効果の比較 ## 概要 @@ -49,7 +51,7 @@ compare_mfx( - p ≤ 0.05 `**` - p ≤ 0.01 `***` - p > 0.1 表示なし
-詳細は[`building_block.style_pvalue()`](man/style_pvalue.md) を参照してください。 +詳細は[`building_block.style_pvalue()`](./style_pvalue.qmd) を参照してください。 - `stats_glance`:**list of str**
- 表の下部に追加する当てはまりの尺度の種類を表す文字列のリスト。リストの値には次の値を指定できます。なお、`None` もしくは空のリスト `[ ]` が指定された場合には非表示となります。 @@ -104,7 +106,7 @@ from palmerpenguins import load_penguins penguins = load_penguins() # サンプルデータの読み込み ``` - `py4st.compare_mfx()` は [`py4st.compare_ols()`](./compare_ols.md) の一般化線型モデルバージョンで、初期設定では `statsmodels` ライブラリの[`.get_margeff()`](https://www.statsmodels.org/dev/generated/statsmodels.discrete.discrete_model.DiscreteResults.get_margeff.html) メソッドから得られた限界効果の推定値を表示します。 + `py4st.compare_mfx()` は [`py4st.compare_ols()`](./compare_ols.qmd) の一般化線型モデルバージョンで、初期設定では `statsmodels` ライブラリの[`.get_margeff()`](https://www.statsmodels.org/dev/generated/statsmodels.discrete.discrete_model.DiscreteResults.get_margeff.html) メソッドから得られた限界効果の推定値を表示します。 ```python penguins['female'] = np.where(penguins['sex'] == 'female', 1, 0) @@ -155,4 +157,4 @@ GT(compare_tab.reset_index())\   `table_style = 'two_line'` としたとき、初期設定ではの回帰係数とp-値の間に改行記号 `'\n'`が挿入されます。`そのため、print()` 関数や `display()` 関数を使った出力では、改行記号 `'\n'` がそのまま表示されます。この場合でも、[`pd.DataFrame.to_excel()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_excel.html) や [`pd.DataFrame.to_markdown()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_markdown.html) を使って Excel ファイルや markdown の表に変換していただくと、改行として反映されます。 *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/compare_ols.md b/man/compare_ols.qmd similarity index 98% rename from man/compare_ols.md rename to man/compare_ols.qmd index 5d81323..058ba57 100644 --- a/man/compare_ols.md +++ b/man/compare_ols.qmd @@ -1,4 +1,6 @@ -# 回帰分析の比較:`py4stats.compare_ols()` +# compare_ols + +回帰係数の比較 ## 概要 @@ -46,7 +48,7 @@ compare_ols( - p ≤ 0.05 `**` - p ≤ 0.01 `***` - p > 0.1 表示なし
-詳細は[`building_block.style_pvalue()`](man/style_pvalue.md) を参照してください。 +詳細は[`building_block.style_pvalue()`](./style_pvalue.qmd) を参照してください。 - `stats_glance`:**list of str**
- 表の下部に追加する当てはまりの尺度の種類を表す文字列のリスト。リストの値には次の値を指定できます。なお、`None` もしくは空のリスト `[ ]` が指定された場合には非表示となります。 @@ -251,7 +253,7 @@ compare_tab4 # 上記のコードと同じ結果 ## 参照 see also - 一般化線形モデルの限界効果を比較する場合は [`py4stats.compare_mfx()`](./compare_mfx.md)をご利用ください。 + 一般化線形モデルの限界効果を比較する場合は [`py4stats.compare_mfx()`](./compare_mfx.qmd)をご利用ください。 *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/diagnose.md b/man/diagnose.qmd similarity index 91% rename from man/diagnose.md rename to man/diagnose.qmd index f6c80cd..c951688 100644 --- a/man/diagnose.md +++ b/man/diagnose.qmd @@ -1,8 +1,10 @@ -# `py4stats.diagnose()`: データフレームの概要 +# diagnose + +データフレームの概要 ## 概要 - R言語の [`dlookr::diagnose()`](https://choonghyunryu.github.io/dlookr/reference/diagnose.data.frame.html) を再現した関数で、データの全般的な状態についての要約を提供します。 +R言語の [`dlookr::diagnose()`](https://choonghyunryu.github.io/dlookr/reference/diagnose.data.frame.html) を再現した関数で、データの全般的な状態についての要約を提供します。 ``` python diagnose(data: IntoFrameT, to_native: bool = True) @@ -45,5 +47,5 @@ print(py4st.diagnose(penguins).round(4)) ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/diagnose_category.md b/man/diagnose_category.qmd similarity index 96% rename from man/diagnose_category.md rename to man/diagnose_category.qmd index 61398c2..0a7f130 100644 --- a/man/diagnose_category.md +++ b/man/diagnose_category.qmd @@ -1,4 +1,6 @@ -# カテゴリー変数の要約 `py4stats.diagnose_category()` +# diagnose_category + +カテゴリー変数の要約 ## 概要 @@ -66,4 +68,4 @@ print(py4st.diagnose_category(penguins2).round(4)) `evenness` は、各列ごとに情報エントロピーを $[0, 1]$ の範囲に正規化した指標です。本実装では、対数の底をカテゴリの個数(`unique`)に設定することで正規化を行っており、これは底を2とした情報エントロピーを `log2(unique)` で割ることと同値です。この指標は正規化エントロピー(normalized entropy)としても知られています。 *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/filtering_out.md b/man/filtering_out.qmd similarity index 90% rename from man/filtering_out.md rename to man/filtering_out.qmd index 2820e3c..a9f1f5e 100644 --- a/man/filtering_out.md +++ b/man/filtering_out.qmd @@ -1,8 +1,10 @@ -# `py4stats.filtering_out()` +# filtering_out + +データフレームの行と列の除外 ## 概要 - `pandas` の [`DataFrame.filter()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.filter.html) メソッドでは引数 `like` に文字列を指定することで、列名に特定の文字列を含む列を選択できますが、反対に `py4st.filtering_out()` では列名に特定の文字列を含む列を除外します。実装の一部はR言語の [`dplyr::select()`](https://dplyr.tidyverse.org/reference/select.html) を参考にしました。 +`pandas` の [`DataFrame.filter()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.filter.html) メソッドでは引数 `like` に文字列を指定することで、列名に特定の文字列を含む列を選択できます。`py4st.filtering_out()` では、反対に列名に特定の文字列を含む列を除外します。実装の一部はR言語の [`dplyr::select()`](https://dplyr.tidyverse.org/reference/select.html) を参考にしました。 ```python filtering_out( @@ -100,4 +102,4 @@ print(py4st.filtering_out(penguins, ends_with = '_mm')) `axis='index'` による行を対象とするフィルタリングは、インデックスの存在に依存します。したがって、`pd.DataFrame` 以外の行ラベルをもたない `DataFrame` バックエンドでは、このオプションは利用できません。 *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/freq_table.md b/man/freq_table.qmd similarity index 92% rename from man/freq_table.md rename to man/freq_table.qmd index 7c59523..ed357de 100644 --- a/man/freq_table.md +++ b/man/freq_table.qmd @@ -1,8 +1,10 @@ -# `py4stats.freq_table()` +# freq_table + +1変数の度数分布表 ## 概要 - R言語の[`DescTools::Freq()`](https://cran.r-project.org/web/packages/DescTools/DescTools.pdf)をオマージュした、1変数の度数分布表を計算する関数。度数 `freq` と相対度数 `perc` に加えて、それぞれの累積値を計算します。 +R言語の[`DescTools::Freq()`](https://cran.r-project.org/web/packages/DescTools/DescTools.pdf)をオマージュした、1変数の度数分布表を計算する関数。度数 `freq` と相対度数 `perc` に加えて、それぞれの累積値を計算します。 ``` python freq_table( @@ -94,4 +96,4 @@ print( #> 13 Gentoo (55.017, 59.6] 3 0.008772 342 1.000000 ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/glance.md b/man/glance.qmd similarity index 96% rename from man/glance.md rename to man/glance.qmd index 0a06627..0607113 100644 --- a/man/glance.md +++ b/man/glance.qmd @@ -1,4 +1,6 @@ -# `py4stats.glance()` +# glance + +線形モデルの当てはまりの尺度 ## 概要 @@ -61,4 +63,4 @@ list(py4st.glance.registry.keys()) *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/heckitmfx_compute.md b/man/heckitmfx_compute.qmd similarity index 96% rename from man/heckitmfx_compute.md rename to man/heckitmfx_compute.qmd index 78038d6..77bfd74 100644 --- a/man/heckitmfx_compute.md +++ b/man/heckitmfx_compute.qmd @@ -1,4 +1,4 @@ -# `heckit_helper.heckitmfx_compute()` +# heckit_helper.heckitmfx_compute ## 概要 @@ -22,7 +22,7 @@ heckitmfx_compute( - `exog_outcome`**pd.DataFrame**(必須)
 Type2トービットモデルのうち第2段階の regression equation(賃金関数)の説明変数からなる pd.DataFrame -これらの引数は [`heckit_helper.Heckit_from_formula()`](https://github.com/Hirototensho/Py4Stats/edit/main/man/Heckit_from_formula.md) の出力を使用することを想定しています(使用例を参照)。 +これらの引数は [`heckit_helper.Heckit_from_formula()`](https://github.com/Hirototensho/Py4Stats/edit/main/man/Heckit_from_formula.qmd) の出力を使用することを想定しています(使用例を参照)。 - `exponentiate`**bool**
 推定結果に指数関数を用いた変換を行うかどうかを表す論理値。もし False (初期設定)であれば限界効果と回帰係数の推定値をそのまま出力し、もし True であれば出力されるデータフレームのうち `unconditional`、`conditional`、`selection`、`beta` の列について指数関数 $100[\exp(x - 1)]$ を用いた変換を行います。例えば被説明変数は対数賃金であれば、変換後の限界効果はパーセンテージで表された賃金の変化率として解釈できます。 @@ -118,4 +118,4 @@ print(heckit_helper.heckitmfx_compute( - 春山鉄源 (2023) 『Pythonで学ぶ入門計量経済学』. https://py4etrics.github.io/index.html - Hoffmann, Rodolfo, and Ana Lucia Kassouf. (2005). Deriving conditional and unconditional marginal effects in log earnings equations estimated by heckman’s procedure. *Applied Economics*, 37(11), 1303–1311. *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/image/coefplot1.png b/man/image/coefplot1.png new file mode 100644 index 0000000..82a4975 Binary files /dev/null and b/man/image/coefplot1.png differ diff --git a/man/image/coefplot2.png b/man/image/coefplot2.png new file mode 100644 index 0000000..7430971 Binary files /dev/null and b/man/image/coefplot2.png differ diff --git a/man/image/coefplot3.png b/man/image/coefplot3.png new file mode 100644 index 0000000..ddcd281 Binary files /dev/null and b/man/image/coefplot3.png differ diff --git a/man/image/plot_Blinder_Oaxaca1.png b/man/image/plot_Blinder_Oaxaca1.png new file mode 100644 index 0000000..8b3dda7 Binary files /dev/null and b/man/image/plot_Blinder_Oaxaca1.png differ diff --git a/man/image/plot_Blinder_Oaxaca2.png b/man/image/plot_Blinder_Oaxaca2.png new file mode 100644 index 0000000..d268b4b Binary files /dev/null and b/man/image/plot_Blinder_Oaxaca2.png differ diff --git a/man/image/plot_mean_diff1.png b/man/image/plot_mean_diff1.png new file mode 100644 index 0000000..987f93f Binary files /dev/null and b/man/image/plot_mean_diff1.png differ diff --git a/man/image/plot_mean_diff2.png b/man/image/plot_mean_diff2.png new file mode 100644 index 0000000..59cf8db Binary files /dev/null and b/man/image/plot_mean_diff2.png differ diff --git a/man/image/plot_median_diff1.png b/man/image/plot_median_diff1.png new file mode 100644 index 0000000..2891587 Binary files /dev/null and b/man/image/plot_median_diff1.png differ diff --git a/man/is_dtype.md b/man/is_dtype.qmd similarity index 83% rename from man/is_dtype.md rename to man/is_dtype.qmd index 9aa1bb8..82d1126 100644 --- a/man/is_dtype.md +++ b/man/is_dtype.qmd @@ -1,5 +1,6 @@ -# データ型を判定する論理関数 -## `building_block.is_character()` `building_block.is_logical()` `building_block.is_numeric()` `building_block.is_integer()` `building_block.is_float()` +# building_block.is_dtypes + +データ型を判定する論理関数 ## 概要 @@ -57,4 +58,4 @@ print([build.is_float(x) for x in x_list]) #> [False, False, False, True] ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/is_dummy.md b/man/is_dummy.qmd similarity index 96% rename from man/is_dummy.md rename to man/is_dummy.qmd index d530d66..04c4d28 100644 --- a/man/is_dummy.md +++ b/man/is_dummy.qmd @@ -1,4 +1,6 @@ -# ダミー変数の判定: `py4stats.is_dummy()` +# is_dummy + +ダミー変数を判定する論理関数 ## 概要 @@ -71,4 +73,4 @@ print(py4st.is_dummy(penguins2)) #> Name: 0, dtype: bool ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/miscellaneous.md b/man/miscellaneous.qmd similarity index 93% rename from man/miscellaneous.md rename to man/miscellaneous.qmd index 644877b..6a76786 100644 --- a/man/miscellaneous.md +++ b/man/miscellaneous.qmd @@ -1,4 +1,6 @@ -# 数字のフォーマットを変更する関数 +# building_block.style_number, style_percent, style_percent + +数字のフォーマットを変更する関数 ## 概要 @@ -61,4 +63,4 @@ print(build.style_percent(pct, unit = 1000, symbol = '‰').to_list()) ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/oxford_comma.md b/man/oxford_comma.qmd similarity index 70% rename from man/oxford_comma.md rename to man/oxford_comma.qmd index 4ee9e02..894f417 100644 --- a/man/oxford_comma.md +++ b/man/oxford_comma.qmd @@ -1,8 +1,10 @@ -# 並列文の作成 `oxford_comma()` +# oxford_comma + +文字列のリストから並列文を作成 ## 概要 - 文字列のリストを与えると、リストの要素を英文における並列文の形に変換する関数です。表記法については [Wikipedia Serial comma](https://en.wikipedia.org/wiki/Serial_comma) を参照し、コードについては [stack overflow:Grammatical List Join in Python [duplicate]](https://stackoverflow.com/questions/19838976/grammatical-list-join-in-python) を参照しました。 +文字列のリストを与えると、リストの要素を英文における並列文の形に変換する関数です。表記法については [Wikipedia Serial comma](https://en.wikipedia.org/wiki/Serial_comma) を参照し、コードについては [stack overflow:Grammatical List Join in Python [duplicate]](https://stackoverflow.com/questions/19838976/grammatical-list-join-in-python) を参照しました。 ```python oxford_comma(x, sep_last = 'and', quotation = True) @@ -48,4 +50,4 @@ print(build.oxford_comma_or('A')) #> 'A' ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/plot_category.md b/man/plot_category.qmd similarity index 98% rename from man/plot_category.md rename to man/plot_category.qmd index b24076a..103985a 100644 --- a/man/plot_category.md +++ b/man/plot_category.qmd @@ -1,4 +1,4 @@ -# `py4stats.plot_category()` +# plot_category カテゴリ変数の回答分布を 100% 積み上げ横棒グラフとして描画します。 @@ -98,4 +98,4 @@ ax.set_title('Survey on attitudes toward reading'); - `sort_by="values"` は、カテゴリの順序情報(例:`pandas` の `ordered categorical`、`Polars` の `Enum` で定義した順序)を前提に、カテゴリ順で描画します。 - **推奨**: sort_by="values" を利用する場合は、入力として `pandas.DataFrame`(各列を `pd.Categorical` に設定)または `polars.DataFrame`(各列を `Enum` に設定)を推奨します。 - `polars.Categorical` の列では、カテゴリ順が期待通りに保持されず、辞書順(例:Agree, Disagree, …)で描画される場合があります。 -- `pyarrow.Table` を入力した場合、`sort_by = 'values’` は `dictionary` 型の制約によりエラーとなる場合があります。その場合は `sort_by="frequency"` を使用してください。 \ No newline at end of file +- `pyarrow.Table` を入力した場合、`sort_by = 'values’` は `dictionary` 型の制約によりエラーとなる場合があります。その場合は `sort_by="frequency"` を使用してください。 diff --git a/man/plot_miss_var.md b/man/plot_miss_var.qmd similarity index 93% rename from man/plot_miss_var.md rename to man/plot_miss_var.qmd index 97eca49..97763c6 100644 --- a/man/plot_miss_var.md +++ b/man/plot_miss_var.qmd @@ -1,8 +1,8 @@ -# `py4stats.plot_miss_var()` +# plot_miss_var ## 概要 -R言語の [`naniar::gg_miss_var()`](https://naniar.njtierney.com/reference/gg_miss_var.html) をオマージュした関数で、データフレームの各変数について欠測値の量を横棒グラフとして可視化します。欠損値統計の計算には [`py4stats.diagnose()`](diagnose.md) を使用しています。 +R言語の [`naniar::gg_miss_var()`](https://naniar.njtierney.com/reference/gg_miss_var.html) をオマージュした関数で、データフレームの各変数について欠測値の量を横棒グラフとして可視化します。欠損値統計の計算には [`py4stats.diagnose()`](diagnose.qmd) を使用しています。 ``` python plot_miss_var( @@ -59,4 +59,4 @@ py4st.plot_miss_var(penguins, values = 'missing_count', miss_only = True) ![plot_miss_var2](image/plot_miss_var2.png) *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/point_range.md b/man/point_range.qmd similarity index 88% rename from man/point_range.md rename to man/point_range.qmd index 3fc4812..c5cc212 100644 --- a/man/point_range.md +++ b/man/point_range.qmd @@ -1,8 +1,10 @@ -# 数値変数の点推定と区間推定:`py4stats.mean_qi()` `py4stats.median_qi()` `py4stats.mean_ci()` +# mean_qi median_qi mean_ci + +数値変数の点推定と区間推定 ## 概要 - R言語の [`ggdist::mean_qi()`](https://mjskay.github.io/ggdist/reference/point_interval.html) をオマージュした数値変数の点推定と区間推定を行う関数です。 +R言語の [`ggdist::mean_qi()`](https://mjskay.github.io/ggdist/reference/point_interval.html) をオマージュした数値変数の点推定と区間推定を行う関数です。 ```python mean_qi( @@ -77,4 +79,4 @@ print(penguins.groupby('species')[['bill_length_mm']].apply(py4st.median_qi).rou #> Gentoo 0 bill_length_mm 47.30 42.65 53.85 ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/predicate_str.md b/man/predicate_str.qmd similarity index 95% rename from man/predicate_str.md rename to man/predicate_str.qmd index 140073b..d3ab63f 100644 --- a/man/predicate_str.md +++ b/man/predicate_str.qmd @@ -1,4 +1,6 @@ -# 文字列のフォーマットについての論理関数
`py4stats.is_number()`, `py4stats.is_ymd()`, `py4stats.is_ymd_like()` +# is_number, is_ymd, is_ymd_like + +文字列のフォーマットに判定する論理関数 ## 概要 @@ -117,4 +119,4 @@ print(data.loc[~py4st.is_number(data['摂食者数']), '摂食者数']) ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/relocate.md b/man/relocate.qmd similarity index 93% rename from man/relocate.md rename to man/relocate.qmd index 06b608d..4fd70e3 100644 --- a/man/relocate.md +++ b/man/relocate.qmd @@ -1,4 +1,6 @@ -# `py4stats.relocate()`: 列を削除せずに並び替える +# relocate + +データフレームの列を削除することなく並び替える関数 ## 概要 @@ -6,12 +8,12 @@ ``` python relocate( - data: IntoFrameT, - *args: Union[str, List[str], narwhals.Expr, narwhals.selectors.Selector], - before: Optional[str] = None, - after: Optional[str] = None, - place: Optional[Literal["first", "last"]] = None, - to_native: bool = True + data: IntoFrameT, + *args: Union[str, List[str], narwhals.Expr, narwhals.selectors.Selector], + before: Optional[str] = None, + after: Optional[str] = None, + place: Optional[Literal["first", "last"]] = None, + to_native: bool = True ): ``` @@ -107,4 +109,4 @@ print(py4st.relocate(penguins_mini, 'year', place = 'last')) ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/remove_empty_constant.md b/man/remove_empty_constant.qmd similarity index 89% rename from man/remove_empty_constant.md rename to man/remove_empty_constant.qmd index a937e84..6a96617 100644 --- a/man/remove_empty_constant.md +++ b/man/remove_empty_constant.qmd @@ -1,8 +1,10 @@ -# 空白列, 定数列の削除:`py4stats.remove_empty()`, `py4stats.remove_constant()` +# remove_empty, remove_constant + +データフレームの空白列および、定数列の削除 ## 概要 - `py4stats.remove_empty()`はR言語の [`janitor:remove_empty()`](https://sfirke.github.io/janitor/reference/remove_empty.html) をオマージュした関数で、全ての要素が `NaN` である列や行をデータフレームから除外します `py4stats.remove_constant()` はR言語の [`janitor:remove_constant()`](https://sfirke.github.io/janitor/reference/remove_constant.html) をオマージュした関数で、1種類だけの要素からなる列をデータフレームから除外します。 +`py4stats.remove_empty()`はR言語の [`janitor:remove_empty()`](https://sfirke.github.io/janitor/reference/remove_empty.html) をオマージュした関数で、全ての要素が `NaN` である列や行をデータフレームから除外します `py4stats.remove_constant()` はR言語の [`janitor:remove_constant()`](https://sfirke.github.io/janitor/reference/remove_constant.html) をオマージュした関数で、1種類だけの要素からなる列をデータフレームから除外します。 ``` python remove_empty( @@ -141,4 +143,4 @@ print(py4st.remove_constant(penguins2, dropna = True).head(3)) #> 2 Adelie 3250.0 ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/scale_wmean.md b/man/scale_wmean.qmd similarity index 91% rename from man/scale_wmean.md rename to man/scale_wmean.qmd index 6d87941..7560ea8 100644 --- a/man/scale_wmean.md +++ b/man/scale_wmean.qmd @@ -1,10 +1,12 @@ -# 数値変換・正規化ユーティリティ: `py4stats.weighted_mean()`, `py4stats.scale()`, `py4stats.min_max()` +# weighted_mean, scale, min_max -本モジュールは、探索的データ解析(EDA)で頻繁に用いられる**加重平均の計算**および **数値データの正規化・標準化**を行う関数群を提供します。 -内部では narwhals を利用することで、pandas・polars など複数のデータフレーム/シリーズ実装に対して共通の API を提供しています。 +加重平均と標準化・正規化ユーティリティ ## 概要 +探索的データ解析(EDA)で頻繁に用いられる**加重平均の計算**および **数値データの正規化・標準化**を行う関数群です。 +内部では narwhals を利用することで、pandas・polars など複数のデータフレーム/シリーズ実装に対して共通の API を提供しています。 + ``` python weighted_mean( x: IntoSeriesT, @@ -84,4 +86,4 @@ print(f"{z1.mean():.2f}, {z1.std():.2f}") z2 = py4st.min_max(x2) print(f"{z2.min():.2f}, {z2.max():.2f}") #> 0.00, 1.00 -``` \ No newline at end of file +``` diff --git a/man/set_miss.md b/man/set_miss.qmd similarity index 97% rename from man/set_miss.md rename to man/set_miss.qmd index b507f13..1676332 100644 --- a/man/set_miss.md +++ b/man/set_miss.qmd @@ -1,4 +1,6 @@ -# `py4stats.set_miss()` +# set_miss + +Series オブジェクトに対する欠測値の挿入 ## 概要 @@ -86,4 +88,4 @@ penguins['island'] = py4st.set_miss( ) py4st.plot_miss_var(penguins, values = 'missing_count') ``` -![set_miss.png](image/set_miss.png) \ No newline at end of file +![set_miss](image/set_miss.png) diff --git a/man/style_pvalue.md b/man/style_pvalue.qmd similarity index 95% rename from man/style_pvalue.md rename to man/style_pvalue.qmd index 43b0e2b..1b58414 100644 --- a/man/style_pvalue.md +++ b/man/style_pvalue.qmd @@ -1,4 +1,6 @@ -# p-値のフォーマットを変更する関数 +# building_block.style_pvalue, 'p_stars' + +p-値のフォーマットを変更する関数 ## 概要 @@ -69,4 +71,4 @@ print(build.p_stars(p_value, stars = stars_dict).to_list()) #> ['', '', '', '', '.', '.', '.', '*', '**', '***'] ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/tabyl.md b/man/tabyl.qmd similarity index 88% rename from man/tabyl.md rename to man/tabyl.qmd index 02a160a..50fa1af 100644 --- a/man/tabyl.md +++ b/man/tabyl.qmd @@ -1,8 +1,10 @@ -# `py4stats.tabyl()` +# tabyl + +レポートティング向けのクロス集計表を作成 ## 概要 - データフレームのクロス集計表を作成します。R言語の [`janitor::tabyl()`](https://sfirke.github.io/janitor/reference/tabyl.html)にいくつかの `adorn_` 関数を追加した状態を再現した関数です。初期設定ではクロス集計表の各セルに度数と相対度数を 「度数(相対度数%)`」 の形式で表示します。 +データフレームのクロス集計表を作成します。R言語の [`janitor::tabyl()`](https://sfirke.github.io/janitor/reference/tabyl.html)にいくつかの `adorn_` 関数を追加した状態を再現した関数です。初期設定ではクロス集計表の各セルに度数と相対度数を 「度数(相対度数%)`」 の形式で表示します。 ```python tabyl( @@ -80,4 +82,4 @@ print(py4st.tabyl(penguins, 'island', 'species', normalize = 'all')) #> All 152 (44.2%) 68 (19.8%) 124 (36.0%) 344 (100.0%) ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/tidy.md b/man/tidy.qmd similarity index 97% rename from man/tidy.md rename to man/tidy.qmd index 256ff70..d7813e9 100644 --- a/man/tidy.md +++ b/man/tidy.qmd @@ -1,4 +1,6 @@ -# `py4stats.tidy()`, `py4stats.tidy_mfx()` +# tidy, tidy_mfx + +線形モデルの推定結果を DataFrame に集約 ## 概要 @@ -112,8 +114,8 @@ print(py4st.tidy_mfx(fit_logit1).round(4)) list(py4st.tidy.registry.keys()) ``` - `py4stats.tidy()` は `functools.singledispatch` を用いたジェネリック関数として実装しています。 [`Py4Etrics`](https://github.com/Py4Etrics/py4etrics) モジュールの `py4etrics.heckit.Heckit()` で作成された `HeckitResults` クラスのオブジェクト用のメソッドについては [`heckit_helper.tidy_heckit()`](./tidy_heckit.md) を参照してください。 + `py4stats.tidy()` は `functools.singledispatch` を用いたジェネリック関数として実装しています。 [`Py4Etrics`](https://github.com/Py4Etrics/py4etrics) モジュールの `py4etrics.heckit.Heckit()` で作成された `HeckitResults` クラスのオブジェクト用のメソッドについては [`heckit_helper.tidy_heckit()`](./tidy_heckit.qmd) を参照してください。 *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/tidy_heckit.md b/man/tidy_heckit.qmd similarity index 94% rename from man/tidy_heckit.md rename to man/tidy_heckit.qmd index 4eb026e..3bbacc4 100644 --- a/man/tidy_heckit.md +++ b/man/tidy_heckit.qmd @@ -1,8 +1,8 @@ -# `heckit_helper.tidy_heckit()` +# heckit_helper.tidy_heckit ## 概要 - R言語の [`broom::tidy()`](https://broom.tidymodels.org/reference/tidy.lm.html) をオマージュした [`regression_tools.tidy()`](./tidy.md) 関数の、`py4etrics.heckit.HeckitResults` クラス専用のメソッドです。[`regression_tools.tidy()`](./tidy.md)はジェネリック関数として実装されているため、`py4st.tidy(x)` としてご利用いただけます。 + R言語の [`broom::tidy()`](https://broom.tidymodels.org/reference/tidy.lm.html) をオマージュした [`regression_tools.tidy()`](./tidy.qmd) 関数の、`py4etrics.heckit.HeckitResults` クラス専用のメソッドです。[`regression_tools.tidy()`](./tidy.qmd)はジェネリック関数として実装されているため、`py4st.tidy(x)` としてご利用いただけます。 ```python tidy_heckit( @@ -111,4 +111,4 @@ print(py4st.tidy(res_heckit, name_selection = exog_select.columns).round(4)) #> S: kidsge6 0.0360 0.0435 0.8281 0.4076 -0.0492 0.1212 ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/tidy_test.md b/man/tidy_test.qmd similarity index 74% rename from man/tidy_test.md rename to man/tidy_test.qmd index d54e5d9..c503a26 100644 --- a/man/tidy_test.md +++ b/man/tidy_test.qmd @@ -1,8 +1,10 @@ -# `py4stats.tidy_test()` +# tidy_test + +$t$ 検定、$F$ 検定に対応した tidy メソッド ## 概要 - R言語の [`broom::tidy()`](https://broom.tidymodels.org/reference/tidy.lm.html) をオマージュした [`py4stats.tidy()`](./tidy.md) 関数のうち、`statsmodels` ライブラリのメソッド [`RegressionResults.t_test()`](https://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.RegressionResults.t_test.html#statsmodels.regression.linear_model.RegressionResults.t_test) もしくは [`RegressionResults.f_test()`](https://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.RegressionResults.f_test.html#statsmodels.regression.linear_model.RegressionResults.f_test) で作成された `statsmodels.stats.contrast.ContrastResults` クラスのオブジェクト専用のメソッドです。[`py4stats.tidy()`](./tidy.md)はジェネリック関数として実装されているため、`py4st.tidy(x)` としてご利用いただけます。 + R言語の [`broom::tidy()`](https://broom.tidymodels.org/reference/tidy.lm.html) をオマージュした [`py4stats.tidy()`](./tidy.qmd) 関数のうち、`statsmodels` ライブラリのメソッド [`RegressionResults.t_test()`](https://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.RegressionResults.t_test.html#statsmodels.regression.linear_model.RegressionResults.t_test) もしくは [`RegressionResults.f_test()`](https://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.RegressionResults.f_test.html#statsmodels.regression.linear_model.RegressionResults.f_test) で作成された `statsmodels.stats.contrast.ContrastResults` クラスのオブジェクト専用のメソッドです。[`py4stats.tidy()`](./tidy.qmd)はジェネリック関数として実装されているため、`py4st.tidy(x)` としてご利用いただけます。 ```python tidy_test(x, conf_level = 0.95, **kwargs) @@ -75,4 +77,4 @@ print(py4st.tidy(fit3.f_test(hypotheses)).round(4)) ``` *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/man/varidate.md b/man/varidate.qmd similarity index 97% rename from man/varidate.md rename to man/varidate.qmd index ea6f220..d5d7595 100644 --- a/man/varidate.md +++ b/man/varidate.qmd @@ -1,4 +1,6 @@ -# 簡易なルールベースのデータ検証ツール `py4stats.check_that()` `py4stats.check_viorate()` +# check_that check_viorate + +簡易なルールベースのデータ検証ツール ## 概要 @@ -11,7 +13,11 @@ check_that( **kwargs: Any, ) -check_viorate(data, rule_dict, **kwargs) +check_viorate( + data: IntoFrameT, + rule_dict: Union[Mapping[str, str], pd.Series], + **kwargs: Any, +) ``` ## 引数 Argument @@ -159,4 +165,4 @@ print(retailers.loc[df_viorate['to'], 'size':'turnover']) - Loo, Mark van der, and Edwin de Jonge. (2022). 『統計的データクリーニングの理論と実践: Rによるデータ編集/欠測補完システム』. 共立出版. 地道 正行, 髙橋 雅夫, 藤野 友和, 安川 武彦〔訳〕 *** -[Return to **Function reference**.](../reference.md) +[Return to **Function reference**.](../reference.qmd) diff --git a/reference.md b/reference.md deleted file mode 100644 index 856266b..0000000 --- a/reference.md +++ /dev/null @@ -1,158 +0,0 @@ -# Function reference - -## Main Module - -### `py4stats.eda_tools` - -`py4stats.eda_tools` モジュールは、探索的データ解析と前処理に関する機能を提供します。複数の DataFrame バックエンドに対して共通の API を提供することを目的として、[`narwhals`](https://narwhals-dev.github.io/narwhals/) ライブラリを用いて実装されています。詳細は [Technical Notes](articles/narwhals_in_py4stats.md) を参照してください。 - -#### データフレームの概要 -[`py4stats.diagnose()`](man/diagnose.md) - -#### クロス集計 - -[`py4stats.tabyl()`](man/tabyl.md) - -[`py4stats.freq_table()`](man/freq_table.md) - -[`py4stats.Pareto_plot()`](man/Pareto_plot.md) - -[`py4stats.plot_category()`](man/plot_category.md) - -### 数値変数の点推定と区間推定 - -[`py4stats.mean_qi()`](man/point_range.md) -[`py4stats.median_qi()`](man/point_range.md) -[`py4stats.mean_ci()`](man/point_range.md) - -#### データフレームの列や行の削除 - -[`py4stats.remove_empty()`](man/remove_empty_constant.md) -[`py4stats.remove_constant()`](man/remove_empty_constant.md) - -[`py4stats.filtering_out()`](man/filtering_out.md) - -#### データフレームの列の並べ替え - -[`py4stats.relocate()`](man/relocate.md) - - -#### 複数のデータフレームの比較 - -[`py4stats.compare_df_cols()`](man/compare_df_cols.md) -[`py4stats.compare_df_stats()`](man/compare_df_cols.md) - -#### 簡易なグループ別統計量の比較 - -[`py4stats.compare_group_means()`](man/compare_group_stats.md) -[`py4stats.compare_group_median()`](man/compare_group_stats.md) - -[`py4stats.plot_mean_diff()`](man/compare_group_stats.md) -[`py4stats.plot_median_diff()`](man/compare_group_stats.md) - -#### 簡易な欠測値の可視化 - -[`py4stats.plot_miss_var()`](man/plot_miss_var.md) - -#### 数値変数の集計と標準化 - -[`py4stats.weighted_mean()`](man/scale_wmean.md) -[`py4stats.scale()`](man/scale_wmean.md) -[`py4stats.min_max()`](man/scale_wmean.md) - -#### 論理関数 - -[`py4stats.is_number()`](man/predicate_str.md) -[`py4stats.is_ymd()`](man/predicate_str.md) -[`py4stats.is_ymd_like()`](man/predicate_str.md) - -[`py4stats.is_dummy()`](man/is_dummy.md) - -#### 簡易なルールベースのデータ検証ツール - -[`py4stats.check_that()`](man/varidate.md) [`py4stats.check_viorate()`](man/varidate.md) - - -*** -### `py4stats.regression_tools` - -`py4stats.regression_tools` は [`statsmodels`](https://www.statsmodels.org/stable/index.html) ライブラリで作成された回帰分析の結果についての可視化と表作成を補助する機能を提供するモジュールです。 - -#### 線形モデルの比較 - -[`py4stats.compare_ols()`](man/compare_ols.md) - -[`py4stats.compare_mfx()`](man/compare_mfx.md) - -#### 線形モデルの可視化 - -[`py4stats.coefplot()`](man/coefplot.md) [`py4stats.mfxplot()`](man/coefplot.md) - -#### 線形モデルを作表するためのバックエンド関数 - -[`py4stats.tidy()`](man/tidy.md)[`py4stats.tidy_mfx()`](man/tidy.md) - -[`py4stats.tidy_test()`](man/tidy_test.md) - -[`py4stats.glance()`](man/glance.md) - -#### Blinder-Oaxaca分解 - -[`py4stats.Blinder_Oaxaca()`](man/Blinder_Oaxaca.md) -[`py4stats.plot_Blinder_Oaxaca()`](man/Blinder_Oaxaca.md) - -## Sub Module - -### `py4stats.heckit_helper` - -`py4stats.regression_tools` の関数を [`py4etrics.heckit`](https://github.com/Py4Etrics/py4etrics) ライブラリで実装された Heckit モデルに対応させるためのメソッドを提供します。 - -[`heckit_helper.Heckit_from_formula()`](man/Heckit_from_formula.md) - -[`heckit_helper.tidy_heckit()`](man/tidy_heckit.md) - -[`heckit_helper.heckitmfx_compute()`](man/heckitmfx_compute.md) - -*** -### `py4stats.building_block` - -`py4stats` ライブラリの実装に使用するアサーション関数やユーティリティ関数を提供します。 -`building_block` モジュール自体は外部から呼び出すことなく内部実装に使用することを想定しています。 - -### 引数のアサーション関数 - -[`building_block.arg_match()`](man/arg_match.md) - -[`building_block.assert_character()`](man/assert_dtype.md) -[`building_block.assert_logical()`](man/assert_dtype.md) -[`building_block.assert_numeric()`](man/assert_dtype.md) -[`building_block.assert_integer()`](man/assert_dtype.md) -[`building_block.assert_count()`](man/assert_dtype.md) -[`building_block.assert_float()`](man/assert_dtype.md) - -### データ型を判定する論理関数 - -[`building_block.is_character()`](man/is_dtype.md) -[`building_block.is_logical()`](man/is_dtype.md) -[`building_block.is_numeric()`](man/is_dtype.md) -[`building_block.is_integer()`](man/is_dtype.md) -[`building_block.is_float()`](man/is_dtype.md) - -### 数字のフォーマット - -[`building_block.style_number()`](man/miscellaneous.md) -[`building_block.style_currency()`](man/miscellaneous.md) -[`building_block.style_percent()`](man/miscellaneous.md) - -[`building_block.style_pvalue()`](man/style_pvalue.md) -[`building_block.p_stars()`](man/style_pvalue.md) - -### 並列文の作成 - -[`building_block.oxford_comma()`](man/oxford_comma.md) -[`building_block.oxford_comma_and()`](man/oxford_comma.md) -[`building_block.oxford_comma_or()`](man/oxford_comma.md) - -*** -[Jump to **Function Get started**.](..//INTRODUCTION.md) -[Jump to **Function reference**.](../reference.md) diff --git a/reference.qmd b/reference.qmd new file mode 100644 index 0000000..c63baa7 --- /dev/null +++ b/reference.qmd @@ -0,0 +1,163 @@ +# Function reference + +## Main Module + +### `py4stats.eda_tools` + +`py4stats.eda_tools` モジュールは、探索的データ解析と前処理に関する機能を提供します。複数の DataFrame バックエンドに対して共通の API を提供することを目的として、[`narwhals`](https://narwhals-dev.github.io/narwhals/) ライブラリを用いて実装されています。詳細は [Technical Notes](articles/narwhals_in_py4stats.qmd) を参照してください。 + +#### データフレームの概要 + +[`py4stats.diagnose()`](man/diagnose.qmd) + +[`py4stats.diagnose_category()`](man/diagnose_category.qmd) + +#### クロス集計 + +[`py4stats.tabyl()`](man/tabyl.qmd) + +[`py4stats.freq_table()`](man/freq_table.qmd) + +[`py4stats.Pareto_plot()`](man/Pareto_plot.qmd) + +[`py4stats.plot_category()`](man/plot_category.qmd) + +### 数値変数の点推定と区間推定 + +[`py4stats.mean_qi()`](man/point_range.qmd) +[`py4stats.median_qi()`](man/point_range.qmd) +[`py4stats.mean_ci()`](man/point_range.qmd) + +#### データフレームの列や行の削除 + +[`py4stats.remove_empty()`](man/remove_empty_constant.qmd) +[`py4stats.remove_constant()`](man/remove_empty_constant.qmd) + +[`py4stats.filtering_out()`](man/filtering_out.qmd) + +#### データフレームの列の並べ替え + +[`py4stats.relocate()`](man/relocate.qmd) + + +#### 複数のデータフレームの比較 + +[`py4stats.compare_df_cols()`](man/compare_df_cols.qmd) +[`py4stats.compare_df_stats()`](man/compare_df_cols.qmd) + +#### 簡易なグループ別統計量の比較 + +[`py4stats.compare_group_means()`](man/compare_group_stats.qmd) +[`py4stats.compare_group_median()`](man/compare_group_stats.qmd) + +[`py4stats.plot_mean_diff()`](man/compare_group_stats.qmd) +[`py4stats.plot_median_diff()`](man/compare_group_stats.qmd) + +#### 簡易な欠測値の可視化 + +[`py4stats.plot_miss_var()`](man/plot_miss_var.qmd) + +[`py4stats.set_miss()`](man/set_miss.qmd) + +#### 数値変数の集計と標準化 + +[`py4stats.weighted_mean()`](man/scale_wmean.qmd) +[`py4stats.scale()`](man/scale_wmean.qmd) +[`py4stats.min_max()`](man/scale_wmean.qmd) + +#### 論理関数 + +[`py4stats.is_number()`](man/predicate_str.qmd) +[`py4stats.is_ymd()`](man/predicate_str.qmd) +[`py4stats.is_ymd_like()`](man/predicate_str.qmd) + +[`py4stats.is_dummy()`](man/is_dummy.qmd) + +#### 簡易なルールベースのデータ検証ツール + +[`py4stats.check_that()`](man/varidate.qmd) [`py4stats.check_viorate()`](man/varidate.qmd) + +*** + +### `py4stats.regression_tools` + +`py4stats.regression_tools` は [`statsmodels`](https://www.statsmodels.org/stable/index.html) ライブラリで作成された回帰分析の結果についての可視化と表作成を補助する機能を提供するモジュールです。 + +#### 線形モデルの比較 + +[`py4stats.compare_ols()`](man/compare_ols.qmd) + +[`py4stats.compare_mfx()`](man/compare_mfx.qmd) + +#### 線形モデルの可視化 + +[`py4stats.coefplot()`](man/coefplot.qmd) [`py4stats.mfxplot()`](man/coefplot.qmd) + +#### 線形モデルを作表するためのバックエンド関数 + +[`py4stats.tidy()`](man/tidy.qmd)[`py4stats.tidy_mfx()`](man/tidy.qmd) + +[`py4stats.tidy_test()`](man/tidy_test.qmd) + +[`py4stats.glance()`](man/glance.qmd) + +#### Blinder-Oaxaca分解 + +[`py4stats.Blinder_Oaxaca()`](man/Blinder_Oaxaca.qmd) +[`py4stats.plot_Blinder_Oaxaca()`](man/Blinder_Oaxaca.qmd) + +## Sub Module + +### `py4stats.heckit_helper` + +`py4stats.regression_tools` の関数を [`py4etrics.heckit`](https://github.com/Py4Etrics/py4etrics) ライブラリで実装された Heckit モデルに対応させるためのメソッドを提供します。 + +[`heckit_helper.Heckit_from_formula()`](man/Heckit_from_formula.qmd) + +[`heckit_helper.tidy_heckit()`](man/tidy_heckit.qmd) + +[`heckit_helper.heckitmfx_compute()`](man/heckitmfx_compute.qmd) + +*** +### `py4stats.building_block` + +`py4stats` ライブラリの実装に使用するアサーション関数やユーティリティ関数を提供します。 +`building_block` モジュール自体は外部から呼び出すことなく内部実装に使用することを想定しています。 + +### 引数のアサーション関数 + +[`building_block.arg_match()`](man/arg_match.qmd) + +[`building_block.assert_character()`](man/assert_dtype.qmd) +[`building_block.assert_logical()`](man/assert_dtype.qmd) +[`building_block.assert_numeric()`](man/assert_dtype.qmd) +[`building_block.assert_integer()`](man/assert_dtype.qmd) +[`building_block.assert_count()`](man/assert_dtype.qmd) +[`building_block.assert_float()`](man/assert_dtype.qmd) + +### データ型を判定する論理関数 + +[`building_block.is_character()`](man/is_dtype.qmd) +[`building_block.is_logical()`](man/is_dtype.qmd) +[`building_block.is_numeric()`](man/is_dtype.qmd) +[`building_block.is_integer()`](man/is_dtype.qmd) +[`building_block.is_float()`](man/is_dtype.qmd) + +### 数字のフォーマット + +[`building_block.style_number()`](man/miscellaneous.qmd) +[`building_block.style_currency()`](man/miscellaneous.qmd) +[`building_block.style_percent()`](man/miscellaneous.qmd) + +[`building_block.style_pvalue()`](man/style_pvalue.qmd) +[`building_block.p_stars()`](man/style_pvalue.qmd) + +### 並列文の作成 + +[`building_block.oxford_comma()`](man/oxford_comma.qmd) +[`building_block.oxford_comma_and()`](man/oxford_comma.qmd) +[`building_block.oxford_comma_or()`](man/oxford_comma.qmd) + +*** +[Jump to **Get started**.](./introduction.qmd) +[Jump to **Readme**.](./index.qmd) \ No newline at end of file diff --git a/theme.scss b/theme.scss new file mode 100644 index 0000000..30df0d3 --- /dev/null +++ b/theme.scss @@ -0,0 +1,31 @@ +/*-- scss:defaults --*/ +$primary: #39729E !default; +$link-color: #39729E !default; + +/*-- scss:rules --*/ + +.sidebar-title { + color: #39729E; +} + +div.sidebar-item-container .active { + font-weight: bold; +} + +.sidebar nav[role=doc-toc] ul>li>a.active, .sidebar nav[role=doc-toc] ul>li>ul>li>a.active{ + font-weight: bold; +} + +/* Code ------------------------------------------------ */ + +code { + color: #373a3c; +} + +code a:any-link { + text-decoration: underline; + text-decoration-color: #ccc; +} + + +