يفتقر الكثير من الرسومات في الفكرة. لذلك قررت تقديم شيء تلقائي لتوليدها.
هكذا يبدو من جهتي:
أي شخص مهتم بكيفية تطبيق ذلك ، من فضلك ، تحت القط.
الجزء 1. بيان المشكلة
المشكلة ، في الواقع ، هي عدم وجود رسوم بيانية في Notion ، ولا يمكنك فقط تصور المعلومات من الجهاز اللوحي (لكنك تريد ذلك). وفقًا لذلك ، تحتاج إلى إنشاء شيء من هذا القبيل:
- ستأخذ قائمة بالصفحات التي من المحتمل أن تكون فيها الرسوم البيانية
- سوف جمع من هذه الصفحات وصفا للجدول الزمني. يجب أن تكون الأوصاف على الصفحات بسبب شمولية قارئ الصفحة + حتى لا تدخل في الشفرة في كثير من الأحيان لإصلاحها.
- سيضيف مخططًا فور وصفه ، مع حذف الإصدار السابق من المخطط.
- ستقوم بذلك تلقائيًا (مرة واحدة في الساعة) ، ويفضل مجانًا.
الجزء 2. وضعه على الرفوف
سنكتب خادم في جانغو. إنه Django ، لأن lib غير الرسمي لواجهة برمجة تطبيقات Notion مكتوب بلغة الثعبان. ثم نقوم بتحميل الشيء كله إلى Heroku. من IFTTT ، سنقوم بسحب شيء على Heroku بتردد معين.

الجزء 3. فهم ما نحتاج إلى كتابته
- طريقة للرد على طلب من IFTTT
- طريقة لتمشيط صفحات الفكرة والبحث عن أوصاف الرسم البياني
- طريقة لاسترداد البيانات لمخطط من جدول
- طريقة لرسم رسم بياني وإضافته إلى صفحة
الجزء 4. كتابة رمز
انتقل إلى Notion ، واضغط على Ctrl + Shift + J ، وانتقل إلى التطبيق -> ملفات تعريف الارتباط ، وانسخ token_v2 واتصل بها TOKEN. يعد ذلك ضروريًا حتى تتمكن المكتبة من التفاعل بطريقة أو بأخرى مع واجهة برمجة تطبيقات Notion.
نحتاج إلى تخزين قائمة الصفحات بطريقة أو بأخرى حيث يمكن العثور على وصف للمخططات. سنبقي هذا العمل بسيطًا:
PAGES = [ "https://www.notion.so/mixedself/Dashboard-40a3156030fd4d9cb1935993e1f2c7eb" ]
من أجل تحليل الوصف نفسه بطريقة أو بأخرى ، نحتاج إلى كلمات رئيسية من أجل:
- الحقول التي ستكون بياناتها على المحور X
- الحقول التي ستكون بياناتها على المحور ص
- عنوان url على اللوحة
سيبدو مثل هذا:
BASE_KEY = "Base:" X_AXIS_KEY = "X axis:" Y_AXIS_KEY = "Y axis:"
وهذا يعني أن الوصف الفارغ للرسم البياني سيبدو كما يلي:
def get_empty_object(): return { "database": "", "x": "", "y": "" }
نحتاج أيضًا إلى التحقق بطريقة أو بأخرى مما إذا كان الوصف فارغًا أم لا. سنقدم وظيفة خاصة لهذا الغرض. إذا لم تكن جميع الحقول فارغة ، فسيكون الكائن مكتملًا ويمكننا البدء في رسم الرسم البياني.
def is_not_empty(thing): return thing != "" def check_for_completeness(object): return is_not_empty(object["database"]) and is_not_empty(object["x"]) and is_not_empty(object["y"])
البيانات (هذا مجرد نص في الواقع) لإنشاء وصف ، تحتاج إلى مسحه بطريقة أو بأخرى. دعنا نكتب بضع وظائف لهذا الغرض. شرح قصير: تخزن الفكرة جريئة (كما في الصورة أعلاه المقطع) __ هنا.
def br_text(text): return "__" + text + "__" def clear_text(text): return text.replace(br_text(BASE_KEY), "").replace(BASE_KEY, "") \ .replace(br_text(X_AXIS_KEY), "").replace(X_AXIS_KEY, "") \ .replace(br_text(Y_AXIS_KEY), "").replace(Y_AXIS_KEY, "").strip()
الآن دعنا نكتب ، ربما ، الوظيفة الرئيسية لشيءنا الصغير. تحت الكود هو شرح لما يجري هنا:
def plot(): client = NotionClient(token_v2=TOKEN) for page in PAGES: blocks = client.get_block(page) thing = get_empty_object() for i in range(len(blocks.children)): block = blocks.children[i] print(block.type) if block.type != "image": title = block.title if BASE_KEY in title: thing["database"] = clear_text(title).split("](")[0].replace("[", "") elif X_AXIS_KEY in title: thing["x"] = clear_text(title) elif Y_AXIS_KEY in title: thing["y"] = clear_text(title) if check_for_completeness(thing):
نحن نربط مكتبتنا بالمفهوم ثم نذهب إلى مجموعة من الصفحات ، حيث يمكننا أن نحتاج إلى رسومات. نتحقق من كل سطر من الصفحة: هل هناك أحد مفاتيحنا هناك أم لا. إذا كان هناك فجأة - نقوم بتنظيف النص من هناك ووضعه في الكائن. بمجرد امتلاء الكائن ، نتحقق مما إذا كان المخطط الذي تم إنشاؤه موجودًا بالفعل (إذا كان الأمر كذلك ، ثم احذفه) ثم انتقل إلى رسم مخطط جديد.
بعد ذلك ، سنكتب وظيفة لجمع البيانات من اللوحة.
def get_lines_array(thing, client): database = client.get_collection_view(thing["database"]) rows = database.default_query().execute() lines_array = [] for i in range(1, len(rows)): previous_row = rows[i - 1] current_row = rows[i] line = [(get_point_from_row(thing, previous_row)), (get_point_from_row(thing, current_row))] lines_array.append(line) return lines_array
هنا نحصل على القاعدة ، ونحصل على جميع خطوطها ونذهب عبر جميع الخطوط ، ونشكل مجموعة من الخطوط من نقطة إلى نقطة.
ما هو get_point_from_row؟ والحقيقة هي أنه إذا كان كائننا هو تاريخ (غالبًا ما تحتاج فقط إلى عرض التاريخ على المحور X) ، فعندئذ لا يمكن عرضه ، وتحتاج إلى مزيد من المعالجة:
def get_point_from_row(thing, row): x_property = row.get_property(thing["x"]) y_property = row.get_property(thing["y"]) if thing["x"] == "date": x_property = x_property.start if thing["y"] == "date": y_property = y_property.start return x_property, y_property
الآن نحن مستعدون لرسم جدولنا الزمني.
def draw_plot(client, thing, block, page): photo = page.children.add_new(ImageBlock) photo.move_to(block, "after") array = get_lines_array(thing, client) print(array) for i in range(1, len(array)): points = reparse_points(array[i - 1:i][0]) plt.plot(points[0], points[1], color="red") if not path.exists("images"): os.mkdir("images") if thing["x"] == "date": x_axis_dates() filename = "images/" + random_string(15) + ".png" plt.savefig(filename) print("Uploading " + filename) photo.upload_file(filename)
نضيف هنا كتلة جديدة (مع صورة) ، حركها تحت وصف الرسم البياني. ثم نقوم بإعادة توزيع النقاط (انظر أدناه) ، ورسم خطوط باستخدام matplotlib ، وحفظ الصورة الناتجة مع اسم ملف عشوائي وتحميله في كتلة الصورة.
يمكننا الحصول على اسم ملف عشوائي مثل هذا:
def random_string(string_length=10): letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(string_length))
ونحتاج إلى إعادة توزيع النقاط نظرًا لحقيقة أن matplotlib يقبل تمثيل البيانات بشكل مختلف عن الطريقة التي يتم بها تنفيذها حاليًا.
def reparse_points(points): return [ [points[0][0], points[1][0]], [points[0][1], points[1][1]], ]
إذا نظرت عن كثب ، فإن الطريقة لا تزال تتحقق مما إذا كانت البيانات التي لدينا على طول المحور X هي التاريخ ، وإذا كانت كذلك ، فسنحتاج فقط إلى عرضها بشكل صحيح:
def x_axis_dates(ax=None, fig=None): if ax is None: ax = plt.gca() if fig is None: fig = plt.gcf() loc = mdates.AutoDateLocator() fmt = mdates.AutoDateFormatter(loc) ax.xaxis.set_major_locator(loc) ax.xaxis.set_major_formatter(fmt) fig.autofmt_xdate()
سنقوم الآن بكتابة وظيفة ستطلق سلسلة رسائل جديدة عندما نتلقى طلب POST.
لماذا بوست؟ فقط في الحالة ، بحيث إذا كان شخص ما ينظر إليك فجأة ، فلن يبدأ البرنامج النصي.
لماذا بالضبط موضوع جديد؟ إن IFTTT ، الذي سنستخدمه كمحرك لعمل هذا الشيء ، لا يعجبه عندما يستغرق الأمر وقتًا طويلاً لانتظار استجابة من الخادم (وفي حالتنا قد يستغرق الأمر وقتًا طويلاً) ، وبعد بعض الوقت قد يتوقف عن تشغيل الفهم.
@csrf_exempt def index(request): if request.method == "POST": thread = Thread(target=plot) thread.start() return HttpResponse("Hello, world.") else: return HttpResponse("Hello, world.")
الجزء 5. IFTTT
انتقل إلى علامة تبويب إنشاء التطبيق الصغير. نختار المشغل (في حالتنا هو التاريخ والوقت) ، قم بتعيين "كل ساعة". نختار Webhook المشغلة (أي ، "ذلك") ، ونحدد عنواننا المحلي (حتى الآن) لاختباره. حسنا ، هذا كل شيء. الاختبار.
تحميل إلى Heroku
لقد فكرت فيما كنا نعبث به مع هذا الزناد من IFTTT - هذا ليس بالدفع. تقدم Heroku سعرًا مجانيًا لاستضافة الأشياء الخاصة بنا. الشيء الرئيسي هو أن الخدمة تنام 6 ساعات على الأقل. وسوف ينام بالتأكيد ، لأننا ندعوه للعمل كل ساعة ، وليس كل دقيقة.
كذلك نفعل ما يلي. انتقل إلى heroku
لإنشاء مشروع جديد . بعد ذلك ، قم بتثبيت
عميلهم على نظام التشغيل الخاص بهم. ثم نقوم بكل شيء وفقًا للإرشادات التي ظهرت بعد إنشاء التطبيق.
بعد تنزيل كل شيء على heroku ، انتقل إلى التطبيق الصغير لدينا وقم بتحرير عنوان URL إلى عنوان جديد.
الجزء 5. IFTTT
شكرا لكل من قرأ هذا المكان. آمل أن يكون هذا المقال ساعدك في شيء.
يمكنك قراءة مقالتين أخريين حول الفكرة:
تصدير نماذج Google تلقائيًا إلى Notion باستخدام IFTTT و Django
إنشاء مكتبة منزلية مع Notion و Python