diff --git a/analysis.py b/analysis.py
index af477da..43a5b45 100644
--- a/analysis.py
+++ b/analysis.py
@@ -67,25 +67,32 @@ def graph_json():
subquery, (C.user == subquery.c.user) & (C.time == subquery.c.latest)
)
for c in session.exec(statement2):
- for p in c.love:
+ for i, p in enumerate(c.love):
edges.append(
{
"id": f"{c.user}->{p}",
"source": c.user,
"target": p,
- "relation": "likes",
+ "size": max(1.0 - 0.1 * i, 0.3),
+ "data": {"relation": 2},
}
)
- continue
for p in c.hate:
edges.append(
{
- id: f"{c.user}-x>{p}",
+ "id": f"{c.user}-x>{p}",
"source": c.user,
"target": p,
- "relation": "dislikes",
+ "size": 0.3,
+ "data": {"relation": 0},
+ "fill": "#ff7c7c",
}
)
+
+ G = nx.DiGraph()
+ G.add_weighted_edges_from([(e["source"], e["target"], e["size"]) for e in edges])
+ in_degrees = G.in_degree(weight="weight")
+ nodes = [dict(node, **{"inDegree": in_degrees[node["id"]]}) for node in nodes]
return JSONResponse({"nodes": nodes, "edges": edges})
diff --git a/src/App.css b/src/App.css
index ed1b8c0..98518f6 100644
--- a/src/App.css
+++ b/src/App.css
@@ -23,28 +23,38 @@ footer {
font-size: x-small;
}
+/*=========Network Controls=========*/
+
.controls {
z-index: 9;
position: absolute;
- top: 24;
- left: 24;
+ width: 240px;
+ right: 24px;
+ top: 1vh;
padding: 16px;
.control {
display: flex;
flex-direction: row;
+ margin: 4px 2px;
+ background-color: aliceblue;
* {
- margin: 0 4px;
+ margin: 4px;
}
}
+
+ #three-slider {
+ display: flex;
+ flex-direction: row;
+ }
}
/* The switch - the box around the slider */
.switch {
position: relative;
width: 68px;
- height: 34px;
+ height: 42px;
}
/* Hide default HTML checkbox */
@@ -239,13 +249,19 @@ button,
#control-panel {
grid-template-columns: repeat(2, 1fr);
}
+
}
+
@media only screen and (max-width: 768px) {
#control-panel {
grid-template-columns: 1fr;
}
+ .networkroute {
+ display: none;
+ }
+
.submit_text {
display: none;
}
@@ -312,6 +328,8 @@ button,
font-size: 150%;
}
+/*======LOGO=======*/
+
.logo {
position: relative;
text-align: center;
@@ -339,6 +357,15 @@ button,
}
}
+.networkroute {
+ z-index: 10;
+ position: absolute;
+ top: 24px;
+ left: 48px;
+}
+
+/*======SPINNER=======*/
+
.loader {
display: block;
position: relative;
diff --git a/src/Header.tsx b/src/Header.tsx
index cf9d832..5ce0ea1 100644
--- a/src/Header.tsx
+++ b/src/Header.tsx
@@ -1,7 +1,5 @@
-import { baseUrl } from "./api";
-
export default function Header() {
- return
+ return
cutt
diff --git a/src/Network.tsx b/src/Network.tsx
index e51f1da..a73da07 100644
--- a/src/Network.tsx
+++ b/src/Network.tsx
@@ -1,17 +1,31 @@
-import { ChangeEvent, useEffect, useRef, useState } from "react";
+import { useEffect, useRef, useState } from "react";
import { apiAuth } from "./api";
-import { GraphCanvas, GraphCanvasRef, GraphEdge, GraphNode, recommendLayout, useSelection } from "reagraph";
+import { GraphCanvas, GraphCanvasRef, GraphEdge, GraphNode, SelectionProps, SelectionResult, useSelection } from "reagraph";
import { customTheme } from "./NetworkTheme";
interface NetworkData {
nodes: GraphNode[],
edges: GraphEdge[],
}
+interface CustomSelectionProps extends SelectionProps {
+ ignore: string[];
+}
+
+const useCustomSelection = (props: CustomSelectionProps): SelectionResult => {
+ var result = useSelection(props);
+ result.actives = result.actives.filter((s) => !props.ignore.includes(s))
+ return result
+}
export const GraphComponent = () => {
const [data, setData] = useState({ nodes: [], edges: [] } as NetworkData);
const [loading, setLoading] = useState(true);
const [threed, setThreed] = useState(false);
+ const [likes, setLikes] = useState(2);
+ const logo = document.getElementById("logo")
+ if (logo) {
+ logo.className = "logo networkroute";
+ }
async function loadData() {
setLoading(true);
@@ -24,12 +38,6 @@ export const GraphComponent = () => {
const graphRef = useRef(null);
- const { selections, actives, onNodeClick, onCanvasClick } = useSelection({
- ref: graphRef,
- nodes: data.nodes,
- edges: data.edges,
- pathSelectionType: 'out',
- });
function handleThreed() {
setThreed(!threed)
@@ -38,9 +46,28 @@ export const GraphComponent = () => {
graphRef.current?.resetControls();
}
+ function showLabel() {
+ switch (likes) {
+ case 0: return "dislike";
+ case 1: return "both";
+ case 2: return "like";
+ }
+ }
+
+ const { selections, actives, onNodeClick, onCanvasClick } = useCustomSelection({
+ ref: graphRef,
+ nodes: data.nodes,
+ edges: data.edges.filter((edge) => edge.data.relation === likes),
+ ignore: data.edges.map((edge) => { return (likes === 1 && edge.data.relation !== 2) ? edge.id : "" }),
+ pathSelectionType: 'out',
+ type: 'multiModifier'
+ });
+
+
return (
+
2D
@@ -49,26 +76,56 @@ export const GraphComponent = () => {
3D
+
+
+
+
+
+
+ setLikes(Number(evt.target.value))}
+ />
+
+
+ {showLabel()}
+
+
+
-
+
+ {loading ?
:
+
edge.data.relation === likes || likes === 1)}
+ selections={selections}
+ actives={actives}
+ onCanvasClick={onCanvasClick}
+ onNodeClick={onNodeClick}
+ />}
);
-
}
diff --git a/src/NetworkTheme.tsx b/src/NetworkTheme.tsx
index 0527313..08f5099 100644
--- a/src/NetworkTheme.tsx
+++ b/src/NetworkTheme.tsx
@@ -34,7 +34,7 @@ export const customTheme: Theme = {
activeFill: '#36C',
opacity: 1,
selectedOpacity: 1,
- inactiveOpacity: 0.2,
+ inactiveOpacity: 0.333,
label: {
stroke: '#fff',
color: '#2A6475',