Hinzufügen von Grafiken zu Notion

Vielen fehlen Grafiken in Notion. Also habe ich beschlossen, eine automatische Datei zu erstellen, um sie zu generieren.

So sieht es meinerseits aus:

Bild
Wer sich dafür interessiert, wie das umgesetzt wird, bitte unter cat.

Teil 1. Erklärung des Problems


Das Problem ist in der Tat, dass es in Notion keine Grafiken gibt und Informationen vom Tablet nicht einfach so visualisiert werden können (aber ich möchte). Dementsprechend müssen Sie Folgendes erstellen:

  1. Es wird eine Liste von Seiten erstellt, auf denen möglicherweise Grafiken angezeigt werden
  2. Wird von diesen Seiten eine Beschreibung des Zeitplans sammeln. Die Beschreibungen sollten wegen der Verständlichkeit für den Seitenleser + auf den Seiten sein, um nicht zu oft in den Code zu kommen.
  3. Fügt unmittelbar nach der Beschreibung ein Diagramm hinzu und löscht die vorherige Version des Diagramms.
  4. Tut es automatisch (einmal pro Stunde) und am besten kostenlos.

Teil 2. Es in die Regale stellen


Wir werden einen Server in Django schreiben. Es ist Django, weil die inoffizielle Bibliothek für die Notion-API in Python geschrieben ist. Dann laden wir das Ganze auf Heroku hoch. Vom IFTTT werden wir unser Ding mit einer bestimmten Frequenz auf Heroku ziehen.

Bild

Teil 3. Verstehen, was wir schreiben müssen


  1. Methode zur Beantwortung einer Anfrage von IFTTT
  2. Methode zum Kämmen von Notion-Seiten und Suchen nach Diagrammbeschreibungen
  3. Methode zum Abrufen von Daten für ein Diagramm aus einer Tabelle
  4. Methode zum Zeichnen und Hinzufügen eines Diagramms zu einer Seite

Teil 4. Einen Code schreiben


Gehen Sie zu Notion, drücken Sie Strg + Umschalt + J, gehen Sie zu Application -> Cookies, kopieren Sie token_v2 und nennen Sie es TOKEN. Dies ist notwendig, damit die Bibliothek irgendwie mit der Notion-API interagieren kann.

Wir müssen irgendwie eine Liste von Seiten speichern, auf denen möglicherweise eine Beschreibung für Diagramme gefunden werden kann. Wir werden dieses Geschäft einfach halten:

PAGES = [ "https://www.notion.so/mixedself/Dashboard-40a3156030fd4d9cb1935993e1f2c7eb" ] 

Um die Beschreibung selbst irgendwie zu analysieren, benötigen wir Schlüsselwörter für:

  1. Felder, deren Daten auf der X-Achse liegen
  2. Felder, deren Daten auf der Y-Achse liegen
  3. URL auf dem Teller

Es wird so aussehen:

 BASE_KEY = "Base:" X_AXIS_KEY = "X axis:" Y_AXIS_KEY = "Y axis:" 

Das heißt, eine leere Beschreibung des Diagramms sieht ungefähr so ​​aus:

 def get_empty_object(): return { "database": "", "x": "", "y": "" } 

Wir müssen auch irgendwie überprüfen, ob die Beschreibung leer ist. Wir werden dafür eine spezielle Funktion einreichen. Wenn nicht alle Felder leer sind, ist das Objekt fertig und wir können mit dem Zeichnen des Graphen beginnen.

 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"]) 

Daten (das ist eigentlich nur Text) Um eine Beschreibung zu generieren, müssen Sie sie irgendwie löschen. Schreiben wir dazu ein paar Funktionen. Kurze Erklärung: Notion speichert fett (wie im Bild über dem Schnitt) __ hier.

 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() 

Jetzt schreiben wir vielleicht die Hauptfunktion für unser kleines Ding. Unter dem Code finden Sie eine Erklärung, was hier vor sich geht:

 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): # not last block if i != len(blocks.children) - 1: next_block = blocks.children[i + 1] # if next block is picture, then it is previous # version of the plot, then we should remove it if blocks.children[i + 1].type == "image": next_block.remove() draw_plot(client, thing, block, blocks) thing = get_empty_object() 

Wir verbinden unsere Bibliothek mit Notion. Dann gehen wir eine Reihe von Seiten durch, auf denen wir möglicherweise Grafiken benötigen. Wir überprüfen jede Zeile der Seite: Ist dort einer unserer Schlüssel oder nicht? Wenn plötzlich da ist - wir säubern den Text von dort und legen ihn in das Objekt. Sobald das Objekt voll ist, prüfen wir, ob das erzeugte Diagramm bereits vorhanden ist (wenn ja, löschen Sie es) und zeichnen ein neues Diagramm.

Als nächstes schreiben wir eine Funktion, um Daten von der Platte zu sammeln.

 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 

Hier bekommen wir die Basis, bekommen alle ihre Linien und gehen durch alle Linien, bilden eine Reihe von Linien von Punkt zu Punkt.

Was ist get_point_from_row? Tatsache ist, dass wenn unser Objekt ein Datum ist (oft müssen Sie nur das Datum auf der X-Achse anzeigen), es einfach nicht angezeigt werden kann und Sie es weiter verarbeiten müssen:

 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 

Jetzt sind wir bereit, unseren Zeitplan zu zeichnen.

 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) 

Hier fügen wir einen neuen Block (mit Foto) hinzu, verschieben ihn unter der Beschreibung des Graphen. Dann analysieren wir die Punkte (siehe unten), zeichnen Linien mit matplotlib, speichern das resultierende Bild mit einem zufälligen Dateinamen und laden es in den Bildblock.

Wir können einen zufälligen Dateinamen wie diesen erhalten:

 def random_string(string_length=10): letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(string_length)) 

Und wir müssen die Punkte neu analysieren, da matplotlib eine andere Datendarstellung als die derzeit implementierte akzeptiert.

 def reparse_points(points): return [ [points[0][0], points[1][0]], [points[0][1], points[1][1]], ] 

Wenn Sie genau hinsehen, überprüft die Methode immer noch, ob es sich bei den Daten auf der X-Achse um das Datum handelt. Wenn dies der Fall ist, müssen Sie diese nur korrekt anzeigen:

 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() 

Jetzt schreiben wir eine Funktion, die einen neuen Thread startet, wenn wir eine POST-Anfrage erhalten.
Warum POST? Nur für den Fall, dass jemand Sie plötzlich ansieht, startet das Skript nicht.

Warum genau der neue Thread? IFTTT, das wir als Auslöser für das Funktionieren dieser Sache verwenden, mag es nicht, wenn das Warten auf eine Antwort vom Server sehr lange dauert (und in unserem Fall kann es lange dauern) und nach einiger Zeit das Auslösen des Verständnisses aufhört.

 @csrf_exempt def index(request): if request.method == "POST": thread = Thread(target=plot) thread.start() return HttpResponse("Hello, world.") else: return HttpResponse("Hello, world.") 

Teil 5. IFTTT


Wechseln Sie zur Registerkarte Applet-Erstellung. Wir wählen den Auslöser (in unserem Fall Datum und Uhrzeit) und stellen "jede Stunde" ein. Wir wählen den ausgelösten (dh "diesen") Webhook aus, geben unsere (bisherige) lokale Adresse an, um ihn zu testen. Nun, das ist es. Test.

Hochladen auf Heroku


Sie dachten, was wir mit diesem Auslöser vom IFTTT anstellen - das ist nicht zu bezahlen. Heroku bietet einen kostenlosen Tarif für das Hosting unserer Produkte. Die Hauptsache ist, dass der Service mindestens 6 Stunden schläft. Und er wird definitiv schlafen, weil wir ihn jede Stunde und nicht jede Minute zur Arbeit rufen.

Weiter machen wir folgendes. Gehe zu Heroku, um ein neues Projekt zu erstellen . Installieren Sie als Nächstes den Client auf dem Betriebssystem. Und dann tun wir alles gemäß den Anweisungen, die nach dem Erstellen der Anwendung angezeigt wurden.

Nachdem Sie alles auf heroku heruntergeladen haben, rufen Sie unser Applet auf und bearbeiten Sie die URL zu einer neuen.

Teil 5. IFTTT


Vielen Dank an alle, die zu diesem Ort gelesen haben. Ich hoffe, dieser Artikel hat dir bei etwas geholfen.

Sie können meine anderen zwei Artikel über Notion lesen:

Exportieren Sie Google Forms mithilfe von IFTTT und Django automatisch nach Notion

Erstellen einer Heimbibliothek mit Notion und Python

Source: https://habr.com/ru/post/de485542/


All Articles