Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

## Установка
```bash
git clone https://github.com/<username>/sets-visualizer.git
git clone https://github.com/6ixyld/sets-visualizer.git
cd sets-visualizer
python -m venv venv
source venv/bin/activate # или venv\Scripts\activate на Windows
Expand Down
95 changes: 95 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from flask import Flask, render_template, request, jsonify
from venn_visual import plot_venn # Убрал лишний импорт
from sets_logic import *

app = Flask(__name__)


@app.route("/", methods=["GET", "POST"])
def index():
img = None
result_text = ""
if request.method == "POST":
# получаем множества из формы
raw_a = request.form.get("set_a", "")
raw_b = request.form.get("set_b", "")
operation = request.form.get(
"operation", "union"
) # получаем выбранную операцию

# преобразование в Python set
a = set(raw_a.replace(" ", "").split(",")) if raw_a else set()
b = set(raw_b.replace(" ", "").split(",")) if raw_b else set()

# Выбор операции
if operation == "union":
result = union(a, b)
operation_name = "объединения"
elif operation == "intersection":
result = intersection(a, b)
operation_name = "пересечения"
elif operation == "difference":
result = difference(a, b)
operation_name = "разности A\\B"
elif operation == "sym_diff":
result = sym_diff(a, b)
operation_name = "симметрической разности"
elif operation == "cartesian":
result = cartesian(a, b)
operation_name = "декартового произведения"

# Форматирование результата
if operation == "cartesian":
result_text = (
f"Результат {operation_name}: {', '.join(str(x) for x in result)}"
)
else:
result_text = f"Результат {operation_name}: {', '.join(str(x) for x in sorted(result))}"

# генерируем диаграмму только для операций с 2-мя множествами
if a and b:
img = plot_venn(a, b)

return render_template("index.html", img=img, result_text=result_text)


@app.route("/process", methods=["POST"])
def process():
data = request.get_json()
a = (
set(data.get("setA", "").replace(" ", "").split(","))
if data.get("setA")
else set()
)
b = (
set(data.get("setB", "").replace(" ", "").split(","))
if data.get("setB")
else set()
)
operation = data.get("operation", "union")

# Выбор операции
if operation == "union":
result = union(a, b)
elif operation == "intersection":
result = intersection(a, b)
elif operation == "difference":
result = difference(a, b)
elif operation == "sym_diff":
result = sym_diff(a, b)
elif operation == "cartesian":
result = cartesian(a, b)
else:
result = set()

# Если результат — множество кортежей (для декартового произведения), конвертируем в список строк
if operation == "cartesian":
result_list = [str(t) for t in result]
else:
result_list = list(result)

return jsonify({"result": result_list})


if __name__ == "__main__":
app.run(debug=True)
Empty file added docs/annotation.docx
Empty file.
Empty file added requirements.txt
Empty file.
14 changes: 14 additions & 0 deletions sets_logic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def union(a, b):
return a | b

def intersection(a, b):
return a & b

def difference(a, b):
return a - b

def sym_diff(a, b):
return a ^ b

def cartesian(a, b):
return {(x, y) for x in a for y in b}
15 changes: 15 additions & 0 deletions static/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function sendData() {
const setA = document.getElementById('setA').value.split(',').map(x => x.trim());
const setB = document.getElementById('setB').value.split(',').map(x => x.trim());
const operation = document.getElementById('operation').value;

fetch('/process', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ setA, setB, operation })
})
.then(res => res.json())
.then(data => {
document.getElementById('result').innerText = `{ ${data.result.join(', ')} }`;
});
}
134 changes: 134 additions & 0 deletions static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 900px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}

.container {
background: white;
border-radius: 20px;
padding: 40px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
margin-top: 20px;
}

h1 {
text-align: center;
color: white;
margin-bottom: 10px;
font-size: 2.8em;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
font-weight: 700;
}

.subtitle {
text-align: center;
color: white;
margin-bottom: 30px;
font-size: 1.2em;
opacity: 0.9;
}

.form-group {
margin-bottom: 25px;
}

label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: #555;
font-size: 1.1em;
}

input,
select,
button {
display: block;
margin: 8px 0;
padding: 15px;
width: 100%;
border: 2px solid #e1e8ed;
border-radius: 12px;
font-size: 16px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-sizing: border-box;
font-family: inherit;
}

input:focus,
select:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.15);
transform: translateY(-2px);
}

button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 18px;
font-size: 18px;
font-weight: 600;
cursor: pointer;
margin-top: 25px;
border-radius: 12px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

button:hover {
transform: translateY(-3px);
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.4);
}

#result {
background: #f8f9fa;
/* Нейтральный серый фон */
color: #2d3436;
/* Темно-серый текст */
border-left: 5px solid #667eea;
padding: 20px;
margin: 30px 0;
border-radius: 12px;
font-size: 1.2em;
font-weight: 500;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
}

.venn-container {
text-align: center;
margin: 40px 0;
padding: 30px;
background: #f8f9fa;
border-radius: 15px;
box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.05);
}

.venn-container h2 {
color: #2d3436;
margin-bottom: 25px;
font-size: 1.8em;
font-weight: 600;
}

.venn-container img {
max-width: 100%;
height: auto;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
border: 3px solid white;
}

.operation-info {
text-align: center;
color: #636e72;
font-style: italic;
margin-top: 10px;
font-size: 0.9em;
}
Empty file added static/venn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="ru">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Визуализация операций над множествами</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}">
</head>

<body>
<h1>Визуализация операций над множествами</h1>
<div class="subtitle">Интерактивная диаграмма Венна с отображением элементов</div>

<div class="container">
<form method="POST" action="/">
<div class="form-group">
<label>Множество A:</label>
<input name="set_a" placeholder="Введите элементы через запятую, например: 1,2,3,5,7"
value="{{ request.form.set_a if request.form }}">
</div>

<div class="form-group">
<label>Множество B:</label>
<input name="set_b" placeholder="Введите элементы через запятую, например: 2,3,4,6,8"
value="{{ request.form.set_b if request.form }}">
</div>

<div class="form-group">
<label>Выберите операцию:</label>
<select name="operation">
<option value="union">Объединение (A ∪ B)</option>
<option value="intersection">Пересечение (A ∩ B)</option>
<option value="difference">Разность (A \ B)</option>
<option value="sym_diff">Симметрическая разность (A Δ B)</option>
<option value="cartesian">Декартово произведение (A × B)</option>
</select>
</div>

<button type="submit">Выполнить операцию</button>
</form>

{% if result_text %}
<div id="result">{{ result_text }}</div>
{% endif %}

{% if img %}
<div class="venn-container">
<img src="data:image/png;base64,{{ img }}" alt="Диаграмма Венна">
<div class="operation-info">Элементы отображаются непосредственно в соответствующих областях диаграммы</div>
</div>
{% endif %}
</div>
</body>

</html>
Loading