diff --git a/.DS_Store b/.DS_Store index 3802f44..c64ec8a 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e17e9f4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +# Use the official Python image +FROM python:3.9-slim + +# Set the working directory in the container +WORKDIR /app + +# Copy the current directory contents to the container +COPY . /app + +# Install Python dependencies +RUN pip install --no-cache-dir dash plotly pandas + +# Expose the port that the Dash app runs on +EXPOSE 8080 + +# Run the application +CMD ["python", "fisher_dash_app.py"] diff --git a/app.py b/app.py new file mode 100644 index 0000000..e69de29 diff --git a/capstone b/capstone new file mode 160000 index 0000000..bcd247e --- /dev/null +++ b/capstone @@ -0,0 +1 @@ +Subproject commit bcd247edd590ad3cb322100a8c88b98b176c2e40 diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..8d81ba6 --- /dev/null +++ b/config.toml @@ -0,0 +1,3 @@ +[server] +enableCORS = false +enableWebsocketCompression = false diff --git a/fisher.html b/fisher.html index 3ddc26a..bf777a3 100644 --- a/fisher.html +++ b/fisher.html @@ -18,38 +18,13 @@

Fisher Doubles Down

After World War II, the world declared, “never again.” Racial pseudoscience and the atrocities it justified faced universal condemnation. Yet, categorization itself persisted. Statistical methods advanced, but their application to groups of people continued to legitimize harmful hierarchies.

-

- Ronald Fisher, a pioneer of modern statistics, carried the torch of eugenics from Francis Galton and Karl Pearson, both of whom laid the groundwork for applying statistical methods to human populations. Fisher’s contributions to statistics are immense: his work on analysis of variance (ANOVA), maximum likelihood estimation, and the design of experiments revolutionized mathematics, genetics, and scientific research. Yet, Fisher also believed deeply in eugenics, insisting that statistical tools could objectively determine which groups were "fit" to thrive. For Fisher, subjective judgments about "inferior" and "superior" populations became "scientific" through the application of mathematical methods. -

-

- Rather than abandoning eugenic thinking after the war, Fisher doubled down—arguing that the Earth’s finite resources required humanity to make hard choices. He claimed that statistical tools could help identify which populations contributed to sustainability and which were burdens. This rationalization gave his worldview a veneer of scientific legitimacy, even as it concealed its subjective roots. -

- - - -
-

- Step into Fisher’s mindset: Adjust the weights assigned to variables like IQ, moral character, and crime statistics to explore how hierarchies might emerge. -

- -
- -
-

- These exercises reveal how statistical tools, designed to understand the world, can easily divide it. From Fisher’s justification of resource allocation to today’s efforts to measure societal progress, the ability to assign weights and create hierarchies reflects subjective values rather than objective truths. -

+ +
+

Adjust the weights assigned to variables like IQ, moral character, and crime statistics to explore how hierarchies might emerge.

+ +
diff --git a/fisher_dash_app.py b/fisher_dash_app.py new file mode 100644 index 0000000..e1ae75b --- /dev/null +++ b/fisher_dash_app.py @@ -0,0 +1,142 @@ +import dash +from dash import dcc, html +from dash.dependencies import Input, Output +import plotly.graph_objects as go +import pandas as pd + +# Initialize Dash app +app = dash.Dash(__name__) +app.title = "Fisher Statistical Analysis Visualization" + +# Data for visualization +fisher_data = pd.DataFrame({ + "Group": ["White", "Black", "Asian", "Hispanic", "Other"], + "IQ": [100, 108, 105, 102, 98], + "Moral Character": [95, 85, 90, 80, 85], + "Violent Crime": [30, 35, 25, 40, 45], + "Income": [75, 45, 70, 50, 55], + "Reproduction Rate": [48, 55, 47, 60, 52] +}) + +# App layout +app.layout = html.Div(style={"font-family": "Avenir", "padding": "10px", "max-width": "1000px", "margin": "0 auto", "font-size": "0.95em"}, children=[ + # Clickable variable titles for toggling visibility + html.Div( + style={"display": "flex", "justify-content": "center", "gap": "8px", "margin-bottom": "10px"}, + children=[ + html.Div("IQ", id="toggle-iq", style={"color": "#636EFA", "font-weight": "bold", "cursor": "pointer"}), + html.Div("Moral Character", id="toggle-moral", style={"color": "#EF553B", "font-weight": "bold", "cursor": "pointer"}), + html.Div("Violent Crime", id="toggle-crime", style={"color": "#00CC96", "font-weight": "bold", "cursor": "pointer"}), + html.Div("Income", id="toggle-income", style={"color": "#AB63FA", "font-weight": "bold", "cursor": "pointer"}), + html.Div("Reproduction Rate", id="toggle-reproduction", style={"color": "#FFA15A", "font-weight": "bold", "cursor": "pointer"}) + ] + ), + + # Bar Chart + dcc.Graph(id="fisher-chart", style={"width": "100%", "height": "400px", "border": "none"}), + + # Sliders with corresponding value display + html.Div( + style={"display": "flex", "justify-content": "space-around", "align-items": "center", "margin-top": "10px"}, + children=[ + html.Div([ + html.Label("IQ", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), + dcc.Slider( + id="weight-iq", + min=0, + max=5, + step=0.1, + value=1, + marks={i: str(round(i, 1)) for i in range(6)} + ), + html.Div(id="weight-iq-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) + ], style={"width": "18%"}), + html.Div([ + html.Label("Moral Character", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), + dcc.Slider( + id="weight-moral", + min=0, + max=5, + step=0.1, + value=1, + marks={i: str(round(i, 1)) for i in range(6)} + ), + html.Div(id="weight-moral-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) + ], style={"width": "18%"}), + html.Div([ + html.Label("Violent Crime", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), + dcc.Slider( + id="weight-crime", + min=0, + max=5, + step=0.1, + value=1, + marks={i: str(round(i, 1)) for i in range(6)} + ), + html.Div(id="weight-crime-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) + ], style={"width": "18%"}), + html.Div([ + html.Label("Income", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), + dcc.Slider( + id="weight-income", + min=0, + max=5, + step=0.1, + value=1, + marks={i: str(round(i, 1)) for i in range(6)} + ), + html.Div(id="weight-income-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) + ], style={"width": "18%"}), + html.Div([ + html.Label("Reproduction Rate", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), + dcc.Slider( + id="weight-reproduction", + min=0, + max=5, + step=0.1, + value=1, + marks={i: str(round(i, 1)) for i in range(6)} + ), + html.Div(id="weight-reproduction-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) + ], style={"width": "18%"}) + ] + ) +]) + +# Callback to update chart and toggle visibility +@app.callback( + Output("fisher-chart", "figure"), + [Input("weight-iq", "value"), + Input("weight-moral", "value"), + Input("weight-crime", "value"), + Input("weight-income", "value"), + Input("weight-reproduction", "value")] +) +def update_fisher_chart(weight_iq, weight_moral, weight_crime, weight_income, weight_reproduction): + weighted_data = fisher_data.copy() + weighted_data["IQ"] *= weight_iq + weighted_data["Moral Character"] *= weight_moral + weighted_data["Violent Crime"] *= weight_crime + weighted_data["Income"] *= weight_income + weighted_data["Reproduction Rate"] *= weight_reproduction + + fig = go.Figure() + for col, color in zip( + ["IQ", "Moral Character", "Violent Crime", "Income", "Reproduction Rate"], + ["#636EFA", "#EF553B", "#00CC96", "#AB63FA", "#FFA15A"] + ): + fig.add_trace(go.Bar(x=weighted_data["Group"], y=weighted_data[col], name=col, marker=dict(color=color), opacity=0.75)) + + fig.update_layout( + barmode="group", + plot_bgcolor="white", + font=dict(family="Avenir"), + xaxis=dict(showgrid=False, showline=True, zeroline=False, title="Group"), + yaxis=dict(showgrid=True, title="Weighted Value"), + margin=dict(l=10, r=10, t=20, b=10) + ) + return fig +if __name__ == "__main__": + app.run_server(debug=True, host="0.0.0.0", port=8080) + + diff --git a/fisher_dash_app_1.py b/fisher_dash_app_1.py new file mode 100644 index 0000000..67a8a49 --- /dev/null +++ b/fisher_dash_app_1.py @@ -0,0 +1,65 @@ +from dash import Dash, dcc, html +from dash.dependencies import Input, Output +import plotly.graph_objects as go +import pandas as pd + +app = Dash(__name__) +app.title = "Fisher Statistical Visualization" + +fisher_data = pd.DataFrame({ + "Group": ["White", "Black", "Asian", "Hispanic", "Other"], + "IQ": [100, 108, 105, 102, 98], + "Moral Character": [95, 85, 90, 80, 85], + "Violent Crime": [30, 35, 25, 40, 45], + "Income": [75, 45, 70, 50, 55], + "Reproduction Rate": [48, 55, 47, 60, 52] +}) + +app.layout = html.Div([ + html.H1("Fisher Statistical Visualization"), + html.Div([ + html.Label("Select Variables:"), + dcc.Checklist( + id="variable-selector", + options=[{"label": col, "value": col} for col in fisher_data.columns[1:]], + value=fisher_data.columns[1:] + ), + html.Div([ + html.Label("Adjust Weights for Each Variable:"), + *[ + html.Div([ + html.Label(col), + dcc.Slider(id=f"{col}-weight", min=0, max=5, step=0.1, value=1) + ]) for col in fisher_data.columns[1:] + ] + ]), + ]), + dcc.Graph(id="fisher-chart") +]) + +@app.callback( + Output("fisher-chart", "figure"), + [ + Input("variable-selector", "value"), + *[Input(f"{col}-weight", "value") for col in fisher_data.columns[1:]] + ] +) +def update_chart(variables, *weights): + selected_data = fisher_data[["Group"] + variables].copy() + for i, col in enumerate(variables): + selected_data[col] *= weights[i] + + fig = go.Figure() + for col in variables: + fig.add_trace(go.Bar(x=selected_data["Group"], y=selected_data[col], name=col)) + + fig.update_layout( + barmode="group", + plot_bgcolor="white", + xaxis=dict(title="Group"), + yaxis=dict(title="Weighted Values") + ) + return fig + +if __name__ == "__main__": + app.run_server(debug=True, host="0.0.0.0", port=8080) diff --git a/fisher_statistical_Dockerfile b/fisher_statistical_Dockerfile new file mode 100644 index 0000000..753407f --- /dev/null +++ b/fisher_statistical_Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.9-slim +WORKDIR /app +COPY . /app +RUN pip install --no-cache-dir dash pandas plotly +EXPOSE 8080 +CMD ["python", "fisher_statistical_app.py"] diff --git a/fisher_statistical_app.py b/fisher_statistical_app.py new file mode 100644 index 0000000..ac836b9 --- /dev/null +++ b/fisher_statistical_app.py @@ -0,0 +1,58 @@ +import dash +from dash import dcc, html +from dash.dependencies import Input, Output +import plotly.graph_objects as go +import pandas as pd + +app = dash.Dash(__name__) +app.title = "Fisher Statistical Visualization" + +fisher_data = pd.DataFrame({ + "Group": ["White", "Black", "Asian", "Hispanic", "Other"], + "IQ": [100, 108, 105, 102, 98], + "Moral Character": [95, 85, 90, 80, 85], + "Violent Crime": [30, 35, 25, 40, 45], + "Income": [75, 45, 70, 50, 55], + "Reproduction Rate": [48, 55, 47, 60, 52] +}) + +app.layout = html.Div([ + html.H1("Fisher Statistical Visualization"), + dcc.Graph(id="stat-chart"), + html.Div([ + html.Label("Adjust Weights:"), + dcc.Slider(id="weight-iq", min=0, max=5, value=1, marks={i: str(i) for i in range(6)}), + dcc.Slider(id="weight-moral", min=0, max=5, value=1, marks={i: str(i) for i in range(6)}), + dcc.Slider(id="weight-crime", min=0, max=5, value=1, marks={i: str(i) for i in range(6)}), + dcc.Slider(id="weight-income", min=0, max=5, value=1, marks={i: str(i) for i in range(6)}), + dcc.Slider(id="weight-reproduction", min=0, max=5, value=1, marks={i: str(i) for i in range(6)}) + ]) +]) + +@app.callback( + Output("stat-chart", "figure"), + [Input("weight-iq", "value"), + Input("weight-moral", "value"), + Input("weight-crime", "value"), + Input("weight-income", "value"), + Input("weight-reproduction", "value")] +) +def update_chart(weight_iq, weight_moral, weight_crime, weight_income, weight_reproduction): + weighted_data = fisher_data.copy() + weighted_data["IQ"] *= weight_iq + weighted_data["Moral Character"] *= weight_moral + weighted_data["Violent Crime"] *= weight_crime + weighted_data["Income"] *= weight_income + weighted_data["Reproduction Rate"] *= weight_reproduction + + fig = go.Figure() + for col, color in zip( + ["IQ", "Moral Character", "Violent Crime", "Income", "Reproduction Rate"], + ["#636EFA", "#EF553B", "#00CC96", "#AB63FA", "#FFA15A"] + ): + fig.add_trace(go.Bar(x=weighted_data["Group"], y=weighted_data[col], name=col, marker=dict(color=color))) + fig.update_layout(barmode="group", title="Weighted Statistical Values") + return fig + +if __name__ == "__main__": + app.run_server(debug=True, host="0.0.0.0", port=8080) diff --git a/fisher_visualization.js b/fisher_visualization.js new file mode 100644 index 0000000..fa2a74e --- /dev/null +++ b/fisher_visualization.js @@ -0,0 +1,76 @@ +// Sample data +const data = [ + { group: "White", iq: 100, moral: 95, crime: 30, income: 75, reproduction: 48 }, + { group: "Black", iq: 108, moral: 85, crime: 35, income: 45, reproduction: 55 }, + { group: "Asian", iq: 105, moral: 90, crime: 25, income: 70, reproduction: 47 }, + { group: "Hispanic", iq: 102, moral: 80, crime: 40, income: 50, reproduction: 60 }, + { group: "Other", iq: 98, moral: 85, crime: 45, income: 55, reproduction: 52 }, +]; + +// Chart dimensions +const width = 800, height = 500, margin = { top: 20, right: 20, bottom: 50, left: 70 }; + +// Scales +const xScale = d3.scaleBand() + .domain(data.map(d => d.group)) + .range([margin.left, width - margin.right]) + .padding(0.1); + +const yScale = d3.scaleLinear() + .domain([0, 400]) + .range([height - margin.bottom, margin.top]); + +// SVG Container +const svg = d3.select("#chart").append("svg") + .attr("width", width) + .attr("height", height); + +// Axes +svg.append("g") + .attr("transform", `translate(0,${height - margin.bottom})`) + .call(d3.axisBottom(xScale)); + +svg.append("g") + .attr("transform", `translate(${margin.left},0)`) + .call(d3.axisLeft(yScale)); + +// Bars +const bars = svg.selectAll(".bar") + .data(data) + .enter() + .append("rect") + .attr("class", "bar") + .attr("x", d => xScale(d.group)) + .attr("y", d => yScale(0)) + .attr("width", xScale.bandwidth()) + .attr("height", 0) + .attr("fill", "steelblue"); + +// Initial chart update +function updateChart(weights) { + const updatedData = data.map(d => ({ + group: d.group, + value: d.iq * weights.iq + d.moral * weights.moral - d.crime * weights.crime + d.income * weights.income - d.reproduction * weights.reproduction + })); + + yScale.domain([0, d3.max(updatedData, d => d.value)]); + + bars.data(updatedData) + .transition() + .duration(500) + .attr("y", d => yScale(d.value)) + .attr("height", d => height - margin.bottom - yScale(d.value)); +} + +// Initial weights +const weights = { iq: 1, moral: 1, crime: 1, income: 1, reproduction: 1 }; +updateChart(weights); + +// Slider event listeners +["iq", "moral", "crime", "income", "reproduction"].forEach(variable => { + d3.select(`#slider-${variable}`).on("input", function () { + weights[variable] = +this.value; + d3.select(`#weight-${variable}`).text(this.value.toFixed(1)); + updateChart(weights); + }); +}); diff --git a/fisher_weight1.py b/fisher_weight1.py index b35b8f4..2fbfcd6 100644 --- a/fisher_weight1.py +++ b/fisher_weight1.py @@ -1,12 +1,9 @@ -import dash -from dash import dcc, html -from dash.dependencies import Input, Output -import plotly.graph_objects as go +import streamlit as st import pandas as pd +import plotly.graph_objects as go -# Initialize Dash app -app = dash.Dash(__name__) -app.title = "Fisher Statistical Visualization" +# Title +st.title("Fisher Statistical Visualization") # Generate random data fisher_data = pd.DataFrame({ @@ -18,139 +15,50 @@ "Reproduction Rate": [48, 55, 47, 60, 52] }) -# App layout -app.layout = html.Div(style={"font-family": "Avenir", "padding": "10px", "max-width": "1000px", "margin": "0 auto", "font-size": "0.95em"}, children=[ - # Clickable variable titles for toggling visibility - html.Div( - style={"display": "flex", "justify-content": "center", "gap": "8px", "margin-bottom": "10px"}, - children=[ - html.Div("IQ", id="toggle-iq", style={"color": "#636EFA", "font-weight": "bold", "cursor": "pointer"}), - html.Div("Moral Character", id="toggle-moral", style={"color": "#EF553B", "font-weight": "bold", "cursor": "pointer"}), - html.Div("Violent Crime", id="toggle-crime", style={"color": "#00CC96", "font-weight": "bold", "cursor": "pointer"}), - html.Div("Income", id="toggle-income", style={"color": "#AB63FA", "font-weight": "bold", "cursor": "pointer"}), - html.Div("Reproduction Rate", id="toggle-reproduction", style={"color": "#FFA15A", "font-weight": "bold", "cursor": "pointer"}) - ] - ), +# Sidebar for variable selection +st.sidebar.title("Adjust Variables") - # Bar Chart - dcc.Graph(id="fisher-chart", style={"width": "100%", "height": "400px", "border": "none"}), +# Checkboxes to toggle visibility of variables +visible_columns = {} +for col in ["IQ", "Moral Character", "Violent Crime", "Income", "Reproduction Rate"]: + visible_columns[col] = st.sidebar.checkbox(col, value=True) - # Sliders with corresponding value display - html.Div( - style={"display": "flex", "justify-content": "space-around", "align-items": "center", "margin-top": "10px"}, - children=[ - html.Div([ - html.Label("IQ", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), - dcc.Slider( - id="weight-iq", - min=0, - max=5, - step=0.1, - value=1, - marks={i: str(round(i, 1)) for i in [0, 1, 2, 3, 4, 5]} - ), - html.Div(id="weight-iq-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) - ], style={"width": "18%"}), - html.Div([ - html.Label("Moral Character", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), - dcc.Slider( - id="weight-moral", - min=0, - max=5, - step=0.1, - value=1, - marks={i: str(round(i, 1)) for i in [0, 1, 2, 3, 4, 5]} - ), - html.Div(id="weight-moral-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) - ], style={"width": "18%"}), - html.Div([ - html.Label("Violent Crime", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), - dcc.Slider( - id="weight-crime", - min=0, - max=5, - step=0.1, - value=1, - marks={i: str(round(i, 1)) for i in [0, 1, 2, 3, 4, 5]} - ), - html.Div(id="weight-crime-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) - ], style={"width": "18%"}), - html.Div([ - html.Label("Income", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), - dcc.Slider( - id="weight-income", - min=0, - max=5, - step=0.1, - value=1, - marks={i: str(round(i, 1)) for i in [0, 1, 2, 3, 4, 5]} - ), - html.Div(id="weight-income-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) - ], style={"width": "18%"}), - html.Div([ - html.Label("Reproduction Rate", style={"font-weight": "bold", "font-size": "0.85em", "text-align": "center"}), - dcc.Slider( - id="weight-reproduction", - min=0, - max=5, - step=0.1, - value=1, - marks={i: str(round(i, 1)) for i in [0, 1, 2, 3, 4, 5]} - ), - html.Div(id="weight-reproduction-value", style={"text-align": "center", "font-size": "0.85em", "margin-top": "-10px"}) - ], style={"width": "18%"}) - ] - ) -]) +# Sliders to adjust weights +weights = { + col: st.sidebar.slider(f"{col} Weight", 0.0, 5.0, 1.0, step=0.1) + for col in visible_columns if visible_columns[col] +} -# Callback to update chart and toggle visibility -@app.callback( - Output("fisher-chart", "figure"), - [Input("weight-iq", "value"), - Input("weight-moral", "value"), - Input("weight-crime", "value"), - Input("weight-income", "value"), - Input("weight-reproduction", "value"), - Input("toggle-iq", "n_clicks"), - Input("toggle-moral", "n_clicks"), - Input("toggle-crime", "n_clicks"), - Input("toggle-income", "n_clicks"), - Input("toggle-reproduction", "n_clicks")] -) -def update_fisher_chart(weight_iq, weight_moral, weight_crime, weight_income, weight_reproduction, *toggle_clicks): - visibility = [True, True, True, True, True] +# Apply weights to data +weighted_data = fisher_data.copy() +for col, weight in weights.items(): + weighted_data[col] *= weight - # Toggle visibility based on click counts - for i, clicks in enumerate(toggle_clicks): - if clicks and clicks % 2 == 1: - visibility[i] = False +# Plot the data +fig = go.Figure() - weighted_data = fisher_data.copy() - weighted_data["IQ"] *= weight_iq - weighted_data["Moral Character"] *= weight_moral - weighted_data["Violent Crime"] *= weight_crime - weighted_data["Income"] *= weight_income - weighted_data["Reproduction Rate"] *= weight_reproduction +for col, color in zip( + ["IQ", "Moral Character", "Violent Crime", "Income", "Reproduction Rate"], + ["#636EFA", "#EF553B", "#00CC96", "#AB63FA", "#FFA15A"] +): + if visible_columns[col]: + fig.add_trace(go.Bar( + x=weighted_data["Group"], + y=weighted_data[col], + name=col, + marker=dict(color=color), + opacity=0.75 + )) - fig = go.Figure() - for col, color, is_visible in zip( - ["IQ", "Moral Character", "Violent Crime", "Income", "Reproduction Rate"], - ["#636EFA", "#EF553B", "#00CC96", "#AB63FA", "#FFA15A"], - visibility - ): - if is_visible: - fig.add_trace(go.Bar(x=weighted_data["Group"], y=weighted_data[col], name=col, marker=dict(color=color), opacity=0.75)) - - fig.update_layout( - barmode="group", - plot_bgcolor="white", - font=dict(family="Avenir"), - xaxis=dict(showgrid=False, showline=True, zeroline=False, title="Group"), - yaxis=dict(showgrid=True, showticklabels=False, title=""), - showlegend=False, - margin=dict(l=10, r=10, t=20, b=10) - ) - return fig +fig.update_layout( + barmode="group", + plot_bgcolor="white", + font=dict(family="Avenir"), + xaxis=dict(showgrid=False, showline=True, zeroline=False, title="Group"), + yaxis=dict(showgrid=True, title="Weighted Value"), + margin=dict(l=10, r=10, t=40, b=10), + height=500 +) -if __name__ == "__main__": - app.run_server(debug=True, port=8050) +# Display chart +st.plotly_chart(fig) diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..8043198 --- /dev/null +++ b/install.sh @@ -0,0 +1,216 @@ +#!/bin/sh +# +# Copyright 2013 Google Inc. All Rights Reserved. +# + +echo Welcome to the Google Cloud CLI! + +# +# +# CLOUDSDK_ROOT_DIR (a) installation root dir +# CLOUDSDK_PYTHON (u) python interpreter path +# CLOUDSDK_GSUTIL_PYTHON (u) python interpreter path for gsutil +# CLOUDSDK_PYTHON_ARGS (u) python interpreter arguments +# CLOUDSDK_PYTHON_SITEPACKAGES (u) use python site packages +# CLOUDSDK_BQ_PYTHON (u) python interpreter for bq +# CLOUDSDK_ENCODING (u) python io encoding for gcloud +# +# (a) always defined by the preamble +# (u) user definition overrides preamble + +# Wrapper around 'which' and 'command -v', tries which first, then falls back +# to command -v +_cloudsdk_which() { + which "$1" 2>/dev/null || command -v "$1" 2>/dev/null +} + +order_python_no_check() { + selected_version="" + for python_version in "$@" + do + if [ -z "$selected_version" ]; then + if _cloudsdk_which $python_version > /dev/null; then + selected_version=$python_version + fi + fi + done + if [ -z "$selected_version" ]; then + selected_version=python + fi + echo $selected_version +} + +order_python() { + selected_version="" + for python_version in "$@" + do + if [ -z "$selected_version" ]; then + if "$python_version" -c "import sys; sys.exit(0 if ((3,8) <= (sys.version_info.major, sys.version_info.minor) <= (3,12)) else 1)" > /dev/null 2>&1; then + selected_version=$python_version + fi + fi + done + echo $selected_version +} + +# Determines the real cloud sdk root dir given the script path. +# Would be easier with a portable "readlink -f". +_cloudsdk_root_dir() { + case $1 in + /*) _cloudsdk_path=$1 + ;; + */*) _cloudsdk_path=$PWD/$1 + ;; + *) _cloudsdk_path=$(_cloudsdk_which $1) + case $_cloudsdk_path in + /*) ;; + *) _cloudsdk_path=$PWD/$_cloudsdk_path ;; + esac + ;; + esac + _cloudsdk_dir=0 + while : + do + while _cloudsdk_link=$(readlink "$_cloudsdk_path") + do + case $_cloudsdk_link in + /*) _cloudsdk_path=$_cloudsdk_link ;; + *) _cloudsdk_path=$(dirname "$_cloudsdk_path")/$_cloudsdk_link ;; + esac + done + case $_cloudsdk_dir in + 1) break ;; + esac + if [ -d "${_cloudsdk_path}" ]; then + break + fi + _cloudsdk_dir=1 + _cloudsdk_path=$(dirname "$_cloudsdk_path") + done + while : + do case $_cloudsdk_path in + */) _cloudsdk_path=$(dirname "$_cloudsdk_path/.") + ;; + */.) _cloudsdk_path=$(dirname "$_cloudsdk_path") + ;; + */bin) dirname "$_cloudsdk_path" + break + ;; + *) echo "$_cloudsdk_path" + break + ;; + esac + done +} +CLOUDSDK_ROOT_DIR=$(_cloudsdk_root_dir "$0") + +setup_cloudsdk_python() { + # if $CLOUDSDK_PYTHON is not set, look for bundled python else + # prefer python3 over python + if [ -z "$CLOUDSDK_PYTHON" ]; then + # Is bundled python present and working? + ARCH=$(uname -m 2>/dev/null) + if [ -x "$CLOUDSDK_ROOT_DIR/platform/bundledpythonunix/bin/python3" ] && \ + [ "$ARCH" = "x86_64" ] && \ + "$CLOUDSDK_ROOT_DIR/platform/bundledpythonunix/bin/python3" --version > /dev/null 2>&1; + then + CLOUDSDK_PYTHON="$CLOUDSDK_ROOT_DIR/platform/bundledpythonunix/bin/python3" + CLOUDSDK_PYTHON_SITEPACKAGES=1 + else + GLOBAL_CONFIG="$HOME/.config/gcloud" + if [ "$CLOUDSDK_CONFIG" ]; + then + GLOBAL_CONFIG="$CLOUDSDK_CONFIG" + fi + # If there is an enabled virtualenv activate it + if [ -f "$GLOBAL_CONFIG/virtenv/bin/activate" ]; + then + if [ -f "$GLOBAL_CONFIG/virtenv/enabled" ]; + then + . "$GLOBAL_CONFIG/virtenv/bin/activate" + fi + fi + CLOUDSDK_PYTHON=$(order_python python3 python python3.11 python3.10 python3.9 python3.8 python3.12) + if [ -z "$CLOUDSDK_PYTHON" ]; then + CLOUDSDK_PYTHON=$(order_python_no_check python3 python) + fi + fi + fi +} + +setup_cloudsdk_python + +# $PYTHONHOME can interfere with gcloud. Users should use +# CLOUDSDK_PYTHON to configure which python gcloud uses. +unset PYTHONHOME + +# if CLOUDSDK_PYTHON_SITEPACKAGES and VIRTUAL_ENV are empty +case :$CLOUDSDK_PYTHON_SITEPACKAGES:$VIRTUAL_ENV: in +:::) # add -S to CLOUDSDK_PYTHON_ARGS if not already there + case " $CLOUDSDK_PYTHON_ARGS " in + *" -S "*) ;; + " ") CLOUDSDK_PYTHON_ARGS="-S" + ;; + *) CLOUDSDK_PYTHON_ARGS="$CLOUDSDK_PYTHON_ARGS -S" + ;; + esac + unset CLOUDSDK_PYTHON_SITEPACKAGES + ;; +*) # remove -S from CLOUDSDK_PYTHON_ARGS if already there + while :; do + case " $CLOUDSDK_PYTHON_ARGS " in + *" -S "*) CLOUDSDK_PYTHON_ARGS=${CLOUDSDK_PYTHON_ARGS%%-S*}' '${CLOUDSDK_PYTHON_ARGS#*-S} ;; + *) break ;; + esac + done + # if CLOUDSDK_PYTHON_SITEPACKAGES is empty + [ -z "$CLOUDSDK_PYTHON_SITEPACKAGES" ] && + CLOUDSDK_PYTHON_SITEPACKAGES=1 + export CLOUDSDK_PYTHON_SITEPACKAGES + ;; +esac + +# Allow users to set the Python interpreter used to launch gsutil, falling +# back to the CLOUDSDK_PYTHON interpreter otherwise. +if [ -z "$CLOUDSDK_GSUTIL_PYTHON" ]; then + CLOUDSDK_GSUTIL_PYTHON="$CLOUDSDK_PYTHON" +fi + +if [ -z "$CLOUDSDK_BQ_PYTHON" ]; then + CLOUDSDK_BQ_PYTHON="$CLOUDSDK_PYTHON" +fi + +if [ -z "$CLOUDSDK_ENCODING" ]; then + if [ -z "$PYTHONIOENCODING" ]; then + CLOUDSDK_ENCODING=UTF-8 + else + CLOUDSDK_ENCODING="$PYTHONIOENCODING" + fi +fi + +export CLOUDSDK_ROOT_DIR +export CLOUDSDK_PYTHON_ARGS +export CLOUDSDK_GSUTIL_PYTHON +export CLOUDSDK_BQ_PYTHON +export CLOUDSDK_ENCODING +export PYTHONIOENCODING="$CLOUDSDK_ENCODING" + +# + +if [ -z "$CLOUDSDK_PYTHON" ]; then + if [ -z "$( _cloudsdk_which python)" ]; then + echo + echo "To use the Google Cloud CLI, you must have Python installed and on your PATH." + echo "As an alternative, you may also set the CLOUDSDK_PYTHON environment variable" + echo "to the location of your Python executable." + exit 1 + fi +fi + +# Warns user if they are running as root. +if [ $(id -u) = 0 ]; then + echo "WARNING: You appear to be running this script as root. This may cause " + echo "the installation to be inaccessible to users other than the root user." +fi + +"$CLOUDSDK_PYTHON" $CLOUDSDK_PYTHON_ARGS "${CLOUDSDK_ROOT_DIR}/bin/bootstrapping/install.py" "$@" diff --git a/landing_page.js b/landing_page.js index 757571f..40381f3 100644 --- a/landing_page.js +++ b/landing_page.js @@ -6,7 +6,7 @@ const lineData = [ { label: 'Family 72: A Case Study', url: 'family-72.html', xPos: 450, length: 420, textOffsetY: -15 }, { label: 'Pearson\'s Legacy', url: 'galton-disciple.html', xPos: 550, length: 420, textOffsetY: 5 }, { label: 'Fisher\'s Controversies', url: 'fisher.html', xPos: 630, length: 330 }, - { label: 'The Persistent Variable', url: 'the_constant_varible.html', xPos: 725, length: 240 }, + { label: 'The Persistent Variable', url: 'the_constant_variable.html', xPos: 725, length: 240 }, { label: 'Modern Metrics', url: 'world-happiness-report.html', xPos: 850, length: 150 } ]; diff --git a/modern_statistical_Dockerfile b/modern_statistical_Dockerfile new file mode 100644 index 0000000..abe5295 --- /dev/null +++ b/modern_statistical_Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.9-slim +WORKDIR /app +COPY . /app +RUN pip install --no-cache-dir dash pandas plotly +EXPOSE 8080 +CMD ["python", "modern_statistical_app.py"] diff --git a/modern_statistical_app.py b/modern_statistical_app.py new file mode 100644 index 0000000..6baac31 --- /dev/null +++ b/modern_statistical_app.py @@ -0,0 +1,37 @@ +import dash +from dash import dcc, html +from dash.dependencies import Input, Output +import plotly.graph_objects as go +import pandas as pd + +app = dash.Dash(__name__) +app.title = "Modern Statistical Analysis Visualization" + +modern_data = pd.DataFrame({ + "Group": ["White", "Black", "Asian", "Hispanic", "Other"], + "IQ": [101, 98, 96, 95, 100], + "Educational Attainment": [90, 75, 79, 70, 80], + "Crime Statistics": [40, 39, 33, 40, 41], + "Income Disparity": [70, 65, 85, 60, 65], + "Health Outcomes": [80, 55, 75, 65, 70] +}) + +app.layout = html.Div([ + html.H1("Modern Statistical Analysis Visualization"), + dcc.Graph(id="modern-chart"), + html.Div([html.Label("Adjust Weights:"), + dcc.Slider(id="weight-iq", min=0, max=5, value=1, marks={i: str(i) for i in range(6)})]) +]) + +@app.callback( + Output("modern-chart", "figure"), + Input("weight-iq", "value") +) +def update_chart(weight_iq): + data = modern_data.copy() + data["IQ"] *= weight_iq + fig = go.Figure(data=[go.Bar(x=data["Group"], y=data["IQ"], name="IQ")]) + return fig + +if __name__ == "__main__": + app.run_server(debug=True, host="0.0.0.0", port=8080) diff --git a/requirements.txt b/requirements.txt index 23b6c3d..fc968d1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -streamlit +dash plotly pandas