feat: introduce weighting and popularity
This commit is contained in:
		
							
								
								
									
										34
									
								
								analysis.py
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								analysis.py
									
									
									
									
									
								
							@@ -69,8 +69,8 @@ def sociogram_data():
 | 
				
			|||||||
            .join(subquery, (C.user == subquery.c.user) & (C.time == subquery.c.latest))
 | 
					            .join(subquery, (C.user == subquery.c.user) & (C.time == subquery.c.latest))
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        for c in session.exec(statement2):
 | 
					        for c in session.exec(statement2):
 | 
				
			||||||
            for p in c.love:
 | 
					            for i, p in enumerate(c.love):
 | 
				
			||||||
                G.add_edge(c.user, p)
 | 
					                G.add_edge(c.user, p, rank=i, popularity=1 - 0.08 * i)
 | 
				
			||||||
                links.append({"source": c.user, "target": p})
 | 
					                links.append({"source": c.user, "target": p})
 | 
				
			||||||
    return G
 | 
					    return G
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,10 +81,11 @@ class Params(BaseModel):
 | 
				
			|||||||
    arrow_size: int | None = Field(default=20, alias="arrowSize")
 | 
					    arrow_size: int | None = Field(default=20, alias="arrowSize")
 | 
				
			||||||
    edge_width: float | None = Field(default=1, alias="edgeWidth")
 | 
					    edge_width: float | None = Field(default=1, alias="edgeWidth")
 | 
				
			||||||
    distance: float | None = 0.2
 | 
					    distance: float | None = 0.2
 | 
				
			||||||
 | 
					    weighting: bool | None = True
 | 
				
			||||||
 | 
					    popularity: bool | None = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def render_sociogram(params: Params):
 | 
					async def render_sociogram(params: Params):
 | 
				
			||||||
    plt.close()
 | 
					 | 
				
			||||||
    plt.figure(figsize=(16, 10), facecolor="none")
 | 
					    plt.figure(figsize=(16, 10), facecolor="none")
 | 
				
			||||||
    ax = plt.gca()
 | 
					    ax = plt.gca()
 | 
				
			||||||
    ax.set_facecolor("none")  # Set the axis face color to none (transparent)
 | 
					    ax.set_facecolor("none")  # Set the axis face color to none (transparent)
 | 
				
			||||||
@@ -92,15 +93,21 @@ async def render_sociogram(params: Params):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    G = sociogram_data()
 | 
					    G = sociogram_data()
 | 
				
			||||||
    pos = nx.spring_layout(G, scale=2, k=params.distance, iterations=50, seed=None)
 | 
					    pos = nx.spring_layout(G, scale=2, k=params.distance, iterations=50, seed=None)
 | 
				
			||||||
    nx.draw_networkx_nodes(
 | 
					    nodes = nx.draw_networkx_nodes(
 | 
				
			||||||
        G,
 | 
					        G,
 | 
				
			||||||
        pos,
 | 
					        pos,
 | 
				
			||||||
        node_color="#99ccff",
 | 
					        node_color=[v for k, v in G.in_degree(weight="popularity")]
 | 
				
			||||||
 | 
					        if params.popularity
 | 
				
			||||||
 | 
					        else "#99ccff",
 | 
				
			||||||
        edgecolors="#404040",
 | 
					        edgecolors="#404040",
 | 
				
			||||||
        linewidths=1,
 | 
					        linewidths=0,
 | 
				
			||||||
 | 
					        # node_shape="8",
 | 
				
			||||||
        node_size=params.node_size,
 | 
					        node_size=params.node_size,
 | 
				
			||||||
 | 
					        cmap="coolwarm",
 | 
				
			||||||
        alpha=0.86,
 | 
					        alpha=0.86,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    if params.popularity:
 | 
				
			||||||
 | 
					        plt.colorbar(nodes)
 | 
				
			||||||
    nx.draw_networkx_labels(G, pos, font_size=params.font_size)
 | 
					    nx.draw_networkx_labels(G, pos, font_size=params.font_size)
 | 
				
			||||||
    nx.draw_networkx_edges(
 | 
					    nx.draw_networkx_edges(
 | 
				
			||||||
        G,
 | 
					        G,
 | 
				
			||||||
@@ -110,6 +117,11 @@ async def render_sociogram(params: Params):
 | 
				
			|||||||
        arrowsize=params.arrow_size,
 | 
					        arrowsize=params.arrow_size,
 | 
				
			||||||
        node_size=params.node_size,
 | 
					        node_size=params.node_size,
 | 
				
			||||||
        width=params.edge_width,
 | 
					        width=params.edge_width,
 | 
				
			||||||
 | 
					        arrowstyle="-|>",
 | 
				
			||||||
 | 
					        # connectionstyle="arc3,rad=0.2",
 | 
				
			||||||
 | 
					        alpha=[1 - 0.08 * G.edges()[*edge]["rank"] for edge in G.edges()]
 | 
				
			||||||
 | 
					        if params.weighting
 | 
				
			||||||
 | 
					        else 1,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    buf = io.BytesIO()
 | 
					    buf = io.BytesIO()
 | 
				
			||||||
@@ -130,13 +142,3 @@ if __name__ == "__main__":
 | 
				
			|||||||
        print("players in DB: ", session.exec(statement).first())
 | 
					        print("players in DB: ", session.exec(statement).first())
 | 
				
			||||||
    G = sociogram_data()
 | 
					    G = sociogram_data()
 | 
				
			||||||
    pos = nx.spring_layout(G, scale=1, k=2, iterations=50, seed=42)
 | 
					    pos = nx.spring_layout(G, scale=1, k=2, iterations=50, seed=42)
 | 
				
			||||||
    edges = nx.draw_networkx_edges(
 | 
					 | 
				
			||||||
        G,
 | 
					 | 
				
			||||||
        pos,
 | 
					 | 
				
			||||||
        arrows=True,
 | 
					 | 
				
			||||||
        arrowsize=12,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    nx.draw_networkx(
 | 
					 | 
				
			||||||
        G, pos, with_labels=True, node_color="#99ccff", font_size=8, node_size=2000
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    plt.show()
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,8 @@ interface Params {
 | 
				
			|||||||
  arrowSize: number;
 | 
					  arrowSize: number;
 | 
				
			||||||
  fontSize: number;
 | 
					  fontSize: number;
 | 
				
			||||||
  distance: number;
 | 
					  distance: number;
 | 
				
			||||||
 | 
					  weighting: boolean;
 | 
				
			||||||
 | 
					  popularity: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function Analysis() {
 | 
					export default function Analysis() {
 | 
				
			||||||
@@ -25,6 +27,8 @@ export default function Analysis() {
 | 
				
			|||||||
    arrowSize: 20,
 | 
					    arrowSize: 20,
 | 
				
			||||||
    fontSize: 10,
 | 
					    fontSize: 10,
 | 
				
			||||||
    distance: 2,
 | 
					    distance: 2,
 | 
				
			||||||
 | 
					    weighting: true,
 | 
				
			||||||
 | 
					    popularity: true,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const [showControlPanel, setShowControlPanel] = useState(false);
 | 
					  const [showControlPanel, setShowControlPanel] = useState(false);
 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					  const [loading, setLoading] = useState(false);
 | 
				
			||||||
@@ -56,6 +60,26 @@ export default function Analysis() {
 | 
				
			|||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
      <div id="control-panel" className={showControlPanel ? "opened" : ""}>
 | 
					      <div id="control-panel" className={showControlPanel ? "opened" : ""}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div className="control">
 | 
				
			||||||
 | 
					          <div className="checkBox">
 | 
				
			||||||
 | 
					            <label>weighting</label>
 | 
				
			||||||
 | 
					            <input
 | 
				
			||||||
 | 
					              type="checkbox"
 | 
				
			||||||
 | 
					              checked={params.weighting}
 | 
				
			||||||
 | 
					              onChange={(evt) => setParams({ ...params, weighting: evt.target.checked })}
 | 
				
			||||||
 | 
					              onMouseUp={() => loadImage()}
 | 
				
			||||||
 | 
					            /></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div className="checkBox">
 | 
				
			||||||
 | 
					            <label>popularity</label>
 | 
				
			||||||
 | 
					            <input
 | 
				
			||||||
 | 
					              type="checkbox"
 | 
				
			||||||
 | 
					              checked={params.popularity}
 | 
				
			||||||
 | 
					              onChange={(evt) => { setParams({ ...params, popularity: evt.target.checked }); loadImage() }}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className="control">
 | 
					        <div className="control">
 | 
				
			||||||
          <label>distance between nodes</label>
 | 
					          <label>distance between nodes</label>
 | 
				
			||||||
          <input
 | 
					          <input
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@ h3 {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  button,
 | 
					  button,
 | 
				
			||||||
  img {
 | 
					  img {
 | 
				
			||||||
    padding: 0 1em;
 | 
					    padding: 0px 1em 4px 1em;
 | 
				
			||||||
    margin: 3px auto;
 | 
					    margin: 3px auto;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -146,7 +146,8 @@ button {
 | 
				
			|||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  flex-direction: column;
 | 
					  flex-direction: column;
 | 
				
			||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  border: 1px solid #404040;
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  border: 2px solid #404040;
 | 
				
			||||||
  padding: 8px;
 | 
					  padding: 8px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user