Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -525,8 +525,19 @@ button.preset-btn:hover,.preset-btn button:hover{background:var(--text)!importan
|
|
| 525 |
.ctl-head{padding-bottom:8px}
|
| 526 |
.ctl-head strong{display:block;font:500 15px/1.2 var(--sans);color:var(--text)}
|
| 527 |
.ctl-head p{margin-top:4px!important;font-size:12px;color:var(--muted)}
|
| 528 |
-
.
|
| 529 |
-
.param-group
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 530 |
.control-panel [data-testid="block-info"],.control-panel label>span{font-size:12.5px!important;color:#D8D5CF!important}
|
| 531 |
.control-panel [data-testid="block-info"]+div,.control-panel .info{color:var(--muted)!important}
|
| 532 |
.control-panel input[type="number"]{font:400 12px var(--mono)!important;background:rgba(255,255,255,.04)!important;border:1px solid var(--line)!important;border-radius:6px!important;color:var(--text)!important}
|
|
@@ -645,8 +656,14 @@ button.compare-button:hover,.compare-button button:hover{background:var(--text)!
|
|
| 645 |
|
| 646 |
/* methods */
|
| 647 |
.methods{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-top:48px}
|
| 648 |
-
.m-col{
|
| 649 |
-
.m-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 650 |
.gradio-container .m-col h3{margin:12px 0 10px!important;font:500 15px/1.3 var(--sans)!important;color:var(--text)!important}
|
| 651 |
.gradio-container .m-col p{font-size:13px;line-height:1.6;color:var(--text-2);margin:0 0 10px!important;text-wrap:pretty}
|
| 652 |
.fx{font:400 12.5px var(--mono);color:var(--text);padding:10px 12px;margin:4px 0 10px;border-radius:8px;background:rgba(0,0,0,.28);border:1px solid var(--line);white-space:nowrap;overflow-x:auto}
|
|
@@ -700,7 +717,7 @@ MASTHEAD = f"""
|
|
| 700 |
<div class="intro">
|
| 701 |
<div class="eyebrow">A laboratory for collective opinion</div>
|
| 702 |
<h1>How opinions <em>move</em> through a network.</h1>
|
| 703 |
-
<p>Set up a synthetic population, choose who talks to whom, add confirmation bias, committed minorities or a persistent external signal
|
| 704 |
</div>
|
| 705 |
"""
|
| 706 |
|
|
@@ -782,20 +799,20 @@ with gr.Blocks(title="SocialDynamics Lab — opinion dynamics simulator") as dem
|
|
| 782 |
with gr.Row(equal_height=False, elem_classes=["lab-row"]):
|
| 783 |
with gr.Column(scale=3, min_width=300, elem_classes=["control-panel"]):
|
| 784 |
gr.HTML('<div class="ctl-head"><strong>Parameters</strong><p>Deterministic for a fixed seed.</p></div>')
|
| 785 |
-
with gr.Accordion("Population & network", open=True, elem_classes=["param-group"]):
|
| 786 |
n_agents = gr.Radio([100, 500, 1000], value=100, label="Population size")
|
| 787 |
network = gr.Dropdown(["Random", "Small World", "Scale Free"], value="Small World", label="Network structure")
|
| 788 |
initial_opinion = gr.Dropdown(["Random", "Neutral", "Polarized"], value="Random", label="Initial opinion state")
|
| 789 |
-
with gr.Accordion("Dynamics", open=True, elem_classes=["param-group"]):
|
| 790 |
confirmation_bias = gr.Slider(0, 1, value=0.45, step=0.01, label="Confirmation bias (β)", info="Suppresses influence from dissimilar neighbours.")
|
| 791 |
social_influence = gr.Slider(0, 1, value=0.45, step=0.01, label="Social influence (α)", info="Speed of movement toward the neighbourhood target.")
|
| 792 |
stubborn_fraction = gr.Slider(0, 0.30, value=0.05, step=0.01, label="Stubborn agents", info="Share of agents that never update.")
|
| 793 |
stubborn_mode = gr.Dropdown(["Keep initial", "Positive (+1)", "Negative (-1)", "Split extremes"], value="Split extremes", label="Stubborn stance")
|
| 794 |
-
with gr.Accordion("External signal", open=False, elem_classes=["param-group"]):
|
| 795 |
misinformation_exposure = gr.Slider(0, 1, value=0.25, step=0.01, label="Misinformation exposure", info="Share of adaptive agents receiving the signal.")
|
| 796 |
misinformation_strength = gr.Slider(0, 1, value=0.35, step=0.01, label="Signal strength")
|
| 797 |
misinformation_direction = gr.Radio(["Positive (+1)", "Negative (-1)"], value="Positive (+1)", label="Signal direction")
|
| 798 |
-
with gr.Accordion("Run settings", open=False, elem_classes=["param-group"]):
|
| 799 |
noise = gr.Slider(0, 0.20, value=0.02, step=0.005, label="Random noise (σ)")
|
| 800 |
steps = gr.Slider(50, 300, value=120, step=10, label="Simulation horizon (steps)")
|
| 801 |
seed = gr.Number(value=42, precision=0, label="Random seed")
|
|
|
|
| 525 |
.ctl-head{padding-bottom:8px}
|
| 526 |
.ctl-head strong{display:block;font:500 15px/1.2 var(--sans);color:var(--text)}
|
| 527 |
.ctl-head p{margin-top:4px!important;font-size:12px;color:var(--muted)}
|
| 528 |
+
.pg-pop{--acc:108,142,245}.pg-dyn{--acc:179,154,232}.pg-sig{--acc:217,164,65}.pg-run{--acc:95,184,138}
|
| 529 |
+
.param-group{position:relative;overflow:hidden;border:1px solid rgba(var(--acc),.18)!important;border-radius:12px!important;background:linear-gradient(180deg,rgba(var(--acc),.07),rgba(var(--acc),.015) 60%)!important;padding:4px 12px 10px!important;margin:0 0 10px!important;box-shadow:inset 0 1px 0 rgba(255,255,255,.04)!important}
|
| 530 |
+
.param-group:before{content:"";position:absolute;left:12px;right:12px;top:0;height:1px;background:linear-gradient(90deg,transparent,rgba(var(--acc),.7),transparent)}
|
| 531 |
+
.param-group>div,.param-group .form,.param-group .block{background:transparent!important;border:0!important}
|
| 532 |
+
.param-group>button,.param-group>.label-wrap,.param-group button.label-wrap{display:flex!important;align-items:center!important;gap:10px!important;width:100%!important;font:500 13px/1.2 var(--sans)!important;letter-spacing:0;color:var(--text)!important;background:transparent!important;border:0!important;padding:10px 0 6px!important}
|
| 533 |
+
.param-group>button:before,.param-group>.label-wrap:before,.param-group button.label-wrap:before{content:"";width:8px;height:8px;border-radius:50%;flex:none;background:rgb(var(--acc));box-shadow:0 0 10px rgba(var(--acc),.8)}
|
| 534 |
+
.param-group .label-wrap .icon,.param-group>button span.icon{color:rgb(var(--acc))!important;margin-left:auto}
|
| 535 |
+
.param-group input[type="range"]{--slider-color:rgb(var(--acc))!important;accent-color:rgb(var(--acc))}
|
| 536 |
+
.param-group input[type="range"]::-webkit-slider-thumb{background:rgb(var(--acc))!important;box-shadow:0 0 0 4px rgba(var(--acc),.18),0 2px 6px rgba(0,0,0,.6)!important}
|
| 537 |
+
.param-group input[type="range"]::-moz-range-thumb{background:rgb(var(--acc))!important}
|
| 538 |
+
.param-group input[type="range"]::-moz-range-progress{background:rgb(var(--acc))!important}
|
| 539 |
+
.param-group label:has(>input[type="radio"]:checked),.param-group label.selected:has(>input[type="radio"]){background:rgba(var(--acc),.22)!important;color:#fff!important}
|
| 540 |
+
.param-group input[type="number"]:focus,.param-group input[type="text"]:focus{border-color:rgba(var(--acc),.6)!important}
|
| 541 |
.control-panel [data-testid="block-info"],.control-panel label>span{font-size:12.5px!important;color:#D8D5CF!important}
|
| 542 |
.control-panel [data-testid="block-info"]+div,.control-panel .info{color:var(--muted)!important}
|
| 543 |
.control-panel input[type="number"]{font:400 12px var(--mono)!important;background:rgba(255,255,255,.04)!important;border:1px solid var(--line)!important;border-radius:6px!important;color:var(--text)!important}
|
|
|
|
| 656 |
|
| 657 |
/* methods */
|
| 658 |
.methods{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-top:48px}
|
| 659 |
+
.m-col:nth-child(1){--acc:108,142,245}.m-col:nth-child(2){--acc:95,184,138}.m-col:nth-child(3){--acc:179,154,232}.m-col:nth-child(4){--acc:217,164,65}
|
| 660 |
+
.m-col{position:relative;overflow:hidden;min-width:0;padding:20px;background:radial-gradient(420px 180px at 0% 0%,rgba(var(--acc),.14),transparent 70%),var(--card-bg)!important;border-color:rgba(var(--acc),.16)!important}
|
| 661 |
+
.m-col:before{content:"";position:absolute;left:20px;right:20px;top:0;height:1px;background:linear-gradient(90deg,transparent,rgba(var(--acc),.8),transparent)}
|
| 662 |
+
.m-num{display:inline-flex;align-items:center;gap:7px;font:500 10.5px var(--mono);color:rgb(var(--acc));padding:4px 9px;border-radius:999px;background:rgba(var(--acc),.12);border:1px solid rgba(var(--acc),.25)}
|
| 663 |
+
.m-num:before{content:"";width:5px;height:5px;border-radius:50%;background:rgb(var(--acc));box-shadow:0 0 8px rgb(var(--acc))}
|
| 664 |
+
.m-col .m-list b{color:rgb(var(--acc))!important}
|
| 665 |
+
.m-col .fx{border-color:rgba(var(--acc),.25)!important;background:rgba(var(--acc),.06)!important}
|
| 666 |
+
.m-col .refs li::marker{color:rgb(var(--acc))}
|
| 667 |
.gradio-container .m-col h3{margin:12px 0 10px!important;font:500 15px/1.3 var(--sans)!important;color:var(--text)!important}
|
| 668 |
.gradio-container .m-col p{font-size:13px;line-height:1.6;color:var(--text-2);margin:0 0 10px!important;text-wrap:pretty}
|
| 669 |
.fx{font:400 12.5px var(--mono);color:var(--text);padding:10px 12px;margin:4px 0 10px;border-radius:8px;background:rgba(0,0,0,.28);border:1px solid var(--line);white-space:nowrap;overflow-x:auto}
|
|
|
|
| 717 |
<div class="intro">
|
| 718 |
<div class="eyebrow">A laboratory for collective opinion</div>
|
| 719 |
<h1>How opinions <em>move</em> through a network.</h1>
|
| 720 |
+
<p>Set up a synthetic population, choose who talks to whom, add confirmation bias, committed minorities or a persistent external signal — then watch local influence rules produce consensus, drift or division.</p>
|
| 721 |
</div>
|
| 722 |
"""
|
| 723 |
|
|
|
|
| 799 |
with gr.Row(equal_height=False, elem_classes=["lab-row"]):
|
| 800 |
with gr.Column(scale=3, min_width=300, elem_classes=["control-panel"]):
|
| 801 |
gr.HTML('<div class="ctl-head"><strong>Parameters</strong><p>Deterministic for a fixed seed.</p></div>')
|
| 802 |
+
with gr.Accordion("Population & network", open=True, elem_classes=["param-group", "pg-pop"]):
|
| 803 |
n_agents = gr.Radio([100, 500, 1000], value=100, label="Population size")
|
| 804 |
network = gr.Dropdown(["Random", "Small World", "Scale Free"], value="Small World", label="Network structure")
|
| 805 |
initial_opinion = gr.Dropdown(["Random", "Neutral", "Polarized"], value="Random", label="Initial opinion state")
|
| 806 |
+
with gr.Accordion("Dynamics", open=True, elem_classes=["param-group", "pg-dyn"]):
|
| 807 |
confirmation_bias = gr.Slider(0, 1, value=0.45, step=0.01, label="Confirmation bias (β)", info="Suppresses influence from dissimilar neighbours.")
|
| 808 |
social_influence = gr.Slider(0, 1, value=0.45, step=0.01, label="Social influence (α)", info="Speed of movement toward the neighbourhood target.")
|
| 809 |
stubborn_fraction = gr.Slider(0, 0.30, value=0.05, step=0.01, label="Stubborn agents", info="Share of agents that never update.")
|
| 810 |
stubborn_mode = gr.Dropdown(["Keep initial", "Positive (+1)", "Negative (-1)", "Split extremes"], value="Split extremes", label="Stubborn stance")
|
| 811 |
+
with gr.Accordion("External signal", open=False, elem_classes=["param-group", "pg-sig"]):
|
| 812 |
misinformation_exposure = gr.Slider(0, 1, value=0.25, step=0.01, label="Misinformation exposure", info="Share of adaptive agents receiving the signal.")
|
| 813 |
misinformation_strength = gr.Slider(0, 1, value=0.35, step=0.01, label="Signal strength")
|
| 814 |
misinformation_direction = gr.Radio(["Positive (+1)", "Negative (-1)"], value="Positive (+1)", label="Signal direction")
|
| 815 |
+
with gr.Accordion("Run settings", open=False, elem_classes=["param-group", "pg-run"]):
|
| 816 |
noise = gr.Slider(0, 0.20, value=0.02, step=0.005, label="Random noise (σ)")
|
| 817 |
steps = gr.Slider(50, 300, value=120, step=10, label="Simulation horizon (steps)")
|
| 818 |
seed = gr.Number(value=42, precision=0, label="Random seed")
|