analitics

Pages

Friday, June 27, 2025

Python 3.13.5 : the manim python module - part 001.

I used this package few days ago and now I wrote about how can used it.
Update the new release of pip is available: 25.0.1 -> 25.1.1 , run this command:
python.exe -m pip install --upgrade pip
The documentation can be found on the official website.
pip install manim
Collecting manim
  Downloading manim-0.19.0-py3-none-any.whl.metadata (11 kB)
...
Successfully installed Pillow-11.2.1 Pygments-2.19.1 audioop-lts-0.2.1 av-13.1.0 beautifulsoup4-4.13.4 click-8.2.1 cloup-3.0.7 colorama-0.4.6 decorator-5.2.1 glcontext-3.0.0 isosurfaces-0.1.2 manim-0.19.0 manimpango-0.6.0 mapbox-earcut-1.0.3 markdown-it-py-3.0.0 mdurl-0.1.2 moderngl-5.12.0 moderngl-window-3.1.1 networkx-3.5 numpy-2.3.0 pycairo-1.28.0 pydub-0.25.1 pyglet-2.1.6 pyglm-2.8.2 rich-14.0.0 scipy-1.15.3 screeninfo-0.8.1 skia-pathops-0.8.0.post2 soupsieve-2.7 srt-3.5.3 svgelements-1.9.6 tqdm-4.67.1 typing-extensions-4.14.0 watchdog-6.0.0
Let's see how can be used to see the help area:
python.exe -m manim render --help
Manim Community v0.19.0

Usage: python -m manim render ...
Let's use this source code:
from manim import *

class AdvancedAnimation(Scene):
    def construct(self):
        # Scene 1: Introduction
        title = Text("Advanced Animation with Manim").scale(0.76)
        self.play(FadeIn(title))
        self.wait(2)

        # Scene 2: Custom Animation
        circle = Circle().set_fill(color=BLUE, opacity=0.5)
        square = Square().set_fill(color=RED, opacity=0.5)
        self.add(circle, square)
        self.play(
            Rotate(circle, angle=TAU),
            Rotate(square, angle=-TAU),
            run_time=2,
            rate_func=linear
        )
        self.wait()

        # Scene 3: Text Animation
        text = Text("This is a custom text animation", font_size=40).to_edge(UP)
        self.play(Write(text), run_time=2)
        self.wait()

        # Scene 4: Shapes Manipulation
        triangle = Triangle().shift(RIGHT * 2)
        self.play(GrowFromCenter(triangle), run_time=1.5)
        self.wait()

        # Scene 5: Transition to next scene
        self.play(Uncreate(triangle), FadeOut(text))

        # Scene 6: Final Animation
        final_text = Text("This is the end of our animation", font_size=50).to_edge(DOWN)
        self.play(FadeIn(final_text), run_time=1.5)
        self.wait(2)

# Run the animation
AdvancedAnimation()
Use this command to render:
python.exe -m manim render manim_test_001.py AdvancedAnimation -p
AdvancedAnimation -p
Manim Community v0.19.0

[06/27/25 19:52:43] INFO     Animation 0 : Partial movie file      scene_file_writer.py:588
                             written in
                             'D:\PythonProjects\manim_projects\med
                             ia\videos\manim_test_001\1080p60\part
                             ial_movie_files\AdvancedAnimation\397
                             7891868_355746014_223132457.mp4'
...
[06/27/25 19:53:56] INFO     Previewed File at:                             file_ops.py:237
                             'D:\PythonProjects\manim_projects\media\videos
                             \manim_test_001\1080p60\AdvancedAnimation.mp4'
The result comes with many files, see this 1080p60 video result:

Python Qt6 : ... simple processing file.

Today I will show you an simple python script with PyQt6.
This script ai build using the artificial inteligence and I tested will process your files by slections : copy to another folder , zip all selected and delete all selected.
import sys
import os
import re
import shutil
import zipfile
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                            QPushButton, QListWidget, QFileDialog, QMessageBox, QDialog, QLabel)
from PyQt6.QtCore import Qt

class CriteriaDialog(QDialog):
    def __init__(self, folder, parent=None):
        super().__init__(parent)
        self.setWindowTitle(f"Processing Folder: {folder}")
        self.layout = QVBoxLayout(self)
        self.layout.addWidget(QLabel(f"Selected folder: {folder}"))
        self.ok_button = QPushButton("OK")
        self.ok_button.clicked.connect(self.accept)
        self.layout.addWidget(self.ok_button)

class DuplicateFinder(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Duplicate File Finder")
        self.setGeometry(100, 100, 600, 400)
        
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)
        
        self.file_list = QListWidget()
        self.file_list.setSelectionMode(QListWidget.SelectionMode.MultiSelection)
        self.layout.addWidget(self.file_list)
        
        button_layout = QHBoxLayout()
        self.select_button = QPushButton("Select Folder")
        self.select_button.clicked.connect(self.select_folder)
        button_layout.addWidget(self.select_button)
        
        self.copy_button = QPushButton("Copy To")
        self.copy_button.clicked.connect(self.copy_files)
        button_layout.addWidget(self.copy_button)
        
        self.zip_button = QPushButton("Zip All")
        self.zip_button.clicked.connect(self.zip_files)
        button_layout.addWidget(self.zip_button)
        
        self.delete_button = QPushButton("Delete All")
        self.delete_button.clicked.connect(self.delete_files)
        button_layout.addWidget(self.delete_button)
        
        self.layout.addLayout(button_layout)
        
        self.files = []
        self.selected_folder = ""
        
    def select_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "Select Folder")
        if folder:
            self.selected_folder = folder
            dialog = CriteriaDialog(folder, self)
            if dialog.exec():
                self.files = []
                self.file_list.clear()
                self.scan_folder(folder)
                self.find_duplicates()
            
    def scan_folder(self, folder):
        for root, _, files in os.walk(folder):
            for file in files:
                file_path = os.path.join(root, file)
                self.files.append({
                    'path': file_path,
                    'name': os.path.basename(file_path),
                    'size': os.path.getsize(file_path),
                    'extension': os.path.splitext(file_path)[1]
                })
                
    def find_duplicates(self):
        duplicates = self.find_by_similar_name()
        self.display_duplicates(duplicates)
        
    def find_by_similar_name(self):
        duplicates = []
        name_groups = {}
        pattern = r'(.+?)(?:[\s_-]*\d{3,}|[\s_-]*\d{1,2}|_)?(?:\.\w+)?$'
        
        for file in self.files:
            match = re.match(pattern, file['name'])
            if match:
                base_name = match.group(1)
                if base_name in name_groups:
                    name_groups[base_name].append(file)
                else:
                    name_groups[base_name] = [file]
        
        for base_name, files in name_groups.items():
            if len(files) > 1:
                duplicates.extend(files)
                
        return duplicates
    
    def display_duplicates(self, duplicates):
        self.file_list.clear()
        for file in duplicates:
            self.file_list.addItem(file['path'])
            
    def copy_files(self):
        if not self.file_list.selectedItems():
            QMessageBox.warning(self, "Warning", "No files selected!")
            return
        dest_folder = QFileDialog.getExistingDirectory(self, "Select Destination Folder")
        if dest_folder:
            for item in self.file_list.selectedItems():
                file_path = item.text()
                dest_path = os.path.join(dest_folder, os.path.basename(file_path))
                shutil.copy2(file_path, dest_path)
            QMessageBox.information(self, "Success", "Files copied!")
            
    def zip_files(self):
        if not self.file_list.selectedItems():
            QMessageBox.warning(self, "Warning", "No files selected!")
            return
        zip_path = QFileDialog.getSaveFileName(self, "Save Zip File", "", "Zip Files (*.zip)")[0]
        if zip_path:
            with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
                for item in self.file_list.selectedItems():
                    file_path = item.text()
                    zipf.write(file_path, os.path.basename(file_path))
            QMessageBox.information(self, "Success", "Files zipped!")
        
    def delete_files(self):
        if not self.file_list.selectedItems():
            QMessageBox.warning(self, "Warning", "No files selected!")
            return
        reply = QMessageBox.question(self, "Confirm", "Delete selected files?",
                                  QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
        if reply == QMessageBox.StandardButton.Yes:
            for item in self.file_list.selectedItems():
                os.remove(item.text())
            self.file_list.clear()
            QMessageBox.information(self, "Success", "Files deleted!")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = DuplicateFinder()
    window.show()
    sys.exit(app.exec())