{"id":13478102,"url":"https://github.com/saforem2/ambivalent","last_synced_at":"2025-04-30T08:25:03.343Z","repository":{"id":214529087,"uuid":"736732194","full_name":"saforem2/ambivalent","owner":"saforem2","description":"Minimal, beautiful (+ highly-customizable) styles for Matplotlib.","archived":false,"fork":false,"pushed_at":"2025-04-22T21:11:18.000Z","size":41444,"stargazers_count":18,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-22T22:24:50.567Z","etag":null,"topics":["matplotlib","minimal","python"],"latest_commit_sha":null,"homepage":"https://saforem2.github.io/ambivalent/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saforem2.png","metadata":{"files":{"readme":"docs/README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-12-28T18:01:23.000Z","updated_at":"2025-02-07T19:14:47.000Z","dependencies_parsed_at":"2023-12-28T19:32:53.578Z","dependency_job_id":"fb089406-448b-47a9-ba81-75b9bffe5707","html_url":"https://github.com/saforem2/ambivalent","commit_stats":null,"previous_names":["saforem2/ambivalent"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saforem2%2Fambivalent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saforem2%2Fambivalent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saforem2%2Fambivalent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saforem2%2Fambivalent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saforem2","download_url":"https://codeload.github.com/saforem2/ambivalent/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251667636,"owners_count":21624541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["matplotlib","minimal","python"],"created_at":"2024-07-31T16:01:52.476Z","updated_at":"2025-04-30T08:25:03.334Z","avatar_url":"https://github.com/saforem2.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# `ambivalent` 🤷🏻‍\nSam Foreman  \n_2024-05-13_\n\n[~~`opinionated`~~](https://github.com/saforem2/opinionated)\n$\\longrightarrow$\n[**`ambivalent`**](https://github.com/saforem2/ambivalent) 🤷🏻‍\n\nClean, simple style for Matplotlib figures.\n\nTransparent backgrounds with grey text\n$\\textcolor{#838383}{\\blacksquare}$ that are accessible / legible and\n`{light, dark}`-mode independent.\n\n## Install\n\n``` bash\npython3 -m pip install ambivalent\n```\n\n## Getting Started\n\n\u003c!-- - Use `ambivalend.STYLES['ambivalent']` as the default style for `matplotlib`. --\u003e\n\n``` python\nimport ambivalent\nimport matplotlib.pyplot as plt\nplt.style.use(ambivalent.STYLES['ambivalent'])\n```\n\n## Examples\n\n### `seaborn` Tips Dataset\n\n- [Seaborn Gallery](https://seaborn.pydata.org/examples/index.html)\n  - [Tips Dataset\n    Example](https://seaborn.pydata.org/generated/seaborn.kdeplot.html)\n\n\u003c!-- \u003cdetails closed\u003e\u003csummary\u003e\u003ccode\u003ecode\u003c/code\u003e:\u003c/summary\u003e --\u003e\n\u003cdetails class=\"code-fold\"\u003e\n\n\u003csummary\u003eCode\u003c/summary\u003e\n\n``` python\nimport seaborn as sns\n\ntips = sns.load_dataset(\"tips\")\ntips.head()\n\nfig, ax = plt.subplots(figsize=(6, 6))  # , ncols=2)\n\n_ = sns.kdeplot(\n   data=tips, x=\"total_bill\", hue=\"size\",\n   fill=True, common_norm=False, palette=\"flare_r\",\n   alpha=.3, linewidth=0,\n   ax=ax,  # [0],\n)\n_ = ax.set_ylabel('')\nplt.show()\n```\n\n\u003c/details\u003e\n\n![](index_files/figure-commonmark/fig-py-tips-density-output-1.svg)\n\n### `seaborn` Scatter Plot\n\n\u003cdetails class=\"code-fold\"\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n``` python\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Load the example diamonds dataset\ndiamonds = sns.load_dataset(\"diamonds\")\n\n# Draw a scatter plot while assigning point colors and sizes to different\n# variables in the dataset\nf, ax = plt.subplots(figsize=(6, 6))\n_ = sns.despine(f, left=True, bottom=True)\n_ = clarity_ranking = [\"I1\", \"SI2\", \"SI1\", \"VS2\", \"VS1\", \"VVS2\", \"VVS1\", \"IF\"]\n_ = sns.scatterplot(x=\"carat\", y=\"price\",\n                hue=\"clarity\", size=\"depth\",\n                palette=\"flare\",\n                hue_order=clarity_ranking,\n                sizes=(1, 8), linewidth=0,\n                data=diamonds, ax=ax)\n```\n\n\u003c/details\u003e\n\n![](index_files/figure-commonmark/fig-py-diamonds-scatter-output-1.svg)\n\n### Histogram + Scatter Plot\n\n\u003cdetails class=\"code-fold\"\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n``` python\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Simulate data from a bivariate Gaussian\nn = 10000\nmean = [0, 0]\ncov = [(2, .4), (.4, .2)]\nrng = np.random.RandomState(0)\nx, y = rng.multivariate_normal(mean, cov, n).T\n\n# Draw a combo histogram and scatterplot with density contours\nf, ax = plt.subplots(figsize=(6, 6))\n_ = sns.scatterplot(x=x, y=y, s=5, color=\"#666666\", alpha=0.3)\n_ = sns.histplot(x=x, y=y, bins=50, pthresh=.1, cmap=\"flare_r\")\n_ = sns.kdeplot(x=x, y=y, levels=5, color=\"w\", linewidths=1)\n_ = ax.set_xlabel('x')\n_ = ax.set_ylabel('y')\n_ = plt.show()\n```\n\n\u003c/details\u003e\n\n![](index_files/figure-commonmark/fig-py-hist-scatter-output-1.svg)\n\n### Jointplot\n\n\u003cdetails class=\"code-fold\"\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n``` python\nimport seaborn as sns\n# Load the penguins dataset\npenguins = sns.load_dataset(\"penguins\")\n# Show the joint distribution using kernel density estimation\nimport matplotlib as mpl\nwith mpl.rc_context(plt.rcParams.update({'axes.grid': False})):\n  g = sns.jointplot(\n      data=penguins,\n      x=\"bill_length_mm\",\n      y=\"bill_depth_mm\",\n      hue=\"species\",\n      edgecolors='none',\n      alpha=0.4,\n  )\n  _ = plt.grid(False)\n  plt.show()\n```\n\n\u003c/details\u003e\n\n![](index_files/figure-commonmark/fig-py-kde-2d-output-1.svg)\n\n### Matplotlib Histograms\n\n\u003cdetails class=\"code-fold\"\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n``` python\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nn_bins = 10\nx = np.random.randn(1000, 3)\n\nplt.rcParams['axes.grid'] = True\n\nfig, ((ax0, ax1), (ax2, ax3)) = plt.subplots(nrows=2, ncols=2)\n\ncolors = ['#333333', '#666666', '#999999']\nax0.hist(x, n_bins, density=True, histtype='bar', color=colors, label=colors)\n_ = ax0.legend()\n_ = ax0.set_title('bars with legend')\n\n_ = ax1.hist(x, n_bins, density=True, histtype='bar', stacked=True, alpha=0.4)\n_ = ax1.set_title('stacked bar')\n\n_ = ax2.hist(x, n_bins, histtype='step', stacked=True, fill=False)\n_ = ax2.set_title('stack step (unfilled)')\n\n# Make a multiple-histogram of data-sets with different length.\nx_multi = [np.random.randn(n) for n in [10000, 5000, 2000]]\n_ = ax3.hist(x_multi, n_bins, histtype='bar')\n_ = ax3.set_title('different sample sizes')\n\n_ = fig.tight_layout()\nplt.show()\n```\n\n\u003c/details\u003e\n\n![](index_files/figure-commonmark/fig-py-mpl-hists-output-1.svg)\n\n## Gallery[^1]\n\n\u003cdetails closed\u003e\n\u003csummary\u003e\n\u003citalic\u003eMore Examples…\u003c/italic\u003e\n\u003c/summary\u003e\n\u003c!-- ::: {#fig-gallery style=\"display: flex; flex-direction:row; align-items: flex-end\"} --\u003e\n\n\u003cdiv layout-nrow=\"3\"\u003e\n\n\u003cdiv\u003e\n\n\u003c/div\u003e\n\n\u003c!-- ::: {layout=\"[[45, 45]]\" layout-valign=\"bottom\" style=\"text-align:center;\"} --\u003e\n\n\u003cdiv\u003e\n\n\u003c/div\u003e\n\n\u003c!-- ::: {layout=\"[[80]]\" style=\"display: flex; text-align:center;\"} --\u003e\n\n\u003cdiv\u003e\n\n\u003c/div\u003e\n\n\u003c/div\u003e\n\n\u003c!-- ::: {.stretch layout=\"[[31, 31, 31]]\" layout-valign=\"bottom\" style=\"display: flex; text-align:center!important;\"} --\u003e\n\n\u003cimg\nsrc=\"https://saforem2.github.io/l2hmc-qcd/qmd/l2hmc-2dU1/assets/output_33_22.svg\"\nclass=\"stretch\" alt=\"|J_{f}|\" /\u003e\n\n\u003cimg\nsrc=\"https://saforem2.github.io/l2hmc-qcd/qmd/l2hmc-2dU1/assets/output_33_23.svg\"\nclass=\"stretch\" alt=\"|J_{b}|\" /\u003e\n\n\u003cimg\nsrc=\"https://saforem2.github.io/l2hmc-qcd/qmd/l2hmc-2dU1/assets/output_33_21.svg\"\nclass=\"stretch\" alt=\"|J|\" /\u003e\n\n\u003cimg src=\"./assets/chains.svg\" class=\"stretch\"\ndata-ref-parent=\"fig-chains-dQ\" /\u003e\n\n\u003cimg\nsrc=\"https://saforem2.github.io/l2hmc-qcd/qmd/l2hmc-2dU1/assets/output_30_68.svg\"\nclass=\"stretch\" /\u003e\n\n\u003cimg\nsrc=\"https://saforem2.github.io/l2hmc-qcd/qmd/l2hmc-2dU1/assets/output_30_68.svg\"\nclass=\"stretch\" /\u003e\n\n\u003cimg\nsrc=\"https://saforem2.github.io/l2hmc-qcd/qmd/l2hmc-2dU1/assets/output_48_1.svg\"\nclass=\"stretch\" data-ref-parent=\"fig-combined-chains\" /\u003e\n\u003c/details\u003e\n\u003c!-- ```{python} --\u003e\n\u003c!-- #| code-fold: true --\u003e\n\u003c!-- #| code-summary: \"boxenplot\" --\u003e\n\u003c!-- #| label: fig-py-boxenplot --\u003e\n\u003c!-- #| output: true --\u003e\n\u003c!-- #| fig-cap: \"Seaborn Boxenplot\" --\u003e\n\u003c!-- #| layout: [[100]] --\u003e\n\u003c!----\u003e\n\u003c!-- import seaborn as sns --\u003e\n\u003c!----\u003e\n\u003c!-- diamonds = sns.load_dataset(\"diamonds\") --\u003e\n\u003c!-- clarity_ranking = [\"I1\", \"SI2\", \"SI1\", \"VS2\", \"VS1\", \"VVS2\", \"VVS1\", \"IF\"] --\u003e\n\u003c!----\u003e\n\u003c!-- sns.boxenplot( --\u003e\n\u003c!--     diamonds, x=\"clarity\", y=\"carat\", --\u003e\n\u003c!--     color=\"b\", order=clarity_ranking, width_method=\"linear\", --\u003e\n\u003c!-- ) --\u003e\n\u003c!-- ``` --\u003e\n\u003c!-- ```{python} --\u003e\n\u003c!-- import warnings --\u003e\n\u003c!-- from ambivalent import STYLES --\u003e\n\u003c!-- import matplotlib.pyplot as plt --\u003e\n\u003c!-- import numpy as np --\u003e\n\u003c!----\u003e\n\u003c!-- plt.style.use(STYLES['ambivalent']) --\u003e\n\u003c!----\u003e\n\u003c!-- # some random data --\u003e\n\u003c!-- x = np.random.randn(1000) --\u003e\n\u003c!-- y = np.random.randn(1000) --\u003e\n\u003c!----\u003e\n\u003c!----\u003e\n\u003c!-- def scatter_hist(x, y, ax, ax_histx, ax_histy, alpha: float = 0.4): --\u003e\n\u003c!--     # no labels --\u003e\n\u003c!--     ax_histx.tick_params(axis=\"x\", labelbottom=False) --\u003e\n\u003c!--     ax_histy.tick_params(axis=\"y\", labelleft=False) --\u003e\n\u003c!----\u003e\n\u003c!--     # the scatter plot: --\u003e\n\u003c!--     ax.scatter(x, y, alpha=alpha) --\u003e\n\u003c!----\u003e\n\u003c!--     # now determine nice limits by hand: --\u003e\n\u003c!--     binwidth = 0.25 --\u003e\n\u003c!--     xymax = max(np.max(np.abs(x)), np.max(np.abs(y))) --\u003e\n\u003c!--     lim = (int(xymax/binwidth) + 1) * binwidth --\u003e\n\u003c!----\u003e\n\u003c!--     bins = np.arange(-lim, lim + binwidth, binwidth) --\u003e\n\u003c!--     ax_histx.hist(x, bins=bins) --\u003e\n\u003c!--     ax_histy.hist(y, bins=bins, orientation='horizontal') --\u003e\n\u003c!-- ``` --\u003e\n\u003c!-- ### 2D Density --\u003e\n\u003c!----\u003e\n\u003c!-- ```{python} --\u003e\n\u003c!-- #| code-fold: true --\u003e\n\u003c!-- #| code-summary: \"Make the plot\" --\u003e\n\u003c!-- #| label: fig-py-density2d --\u003e\n\u003c!-- #| output: true --\u003e\n\u003c!-- #| fig-cap: \"2D Density plot\" --\u003e\n\u003c!-- #| layout: [[100]] --\u003e\n\u003c!----\u003e\n\u003c!-- # Start with a square Figure. --\u003e\n\u003c!-- fig = plt.figure(figsize=(6, 6)) --\u003e\n\u003c!-- # Add a gridspec with two rows and two columns and a ratio of 1 to 4 between --\u003e\n\u003c!-- # the size of the marginal axes and the main axes in both directions. --\u003e\n\u003c!-- # Also adjust the subplot parameters for a square plot. --\u003e\n\u003c!-- gs = fig.add_gridspec(2, 2,  width_ratios=(4, 1), height_ratios=(1, 4), --\u003e\n\u003c!--                       left=0.1, right=0.9, bottom=0.1, top=0.9, --\u003e\n\u003c!--                       wspace=0.15, hspace=0.15) --\u003e\n\u003c!-- # Create the Axes. --\u003e\n\u003c!-- ax = fig.add_subplot(gs[1, 0]) --\u003e\n\u003c!-- ax_histx = fig.add_subplot(gs[0, 0], sharex=ax) --\u003e\n\u003c!-- ax_histy = fig.add_subplot(gs[1, 1], sharey=ax) --\u003e\n\u003c!-- _ = fig.axes[1].grid(False) --\u003e\n\u003c!-- _ = fig.axes[2].set_xticklabels([]) --\u003e\n\u003c!-- _ = fig.axes[1].set_yticklabels([]) --\u003e\n\u003c!-- _ = fig.axes[2].grid(False) --\u003e\n\u003c!-- _ = fig.axes[0].set_xticklabels(fig.axes[0].get_xticklabels()) --\u003e\n\u003c!-- _ = fig.axes[0].set_yticklabels(fig.axes[0].get_yticklabels()) --\u003e\n\u003c!----\u003e\n\u003c!-- # Draw the scatter plot and marginals. --\u003e\n\u003c!-- _ = scatter_hist(x, y, ax, ax_histx, ax_histy) --\u003e\n\u003c!-- _ = plt.show() --\u003e\n\u003c!-- ``` --\u003e\n\u003c!----\u003e\n\u003c!----\u003e\n\u003c!-- ```{python} --\u003e\n\u003c!-- import numpy as np --\u003e\n\u003c!-- import matplotlib.animation as animation --\u003e\n\u003c!----\u003e\n\u003c!-- # Fixing random state for reproducibility --\u003e\n\u003c!-- np.random.seed(19680801) --\u003e\n\u003c!----\u003e\n\u003c!----\u003e\n\u003c!-- def random_walk(num_steps, max_step=0.05): --\u003e\n\u003c!--     \"\"\"Return a 3D random walk as (num_steps, 3) array.\"\"\" --\u003e\n\u003c!--     start_pos = np.random.random(3) --\u003e\n\u003c!--     steps = np.random.uniform(-max_step, max_step, size=(num_steps, 3)) --\u003e\n\u003c!--     walk = start_pos + np.cumsum(steps, axis=0) --\u003e\n\u003c!--     return walk --\u003e\n\u003c!----\u003e\n\u003c!----\u003e\n\u003c!-- def update_lines(num, walks, lines): --\u003e\n\u003c!--     for line, walk in zip(lines, walks): --\u003e\n\u003c!--         # NOTE: there is no .set_data() for 3 dim data... --\u003e\n\u003c!--         line.set_data(walk[:num, :2].T) --\u003e\n\u003c!--         line.set_3d_properties(walk[:num, 2]) --\u003e\n\u003c!--     return lines --\u003e\n\u003c!----\u003e\n\u003c!----\u003e\n\u003c!-- # Data: 40 random walks as (num_steps, 3) arrays --\u003e\n\u003c!-- num_steps = 30 --\u003e\n\u003c!-- walks = [random_walk(num_steps) for index in range(40)] --\u003e\n\u003c!----\u003e\n\u003c!-- # Attaching 3D axis to the figure --\u003e\n\u003c!-- fig = plt.figure() --\u003e\n\u003c!-- ax = fig.add_subplot(projection=\"3d\") --\u003e\n\u003c!----\u003e\n\u003c!-- # Create lines initially without data --\u003e\n\u003c!-- lines = [ax.plot([], [], [])[0] for _ in walks] --\u003e\n\u003c!----\u003e\n\u003c!-- # Setting the axes properties --\u003e\n\u003c!-- _ = ax.set(xlim3d=(0, 1), xlabel='X') --\u003e\n\u003c!-- _ = ax.set(ylim3d=(0, 1), ylabel='Y') --\u003e\n\u003c!-- _ = ax.set(zlim3d=(0, 1), zlabel='Z') --\u003e\n\u003c!----\u003e\n\u003c!-- # Creating the Animation object --\u003e\n\u003c!-- ani = animation.FuncAnimation( --\u003e\n\u003c!--     fig, update_lines, num_steps, fargs=(walks, lines), interval=100) --\u003e\n\u003c!----\u003e\n\u003c!-- plt.show() --\u003e\n\u003c!-- ``` --\u003e\n\n\u003e [!TIP]\n\u003e\n\u003e ### \u003cspan class=\"dim-text\"\u003e💝 Status\u003c/span\u003e\n\u003e\n\u003e \u003cspan style=\"text-align:center;\"\u003e![](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fsaforem2.github.io%2Fambivalent\u0026count_bg=%23222222\u0026title_bg=%23303030\u0026icon=\u0026icon_color=%23E7E7E7)\u003c/span\u003e\n\u003e\n\u003e \u003cpre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"\u003e\u003cspan style=\"color: #7f7f7f; text-decoration-color: #7f7f7f; font-style: italic\"\u003eLast Updated\u003c/span\u003e: \u003cspan style=\"color: #f06292; text-decoration-color: #f06292; font-weight: bold\"\u003e05\u003c/span\u003e\u003cspan style=\"color: #f06292; text-decoration-color: #f06292\"\u003e/\u003c/span\u003e\u003cspan style=\"color: #f06292; text-decoration-color: #f06292; font-weight: bold\"\u003e13\u003c/span\u003e\u003cspan style=\"color: #f06292; text-decoration-color: #f06292\"\u003e/\u003c/span\u003e\u003cspan style=\"color: #f06292; text-decoration-color: #f06292; font-weight: bold\"\u003e2024\u003c/span\u003e \u003cspan style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"\u003e@\u003c/span\u003e \u003cspan style=\"color: #1a8fff; text-decoration-color: #1a8fff; font-weight: bold\"\u003e21:56:28\u003c/span\u003e\n\u003e \u003c/pre\u003e\n\n[^1]: Examples from [Matplotlib\n    Examples](https://matplotlib.org/stable/gallery/index.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaforem2%2Fambivalent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaforem2%2Fambivalent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaforem2%2Fambivalent/lists"}