From 535090eb090ccc48feb0458cc5b40c7138326315 Mon Sep 17 00:00:00 2001 From: tsuki Date: Tue, 3 Oct 2023 22:12:16 -0700 Subject: [PATCH 01/17] Update Algorithm.py --- Algorithm.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Algorithm.py b/Algorithm.py index d61ee9f..0d47092 100644 --- a/Algorithm.py +++ b/Algorithm.py @@ -3,18 +3,18 @@ import Node as nn import math, random -# Loop through database -# If a node is negative, lower the chances of its neighbors being p_zero by their age likelihood -# Sample most likely p_zero -# Repeat - -# After (.6 * SIZE) times: -# Run simulation on most likely and find infection pattern -# Calculate likelihood of being p_zero - class Algorithm(): - def __init__(self, size): - self.nodeLikelihoods = [5] * size + def __init__(self, size, negativeEffectBias, positiveBias, positiveEffectBias, similarityWeight): + self.nodeLikelihoods = [1] * size + # self.percentSamplesAlloted = 0.2 + # self.percentTracesAlloted = 0.05 + + self.negativeEffectBias = negativeEffectBias + + self.positiveBias = positiveBias + self.positiveEffectBias = positiveEffectBias + + self.similarityWeight = similarityWeight def InitialScan(self, nodes): # All negative nodes can't be patient zero, and the chances @@ -23,11 +23,11 @@ def InitialScan(self, nodes): if node.state == 0: self.nodeLikelihoods[node.id] = 0 for neighbor in node.connections: - self.nodeLikelihoods[neighbor.id] /= 2 + self.nodeLikelihoods[neighbor.id] += self.negativeEffectBias elif node.state == 1: - self.nodeLikelihoods[node.id] += 0.1 + self.nodeLikelihoods[node.id] += self.positiveBias for neighbor in node.connections: - self.nodeLikelihoods[neighbor.id] += 0.1 + self.nodeLikelihoods[neighbor.id] += self.positiveEffectBias def ChooseOneToSample(self, player): # Find most likely after initial scan @@ -52,7 +52,7 @@ def ChooseOneToSample(self, player): return random.choice(likelyNodes) - def FindDifference(list1, list2): + def FindDifference(self, list1, list2): # Calculate Jaccard similarity intersection = len(set(list1).intersection(set(list2))) union = len(set(list1).union(set(list2))) @@ -72,9 +72,9 @@ def TraceSpreadPattern(self, Player, target_node): infectionsForNewPlayer = [node.state for node in new_player.nodes] infectionsForCurrentPlayer = [node.state for node in Player.nodes] - difference = math.fabs(Algorithm.FindDifference(infectionsForNewPlayer, infectionsForCurrentPlayer)) + difference = math.fabs(self.FindDifference(infectionsForNewPlayer, infectionsForCurrentPlayer)) - self.nodeLikelihoods[Player.nodes[target_node].id] -= difference + self.nodeLikelihoods[Player.nodes[target_node].id] -= (difference * self.similarityWeight) def getSortedIds(self): indexed_arr = [(value, index) for index, value in enumerate(self.nodeLikelihoods)] @@ -85,4 +85,4 @@ def getSortedIds(self): # Extract the sorted indices sorted_indices = [index for _, index in sorted_arr] - return sorted_indices \ No newline at end of file + return sorted_indices From 485b0660eefc68302485769c8cbe57753fd5dc2a Mon Sep 17 00:00:00 2001 From: tsuki Date: Tue, 3 Oct 2023 22:12:36 -0700 Subject: [PATCH 02/17] Update Node.py --- Node.py | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/Node.py b/Node.py index a517fa0..eac6bbc 100644 --- a/Node.py +++ b/Node.py @@ -12,13 +12,10 @@ def __init__(self, id, centerValues): self.visibleToPlayer = False self.isPatientZero = False self.timeInfected = None + self.selectedByAI = "False" - while True: - self.X = random.randint(2, 98) * 30 - self.Y = random.randint(2, 98) * 30 - - if (self.X, self.Y) not in centerValues: - break + self.X = 0 + self.Y = 0 self.age = random.randint(1, 80) @@ -55,12 +52,13 @@ def calculateLikelihood(self, enableAlwaysInfection=False): def infectNeighbors(self, time): # Infect all uninfected neighbors for neighbor in self.connections: - # Calculate infection likelihood - likelihood = neighbor.calculateLikelihood() - - if random.randint(0, 1000)/10 <= likelihood: - neighbor.state = 1 - neighbor.timeInfected = time + if neighbor.state == 0: + # Calculate infection likelihood + likelihood = neighbor.calculateLikelihood() + + if random.randint(0, 1000)/10 <= likelihood: + neighbor.state = 1 + neighbor.timeInfected = time def createNodeNetwork(numberOfNodes, nodes, min_connections, max_connections): # Initialize center values: @@ -79,18 +77,6 @@ def createNodeNetwork(numberOfNodes, nodes, min_connections, max_connections): for node in nodes: node.makeConnections(nodes, min_connections, max_connections) - # print("------ Creating Network -----") - - # For testing: Print network of nodes - # for i in range(len(nodes)): - #neighborPos = nodes[i].connectNumbers -#please do not touch this code i had to go but i will get this sorted out pls pls thanks - # print(f"Node {i}: Connected with {nodes[i].connectNumbers}") - - #window.DrawLines(i, neighborPos) - - # print("--------- DONE -----------") - def runInfectionSimulation(numDays, nodes, selected_p_zero=None): # Select patient zero p_zero = selected_p_zero if selected_p_zero else random.choice(nodes) @@ -116,4 +102,4 @@ def runInfectionSimulation(numDays, nodes, selected_p_zero=None): if node.state == 1: node.infectNeighbors(day) - return p_zero.id \ No newline at end of file + return p_zero.id From d7b5afea2fe8f14dce2e76f17bd33bec6872d076 Mon Sep 17 00:00:00 2001 From: tsuki Date: Tue, 3 Oct 2023 22:12:56 -0700 Subject: [PATCH 03/17] Update Player.py --- Player.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Player.py b/Player.py index ff58d96..e7e38a4 100644 --- a/Player.py +++ b/Player.py @@ -2,12 +2,12 @@ import Node as nn class Player(): - def __init__(self): + def __init__(self, size, time, min, max, percent): self.nodes = [] # list of "Node" objects - self.size = 820 - self.time = 4 - self.min_connections, self.max_connections = 1, 2 - self.num_visible_to_player = round(0.3 * self.size) # Replace .1 with percent nodes visible to player + self.size = size + self.time = time + self.min_connections, self.max_connections = min, max + self.num_visible_to_player = round(percent * self.size) # Replace .1 with percent nodes visible to player # new shit self.sampled = [] @@ -54,4 +54,3 @@ def lockin(self, prediction_id): self.is_winner = False self.is_done = True - From b71dd310e2a40cd4ab67db7362dfbc62f88e8bba Mon Sep 17 00:00:00 2001 From: tsuki Date: Tue, 3 Oct 2023 22:13:25 -0700 Subject: [PATCH 04/17] Update and rename Window.py to Graph.py --- Graph.py | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Window.py | 56 ------------------------------------ 2 files changed, 85 insertions(+), 56 deletions(-) create mode 100644 Graph.py delete mode 100644 Window.py diff --git a/Graph.py b/Graph.py new file mode 100644 index 0000000..9bf4d71 --- /dev/null +++ b/Graph.py @@ -0,0 +1,85 @@ +import networkx as nx +import matplotlib.pyplot as plt +from pyvis.network import Network + +def CreateGraphHTML(player, path): + G = nx.Graph() + + elements = [] + + for i, node in enumerate(player.nodes): + + if node.visibleToPlayer: + if node.state == 1 and node.isPatientZero: + status = "Infected" + color = "purple" + elif node.state == 1: + status = "Infected" + color = "red" + else: + status = "Not Infected" + color = "green" + else: + status = "Unknown" + color = "gray" + + elements.append((i, {"ID": str(node.id),\ + "Status": status,\ + "color": color,\ + "Age": str(node.age),\ + "Connections": str(node.connectNumbers),\ + "TimeInfected": str(node.timeInfected) if node.timeInfected else "N/A",\ + "chosen": node.selectedByAI + })) + + G.add_nodes_from(elements) + + for node in player.nodes: + for connection in node.connectNumbers: + G.add_edge(node.id, connection) + + nt = Network(notebook=True) + nt.from_nx(G) + + nt.width = "70%" + + nt.set_options(""" + var options = { + "physics": { + "forceAtlas2Based": { + "springLength": 100 + }, + "minVelocity": 0.75, + "solver": "forceAtlas2Based" + } + } + """) + + # Add node information to be displayed on hover + for node in nt.nodes: + node_str = """Node {ID} - Status: {Status} + + Age: {Age} y/o + Connections: {Connections} + Time Infected: {TimeInfected} + + Chosen By AI: {chosen} + """ + node["title"] = node_str.format(**node) + + if node["chosen"] == "True": + node["size"] = 30 + + # nt.show("template.html") # Save the visualization to an HTML file + + html = nt.generate_html().split("\n") + + if len(player.nodes) < 100: + node_line, edges_line = 90, 91 + else: + node_line, edges_line = 168, 169 + + nodes = html[node_line] + edges = html[edges_line] + + return nodes, edges diff --git a/Window.py b/Window.py deleted file mode 100644 index 90c9d6e..0000000 --- a/Window.py +++ /dev/null @@ -1,56 +0,0 @@ -import tkinter as tk -import keyboard - -def onObjectClick(root, canvas, player): - def inner(event): - canvas_item = event.widget.find_withtag(tk.CURRENT) - if canvas_item: - print(event.x, event.y) - tags = event.widget.gettags(canvas_item[0]) - for tag in tags: - if tag.startswith("Node-"): - node_id = tag[len("Node-"):] - # Now you have the node_id - - if keyboard.is_pressed('enter'): - print(f'The player is locking in {node_id}') - player.lockin(int(node_id)) - update(root, canvas, player) - else: - player.sample(int(node_id)) - update(root, canvas, player) - - break # Assuming there's only one "Node-" tag per object - - return inner - -def CreateNetwork(root, canvas, player): - running = True - - while running: - for node in player.nodes: - for neighbor in node.connections: - canvas.create_line(node.X+15, node.Y+15, neighbor.X+15, neighbor.Y+15, fill="burlywood", dash=(100)) - - for node in player.nodes: - if node.visibleToPlayer: - color = "tomato" if node.state == 1 else "pale green" - color = "purple" if node.isPatientZero else color - else: - color = "white" - - newNode = canvas.create_oval(node.X, node.Y, \ - node.X + 30, node.Y + 30, \ - fill=color, outline="white", \ - width=2, tags="Node-"+str(node.id)) - - canvas.tag_bind("Node-"+str(node.id), '', onObjectClick(root, canvas, player)) - - canvas.pack() - root.update() - - - -def update(root, canvas, player): - canvas.delete("all") # reload canvas - CreateNetwork(root, canvas, player) \ No newline at end of file From 678fe2d701a849f5f0adc8a32b7c05aa8da9146a Mon Sep 17 00:00:00 2001 From: tsuki Date: Tue, 3 Oct 2023 22:13:52 -0700 Subject: [PATCH 05/17] Update main.py --- main.py | 125 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 36 deletions(-) diff --git a/main.py b/main.py index f39675d..f99c86a 100644 --- a/main.py +++ b/main.py @@ -1,49 +1,102 @@ import Player as p -import tkinter as tk -import Window as window +import Graph as graph import Algorithm as a +import random +import math -player = p.Player() -nodes = player.nodes -print("-------------------------------------------------") -print(f"Actual Patient Zero: {player.p_zero}") +from flask import Flask, render_template -# Set up tkinter canvas -root = tk.Tk() -canvas = tk.Canvas(root, width=620, height=620) -canvas.config(background="gray90") +def run_ai(ai, player, percentSamples, percentTraced): -""" -THIS IS THE ACTUAL AI PART --------------------------------------------------- -""" -ai = a.Algorithm(len(player.nodes)) + numSamples = round(percentSamples * player.size) + numTraced = round(percentTraced * numSamples) + numberToSelect = math.ceil(0.03 * player.size) + + for _ in range(numSamples): + chosen = ai.ChooseOneToSample(player) + player.sample(chosen) + + print(f"Sampled {len(player.sampled)} Nodes: {player.sampled}") + + # After, calculate likelihoods + sorted_indices = ai.getSortedIds() + + # Find spread pattern for most likely + for Id in sorted_indices[-numTraced:]: + ai.TraceSpreadPattern(player, Id) + + traced = sorted_indices[-numTraced:] + + print(f"Traced Spread Patterns For {sorted_indices[-numTraced:]}") + + # Compare likelihoods again + sorted_indices = ai.getSortedIds() + + # Print 5 Top Choices (rightmost is the one it's most confident in) + print(f"Top Choices From AI (least confident to most confident, right being most confident): \n{sorted_indices[-numberToSelect:]}") + + for nodeNumber in sorted_indices[-numberToSelect:]: + player.nodes[nodeNumber].selectedByAI = "True" -# Sample 20 Nodes -for i in range(20): - chosen = ai.ChooseOneToSample(player) - player.sample(chosen) + return sorted_indices, traced -print(f"Sampled {len(player.sampled)} Nodes: {player.sampled}") +app = Flask(__name__, template_folder = 'templates', static_folder='static') -# After, calculate likelihoods -sorted_indices = ai.getSortedIds() +@app.route('/') +def index(): -# Find spread pattern for most likely -for Id in sorted_indices[-100:]: - ai.TraceSpreadPattern(player, Id) + # NEAT GENOME SHIT: (THESE WILL BE GENERATED) + # RIGHT NOW THEY ARE NUMBERS PULLED FROM MY ASS + negativeEffectBias = 0.1 + positiveBias = 0.1 + positiveEffectBias = 0.05 + similarityWeight = 1 + percentSamples = 0.1 + percentTraced = 0.5 + + player = p.Player( + size = random.randint(100, 250), + time = random.randint(2, 5), + min = random.randint(2, 4), + max = random.randint(3, 5), + percent = random.uniform(0, 0.1) # initially given + ) -print(f"Traced Spread Patterns For {sorted_indices[-100:]}") + ai = a.Algorithm( + size=player.size, -# Compare likelihoods again -sorted_indices = ai.getSortedIds() + # NEAT + negativeEffectBias=negativeEffectBias, + positiveBias=positiveBias, + positiveEffectBias=positiveEffectBias, + similarityWeight=similarityWeight + ) + + sorted, traced = run_ai(ai, player, percentSamples, percentTraced) + + # Start window loop + nodes, edges = graph.CreateGraphHTML(player, "templates/index.html") -# Print 5 Top Choices (rightmost is the one it's most confident in) -print(f"Top Choices From AI (least confident to most confident, right being most confident): \n{sorted_indices[-5:]}") + return render_template( + 'index.html', + + nodes=nodes, + edges=edges, + + actual_p_zero=player.p_zero, + sampled=str(player.sampled), + sorted=sorted[-20:], + traced=str(traced), + + num_nodes=len(player.nodes), + alloted_time=player.time, + min=player.min_connections, + max=player.max_connections, + num_visible=player.num_visible_to_player + ) -""" -THIS IS THE ACTUAL AI PART --------------------------------------------------- -""" - - -# # Start window loop -# window.CreateNetwork(root, canvas, player) +if __name__ == "__main__": # Makes sure this is the main process + app.run( # Starts the site + host='0.0.0.0', # EStablishes the host, required for repl to detect the site + port=random.randint(2000, 9000) # Randomly select the port the machine hosts on. + ) From 5ffbcb4c38fee906f559dc56ef6dba12a3fbae96 Mon Sep 17 00:00:00 2001 From: tsuki Date: Tue, 3 Oct 2023 22:22:47 -0700 Subject: [PATCH 06/17] Create index.html --- templates/index.html | 260 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 templates/index.html diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..1511caa --- /dev/null +++ b/templates/index.html @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + +
+
+
+
+
0%
+
+
+
+
+
+
+
+

Random Node Network

+

Visualized at Left

+
+

Drag around the simulation at left, hover over nodes to view their information, etc.

+
+
Color Key
+

Green = Not Infected

+

Red = Infected

+

Gray = Unknown (Not sampled)

+

Purple = Actual Patient Zero (if sampled)

+
+

Large Nodes = The top five nodes that are likely to be patient zero according to our algorithm.

+
+

Additional information about the network and our algorithm below...

+
+
+ + +
+ +
+

Network Information:

+

Actual Patient Zero: Node {{ actual_p_zero }}

+

Number of Nodes: {{ num_nodes }}

+

Allowed Time To Spread: {{ alloted_time }} iterations

+

Minimum Connections: {{ min }}

+

Maximum Connections: {{ max}}

+
+
+

Algorithm Information:

+

Number of Nodes Initially Given: {{ num_visible }}

+

AI - Sampled The Following Nodes:

+

{{ sampled }}

+

AI - Traced Infection Paterns For:

+

{{ traced }}

+
+
+

Result Information:

+

Top 10 Sorted Nodes:

+

{{ sorted[-10:] }}

+
+

Most Likely Nodes:

+

{{ sorted[-5:] }}

+

Algorithm: Probability-Based

+
+ +
+
+ + + + + From d8511144458df9fe8f375e5e187548fbf98e0d36 Mon Sep 17 00:00:00 2001 From: tsuki Date: Tue, 3 Oct 2023 22:25:29 -0700 Subject: [PATCH 07/17] Create styles.css --- static/styles.css | 1 + 1 file changed, 1 insertion(+) create mode 100644 static/styles.css diff --git a/static/styles.css b/static/styles.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/static/styles.css @@ -0,0 +1 @@ + From bd6a52312f3da0caf6fa06cd34efa5958c87e5af Mon Sep 17 00:00:00 2001 From: tsuki Date: Sat, 21 Oct 2023 19:54:26 -0700 Subject: [PATCH 08/17] Update and rename styles.css to main.css --- static/main.css | 349 ++++++++++++++++++++++++++++++++++++++++++++++ static/styles.css | 1 - 2 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 static/main.css delete mode 100644 static/styles.css diff --git a/static/main.css b/static/main.css new file mode 100644 index 0000000..be1a66f --- /dev/null +++ b/static/main.css @@ -0,0 +1,349 @@ +.page-container { + width: 100%; + display: flex; + overflow: auto; + min-height: 100vh; + align-items: center; + flex-direction: column; +} +.page-navbar-interactive { + width: 100%; + display: flex; + align-items: center; + padding-top: var(--dl-space-space-twounits); + padding-left: var(--dl-space-space-threeunits); + padding-right: 12px; + padding-bottom: var(--dl-space-space-twounits); + justify-content: space-between; + background-color: #390B34; +} +.page-navlink { + display: contents; +} +.page-image { + width: 200px; + object-fit: cover; + transition: 0.3s; + text-decoration: none; +} +.page-image:hover { + width: 210px; +} +.page-desktop-menu { + flex: 1; + display: flex; + justify-content: space-between; +} +.page-links { + flex: 1; + display: flex; + align-items: center; + flex-direction: row; + justify-content: flex-start; +} +.page-navlink1 { + color: rgb(255, 255, 255); + font-size: 20px; + transition: 0.3s; + font-family: "Poppins"; + font-weight: bold; + margin-left: var(--dl-space-space-twounits); + text-decoration: none; +} +.page-navlink1:hover { + color: #cbc23e; +} +.page-navlink2 { + color: rgb(255, 255, 255); + font-size: 20px; + transition: 0.3s; + font-family: "Poppins"; + font-weight: bold; + margin-left: var(--dl-space-space-twounits); + text-decoration: none; +} +.page-navlink2:hover { + color: #00e5f3; +} +.page-navlink3 { + color: rgb(255, 255, 255); + font-size: 20px; + transition: 0.3s; + font-family: "Poppins"; + font-weight: bold; + margin-left: var(--dl-space-space-twounits); +} +.page-navlink3:hover { + color: #ef2cdd; +} +.page-buttons { + display: flex; + align-items: center; + flex-direction: row; + justify-content: space-between; +} +.page-login { + width: 152px; + height: 40px; + transition: 0.3s; + border-width: 0px; + margin-right: var(--dl-space-space-twounits); +} +.page-login:hover { + color: #bb15a4; + width: 185px; + height: 49px; + font-size: 20px; + box-shadow: 0px 0px 20px 5px #c2c845; + background-color: #ffffff; +} +.page-text { + font-size: 15px; + font-style: normal; + font-family: "Poppins"; + font-weight: 700; +} +.page-burger-menu { + display: none; +} +.page-icon { + width: var(--dl-size-size-xsmall); + height: var(--dl-size-size-xsmall); +} +.page-mobile-menu { + top: 0px; + left: 0px; + width: 100%; + height: 100vh; + display: flex; + padding: 32px; + z-index: 100; + position: absolute; + transform: translateY(-100%); + transition: 0.5s; + flex-direction: column; + justify-content: space-between; + background-color: #fff; +} +.page-nav { + display: flex; + align-items: flex-start; + flex-direction: column; +} +.page-top { + width: 100%; + display: flex; + align-items: center; + margin-bottom: var(--dl-space-space-threeunits); + justify-content: space-between; +} +.page-logo { + height: 2rem; +} +.page-close-menu { + display: flex; + align-items: center; + justify-content: center; +} +.page-icon02 { + width: var(--dl-size-size-xsmall); + height: var(--dl-size-size-xsmall); +} +.page-links1 { + flex: 0 0 auto; + display: flex; + align-self: flex-start; + align-items: flex-start; + flex-direction: column; +} +.page-text03 { + margin-bottom: var(--dl-space-space-unit); +} +.page-text04 { + margin-bottom: var(--dl-space-space-unit); +} +.page-text05 { + margin-bottom: var(--dl-space-space-unit); +} +.page-text06 { + margin-bottom: var(--dl-space-space-unit); +} +.page-text07 { + margin-bottom: var(--dl-space-space-unit); +} +.page-buttons1 { + display: flex; + margin-top: var(--dl-space-space-unit); + align-items: center; + flex-direction: row; + justify-content: space-between; +} +.page-login1 { + margin-right: var(--dl-space-space-twounits); +} +.page-icon04 { + width: var(--dl-size-size-xsmall); + height: var(--dl-size-size-xsmall); + margin-right: var(--dl-space-space-twounits); +} +.page-icon06 { + width: var(--dl-size-size-xsmall); + height: var(--dl-size-size-xsmall); + margin-right: var(--dl-space-space-twounits); +} +.page-icon08 { + width: var(--dl-size-size-xsmall); + height: var(--dl-size-size-xsmall); +} +.page-container1 { + width: 100%; + height: 100vh; + display: flex; + align-items: center; + justify-content: flex-start; +} +.page-container2 { + flex: 0 0 auto; + width: 25%; + height: 100%; + display: flex; + position: relative; + align-items: center; + flex-direction: column; + justify-content: flex-start; + background-color: #1f0644; +} +.page-text08 { + color: rgb(255, 255, 255); + align-self: center; + font-size: 30px; + /* margin-top: var(--dl-space-space-fiveunits); */ + text-align: center; + margin-left: var(--dl-space-space-oneandhalfunits); + margin-right: var(--dl-space-space-oneandhalfunits); +} +.page-text16 { + width: 80%; + padding: 20px; + font-size: 25px; + text-align: center; + border-radius: var(--dl-radius-radius-radius8); + background-color: rgb(81, 13, 97); +} +.page-text17 { + color: #ffffff; + font-family: "PT Sans"; + font-weight: 700; +} +.page-text18 { + color: #ffffff; + font-family: "PT Sans"; + font-weight: 700; +} +.page-text19 { + color: #ffffff; + font-family: "PT Sans"; +} +.page-text20 { + color: #ffffff; + font-family: "PT Sans"; +} +.page-text21 { + color: #ffffff; + font-family: "PT Sans"; +} +.page-text22 { + color: #ffffff; + font-family: "PT Sans"; +} +.page-text23 { + color: #ff6577; + font-family: "PT Sans"; +} +.page-text24 { + color: #ffffff; + font-family: "PT Sans"; +} +.page-text25 { + color: #93ffa6; + font-family: "PT Sans"; +} +.page-text26 { + color: #ffffff; + font-family: "PT Sans"; +} +.page-text27 { + color: #e1e1e1; + font-family: "PT Sans"; +} +.page-text28 { + color: #ffffff; + font-family: "PT Sans"; +} +.page-text29 { + color: #ffffff; + font-family: "PT Sans"; +} +.page-text30 { + color: #ebd480; + font-style: italic; + font-family: "PT Sans"; +} +.page-text31 { + color: #ffffff; + font-style: italic; + font-family: "PT Sans"; +} +.page-text32 { + color: #ffffff; +} +.page-container3 { + flex: 0 0 auto; + width: 75%; + /* border: 2px dashed rgba(120, 120, 120, 0.4); */ + height: 100%; + display: flex; + align-items: flex-start; + flex-direction: column; +} +@media(max-width: 767px) { + .page-navbar-interactive { + padding-left: var(--dl-space-space-twounits); + padding-right: var(--dl-space-space-twounits); + } + .page-desktop-menu { + display: none; + } + .page-burger-menu { + display: flex; + align-items: center; + justify-content: center; + } + .page-text03 { + margin-bottom: var(--dl-space-space-unit); + } + .page-text04 { + margin-left: 0; + margin-bottom: var(--dl-space-space-unit); + } + .page-text05 { + margin-left: 0; + margin-bottom: var(--dl-space-space-unit); + } + .page-text06 { + margin-left: 0; + margin-bottom: var(--dl-space-space-unit); + } + .page-text07 { + margin-left: 0; + margin-bottom: var(--dl-space-space-unit); + } +} +@media(max-width: 479px) { + .page-navbar-interactive { + padding: var(--dl-space-space-unit); + } + .page-mobile-menu { + padding: 16px; + } +} diff --git a/static/styles.css b/static/styles.css deleted file mode 100644 index 8b13789..0000000 --- a/static/styles.css +++ /dev/null @@ -1 +0,0 @@ - From 2a456712af3201e208e7c7b56da8f5ea0832bd25 Mon Sep 17 00:00:00 2001 From: tsuki Date: Sat, 21 Oct 2023 19:55:09 -0700 Subject: [PATCH 09/17] Add UI to Network --- templates/index.html | 115 ++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 40 deletions(-) diff --git a/templates/index.html b/templates/index.html index 1511caa..eea7c19 100644 --- a/templates/index.html +++ b/templates/index.html @@ -104,46 +104,71 @@ border-radius:72px; box-shadow: 0px 0px 10px rgba(0,0,0,0.2); } - - - - + nav { + background-color: #333; + color: #fff; + padding: 20px; + } - - -
-
-
-
-
0%
-
-
+
+ +
+
+
+

+ "Unnamed Network" +
+ 10/20/23 +

+ + Network Info: +
+
+ {{ num_nodes }} Nodes Total +
+
+ {{ num_positive }} Positive +
+ {{ num_negative }} Negative +
+ {{ num_unknown }} Unknown +
+
+ Click around + + to change this info box! + +
+
+
+
+
+
+
+
+
0%
+
+
+
-
-
-
-

Random Node Network

-

Visualized at Left

-
-

Drag around the simulation at left, hover over nodes to view their information, etc.

-
-
Color Key
-

Green = Not Infected

-

Red = Infected

-

Gray = Unknown (Not sampled)

-

Purple = Actual Patient Zero (if sampled)

-
-

Large Nodes = The top five nodes that are likely to be patient zero according to our algorithm.

-
-

Additional information about the network and our algorithm below...

+
- +
+
+
+ + + + - +