33

I need to send stock market data and the formatting sucks right now. Need to send something liike this

| Symbol | Price | Change | 
|--------|-------|--------|
| ABC | 20.85 | 1.626 | 
| DEF | 78.95 | 0.099 | 
| GHI | 23.45 | 0.192 | 
| JKL | 98.85 | 0.292 |

This is what I have tried.

| Symbol | Price | Change |  
|--------|-------|--------|  
| ABC | 20.85 | 1.626 |   
| DEF | 78.95 | 0.099 |   
| GHI | 23.45 | 0.192 |    
| JKL | 98.85 | 0.292 |
mate00
  • 2,727
  • 5
  • 26
  • 34
Aditya
  • 677
  • 2
  • 9
  • 15

10 Answers10

20

Set the Telegram API parse_mode parameter to HTML and wrap the message in <pre></pre> , but remember that telegram API does not support nested tags.

<pre>
| Tables   |      Are      |  Cool |
|----------|:-------------:|------:|
| col 1 is |  left-aligned | $1600 |
| col 2 is |    centered   |   $12 |
| col 3 is | right-aligned |    $1 |
</pre>

Result in Telegram messanger:

ScreenShot from telegram bot

Updated. How convert the tables in the picture

There will be a problem on the small screens of smartphones. So this method is not good. The only option is to convert the tables in the picture and so send :

  1. Or you can convert HTML to image using a headerless browser on your server.
  2. Or you can convert HTML to image using here external API services
  3. Or you can convert HTML to image using more difficult way by php GD
Ruslan Novikov
  • 1,320
  • 15
  • 21
  • 1
    How to convert table into picture ? – Sunny Apr 12 '21 at 23:16
  • 1
    how can I convert pandas dataframe to this html format? I tried df.to_html() but that didn work. – Kundan Nov 03 '21 at 15:58
  • Kundan, I don't know pandas dataframe for Python. But I know that too complicated convert any HTML to rich txt format for Telegram message. You should use Telegram service for instance view HTML articles https://telegram.org/blog/instant-view in your project – Ruslan Novikov Nov 04 '21 at 08:55
14

Try this

```| Symbol | Price | Change |
|--------|-------|--------|
| ABC    | 20.85 |  1.626 |
| DEF    | 78.95 |  0.099 |
| GHI    | 23.45 |  0.192 |
| JKL    | 98.85 |  0.292 |```
iliyesku
  • 361
  • 2
  • 10
14

Import "prettytable" library in python to format your table:

import prettytable as pt
from telegram import ParseMode
from telegram.ext import CallbackContext, Updater


def send_table(update: Updater, context: CallbackContext):
    table = pt.PrettyTable(['Symbol', 'Price', 'Change'])
    table.align['Symbol'] = 'l'
    table.align['Price'] = 'r'
    table.align['Change'] = 'r'

    data = [
        ('ABC', 20.85, 1.626),
        ('DEF', 78.95, 0.099),
        ('GHI', 23.45, 0.192),
        ('JKL', 98.85, 0.292),
    ]
    for symbol, price, change in data:
        table.add_row([symbol, f'{price:.2f}', f'{change:.3f}'])

    update.message.reply_text(f'<pre>{table}</pre>', parse_mode=ParseMode.HTML)
    # or use markdown
    update.message.reply_text(f'```{table}```', parse_mode=ParseMode.MARKDOWN_V2)

You will receive message like:

+--------+-------+--------+
| Symbol | Price | Change |
+--------+-------+--------+
| ABC    | 20.85 |  1.626 |
| DEF    | 78.95 |  0.099 |
| GHI    | 23.45 |  0.192 |
| JKL    | 98.85 |  0.292 |
+--------+-------+--------+
Rioka
  • 321
  • 3
  • 4
8

You can use HTML or Markdown markup to send something like <pre> in HTML. Just like this example.

Sean Wei
  • 7,433
  • 1
  • 19
  • 39
2

I found this library - TableJs - that solves this problem. Works great on desktop clients however android clients didn't seem to render it properly.

Aditya
  • 677
  • 2
  • 9
  • 15
  • I had the same problem on Android, but fixed it by overriding the `config.border` property and using a more basic character set. – Joe Coder Jan 18 '22 at 17:18
2

Here is my solution using puppeteer to screenshot on the table element

First of all you need to generate the table HTML code here is the code to generate that code

async function generateHtml(rows) {
    return `<!DOCTYPE html>
    <html>
    <head>
    <style>
    thead,
tfoot {
    background-color: #3f87a6;
    color: #fff;
}

tbody {
    background-color: #e4f0f5;
}

caption {
    padding: 10px;
    caption-side: bottom;
}

table {
    border-collapse: collapse;
    border: 2px solid rgb(200, 200, 200);
    letter-spacing: 1px;
    font-family: sans-serif;
    font-size: .8rem;
}

td,
th {
    border: 1px solid rgb(190, 190, 190);
    padding: 5px 10px;
}

td {
    text-align: center;
}

    </style>
    </head>
    <body>
    <table>
    <caption>Pornhub Pages Summary</caption>
    <thead>
        <tr>
            <th>ID</th>
            <th scope="col">Progress</th>
            <th scope="col">Stucked</th>
            <th scope="col">Finished</th>
            <th scope="col">Busy</th>
        </tr>
    </thead>
    <tbody>
        ${rows}
    </tbody>
</table>
    </body>
    </html>`
}

And here is the code for generate the rows argument of the above function

async function getTheImgOfTheSummaryOfThePages() {
    const rows = []
    for (const [index, val] of statuesOfThePages.entries()) {
        const row = `<tr>
        <th scope="row">${index}</th>
        <th>${val.progress}</th>
        <th>${val.stucked}</th>
        <th>${val.finished}</th>
        <th>${val.pageBusy}</th>
      </tr>`

        rows.push(row)
    }

    const path = './summaryOfThePagesOfPornhub.png'
    const html = await generateHtml(rows.join('\n'))
    await util.takescrrenshotOnTheHtml(html, browser, path, 'table')
    return path
}

And here is the code for screenshot on the table element

async function takescrrenshotOnTheHtml(html, browser, pathToSave, onElement) {
    const page = await newPage(browser);
    await page.setContent(html)
    const element = await page.$(onElement)
    await element.screenshot({path: pathToSave})
    await page.close()
}

Here is the result enter image description here

Well you just need to change the table headers and the rows of the table

OnTheRoad
  • 527
  • 6
  • 24
2

The easiest and most professional method is to use Telegram Web App Bot, which was added in the recent update.

step 1: create html file and write your table.

step2: add this script to your html file. <script src="https://telegram.org/js/telegram-web-app.js"></script>

step 3: redirect user to page with this method of api

{
    "text": "Test web_app",
    "web_app": {
        "url": "https://yourDomain/yourFile.html"
    }
}

note: page will show in bot page not browser

for more info read official document: https://core.telegram.org/bots/webapps#initializing-web-apps

1

Formatting the text as "Monospace" works too

dnth
  • 879
  • 2
  • 12
  • 22
0

I wrote a code to build a Telegram html table from an array of strings.

Just build an array with the lines with columns data separated by ";" and this code will output the Telegram ready table.

Enjoy, figure out the parameters :)

You must use "parse_mode" = "html" when sending the message to Telegram Api.

public string BuildTelegramTable(
            List<string> table_lines,
            string tableColumnSeparator = "|", char inputArraySeparator = ';',
            int maxColumnWidth = 0, bool fixedColumnWidth = false, bool autoColumnWidth = false,
            int minimumColumnWidth = 4, int columnPadRight = 0, int columnPadLeft = 0,
            bool beginEndBorders = true)
        {
            var prereadyTable = new List<string>() { "<pre>" };
            var columnsWidth = new List<int>();
            var firstLine = table_lines[0];
            var lineVector = firstLine.Split(inputArraySeparator);

            if (fixedColumnWidth && maxColumnWidth == 0) throw new ArgumentException("For fixedColumnWidth usage must set maxColumnWidth > 0");
            else if (fixedColumnWidth && maxColumnWidth > 0)
            {
                for(var x=0;x<lineVector.Length;x++)
                    columnsWidth.Add(maxColumnWidth + columnPadRight + columnPadLeft);
            }
            else
            {
                for(var x=0;x<lineVector.Length;x++)
                {
                    var columnData = lineVector[x].Trim();
                    var columnFullLength = columnData.Length;

                    if (autoColumnWidth)
                        table_lines.ForEach(line => columnFullLength = line.Split(inputArraySeparator)[x].Length > columnFullLength ? line.Split(inputArraySeparator)[x].Length : columnFullLength);
                    
                    columnFullLength = columnFullLength < minimumColumnWidth ? minimumColumnWidth : columnFullLength;

                    var columnWidth = columnFullLength + columnPadRight + columnPadLeft;

                    if (maxColumnWidth > 0 && columnWidth > maxColumnWidth)
                        columnWidth = maxColumnWidth;

                    columnsWidth.Add(columnWidth);
                }
            }

            foreach(var line in table_lines)
            {
                lineVector = line.Split(inputArraySeparator);

                var fullLine = new string[lineVector.Length+(beginEndBorders ? 2 : 0)];
                if (beginEndBorders) fullLine[0] = "";

                for(var x=0;x<lineVector.Length;x++)
                {
                    var clearedData = lineVector[x].Trim();
                    var dataLength = clearedData.Length;
                    var columnWidth = columnsWidth[x];
                    var columnSizeWithoutTrimSize = columnWidth - columnPadRight - columnPadLeft;
                    var dataCharsToRead = columnSizeWithoutTrimSize > dataLength ? dataLength : columnSizeWithoutTrimSize;
                    var columnData = clearedData.Substring(0,dataCharsToRead);
                    columnData = columnData.PadRight(columnData.Length + columnPadRight);
                    columnData = columnData.PadLeft(columnData.Length + columnPadLeft);

                    var column = columnData.PadRight(columnWidth);

                    fullLine[x+(beginEndBorders ? 1 : 0)] = column;
                }

                if (beginEndBorders) fullLine[fullLine.Length - 1] = "";

                prereadyTable.Add(string.Join(tableColumnSeparator,fullLine));
            }

            prereadyTable.Add("</pre>");

            return string.Join("\r\n",prereadyTable);
        }
Allan Zeidler
  • 317
  • 2
  • 7
0
import warnings
from PIL import Image, ImageDraw, ImageFont

def table_to_image(my_table):
    warnings.filterwarnings('ignore', category=DeprecationWarning)
    font = ImageFont.truetype("courbd.ttf", 15)
    text_width, text_height = font.getsize_multiline(my_table.get_string())
    im = Image.new("RGB", (text_width + 15, text_height + 15), "white")
    draw = ImageDraw.Draw(im)
    draw.text((7, 7), my_table.get_string(), font=font, fill="black")
    im.show()
    im.save(my_table_image.png, 'PNG')
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 29 '22 at 15:12