from IPython.core.display import display, HTML
display(HTML(""))
import pandas
import hvplot.pandas
import panel
df = pandas.read_csv("SSNames.csv")
df = df.set_index("index")
df.index.name = "year"
left_panel_width=300
panel.extension() #this call is neccessary to make panel behave inside jupyter
df.sample(10)
def plotter(names_list, names_list2, years, scale, scale2):
################
# Input cleaning
# Handles empty input(s), cleans format/capitalization for matching, builds lists
if len(names_list) == 0:
names_list = "No"
names_list_f = "No"
else:
names_list_f = [x.strip().capitalize() for x in names_list.split(",")]
if len(names_list2) == 0:
names_list2 = "No"
names_list2_f = "No"
else:
names_list2_f = [x.strip().capitalize() for x in names_list2.split(",")]
###############
# Dataframe re-configure based on names input
# source used as preliminary dataframe stripped down to only input names,
# names converted to 'name (F/M)'
test_frames = df[
df["Name"].map(lambda x: x in names_list_f) & (df["Gender"] == "M")
]
test_frames2 = df[
df["Name"].map(lambda x: x in names_list2_f) & (df["Gender"] == "F")
]
frames = pandas.concat([test_frames, test_frames2])
frames["NameG"] = frames.apply(
lambda x: x["Name"] + " (" + x["Gender"] + ")", axis=1
)
frames.drop(["Gender", "Name"], inplace=True, axis=1)
frames.index.name = "year"
listed_names = [i for i in pandas.DataFrame(frames.groupby("NameG"))[0]]
source = (
frames[frames["NameG"] == names_list[0]]
.drop(["NameG", "Normalized"], axis=1)
.join(
[
frames.groupby("NameG")
.get_group(i)
.rename({"Normalized": i}, axis=1)
.drop("NameG", axis=1)
for i in listed_names
],
how="outer",
)
)
source = source.fillna(0)
###############
# Conditional axis labeling based on optional checkboxes
# modifies data in source dataframe by optional metric(s)
# finally, returns hvplot objects that contain our final plots
label = "% of All Names"
if scale:
averages = source.join(yearly_average, how="outer")
for i in listed_names:
source[i] = averages[i] / averages["Normalized"]
label = "% of Names / Yearly-Average"
if scale2:
averages2 = source.join(yearly_unique, how="outer")
for i in listed_names:
source[i] = averages2[i] * averages2["Normalized"] / 100000
if scale:
label = "(% of Names / Yearly-Average) * Yearly-Uniques / 10^5"
else:
label = "% of Names * Yearly-Uniques / 10^5"
if "No (F)" in listed_names:
listed_names.remove("No (F)")
if "No (M)" in listed_names:
listed_names.remove("No (M)")
to_plot = source[(source.index >= years[0]) & (source.index <= years[1])]
return to_plot.hvplot(
x="year",
y=(listed_names),
alpha=0.04,
kind="area",
legend="top_left",
height=400,
width=800,
value_label=label,
) * to_plot.hvplot(
x="year",
y=(listed_names),
kind="line",
legend="top_left",
height=400,
width=800,
value_label=label,
).opts(
toolbar=None
)
tickers_male = panel.widgets.TextInput(
name="Names (M)",
value="Andrew",
placeholder="Enter Names Here",
width=left_panel_width,
margin=(100, 30, 0, 10),
)
tickers_female = panel.widgets.TextInput(
name="Names (F)", placeholder="Enter Names Here", width=left_panel_width
)
tickers_female.value = (
"Sarah" # Alternative default value in original widget declaration
)
years_range = panel.widgets.RangeSlider(
name="Years",
start=1880,
end=2018,
value=(1880, 2018),
step=1.0,
width=left_panel_width,
)
checkbox_year = panel.widgets.Checkbox(name="Scale by Yearly Average")
checkbox_nunique = panel.widgets.Checkbox(name="Scale by Yearly Unique Name Entries")
yearly_average = df.reset_index().groupby("year").mean()
# This metric double-counts names both in M and F categories;
# a careful analysis might want to split them up.
yearly_unique = (
df.reset_index().groupby("year").count()["Normalized"]
)
$ panel serve
interact = panel.interact(
plotter,
names_list=tickers_male,
names_list2=tickers_female,
years=years_range,
scale=checkbox_year,
scale2=checkbox_nunique,
)
html_pane = panel.pane.HTML(
"""Social Security Names Plotter
""",
sizing_mode="stretch_width",
)
html_pane2 = panel.pane.HTML(
"""Names are not case-sensitive, and should be entered like: Andrew, Dillon, Travis
Hit enter in text field to re-render
""",
sizing_mode="stretch_width",
)
panel.Row(
panel.Column(interact[0], html_pane2),
panel.Column(html_pane, interact[1]),
).servable()