**Live ** YnM Statisztika
<link href="/css/ynm.statisztika.css" rel="stylesheet">
<?php
// PHP code to process log files and generate $nodes and $links
$logFiles = glob("/home/ai/.sopel/szobak/magyar-*.log"); // Collect all log files
$users = []; // Array to store user activity count
$interactions = []; // Array to store interactions between users
// Process each log file
foreach ($logFiles as $logFile) {
$logData = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); // Read file line by line
foreach ($logData as $line) {
// Parse lines with a specific format
if (preg_match('/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2}\s+<YnM-Bridge>\s+\[(.*?)\](.*)/', $line, $matches)) {
$user = trim($matches[1]); // Extract user name
$message = trim($matches[2]); // Extract message
// Count user activity
if (!isset($users[$user])) {
$users[$user] = 0;
}
$users[$user]++;
// Count interactions (mentions)
if (preg_match('/@(\w+)/', $message, $mentioned)) {
$mentionedUser = $mentioned[1];
$pair = [$user, $mentionedUser];
sort($pair); // Sort the pair to ensure consistency
$pairKey = implode("-", $pair); // Create a unique key for the pair
if (!isset($interactions[$pairKey])) {
$interactions[$pairKey] = 0;
}
$interactions[$pairKey]++;
}
}
}
}
// Sort users and interactions in descending order
arsort($users);
arsort($interactions);
// Generate nodes and links for the D3.js visualization
$allUsers = array_keys($users); // List of all users
$nodes = [];
foreach ($allUsers as $user) {
$nodes[] = "{ id: '" . addslashes($user) . "' }"; // Add each user to the nodes list
}
$links = [];
foreach ($interactions as $pair => $count) {
list($user1, $user2) = explode("-", $pair);
// Ensure both users in the pair exist in the nodes array
if (in_array($user1, $allUsers) && in_array($user2, $allUsers)) {
$links[] = "{ source: '" . addslashes($user1) . "', target: '" . addslashes($user2) . "', value: $count }";
}
}
?>
<script src="https://d3js.org/d3.v7.min.js"></script>
<h2 class="ynm-statisztika text-center">Kapcsolati háló</h2>
<!-- SVG container for network diagram -->
<div class="svg-container text-center">
<svg viewBox="0 0 800 600" preserveAspectRatio="xMidYMid meet"></svg>
</div>
<h2 class="ynm-statisztika text-center">Felhasználói aktivitás</h2>
<!-- D3.js bar chart for user activity -->
<div class="svg-container text-center">
<svg id="activity-chart" width="100%" height="400"></svg>
</div>
<!-- Empty SVG for network diagram (second diagram) -->
<div class="svg-container text-center">
<svg viewBox="0 0 100% 100%" preserveAspectRatio="xMidYMid meet"></svg>
</div>
<h2 class="mt-4 text-center">Ki kivel beszélt</h2>
<table class="table table-bordered table-striped">
<thead class="table-dark">
<tr><th>Páros</th><th>Üzenetek száma</th></tr>
</thead>
<tbody>
<?php foreach ($interactions as $pair => $count) { ?>
<tr><td><?php echo htmlspecialchars($pair); ?></td><td><?php echo $count; ?></td></tr>
<?php } ?>
</tbody>
</table>
<h2 class="mt-4 text-center">Felhasználói aktivitás</h2>
<table class="table table-bordered table-striped">
<thead class="table-dark">
<tr><th>Felhasználó</th><th>Üzenetek száma</th></tr>
</thead>
<tbody>
<?php foreach ($users as $user => $count) { ?>
<tr><td><?php echo htmlspecialchars($user); ?></td><td><?php echo $count; ?></td></tr>
<?php } ?>
</tbody>
</table>
<?php
// Ensure all users in the interactions are added to nodes
$allUsers = array_keys($users); // List of users from message activity
$nodes = [];
foreach ($allUsers as $user) {
$nodes[] = "{ id: '" . addslashes($user) . "' }"; // Add each user to the nodes list
}
$links = [];
foreach ($interactions as $pair => $count) {
list($user1, $user2) = explode("-", $pair);
// Ensure both users in the pair exist in the nodes array
if (in_array($user1, $allUsers) && in_array($user2, $allUsers)) {
$links[] = "{ source: '" . addslashes($user1) . "', target: '" . addslashes($user2) . "', value: $count }";
}
}
?>
<script>
// D3.js bar chart for user activity
const usersData = <?php echo json_encode($users); ?>; // Data passed from PHP to JavaScript
const margin = { top: 20, right: 20, bottom: 40, left: 50 };
const width = 800 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
const svg1 = d3.select("#activity-chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
const x = d3.scaleBand()
.domain(Object.keys(usersData))
.range([0, width])
.padding(0.1);
const y = d3.scaleLinear()
.domain([0, d3.max(Object.values(usersData))])
.nice()
.range([height, 0]);
const colorScale = d3.scaleLinear()
.domain([0, d3.max(Object.values(usersData))])
.range(["lightblue", "darkblue"]);
// Add X and Y axes
svg1.append("g")
.selectAll(".x-axis")
.data(Object.keys(usersData))
.enter()
.append("text")
.attr("x", (d, i) => x(d) + x.bandwidth() / 2)
.attr("y", height + 20)
.attr("text-anchor", "middle")
.style("font-size", "12px")
.text(d => d);
svg1.append("g")
.selectAll(".y-axis")
.data([0])
.enter()
.append("g")
.call(d3.axisLeft(y))
.attr("transform", "translate(0, 0)");
// Add bars (rectangles) to the chart
svg1.selectAll(".bar")
.data(Object.entries(usersData))
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", d => x(d[0]))
.attr("y", d => y(d[1]))
.attr("width", x.bandwidth())
.attr("height", d => height - y(d[1]))
.attr("fill", d => colorScale(d[1]));
// Add labels above the bars
svg1.selectAll(".label")
.data(Object.entries(usersData))
.enter()
.append("text")
.attr("class", "label")
.attr("x", d => x(d[0]) + x.bandwidth() / 2)
.attr("y", d => y(d[1]) - 5)
.attr("text-anchor", "middle")
.style("font-size", "12px")
.text(d => d[1]);
// D3.js network diagram for interactions
const nodes = [
<?php echo implode(",", $nodes); ?>
].filter(node => node.id !== "markuslajos"); // Filter out "markuslajos"
const links = [
<?php echo implode(",", $links); ?>
];
const svg2 = d3.select("svg"),
simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id).distance(100))
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(width / 2, height / 2))
.on("tick", ticked);
const colorScale2 = d3.scaleLinear()
.domain([1, d3.max(links, d => d.value)])
.range(["green", "red"]);
const link = svg2.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("class", "link")
.style("stroke", d => colorScale2(d.value))
.style("stroke-width", 2);
const node = svg2.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 10)
.style("fill", (d, i) => d3.schemeCategory10[i % 10]);
node.append("title").text(d => d.id);
const connectedGroup = svg2.append("g")
.attr("class", "connectedGroup");
connectedGroup.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("x", d => d.x)
.attr("y", d => d.y - 25)
.text(d => d.id)
.style("font-size", "12px")
.style("text-anchor", "middle")
.style("fill", "black");
function ticked() {
link.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node.attr("cx", d => d.x)
.attr("cy", d => d.y);
node.attr("cx", function(d) {
return Math.max(10, Math.min(width - 10, d.x));
})
.attr("cy", function(d) {
return Math.max(10, Math.min(height - 10, d.y));
});
connectedGroup.selectAll("text")
.attr("x", d => d.x)
.attr("y", d => d.y - 25);
}
</script>