Ajouter des graphiques à Notion

Beaucoup manquent de graphiques dans Notion. J'ai donc décidé de déposer une chose automatique pour les générer.

Voici à quoi ça ressemble de ma part:

image
Toute personne intéressée par la façon dont cela est mis en œuvre, s'il vous plaît, sous cat.

Partie 1. Énoncé du problème


Le problème, en fait, est qu'il n'y a pas de graphiques dans Notion, et vous ne pouvez pas simplement visualiser les informations de la tablette (mais vous le souhaitez). En conséquence, vous devez créer une chose telle que:

  1. Prendra une liste de pages où les graphiques pourraient être potentiellement
  2. Collectera à partir de ces pages une description du calendrier. Les descriptions doivent être sur les pages en raison de la compréhensibilité pour le lecteur de page + afin de ne pas entrer trop souvent dans le code pour le corriger.
  3. Ajoutera un graphique immédiatement après sa description, supprimant la version précédente du graphique.
  4. Le fera automatiquement (une fois par heure), et de préférence gratuitement.

Partie 2. Le mettre sur les étagères


Nous allons écrire un serveur dans Django. Il s'agit de Django, car la bibliothèque non officielle de l'API Notion est écrite en python. Ensuite, nous téléchargeons le tout sur Heroku. De IFTTT nous tirerons notre truc sur Heroku avec une certaine fréquence.

image

Partie 3. Comprendre ce que nous devons écrire


  1. Méthode pour répondre à une demande de IFTTT
  2. Méthode pour peigner les pages Notion et rechercher des descriptions de graphiques
  3. Méthode de récupération des données d'un graphique à partir d'une table
  4. Méthode pour dessiner un graphique et l'ajouter à une page

Partie 4. Écrire un code


Allez dans Notion, appuyez sur Ctrl + Maj + J, allez dans Application -> Cookies, copiez token_v2 et appelez-le TOKEN. Cela est nécessaire pour que la bibliothèque puisse interagir avec l'API Notion.

Nous devons en quelque sorte stocker une liste de pages où une description des graphiques pourrait potentiellement être trouvée. Nous garderons cette entreprise simple:

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

Afin d'analyser la description elle-même, nous avons besoin de mots clés pour:

  1. Champs dont les données seront sur l'axe X
  2. Champs dont les données seront sur l'axe Y
  3. URL sur la plaque

Cela ressemblera à ceci:

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

Autrement dit, une description vide du graphique ressemblera à ceci:

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

Nous devons également vérifier en quelque sorte si la description est vide. Nous allons déposer une fonction spéciale pour cela. Si tous les champs ne sont pas vides, alors l'objet est complet et nous pouvons commencer à dessiner le graphique.

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

Les données (c'est juste du texte en fait) afin de générer une description, vous devez en quelque sorte l'effacer. Écrivons quelques fonctions pour cela. Brève explication: Notion stocke les caractères gras (comme dans l'image ci-dessus la coupe) __ ici.

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

Écrivons maintenant, peut-être, la fonction principale de notre petite chose. Sous le code se trouve une explication de ce qui se passe ici:

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

Nous connectons notre bibliothèque à Notion. Ensuite, nous parcourons un tableau de pages, où nous pouvons potentiellement avoir besoin de graphiques. Nous vérifions chaque ligne de la page: y a-t-il ou non une de nos clés. S'il y a soudainement - nous nettoyons le texte à partir de là et le mettons dans l'objet. Dès que l'objet est plein, nous vérifions si le graphique généré est déjà là (si c'est le cas, supprimez-le) et allez dessiner un nouveau graphique.

Ensuite, nous allons écrire une fonction pour collecter les données de la plaque.

 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 

Ici, nous obtenons la base, obtenons toutes ses lignes et parcourons toutes les lignes, formant un ensemble de lignes de point en point.

Qu'est-ce que get_point_from_row? Le fait est que si notre objet est une date (il vous suffit souvent d'afficher la date sur l'axe X), elle ne peut tout simplement pas être affichée et vous devez la traiter davantage:

 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 

Nous sommes maintenant prêts à dessiner notre calendrier.

 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) 

Ici, nous ajoutons un nouveau bloc (avec photo), déplacez-le sous la description du graphique. Ensuite, nous réanalysons les points (voir ci-dessous), dessinons des lignes à l'aide de matplotlib, sauvegardons l'image résultante avec un nom de fichier aléatoire et chargez-la dans le bloc d'image.

Nous pouvons obtenir un nom de fichier aléatoire comme celui-ci:

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

Et nous devons analyser à nouveau les points, car matplotlib accepte une représentation des données différente de la façon dont elle est actuellement implémentée.

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

Si vous regardez de plus près, la méthode vérifie toujours si les données que nous avons le long de l'axe X sont la date. Si elles le sont, il nous suffit de les afficher correctement:

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

Nous allons maintenant écrire une fonction qui lancera un nouveau fil de discussion lorsque nous recevrons une demande POST.
Pourquoi POST? Juste au cas où, si quelqu'un vous regarde soudainement, le script ne démarre pas.

Pourquoi exactement le nouveau fil? IFTTT, que nous utiliserons comme déclencheur pour que cette chose fonctionne, ne l'aime pas quand il faut très longtemps pour attendre une réponse du serveur (et dans notre cas, cela peut prendre beaucoup de temps), et après un certain temps, il peut cesser de déclencher la compréhension.

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

Partie 5. IFTTT


Accédez à l'onglet de création d'applet. Nous sélectionnons le déclencheur (dans notre cas, il s'agit de la date et de l'heure), réglé sur «toutes les heures». Nous sélectionnons le Webhook déclenché (c'est-à-dire «que»), spécifions notre (jusqu'à présent) adresse locale afin de le tester. Eh bien, c'est tout. Testez.

Télécharger sur Heroku


Vous pensiez à quoi nous jouions avec ce déclencheur de l'IFTTT - ce n'est pas à payer. Heroku propose un tarif gratuit pour l'hébergement de nos produits. L'essentiel est que le service dorme au moins 6 heures. Et il dormira certainement, car nous l'appelons au travail toutes les heures, et non toutes les minutes.

De plus, nous faisons ce qui suit. Accédez à Heroku pour créer un nouveau projet . Ensuite, installez leur client sur leur système d'exploitation. Et puis nous faisons tout selon les instructions qui sont apparues après la création de l'application.

Après avoir tout téléchargé sur heroku, accédez à notre applet et modifiez l'URL en une nouvelle.

Partie 5. IFTTT


Merci à tous ceux qui ont lu cet endroit. J'espère que cet article vous a aidé avec quelque chose.

Vous pouvez lire mes deux autres articles sur Notion:

Exportez automatiquement Google Forms vers Notion à l'aide d'IFTTT et de Django

Créer une bibliothèque personnelle avec Notion et Python

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


All Articles