Agregar gráficos a Notion

Muchos carecen de gráficos en Notion. Entonces decidí archivar una cosa automática para generarlos.

Así es como se ve de mi parte:

imagen
Cualquier persona interesada en cómo se implementa esto, por favor, bajo cat.

Parte 1. Declaración del problema


El problema, de hecho, es que no hay gráficos en Notion, y no puedes visualizar la información de la tableta (pero quieres). En consecuencia, debe crear tal cosa que:

  1. Tomará una lista de páginas donde los gráficos podrían ser potencialmente
  2. Recopilaremos de estas páginas una descripción del horario. Las descripciones deben estar en las páginas debido a la comprensión para el lector de páginas + para no entrar en el código con demasiada frecuencia.
  3. Agregará un gráfico inmediatamente después de su descripción, eliminando la versión anterior del gráfico.
  4. Lo hará automáticamente (una vez por hora), y preferiblemente de forma gratuita.

Parte 2. Poniéndolo en los estantes


Vamos a escribir un servidor en Django. Es Django, porque la lib no oficial para Notion API está escrita en python. Luego cargamos todo a Heroku. Desde IFTTT tiraremos de nuestras cosas en Heroku con cierta frecuencia.

imagen

Parte 3. Comprender lo que necesitamos escribir


  1. Método para responder a una solicitud de IFTTT
  2. Método para peinar páginas de Notion y buscar descripciones gráficas
  3. Método para recuperar datos de un gráfico de una tabla
  4. Método para dibujar un gráfico y agregarlo a una página

Parte 4. Escribir un código


Vaya a Notion, presione Ctrl + Shift + J, vaya a Aplicación -> Cookies, copie token_v2 y llámelo TOKEN. Esto es necesario para que la biblioteca pueda interactuar de alguna manera con la API de Notion.

Necesitamos almacenar de alguna manera una lista de páginas donde se pueda encontrar una descripción de los gráficos. Mantendremos este negocio simple:

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

Para analizar de alguna manera la descripción en sí, necesitamos palabras clave para:

  1. Campos cuyos datos estarán en el eje X
  2. Campos cuyos datos estarán en el eje Y
  3. Url en el plato

Se verá así:

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

Es decir, una descripción vacía del gráfico se verá así:

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

También debemos verificar de alguna manera si la descripción está vacía. Archivaremos una función especial para esto. Si todos los campos no están vacíos, entonces el objeto está completo y podemos comenzar a dibujar el gráfico.

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

Datos (esto es solo texto de hecho) para generar una descripción, de alguna manera necesita borrarla. Escribamos un par de funciones para esto. Breve explicación: Notion almacena negrita (como en la imagen sobre el corte) __ aquí.

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

Ahora escribamos, quizás, la función principal de nuestra pequeña cosa. Debajo del código hay una explicación de lo que está sucediendo aquí:

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

Conectamos nuestra biblioteca a Notion. Luego, revisamos una variedad de páginas, donde potencialmente podemos necesitar gráficos. Verificamos cada línea de la página: ¿hay una de nuestras claves allí o no? Si de repente lo hay, limpiamos el texto desde allí y lo colocamos en el objeto. Tan pronto como el objeto esté lleno, verificamos si el gráfico generado ya ha estado allí (si es así, luego lo eliminamos) y vamos a dibujar un nuevo gráfico.

A continuación, escribiremos una función para recopilar datos de la placa.

 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 

Aquí obtenemos la base, obtenemos todas sus líneas y las atravesamos, formando un conjunto de líneas de punto a punto.

¿Qué es get_point_from_row? El hecho es que si nuestro objeto es una fecha (a menudo solo necesita mostrar la fecha en el eje X), entonces simplemente no se puede mostrar, y necesita procesarla aún más:

 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 

Ahora estamos listos para dibujar nuestro horario.

 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) 

Aquí agregamos un nuevo bloque (con foto), muévelo debajo de la descripción del gráfico. Luego volvemos a analizar los puntos (ver más abajo), dibujamos líneas usando matplotlib, guardamos la imagen resultante con un nombre de archivo aleatorio y la cargamos en el bloque de imágenes.

Podemos obtener un nombre de archivo aleatorio como este:

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

Y tenemos que volver a analizar los puntos debido al hecho de que matplotlib acepta una representación de datos diferente de la forma en que se implementa actualmente.

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

Si observa de cerca, el método todavía tiene una verificación de si los datos que tenemos a lo largo del eje X son la fecha. Si lo son, entonces solo tenemos que mostrarlos correctamente:

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

Ahora escribiremos una función que lanzará un nuevo hilo cuando recibamos una solicitud POST.
¿Por qué publicar? Por si acaso, de modo que si alguien te mira de repente, el guión no comienza.

¿Por qué exactamente el nuevo hilo? IFTTT, que usaremos como desencadenante para que esto funcione, no le gusta cuando lleva mucho tiempo esperar una respuesta del servidor (y en nuestro caso puede llevar mucho tiempo), y después de un tiempo puede dejar de desencadenar la comprensión.

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

Parte 5. IFTTT


Vaya a la pestaña de creación de applet. Seleccionamos el disparador (en nuestro caso es Fecha y hora), establecemos "cada hora". Seleccionamos el Webhook activado (es decir, "ese"), especificamos nuestra dirección local (hasta ahora) para probarla. Bueno, eso es todo. Prueba.

Subir a Heroku


Pensaste con lo que estábamos jugando con este disparador del IFTTT: esto no es para pagar. Heroku ofrece una tarifa gratuita para alojar nuestras cosas. Lo principal es que el servicio duerme al menos 6 horas. Y definitivamente dormirá, porque lo llamamos a trabajar cada hora, y no cada minuto.

Además hacemos lo siguiente. Ve a heroku para crear un nuevo proyecto . A continuación, instale su cliente en su sistema operativo. Y luego hacemos todo de acuerdo con las instrucciones que aparecieron después de crear la aplicación.

Después de descargar todo en heroku, vaya a nuestro applet y edite la URL a una nueva.

Parte 5. IFTTT


Gracias a todos los que leyeron a este lugar. Espero que este artículo te haya ayudado con algo.

Puedes leer mis otros dos artículos sobre Notion:

Exporte automáticamente Google Forms a Notion usando IFTTT y Django

Hacer una biblioteca doméstica con Notion y Python

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


All Articles