How to query database using variable and get all results not just one row

Hello I am trying to query a database to show records only for the current user using variable I get the correct data but only 1 row with results any guidance?

// Query database to retrieve records associated with the user
$sql = "SELECT * FROM table_name WHERE variable_name = :variable_name";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':variable_name', $variable_name, PDO::PARAM_STR);
$stmt->execute();
$records = $stmt->fetchAll(PDO::FETCH_ASSOC);

Here’s When Website Breadcrumbs Actually Help Your Visitors

Similar to directory levels in an operating system, breadcrumbs are secondary navigational tools that help visiting users identify their current positions on websites, mobile applications, and even some offline systems. In a nutshell, breadcrumbs can help both search engines and human users find their way around your site, but it’s […]

The post Here’s When Website Breadcrumbs Actually Help Your Visitors appeared first on .

Hiding Data in DB2

In this article, we'll talk about fine-grained access control in DB2 - hiding data that is, in fact, present in the database, but should not be accessible to certain users.

Fine-grained access control is usually done in the database itself as the data is being accessed, but it can also be done between the database server and the database client using a programmable proxy.

Vanilla JavaScript, Libraries, And The Quest For Stateful DOM Rendering

In his seminal piece “The Market For Lemons”, renowned web crank Alex Russell lays out the myriad failings of our industry, focusing on the disastrous consequences for end users. This indignation is entirely appropriate according to the bylaws of our medium.

Frameworks factor highly in that equation, yet there can also be good reasons for front-end developers to choose a framework, or library for that matter: Dynamically updating web interfaces can be tricky in non-obvious ways. Let’s investigate by starting from the beginning and going back to the first principles.

Markup Categories

Everything on the web starts with markup, i.e. HTML. Markup structures can roughly be divided into three categories:

  1. Static parts that always remain the same.
  2. Variable parts that are defined once upon instantiation.
  3. Variable parts that are updated dynamically at runtime.

For example, an article’s header might look like this:

<header>
  <h1>«Hello World»</h1>
  <small>«123» backlinks</small>
</header>

Variable parts are wrapped in «guillemets» here: “Hello World” is the respective title, which only changes between articles. The backlinks counter, however, might be continuously updated via client-side scripting; we’re ready to go viral in the blogosphere. Everything else remains identical across all our articles.

The article you’re reading now subsequently focuses on the third category: Content that needs to be updated at runtime.

Color Browser

Imagine we’re building a simple color browser: A little widget to explore a pre-defined set of named colors, presented as a list that pairs a color swatch with the corresponding color value. Users should be able to search colors names and toggle between hexadecimal color codes and Red, Blue, and Green (RGB) triplets. We can create an inert skeleton with just a little bit of HTML and CSS:

See the Pen Color Browser (inert) [forked] by FND.

Client-Side Rendering

We’ve grudgingly decided to employ client-side rendering for the interactive version. For our purposes here, it doesn’t matter whether this widget constitutes a complete application or merely a self-contained island embedded within an otherwise static or server-generated HTML document.

Given our predilection for vanilla JavaScript (cf. first principles and all), we start with the browser’s built-in DOM APIs:

function renderPalette(colors) {
  let items = [];
  for(let color of colors) {
    let item = document.createElement("li");
    items.push(item);

    let value = color.hex;
    makeElement("input", {
      parent: item,
      type: "color",
      value
    });
    makeElement("span", {
      parent: item,
      text: color.name
    });
    makeElement("code", {
      parent: item,
      text: value
    });
  }

  let list = document.createElement("ul");
  list.append(...items);
  return list;
}
Note:
The above relies on a small utility function for more concise element creation:
function makeElement(tag, { parent, children, text, ...attribs }) {
  let el = document.createElement(tag);

  if(text) {
    el.textContent = text;
  }

  for(let [name, value] of Object.entries(attribs)) {
    el.setAttribute(name, value);
  }

  if(children) {
    el.append(...children);
  }

  parent?.appendChild(el);
  return el;
}
You might also have noticed a stylistic inconsistency: Within the items loop, newly created elements attach themselves to their container. Later on, we flip responsibilities, as the list container ingests child elements instead.

Voilà: renderPalette generates our list of colors. Let’s add a form for interactivity:

function renderControls() {
  return makeElement("form", {
    method: "dialog",
    children: [
      createField("search", "Search"),
      createField("checkbox", "RGB")
    ]
  });
}

The createField utility function encapsulates DOM structures required for input fields; it’s a little reusable markup component:

function createField(type, caption) {
  let children = [
    makeElement("span", { text: caption }),
    makeElement("input", { type })
  ];
  return makeElement("label", {
    children: type === "checkbox" ? children.reverse() : children
  });
}

Now, we just need to combine those pieces. Let’s wrap them in a custom element:

import { COLORS } from "./colors.js"; // an array of { name, hex, rgb } objects

customElements.define("color-browser", class ColorBrowser extends HTMLElement {
  colors = [...COLORS]; // local copy

  connectedCallback() {
    this.append(
      renderControls(),
      renderPalette(this.colors)
    );
  }
});

Henceforth, a <color-browser> element anywhere in our HTML will generate the entire user interface right there. (I like to think of it as a macro expanding in place.) This implementation is somewhat declarative1, with DOM structures being created by composing a variety of straightforward markup generators, clearly delineated components, if you will.

1 The most useful explanation of the differences between declarative and imperative programming I’ve come across focuses on readers. Unfortunately, that particular source escapes me, so I’m paraphrasing here: Declarative code portrays the what while imperative code describes the how. One consequence is that imperative code requires cognitive effort to sequentially step through the code’s instructions and build up a mental model of the respective result.

Interactivity

At this point, we’re merely recreating our inert skeleton; there’s no actual interactivity yet. Event handlers to the rescue:

class ColorBrowser extends HTMLElement {
  colors = [...COLORS];
  query = null;
  rgb = false;

  connectedCallback() {
    this.append(renderControls(), renderPalette(this.colors));
    this.addEventListener("input", this);
    this.addEventListener("change", this);
  }

  handleEvent(ev) {
    let el = ev.target;
    switch(ev.type) {
    case "change":
      if(el.type === "checkbox") {
        this.rgb = el.checked;
      }
      break;
    case "input":
      if(el.type === "search") {
        this.query = el.value.toLowerCase();
      }
      break;
    }
  }
}
Note:
handleEvent means we don’t have to worry about function binding. It also comes with various advantages. Other patterns are available.

Whenever a field changes, we update the corresponding instance variable (sometimes called one-way data binding). Alas, changing this internal state2 is not reflected anywhere in the UI so far.

2 In your browser’s developer console, check document.querySelector("color-browser").query after entering a search term.

Note that this event handler is tightly coupled to renderControls internals because it expects a checkbox and search field, respectively. Thus, any corresponding changes to renderControls — perhaps switching to radio buttons for color representations — now need to take into account this other piece of code: action at a distance! Expanding this component’s contract to include field names could alleviate those concerns.

We’re now faced with a choice between:

  1. Reaching into our previously created DOM to modify it, or
  2. Recreating it while incorporating a new state.
Rerendering

Since we’ve already defined our markup composition in one place, let’s start with the second option. We’ll simply rerun our markup generators, feeding them the current state.

class ColorBrowser extends HTMLElement {
  // [previous details omitted]

  connectedCallback() {
    this.#render();
    this.addEventListener("input", this);
    this.addEventListener("change", this);
  }

  handleEvent(ev) {
    // [previous details omitted]
    this.#render();
  }

  #render() {
    this.replaceChildren();
    this.append(renderControls(), renderPalette(this.colors));
  }
}

We’ve moved all rendering logic into a dedicated method3, which we invoke not just once on startup but whenever the state changes.

3 You might want to avoid private properties, especially if others might conceivably build upon your implementation.

Next, we can turn colors into a getter to only return entries matching the corresponding state, i.e. the user’s search query:

class ColorBrowser extends HTMLElement {
  query = null;
  rgb = false;

  // [previous details omitted]

  get colors() {
    let { query } = this;
    if(!query) {
      return [...COLORS];
    }

    return COLORS.filter(color => color.name.toLowerCase().includes(query));
  }
}
Note:
I’m partial to the bouncer pattern.
Toggling color representations is left as an exercise for the reader. You might pass this.rgb into renderPalette and then populate <code> with either color.hex or color.rgb, perhaps employing this utility:
function formatRGB(value) {
  return value.split(",").
    map(num => num.toString().padStart(3, " ")).
    join(", ");
}

This now produces interesting (annoying, really) behavior:

See the Pen Color Browser (defective) [forked] by FND.

Entering a query seems impossible as the input field loses focus after a change takes place, leaving the input field empty. However, entering an uncommon character (e.g. “v”) makes it clear that something is happening: The list of colors does indeed change.

The reason is that our current do-it-yourself (DIY) approach is quite crude: #render erases and recreates the DOM wholesale with each change. Discarding existing DOM nodes also resets the corresponding state, including form fields’ value, focus, and scroll position. That’s no good!

Incremental Rendering

The previous section’s data-driven UI seemed like a nice idea: Markup structures are defined once and re-rendered at will, based on a data model cleanly representing the current state. Yet our component’s explicit state is clearly insufficient; we need to reconcile it with the browser’s implicit state while re-rendering.

Sure, we might attempt to make that implicit state explicit and incorporate it into our data model, like including a field’s value or checked properties. But that still leaves many things unaccounted for, including focus management, scroll position, and myriad details we probably haven’t even thought of (frequently, that means accessibility features). Before long, we’re effectively recreating the browser!

We might instead try to identify which parts of the UI need updating and leave the rest of the DOM untouched. Unfortunately, that’s far from trivial, which is where libraries like React came into play more than a decade ago: On the surface, they provided a more declarative way to define DOM structures4 (while also encouraging componentized composition, establishing a single source of truth for each individual UI pattern). Under the hood, such libraries introduced mechanisms5 to provide granular, incremental DOM updates instead of recreating DOM trees from scratch — both to avoid state conflicts and to improve performance6.

4 In this context, that essentially means writing something that looks like HTML, which, depending on your belief system, is either essential or revolting. The state of HTML templating was somewhat dire back then and remains subpar in some environments.
5 Nolan Lawson’s “Let’s learn how modern JavaScript frameworks work by building one” provides plenty of valuable insights on that topic. For even more details, lit-html’s developer documentation is worth studying.
6 We’ve since learned that some of those mechanisms are actually ruinously expensive.

The bottom line: If we want to encapsulate markup definitions and then derive our UI from a variable data model, we kinda have to rely on a third-party library for reconciliation.

Actus Imperatus

At the other end of the spectrum, we might opt for surgical modifications. If we know what to target, our application code can reach into the DOM and modify only those parts that need updating.

Regrettably, though, that approach typically leads to calamitously tight coupling, with interrelated logic being spread all over the application while targeted routines inevitably violate components’ encapsulation. Things become even more complicated when we consider increasingly complex UI permutations (think edge cases, error reporting, and so on). Those are the very issues that the aforementioned libraries had hoped to eradicate.

In our color browser’s case, that would mean finding and hiding color entries that do not match the query, not to mention replacing the list with a substitute message if no matching entries remain. We’d also have to swap color representations in place. You can probably imagine how the resulting code would end up dissolving any separation of concerns, messing with elements that originally belonged exclusively to renderPalette.

class ColorBrowser extends HTMLElement {
  // [previous details omitted]

  handleEvent(ev) {
    // [previous details omitted]

    for(let item of this.#list.children) {
      item.hidden = !item.textContent.toLowerCase().includes(this.query);
    }
    if(this.#list.children.filter(el => !el.hidden).length === 0) {
      // inject substitute message
    }
  }

  #render() {
    // [previous details omitted]

    this.#list = renderPalette(this.colors);
  }
}

As a once wise man once said: That’s too much knowledge!

Things get even more perilous with form fields: Not only might we have to update a field’s specific state, but we would also need to know where to inject error messages. While reaching into renderPalette was bad enough, here we would have to pierce several layers: createField is a generic utility used by renderControls, which in turn is invoked by our top-level ColorBrowser.

If things get hairy even in this minimal example, imagine having a more complex application with even more layers and indirections. Keeping on top of all those interconnections becomes all but impossible. Such systems commonly devolve into a big ball of mud where nobody dares change anything for fear of inadvertently breaking stuff.

Conclusion

There appears to be a glaring omission in standardized browser APIs. Our preference for dependency-free vanilla JavaScript solutions is thwarted by the need to non-destructively update existing DOM structures. That’s assuming we value a declarative approach with inviolable encapsulation, otherwise known as “Modern Software Engineering: The Good Parts.”

As it currently stands, my personal opinion is that a small library like lit-html or Preact is often warranted, particularly when employed with replaceability in mind: A standardized API might still happen! Either way, adequate libraries have a light footprint and don’t typically present much of an encumbrance to end users, especially when combined with progressive enhancement.

I don’t wanna leave you hanging, though, so I’ve tricked our vanilla JavaScript implementation to mostly do what we expect it to:

See the Pen Color Browser [forked] by FND.

Code Review That Matters: Tips and Best Practices

First of all, what’s a code review? Basically, it’s a review of written code performed by other team members. The result of the code review is feedback on the completed task: change requests and comments or green light for further testing and release.

Even though the task itself seems pretty straightforward, there are many things to take into account and a number of different ways of performing code review, and there is no unified guide that would work for every company or project.

An Introduction to DDL, DML, and DCL Commands in MySQL: A Comprehensive Guide With Examples

MySQL is widely recognized as one of the most popular open-source relational database management systems. It holds immense significance in the realm of web development, data analytics, and beyond. Its adaptability and user-friendly nature have positioned it as the preferred choice for managing structured data. 

MySQL commands are classified into various types, primarily based on their purpose within the database. These types encompass Data Definition Language (DDL), Data Manipulation Language (DML), and Data Control Language (DCL). A comprehensive understanding of these commands and their practical applications is essential for individuals involved in MySQL database operations. This article delves into each category, offering precise definitions and illustrative examples to enhance comprehension.

Automation Testing on Cloud: Flexible, Scalable, Powerful

Cloud technologies have taken the world by storm, allowing people to save their resources and time significantly for computing needs. They eliminate the need to spend money, time, and effort on setting up and maintaining a physical infrastructure. As a result, most development companies are shifting to cloud technologies to improve their overall.

This rapid increase in the shift to cloud technologies has stimulated the adoption of automation testing on the cloud. It refers to utilizing cloud computing environments to test software solutions and their individual components for the intended functionality. 

How to Create Custom WordPress Layouts With Elementor

Do you want to create your own custom page layouts in WordPress?

Elementor is a drag-and-drop WordPress page builder that allows you to easily design custom WordPress layouts without having any coding knowledge.

In this article, we will show you how to easily create custom WordPress layouts with Elementor with just a few clicks.

How to create custom WordPress layouts with Elementor

Why and When Do You Need Custom WordPress Layouts?

Many free and premium WordPress themes come with multiple layout choices for different kinds of pages. However, sometimes, none of these layouts will meet your requirements.

If you know how to code in PHP, HTML, and CSS, then you can create your own page templates or even build a child theme for your site. However, the majority of WordPress users are not developers, so this option doesn’t work for them.

Wouldn’t it be great if you could just design page layouts using a drag-and-drop interface?

This is exactly what Elementor does. It is a drag-and-drop WordPress page builder plugin that allows you to easily create your own custom WordPress layouts without any coding skills.

It has an intuitive user interface that lets you build custom layouts with a live preview. It comes with many ready-to-use modules for all kinds of web design elements.

Elementor has several professionally designed templates that you can instantly load and use as a starting point. It works with all standard-compliant WordPress themes and is compatible with all popular WordPress plugins.

Having said that, let’s take a look at how to create custom WordPress layouts with Elementor.

Getting Started With Elementor

First, you will need to purchase the Elementor Pro plugin. It is the paid version of the free Elementor plugin and gives you access to additional features and 1 year of support.

Next, you will need to install and activate the Elementor plugin. For more details, see our step-by-step guide on how to install a WordPress plugin.

Upon activation, you must visit the Elementor » Settings page to configure the plugin settings.

Enable Elementor for different posts

Here, you can enable Elementor for different post types. By default, it is enabled for your WordPress posts and pages. If you have custom post types on your site, then those will also appear here, and you can enable them as well.

You can exclude or include user roles that can use Elementor when writing posts or pages. By default, the page builder is enabled only for administrators.

Then, don’t forget to click on the ‘Save changes’ button to store your settings.

Creating Custom WordPress Layouts With Elementor

First, you need to create a new page or post on your WordPress site. On the post editing screen, you will notice the new ‘Edit with Elementor’ button.

Edit with Elementor

Clicking on it will launch the Elementor user interface, where you can edit your page using Elementor’s drag-and-drop page builder.

You can add sections and build your page from scratch, or you can pick a template.

Edit a page with Elementor

Templates give you a quick and easy way to get started. Elementor comes with several professionally designed templates that you can customize as much as you want.

Let’s start with a template by clicking on the ‘Add Template’ button.

This will bring up a popup where you will be able to see the different templates that are available. You should look for a template that is similar to what you want for your page layout.

In our example, we are looking at 404 page templates.

Select a template in Elementor

Now, you need to click to select the template you like and then click on the ‘Insert’ button to add it to your page.

Elementor will now load the template for you.

You can now start editing the template to match your needs. Simply point and click on any element to select it, and Elementor will show you its settings in the left column.

Point any element and edit it

How Elementor Layouts Work

Now, let’s talk about how Elementor layouts work.

Elementor layouts are built using sections, columns, and widgets. Sections are like rows or blocks that you place on your page.

Each section can have multiple columns, and each section and column can have its own styles, colors, content, and so on.

You can add anything in your columns and sections using Elementor widgets. These widgets are different kinds of content blocks that you can place in your Elementor sections.

Simply select a widget and drop it into your section or column. There is an extensive set of widgets available that cover all the popular web design elements that you can think of.

Add blocks to the layout

You can add images, text, headings, image galleries, videos, maps, icons, testimonials, sliders, carousels, and so much more.

You can also add default WordPress widgets and even the widgets created by other WordPress plugins on your site. For example, if you are using WPForms to create different forms for your site, then you can use its widget in Elementor.

Once you are done editing, you can click on the arrow next to the ‘Publish’ button to view different save options.

Click the save options

Note: Saving a page layout will not publish the page on your WordPress site, but it will save it.

You can now preview your page or go to the WordPress dashboard.

This will bring you back to the WordPress post editor. You can now save your WordPress page or publish it on your website.

Update or publish page edited with Elementor

Creating Your Own Templates in Elementor

Elementor allows you to save your own custom layouts as templates. This way, you can reuse your own templates to create new pages even faster in the future.

Simply edit the page you would like to save as a template with Elementor.

In the Elementor builder interface, click on the arrow next to the ‘Publish’ button. You will now see more options to save your post. Simply click the ‘Save as Template’ option.

Save as template option in Elementor

This will bring up a popup where you need to provide a name for your template.

After entering the name, click the ‘Save’ button.

Save your page to library

Next time you are creating a custom page layout, you will be able to select it from the ‘My Templates’ tab.

All you have to do is click the ‘Insert’ button for your custom page layout.

View page layout in library

You can also export this template and use it on other WordPress sites using Elementor.

Simply click the 3 dots icon and then click the ‘Export’ option.

Export page layout template

From here, you can download the template onto your computer.

Elementor Alternatives for Creating Custom Layouts

Besides Elementor, there are other landing page and website builders that let you create custom layouts for your site.

Here are some of the best Elementor alternatives you can use:

  • SeedProd is the best drag-and-drop WordPress website builder that lets you create custom layouts for your landing pages. There are 300+ theme or landing page templates to choose from. SeedProd also offers tons of customization options and blocks to create stunning pages. For more details, you can see our complete SeedProd review.
  • Divi is a visual theme and page builder. It’s been in the industry for over 14 years and offers different features for creating WordPress layouts, including a layout library. There are lots of customization options in the visual builder, and you don’t have to edit any code.
  • Thrive Architect is a powerful and beginner-friendly page builder that you can use to create beautiful layouts. It comes with 352+ templates and many customization options. You can use its front-end visual builder to edit any element on the page. For more details, see our Thrive Architect review.
  • Beaver Builder is another popular drag-and-drop page builder for WordPress. It is easy to use, and you can easily set up layouts for pages and posts using Beaver Builder. It also offers pre-built templates for landing pages, but there are not as many as with SeedProd or Divi.

We hope this article helped you learn how to create custom WordPress layouts with Elementor. You may also want to see our expert comparison of Elementor vs. Divi vs. SeedProd and our picks for the best web design software.

If you liked this article, then please subscribe to our YouTube Channel for WordPress video tutorials. You can also find us on Twitter and Facebook.

The post How to Create Custom WordPress Layouts With Elementor first appeared on WPBeginner.

Spring Strategy Pattern Example

In this example, we'll learn about the Strategy pattern in Spring. We'll cover different ways to inject strategies, starting from a simple list-based approach to a more efficient map-based method. To illustrate the concept, we'll use the three Unforgivable curses from the Harry Potter series — Avada Kedavra, Crucio, and Imperio.

What Is the Strategy Pattern?

The Strategy Pattern is a design principle that allows you to switch between different algorithms or behaviors at runtime. It helps make your code flexible and adaptable by allowing you to plug in different strategies without changing the core logic of your application.

Breaking Barriers: The Rise of Synthetic Data in Machine Learning and AI

In the evergrowing realm of Artificial Intelligence (AI) and Machine Learning (ML), the existing methods to acquire and utilize data are undergoing a significant transformation. As the demand for more optimized and sophisticated algorithms continues to rise, the need for high-quality datasets to train the AI/ML modules also keeps increasing. However, using real-world data to train comes with its complexities, such as privacy and regulatory concerns and the limitations of available datasets. These limitations have paved the way for a counter approach: synthetic data generation. This article navigates through this groundbreaking paradigm shift as the popularity and demand for synthetic data keep growing exponentially, exhibiting great potential in reshaping the future of intelligent technologies.

The Need for Synthetic Data Generation

The need for synthetic data in AI and ML stems from several challenges associated with real-world data. For instance, obtaining large and diverse datasets to train the intelligent machine is a formidable task, especially for industries where data is limited or subjected to privacy and regulatory restrictions. Synthetic data helps generate artificial datasets that replicate the characteristics of the original dataset.

The Cost Crisis in Observability Tooling

The cost of services is on everybody’s mind right now, with interest rates rising, economic growth slowing, and organizational budgets increasingly feeling the pinch. But I hear a special edge in people’s voices when it comes to their observability bill, and I don’t think it’s just about the cost of goods sold. I think it’s because people are beginning to correctly intuit that the value they get out of their tooling has become radically decoupled from the price they are paying. 

In the happiest cases, the price you pay for your tools is “merely” rising at a rate several times faster than the value you get out of them. But that’s actually the best-case scenario. For an alarming number of people, the value they get actually decreases as their bill goes up.

Common Cybersecurity Threats and How To Protect Yourself

Cybersecurity threats are acts performed by people with hurtful expectations, whose objective is to take information, do harm or disrupt computing systems. Normal classes of cyber threats include malware, social engineering, man-in-the-middle (MitM) attacks, denial of service (DoS), and injection attacks — we portray every one of these categories in more detail below.

In the interconnected universe of today, understanding normal cybersecurity threats is fundamental for defending your computerized presence. Dangers, for example, phishing, malware, and ransomware, continually advance, requiring proactive measures for protection.

Extract Tabular Data from PDF Images using Hugging Face Table Transformer

In a previous article, I explained how to extract tabular data from PDF image documents using Multimodal Google Gemini Pro. However, there are a couple of disadvantages with Google Gemini Pro. First, Google Gemini Pro is not free, and second, it needs complex prompt engineering to retrieve table, columns, and row pixel coordinates.

To solve the problems above, in this article, you will see how to extract tables from PDF image documents using Microsoft's Table Transformer from the Hugging Face library. You will see how to detect tables, rows, and columns within a table, extract cell values from tables using an OCR, and save the table as CSV. So, let's begin without ado.

Installing and Importing Required Libraries

The first step is to install various libraries you will need to run scripts in this article.

!pip install transformers
!sudo apt install tesseract-ocr
!pip install pytesseract
!pip install easyocr
!sudo apt-get install -y poppler-utils
!pip install pdf2image
!wget "https://fonts.google.com/download?family=Roboto" -O roboto.zip
!unzip roboto.zip -d ./roboto

The following script imports the required libraries into your application.


from transformers import AutoImageProcessor, TableTransformerForObjectDetection
import torch
from PIL import Image, ImageDraw, ImageFont
import matplotlib.pyplot as plt
import csv
import numpy as np
import pandas as pd
from pdf2image import convert_from_path
from tqdm.auto import tqdm
import pytesseract
import easyocr

Table Detection with Table Transformer

The Table Transformer has two sub-models: table-transformer-detection, and table-structure-recognition-v1.1-all model. As a first step, we will detect tables within a PDF document using the table-transformer-detection model.

Importing and Converting PDF to Image

The following script defines the pdf_to_img() function that converts PDF documents to bytes images. This step is mandatory since the Table transformer expects documents in image format.

# convert PDF to Image
def pdf_to_img(image_path):

  image = convert_from_path(pdf_path)[0].convert("RGB")
  return image

pdf_path = '/content/sample_input_ieee-10.pdf'
image = pdf_to_img(pdf_path)
image

Output:

image1.png

The above output shows the input image. We will detect tables inside this image.

Detecting Tables

The following script imports the preprocessor and model objects for the table-transformer-detection model. The preprocessor converts the input image to a format the table-transformer-detection model can process.


model_name = "microsoft/table-transformer-detection"
# define image preprocessor for table transformer
image_processor = AutoImageProcessor.from_pretrained(model_name)

# import table transformer model for table detection
model = TableTransformerForObjectDetection.from_pretrained(model_name,
                                                           revision="no_timm")

Next, we define the detect_table() function that accepts the input image as a parameter. The method preprocesses the image and then passes it to the table-transformer-detection model.

The preprocesses objects post_process_object_detection() method processes the output from the table-transformer-detection model. The final processed output consists of the label, bounding box coordinates, and the prediction confidence score for the detected tables. The detect_table() function returns the final output.


def detect_table(image_doc):

  # preproces image document
  inputs = image_processor(images = image_doc, return_tensors="pt")

  # detect tables
  outputs = model(**inputs)

  # convert outputs (bounding boxes and class logits) to Pascal VOC format (xmin, ymin, xmax, ymax)
  target_sizes = torch.tensor([image_doc.size[::-1]])
  results = image_processor.post_process_object_detection(outputs,
                                                          threshold=0.9,
                                                          target_sizes=target_sizes)[0]

  return results


results = detect_table(image)
results

Output:


{'scores': tensor([0.9993, 0.9996], grad_fn=<IndexBackward0>),
 'labels': tensor([0, 0]),
 'boxes': tensor([[ 111.4175,  232.4397, 1481.5710,  606.8784],
         [ 110.4231,  738.1602, 1471.6283,  916.2267]],
        grad_fn=<IndexBackward0>)}

The above output shows the confidence score, labels (0 for table), and bounding box coordinates for the two detected tables.

Next, we define the get_table_bbox() function, which prints the labels, confidence scores, and bounding box coordinates for the detected tables. The function also returns the detected bounding box coordinates for all the tables.


def get_table_bbox(results):

  tables_coordinates = []

  # iterate through all the detected table data
  for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
    box = [round(i, 2) for i in box.tolist()]

    # store bbox coodinates in Pascal VOC format for later use
    table_dict = {"xmin" : box[0],
                  "ymin" : box[1],
                  "xmax" : box[2],
                  "ymax" : box[3]}

    tables_coordinates.append(table_dict)

    # print prediction label, prediction confidence score, and bbox values
    print(
        f"Detected {model.config.id2label[label.item()]} with confidence "
        f"{round(score.item(), 3)} at location {box}"
        )

  return tables_coordinates

table_bbox = get_table_bbox(results)

Output:


Detected table with confidence 0.999 at location [69.43, 344.96, 660.61, 488.47]
Detected table with confidence 0.989 at location [68.7, 549.5, 657.53, 838.82]
Display Tables

Finally, the script below plots the original image and draws red rectangles around the detected tables using their bounding box coordinates.


def highlight_tables(image, table_bbox, padding):
    # Create a drawing context for doc image
    doc_image = image.copy()
    draw = ImageDraw.Draw(doc_image)

    # Iterate over each table in the list
    for table in table_bbox:
        # Define the coordinates for the rectangle with padding for each table
        rectangle_coords = (table["xmin"] - padding,
                            table["ymin"] - padding,
                            table["xmax"] + padding,
                            table["ymax"] + padding)

        # Draw a red rectangle around the detected table
        draw.rectangle(rectangle_coords, outline="red", width=2)

    return doc_image

padding = 10
table_detected_image = highlight_tables(image, table_bbox, padding)
table_detected_image

Output:

image2.png

You can see the detected tables in the above image.

Subsequently, we define the get_cropped_image() function that accepts the original image, the corresponding bounding box coordinates, and padding values as parameters. The get_cropped_image() function returns the cropped table, which you can use to extract rows and columns.

def get_cropped_image(image, table, padding):
  # Create a new image object with the cropped area
  cropped_image = image.copy().crop((table["xmin"] -padding,
                             table["ymin"] - padding,
                             table["xmax"] + padding,
                             table["ymax"] + padding
                             ))

  return cropped_image

cropped_image = get_cropped_image(image, table_bbox[1], padding)
cropped_image

Output:

image3.png

Extract Table data

Now that we have cropped a table, we can extract rows and columns.

Extract Table Features

You can extract table rows and columns using the table-structure-recognition-v1.1-all model. The following script imports this model.


# import model for detecting table features e.g. rows, columns, etc
structure_model = TableTransformerForObjectDetection.from_pretrained("microsoft/table-structure-recognition-v1.1-all")

We define the get_table_features() function that accepts the cropped table image as a parameter and returns the labels, confidence scores, and the bounding box coordinates for the detected rows and columns. The function also prints these values.


def get_table_features(cropped_image):

  # preprocess image input for table transformer
  inputs = image_processor(images = cropped_image, return_tensors="pt")

  # make prediction using table transformer
  outputs = structure_model(**inputs)

  # post process output to Pasval VOC bbox format
  target_sizes = torch.tensor([cropped_image.size[::-1]])
  results = image_processor.post_process_object_detection(outputs, threshold=0.9, target_sizes=target_sizes)[0]

  # define a list to store detected features
  features = []

  # iterate through all the detected features and store feature label, confidence score, and bbox values to cells list
  for i, (score, label, box) in enumerate(zip(results["scores"], results["labels"], results["boxes"])):
      box = [round(i, 2) for i in box.tolist()]
      score = score.item()
      label = structure_model.config.id2label[label.item()]

      cell_dict = {"label":label,
                  "score":score,
                  "bbox":box
                  }


      # print table features
      features.append(cell_dict)
      print(
          f"Detected {label} with confidence "
          f"{round(score, 3)} at location {box}"
      )

  return outputs


features = get_table_features(cropped_image)

Output:

image4.png

Display Detected features

Next, we define the display_detected_features() function that draws rectangles around detected rows and columns.


def display_detected_features(cropped_image, features):

  cropped_table_visualized = cropped_image.copy()
  draw = ImageDraw.Draw(cropped_table_visualized)

  # increase font size for text labels
  font = ImageFont.truetype("/content/roboto/Roboto-Bold.ttf", 15)

  # iterate through all features and display bounding box with text labels
  for feature in features:
      draw.rectangle(feature["bbox"], outline="red")

      text_position = (feature["bbox"][0], feature["bbox"][1] - 3)

      draw.text(text_position, feature["label"], fill="blue", font = font)

  # return cropped image with bounding box
  return cropped_table_visualized

display_detected_features(cropped_image, features)

Output:

image5.png

Extract Cell Text Using OCR and Convert to CSV

In the final step, we will detect cell text and convert the detected table to CSV format.

Extract Cells Coordinates

We define the get_cell_coordinates_by_row() function that iterates through the detected rows and extracts column values for each row. The function returns a list of rows where each row contains cell values for all the columns.

def get_cell_coordinates_by_row(table_data):
    # Extract rows and columns
    rows = [entry for entry in table_data if entry['label'] == 'table row']
    columns = [entry for entry in table_data if entry['label'] == 'table column']

    # Sort rows and columns by their Y and X coordinates, respectively
    rows.sort(key=lambda x: x['bbox'][1])
    columns.sort(key=lambda x: x['bbox'][0])

    # Function to find cell coordinates
    def find_cell_coordinates(row, column):
        cell_bbox = [column['bbox'][0], row['bbox'][1], column['bbox'][2], row['bbox'][3]]
        return cell_bbox

    # Generate cell coordinates and count cells in each row
    cell_coordinates = []

    for row in rows:
        row_cells = []
        for column in columns:
            cell_bbox = find_cell_coordinates(row, column)
            row_cells.append({'cell': cell_bbox})

        # Append row information to cell_coordinates
        cell_coordinates.append({'cells': row_cells, 'cell_count': len(row_cells)})


    return cell_coordinates

cell_coordinates = get_cell_coordinates_by_row(features)
Extract Text from Cell Coordinates using OCR

Finally, we define the apply_ocr() function that iterates through all the rows and then applies the PyTesseract OCR to extract cell values for all the columns in a row. The function returns a dictionary where each dictionary value is a list of items corresponding to row cell values from the input table, as you can see in the output of the following script.


def apply_ocr(cell_coordinates, cropped_image):
    # let's OCR row by row
    data = dict()
    max_num_columns = 0
    for idx, row in enumerate(tqdm(cell_coordinates)):
        row_text = []
        for cell in row["cells"]:
            # crop cell out of image
            cell_image = np.array(cropped_image.crop(cell["cell"]))

            # apply OCR using PyTesseract
            text = pytesseract.image_to_string(cell_image, lang='eng', config='--psm 6').strip()
            if text:
                row_text.append(text)


        if len(row_text) > max_num_columns:
            max_num_columns = len(row_text)

        data[idx] = row_text

    print("Max number of columns:", max_num_columns)

    # pad rows which don't have max_num_columns elements
    for row, row_data in data.copy().items():
        if len(row_data) != max_num_columns:
            row_data = row_data + ["" for _ in range(max_num_columns - len(row_data))]
        data[row] = row_data
        print(row_data)

    return data

data = apply_ocr(cell_coordinates, cropped_image)

Output:

image6.png

As a last step, we iterate through the table rows data dictionary and write the row values line by line to a CSV file using the csv.writer() method.


def write_csv(data):

  with open('output.csv','w') as result_file:
      wr = csv.writer(result_file, dialect='excel')
      for row, row_text in data.items():

        wr.writerow(row_text)

write_csv(data)

df = pd.read_csv("output.csv")
df

Output:

image7.png

The above output shows the Pandas dataframe containing the data from the generated CSV file.

I hope you liked this tutorial. Feel free to leave your feedback or comments.

Orchestrating dbt Workflows: The Duel of Apache Airflow and AWS Step Functions

Think of data pipeline orchestration as the backstage crew of a theater, ensuring every scene flows seamlessly into the next. In the data world, tools like Apache Airflow and AWS Step Functions are the unsung heroes that keep the show running smoothly, especially when you're working with dbt (data build tool) to whip your data into shape and ensure that the right data is available at the right time. Both tools are often used alongside dbt (data build tool), which has emerged as a powerful tool for transforming data in a warehouse. 

In this article, we will introduce dbt, Apache Airflow, and AWS Step Functions and then delve into the pros and cons of using Apache Airflow and AWS Step Functions for data pipeline orchestration involving dbt. A note that dbt has a paid version of dbt cloud and a free open source version; we are focussing on dbt-core, the free version of dbt.

Flexible Data Generation With Datafaker Gen

Introduction to Datafaker

Datafaker is a modern framework that enables JVM programmers to efficiently generate fake data for their projects using over 200 data providers allowing for quick setup and usage. Custom providers could be written when you need some domain-specific data. In addition to providers, the generated data can be exported to popular formats like CSV, JSON, SQL, XML, and YAML.

For a good introduction to the basic features, see "Datafaker: An Alternative to Using Production Data."

Securing the Digital Frontline: Cybersecurity Trends and Best Practices in Networking

In the fast-paced digital landscape, where connectivity is paramount, the need for robust cybersecurity measures in networking has never been more critical. This article delves into the latest trends and best practices in cybersecurity, aiming to provide insights into how organizations can fortify their networks against the ever-evolving array of cyber threats.                               

Evolution of Cyber Threats

As technology advances, so do the tactics employed by cybercriminals. Understanding the evolution of cyber threats is essential for designing effective cybersecurity strategies.

Sophisticated Malware and Ransomware

The proliferation of sophisticated malware and ransomware attacks poses a significant threat to networks. Cybercriminals continuously refine their techniques, making it imperative for organizations to deploy advanced threat detection and prevention mechanisms.

Most Popular Telegraf Input Plugins and Integrations With InfluxDB

Telegraf is an open-source server agent designed for collecting, processing, aggregating, and writing metrics. Developed by InfluxData, it is part of the InfluxDB time series database platform. Known for its simplicity and ease of use, Telegraf offers a plug-and-play architecture with an array of input, output, and processor plugins. This flexibility allows Telegraf to seamlessly gather metrics from a diverse set of sources and write them into InfluxDB, serving as a vital component in monitoring and observability stacks.

One of Telegraf's strengths is its ability to integrate with a wide range of tools and services, enhancing the capabilities of InfluxDB. It supports various data formats and network protocols, enabling integrations with common systems like databases, message queues, and web services. Some notable integrations include popular databases like MySQL, PostgreSQL, and MongoDB, messaging systems like Kafka and MQTT, and cloud services from providers such as AWS, Google Cloud, and Microsoft Azure. Additionally, Telegraf can collect data from various sources like sensors, IoT devices, and virtual systems and applications, making it a versatile tool for comprehensive monitoring solutions in diverse IT environments. This post covers the top types of Telegraf input plugins.