adviz
Advanced tools
| Metadata-Version: 2.4 | ||
| Name: adviz | ||
| Version: 0.0.24 | ||
| Version: 0.0.25 | ||
| Summary: advertools visualizations | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/eliasdabbas/adviz |
@@ -1,2 +0,2 @@ | ||
| __version__ = "0.0.24" | ||
| __version__ = "0.0.25" | ||
@@ -3,0 +3,0 @@ from dash_bootstrap_templates import load_figure_template |
+36
-26
@@ -11,3 +11,3 @@ """Get the top `n` values per period, and create a "racing" bar chart across periods.""" | ||
| import plotly.express as px | ||
| from plotly.subplots import make_subplots | ||
| import adviz | ||
@@ -20,7 +20,10 @@ | ||
| title="Racing Chart", | ||
| subtitle=None, | ||
| frame_duration=500, | ||
| theme='none', | ||
| template="none", | ||
| width=None, | ||
| height=600, | ||
| font_size=12): | ||
| font_size=12, | ||
| **kwargs, | ||
| ): | ||
| """ | ||
@@ -32,19 +35,21 @@ Create a racing bar chart showing the top `n` values for each period. | ||
| df : pandas.DataFrame | ||
| A DataFrame containing three columns for entity, metric, and period. The | ||
| names can be anything bu they have to be in this specific order. | ||
| A DataFrame containing three columns for entity, metric, and period. The | ||
| names can be anything bu they have to be in this specific order. | ||
| n : int | ||
| The number of top items to display for each period. | ||
| The number of top items to display for each period. | ||
| title : str | ||
| The title of the chart. | ||
| The title of the chart. | ||
| subtitle : str | ||
| The subtitle of the chart. | ||
| frame_duration : int | ||
| The duration of each frame during animation, before transitioning to the | ||
| following frame, in milliseconds. | ||
| theme : str | ||
| The theme of the chart. Any of the following values can be used: | ||
| The duration of each frame during animation, before transitioning to the | ||
| following frame, in milliseconds. | ||
| template : str | ||
| The template of the chart. | ||
| width : int | ||
| The width of the chart in pixels. | ||
| The width of the chart in pixels. | ||
| height : int | ||
| The height of the chart in pixels. | ||
| The height of the chart in pixels. | ||
| font_size : int | ||
| The size of the fonts in the chart. | ||
| The size of the fonts in the chart. | ||
@@ -57,7 +62,7 @@ Returns | ||
| # df[f'{df.columns[1]} %'] = df.groupby(df.columns[2])[df.columns[1]].transform(lambda x: x / x.sum()) | ||
| top_n_df = (df | ||
| .sort_values([df.columns[2], df.columns[1]], | ||
| ascending=[True, False]) | ||
| top_n_df = ( | ||
| df.sort_values([df.columns[2], df.columns[1]], ascending=[True, False]) | ||
| .groupby(df.columns[2]) | ||
| .head(n)) | ||
| .head(n) | ||
| ) | ||
| fig = px.bar( | ||
@@ -73,15 +78,20 @@ top_n_df, | ||
| title=title, | ||
| template=theme, | ||
| range_x=[0,top_n_df[df.columns[1]].max() * 1.05], | ||
| template=template, | ||
| range_x=[0, top_n_df[df.columns[1]].max() * 1.05], | ||
| **kwargs, | ||
| ) | ||
| fig.layout.yaxis.autorange = 'reversed' | ||
| fig.layout.yaxis.autorange = "reversed" | ||
| fig.layout.font.size = font_size | ||
| fig.layout.sliders[0].currentvalue.xanchor = 'right' | ||
| fig.layout.sliders[0].currentvalue.prefix = fig.layout.sliders[0].currentvalue.prefix.replace('=', ': ') | ||
| fig.layout.sliders[0].currentvalue.xanchor = "right" | ||
| fig.layout.sliders[0].currentvalue.prefix = fig.layout.sliders[ | ||
| 0 | ||
| ].currentvalue.prefix.replace("=", ": ") | ||
| fig.layout.sliders[0].currentvalue.font.size = font_size * 1.5 | ||
| fig.layout.sliders[0].bgcolor = '#D5D5D5' | ||
| fig.layout.sliders[0].bgcolor = "#D5D5D5" | ||
| fig.layout.sliders[0].borderwidth = 0 | ||
| fig.layout.updatemenus[0]['buttons'][0]['args'][1]['frame']['duration'] = frame_duration | ||
| fig.layout.updatemenus[0]["buttons"][0]["args"][1]["frame"]["duration"] = ( | ||
| frame_duration | ||
| ) | ||
| for step, total in zip(fig.layout.sliders[0].steps, period_totals.iloc[:, 1]): | ||
| step['label'] = f"{step['label']}<br>Total: {total:,}" | ||
| step["label"] = f"{step['label']}<br>Total: {total:,}" | ||
| return fig |
+95
-78
@@ -11,2 +11,3 @@ """Using multiple SERP datasets, create a heatmap for each domain, showing how often it appeared on each position of the SERPs, with some summary statistics.""" | ||
| import pandas as pd | ||
| pd.options.display.max_columns = None | ||
@@ -16,3 +17,3 @@ | ||
| def _concat(text): | ||
| return '<br>'.join(sorted(text)) | ||
| return "<br>".join(sorted(text)) | ||
@@ -25,4 +26,5 @@ # %% ../nbs/06_serp_heatmap.ipynb 7 | ||
| width=None, | ||
| title='SERP Heatmap', | ||
| theme='none'): | ||
| title="SERP Heatmap", | ||
| template="none", | ||
| ): | ||
| """Create a heatmap for visualizing domain positions on SERPs. | ||
@@ -44,4 +46,4 @@ | ||
| The title of the chart. | ||
| theme : str | ||
| The theme to apply to the chart. | ||
| template : str | ||
| The template to apply to the chart. | ||
@@ -52,81 +54,96 @@ Returns | ||
| """ | ||
| df = serp_df[['searchTerms', 'rank', 'displayLink']] | ||
| top_domains = df['displayLink'].value_counts()[:num_domains].index.tolist() | ||
| top_df = df[df['displayLink'].isin(top_domains) & df['displayLink'].ne('')] | ||
| top_df_counts_means = ( | ||
| top_df | ||
| .groupby('displayLink', as_index=False) | ||
| .agg({'rank': ['count', 'mean']})) | ||
| top_df_counts_means.columns = ['displayLink', 'rank_count', 'avg_pos'] | ||
| top_df = (pd.merge(top_df, top_df_counts_means) | ||
| .sort_values(['rank_count', 'avg_pos'], | ||
| ascending=[False, True])) | ||
| hovertxt_df = (top_df | ||
| .groupby(['rank', 'displayLink'], as_index=False) | ||
| .agg({'searchTerms': _concat})) | ||
| rank_counts = (top_df | ||
| .groupby(['displayLink', 'rank']) | ||
| .agg({'rank': ['count']}) | ||
| .reset_index()) | ||
| rank_counts.columns = ['displayLink', 'rank', 'count'] | ||
| df = serp_df[["searchTerms", "rank", "displayLink"]] | ||
| top_domains = df["displayLink"].value_counts()[:num_domains].index.tolist() | ||
| top_df = df[df["displayLink"].isin(top_domains) & df["displayLink"].ne("")] | ||
| top_df_counts_means = top_df.groupby("displayLink", as_index=False).agg( | ||
| {"rank": ["count", "mean"]} | ||
| ) | ||
| top_df_counts_means.columns = ["displayLink", "rank_count", "avg_pos"] | ||
| top_df = pd.merge(top_df, top_df_counts_means).sort_values( | ||
| ["rank_count", "avg_pos"], ascending=[False, True] | ||
| ) | ||
| hovertxt_df = top_df.groupby(["rank", "displayLink"], as_index=False).agg( | ||
| {"searchTerms": _concat} | ||
| ) | ||
| rank_counts = ( | ||
| top_df.groupby(["displayLink", "rank"]).agg({"rank": ["count"]}).reset_index() | ||
| ) | ||
| rank_counts.columns = ["displayLink", "rank", "count"] | ||
| summary = ( | ||
| df | ||
| .groupby(['displayLink'], as_index=False) | ||
| .agg({'rank': ['count', 'mean']}) | ||
| .sort_values(('rank', 'count'), ascending=False) | ||
| .assign(coverage=lambda df: (df[('rank', 'count')] | ||
| .div(df[('rank', 'count')] | ||
| .sum())))) | ||
| summary.columns = ['displayLink', 'count', 'avg_pos', 'coverage'] | ||
| summary['displayLink'] = summary['displayLink'].str.replace('www.', '', regex=True) | ||
| summary['avg_pos'] = summary['avg_pos'].round(1) | ||
| summary['coverage'] = (summary['coverage'].mul(100) | ||
| .round(1).astype(str).add('%')) | ||
| num_queries = df['searchTerms'].nunique() | ||
| df.groupby(["displayLink"], as_index=False) | ||
| .agg({"rank": ["count", "mean"]}) | ||
| .sort_values(("rank", "count"), ascending=False) | ||
| .assign( | ||
| coverage=lambda df: (df[("rank", "count")].div(df[("rank", "count")].sum())) | ||
| ) | ||
| ) | ||
| summary.columns = ["displayLink", "count", "avg_pos", "coverage"] | ||
| summary["displayLink"] = summary["displayLink"].str.replace("www.", "", regex=True) | ||
| summary["avg_pos"] = summary["avg_pos"].round(1) | ||
| summary["coverage"] = summary["coverage"].mul(100).round(1).astype(str).add("%") | ||
| num_queries = df["searchTerms"].nunique() | ||
| fig = go.Figure() | ||
| fig.add_scatter( | ||
| x=top_df['displayLink'].str.replace('www\.', '', regex=True), | ||
| y=top_df['rank'], | ||
| mode='markers', | ||
| hovertext=top_df['searchTerms'], | ||
| marker={'size': 30, 'opacity': 1/rank_counts['count'].max()}) | ||
| x=top_df["displayLink"].str.replace(r"www\.", "", regex=True), | ||
| y=top_df["rank"], | ||
| mode="markers", | ||
| hovertext=top_df["searchTerms"], | ||
| marker={"size": 30, "opacity": 1 / rank_counts["count"].max()}, | ||
| ) | ||
| fig.add_scatter( | ||
| x=rank_counts['displayLink'].str.replace('www\.', '', regex=True), | ||
| y=rank_counts['rank'], mode='text', | ||
| text=rank_counts['count']) | ||
| for domain in rank_counts['displayLink'].unique(): | ||
| rank_counts_subset = rank_counts[rank_counts['displayLink'] == domain] | ||
| x=rank_counts["displayLink"].str.replace(r"www\.", "", regex=True), | ||
| y=rank_counts["rank"], | ||
| mode="text", | ||
| text=rank_counts["count"], | ||
| ) | ||
| for domain in rank_counts["displayLink"].unique(): | ||
| rank_counts_subset = rank_counts[rank_counts["displayLink"] == domain] | ||
| fig.add_scatter( | ||
| x=[domain.replace('www.', '')], | ||
| x=[domain.replace("www.", "")], | ||
| y=[0], | ||
| mode='text', | ||
| marker={'size': 50}, | ||
| text=str(rank_counts_subset['count'].sum())) | ||
| mode="text", | ||
| marker={"size": 50}, | ||
| text=str(rank_counts_subset["count"].sum()), | ||
| ) | ||
| fig.add_scatter( | ||
| x=[domain.replace('www.', '')], | ||
| x=[domain.replace("www.", "")], | ||
| y=[-1], | ||
| mode='text', | ||
| text=format(rank_counts_subset['count'].sum() / num_queries, '.1%')) | ||
| mode="text", | ||
| text=format(rank_counts_subset["count"].sum() / num_queries, ".1%"), | ||
| ) | ||
| fig.add_scatter( | ||
| x=[domain.replace('www.', '')], | ||
| x=[domain.replace("www.", "")], | ||
| y=[-2], | ||
| mode='text', | ||
| marker={'size': 50}, | ||
| text=str(round(rank_counts_subset['rank'] | ||
| .mul(rank_counts_subset['count']) | ||
| .sum() / rank_counts_subset['count'] | ||
| .sum(), 1))) | ||
| mode="text", | ||
| marker={"size": 50}, | ||
| text=str( | ||
| round( | ||
| rank_counts_subset["rank"].mul(rank_counts_subset["count"]).sum() | ||
| / rank_counts_subset["count"].sum(), | ||
| 1, | ||
| ) | ||
| ), | ||
| ) | ||
| fig.add_scatter( | ||
| x=hovertxt_df['displayLink'].str.replace('^www\.', '', regex=True), | ||
| y=hovertxt_df['rank'], | ||
| name='', | ||
| hovertemplate='<b>%{x}</b><br>%{hovertext}', | ||
| hoverlabel={'bgcolor': '#efefef'}, | ||
| hovertext=hovertxt_df['searchTerms'], | ||
| mode='markers', marker={'opacity': 0, 'size': 30}) | ||
| minrank, maxrank = int(min(top_df['rank'].unique())), int(max(top_df['rank'].unique())) | ||
| fig.layout.yaxis.tickvals = [-2, -1, 0] + list(range(minrank, maxrank+1)) | ||
| fig.layout.yaxis.ticktext = ['Avg. Pos.', 'Coverage', 'Total<br>appearances'] + list(range(minrank, maxrank+1)) | ||
| x=hovertxt_df["displayLink"].str.replace(r"^www\.", "", regex=True), | ||
| y=hovertxt_df["rank"], | ||
| name="", | ||
| hovertemplate="<b>%{x}</b><br>%{hovertext}", | ||
| hoverlabel={"bgcolor": "#efefef"}, | ||
| hovertext=hovertxt_df["searchTerms"], | ||
| mode="markers", | ||
| marker={"opacity": 0, "size": 30}, | ||
| ) | ||
| minrank, maxrank = ( | ||
| int(min(top_df["rank"].unique())), | ||
| int(max(top_df["rank"].unique())), | ||
| ) | ||
| fig.layout.yaxis.tickvals = [-2, -1, 0] + list(range(minrank, maxrank + 1)) | ||
| fig.layout.yaxis.ticktext = [ | ||
| "Avg. Pos.", | ||
| "Coverage", | ||
| "Total<br>appearances", | ||
| ] + list(range(minrank, maxrank + 1)) | ||
| fig.layout.height = max([600, 100 + ((maxrank - minrank) * 50)]) | ||
| fig.layout.yaxis.title = 'SERP Rank<br>(number of appearances)' | ||
| fig.layout.yaxis.title = "SERP Rank<br>(number of appearances)" | ||
| fig.layout.showlegend = False | ||
@@ -136,12 +153,12 @@ fig.layout.margin.r = 2 | ||
| fig.layout.margin.pad = 0 | ||
| fig.layout.yaxis.autorange = 'reversed' | ||
| fig.layout.yaxis.autorange = "reversed" | ||
| fig.layout.yaxis.zeroline = False | ||
| fig.layout.template = theme | ||
| fig.layout.template = template | ||
| fig.layout.title = title | ||
| fig.layout.height = height | ||
| fig.layout.width = width | ||
| fig.layout.xaxis.showgrid = False | ||
| fig.layout.yaxis.ticks = 'inside' | ||
| fig.layout.xaxis.ticks = 'inside' | ||
| fig.layout.yaxis.griddash = 'dot' | ||
| fig.layout.xaxis.showgrid = False | ||
| fig.layout.yaxis.ticks = "inside" | ||
| fig.layout.xaxis.ticks = "inside" | ||
| fig.layout.yaxis.griddash = "dot" | ||
| return fig |
@@ -22,5 +22,5 @@ """Create a treemap for visualizing status code on two levels: the status category (100, 200, 300, 400, 500) and the status codes' actual values (200, 301, 404, etc.)""" | ||
| width=None, | ||
| theme="none", | ||
| template="none", | ||
| title="Status Codes", | ||
| export_to_html=None, | ||
| subtitle=None, | ||
| ): | ||
@@ -38,11 +38,11 @@ """Create a treemap to visualize a list of status codes. | ||
| The desired width of the figure in pixels | ||
| theme : str | ||
| Name of theme to use for the chart. Available themes: | ||
| template : str | ||
| Name of template to use for the chart. Available themes: | ||
| ggplot2, seaborn, simple_white, plotly, plotly_white, plotly_dark, | ||
| presentation, xgridoff, ygridoff, gridon, none | ||
| title: str | ||
| title : str | ||
| The title of the figure. You can use/include the following HTML tags in | ||
| the title: `<a>`, `<b>`, `<br>`, `<i>`, `<sub>`, `<sup>` | ||
| export_to_html: str, optional | ||
| The path to the HTML file if you want to save it as a shareable file | ||
| subtitle : str | ||
| The subtitle of the figure, by default 70% of the font size of the title | ||
@@ -68,3 +68,4 @@ Returns | ||
| title=title, | ||
| template=theme, | ||
| subtitle=subtitle, | ||
| template=template, | ||
| ) | ||
@@ -75,4 +76,2 @@ status_fig.data[0].marker.line.width = 0.01 | ||
| status_fig.data[0]["hovertemplate"] = _texttemplate | ||
| if export_to_html: | ||
| status_fig.write_html(export_to_html) | ||
| return status_fig |
@@ -25,5 +25,6 @@ """Visualizing a website's URL structure with a treemap""" | ||
| width=None, | ||
| theme="none", | ||
| template="none", | ||
| domain="example.com", | ||
| title="URL Structure", | ||
| subtitle=None, | ||
| ): | ||
@@ -44,12 +45,12 @@ """ | ||
| The width of the chart in pixels. | ||
| theme : str | ||
| Name of theme to use for the chart. Available themes: | ||
| ggplot2, seaborn, simple_white, plotly, plotly_white, plotly_dark, | ||
| presentation, xgridoff, ygridoff, gridon, none. | ||
| template : str | ||
| Name of template to use for the chart. | ||
| domain : str | ||
| The main domain of the URL list. This will be displayed at the top | ||
| panel in the treemap to display values like a breadcrumb. | ||
| title: str | ||
| title : str | ||
| The title of the figure. You can use/include the following HTML tags in | ||
| the title: `<a>`, `<b>`, `<br>`, `<i>`, `<sub>`, `<sup>` | ||
| subtitle : str | ||
| The subtitle of the figure. | ||
@@ -90,3 +91,4 @@ Returns | ||
| title=title, | ||
| template=theme, | ||
| subtitle=subtitle, | ||
| template=template, | ||
| values="count", | ||
@@ -93,0 +95,0 @@ ) |
+46
-27
@@ -20,6 +20,7 @@ """Count repeated values in a `list`, `pandas.Series`, or `pandas.DataFrame`. This function adds to the pandas `value_counts` method in a few ways. It counts values absolutely, and as a percentage. It provides cumulative counts and cumulative percentages. It also lumps all values beyond the `show_top` values under "Others:". You alsoe get the values colored with the sequential color scale of your choice.""" | ||
| title=None, | ||
| subtitle=None, | ||
| style=True, | ||
| width=900, | ||
| height=650, | ||
| colorscale='cividis', | ||
| colorscale="cividis", | ||
| ): | ||
@@ -41,2 +42,4 @@ """ | ||
| The title of the chart. | ||
| subtitle : str | ||
| The subtitle of the chart. | ||
| style : bool | ||
@@ -63,29 +66,35 @@ Whether or not to style the resulting table with a heatmap. | ||
| others_df = pd.DataFrame( | ||
| [['Others:'] + ['' for i in range(len(val_counts.columns)-2)] + [val_counts[show_top:]['count'].sum()]], | ||
| columns=val_counts.columns) | ||
| val_counts = pd.concat([ | ||
| val_counts[:show_top], | ||
| others_df | ||
| ]) | ||
| [ | ||
| ["Others:"] | ||
| + ["" for i in range(len(val_counts.columns) - 2)] | ||
| + [val_counts[show_top:]["count"].sum()] | ||
| ], | ||
| columns=val_counts.columns, | ||
| ) | ||
| val_counts = pd.concat([val_counts[:show_top], others_df]) | ||
| if sort_others: | ||
| val_counts = val_counts.sort_values(by=['count'], ascending=False) | ||
| val_counts = val_counts.sort_values(by=["count"], ascending=False) | ||
| count_df = (val_counts | ||
| .assign( | ||
| cum_count=lambda df: df['count'].cumsum(), | ||
| perc=lambda df: df['count'].div(df['count'].sum()), | ||
| cum_perc=lambda df: df['perc'].cumsum()) | ||
| ) | ||
| count_df = val_counts.assign( | ||
| cum_count=lambda df: df["count"].cumsum(), | ||
| perc=lambda df: df["count"].div(df["count"].sum()), | ||
| cum_perc=lambda df: df["perc"].cumsum(), | ||
| ) | ||
| if not style: | ||
| return count_df | ||
| count_df.insert(0, 'rank', range(1, len(count_df)+1)) | ||
| count_df.insert(0, "rank", range(1, len(count_df) + 1)) | ||
| num_columns = count_df.shape[1] | ||
| count_df = count_df.rename(columns={'cum_count': 'cum. count', 'perc': '%', 'cum_perc': 'cum. %'}) | ||
| count_df = count_df.rename( | ||
| columns={"cum_count": "cum. count", "perc": "%", "cum_perc": "cum. %"} | ||
| ) | ||
| subplot_titles = count_df.columns | ||
| fig = make_subplots( | ||
| cols=num_columns, rows=1, | ||
| column_widths=[0.05] + [0.65/(num_dims) for d in range(num_dims)] + [.15, .15, .15, .15], | ||
| cols=num_columns, | ||
| rows=1, | ||
| column_widths=[0.05] | ||
| + [0.65 / (num_dims) for d in range(num_dims)] | ||
| + [0.15, 0.15, 0.15, 0.15], | ||
| horizontal_spacing=0, | ||
| subplot_titles=subplot_titles | ||
| subplot_titles=subplot_titles, | ||
| ) | ||
@@ -95,17 +104,27 @@ for i in range(count_df.shape[1]): | ||
| fig.add_heatmap( | ||
| z=[[100] for i in range(len(tempdf))] if i in range(num_dims+1) else tempdf, | ||
| col=i+1, | ||
| z=[[100] for i in range(len(tempdf))] | ||
| if i in range(num_dims + 1) | ||
| else tempdf, | ||
| col=i + 1, | ||
| row=1, | ||
| hoverinfo='skip', | ||
| hoverinfo="text" if i == 1 else "skip", | ||
| showscale=False, | ||
| name=subplot_titles[i], | ||
| colorscale='RdBu' if i in range(num_dims+1) else colorscale, | ||
| texttemplate="%{text}" if i in range(num_dims+1) else "%{text:,.0f}" if subplot_titles[i].endswith('count') else "%{text:.1%}", | ||
| textfont={'size': 16}, | ||
| text=tempdf) | ||
| colorscale="RdBu" if i in range(num_dims + 1) else colorscale, | ||
| texttemplate="%{text}" | ||
| if i in range(num_dims + 1) | ||
| else "%{text:,.0f}" | ||
| if subplot_titles[i].endswith("count") | ||
| else "%{text:.1%}", | ||
| textfont={"size": 16}, | ||
| text=tempdf, | ||
| ) | ||
| fig.layout.width = width | ||
| fig.layout.height = height | ||
| fig.update_xaxes(showticklabels=False, showgrid=False, zeroline=False) | ||
| fig.update_yaxes(showticklabels=False, showgrid=False, zeroline=False, autorange='reversed') | ||
| fig.update_yaxes( | ||
| showticklabels=False, showgrid=False, zeroline=False, autorange="reversed" | ||
| ) | ||
| fig.layout.title = title | ||
| fig.layout.title.subtitle.text = subtitle | ||
| return fig |
+1
-1
| Metadata-Version: 2.4 | ||
| Name: adviz | ||
| Version: 0.0.24 | ||
| Version: 0.0.25 | ||
| Summary: advertools visualizations | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/eliasdabbas/adviz |
+1
-1
| [DEFAULT] | ||
| repo = adviz | ||
| lib_name = adviz | ||
| version = 0.0.24 | ||
| version = 0.0.25 | ||
| min_python = 3.7 | ||
@@ -6,0 +6,0 @@ license = apache2 |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
85404
0.25%1927
2.39%