chrisgrieser5k downloadsQualitative Data Analysis (QDA) for social scientists. An open alternative to MAXQDA and atlas.ti, using Markdown to store data and research codes.
Qualitative Data analysis Realized in Obsidian
Quadro is an Obsidian plugin for social-scientific qualitative data analysis (QDA). It is an open alternative to MAXQDA and atlas.ti, using Markdown to store data and codes.
The plugin supports coding in the tradition of Grounded Theory, and data extraction following the principles of Qualitative Content Analysis (as outlined by Gläser and Laudel).
This plugin utilizes the rich text-processing capabilities of Obsidian to provide a lightweight application for qualitative data analysis.
All data is stored as Markdown files. Markdown is a human-readable, non-proprietary, and commonly used open standard for plain text files. This means:
Notepad.exe or
TextEdit.app.)MAXQDA or atlas.ti.Being an Obsidian plugin, the Qualitative Data Analysis is embedded in the extensive functionality and plugin ecosystem of Obsidian:
Google Docs.Obsidian is free to use for academic purposes, and Quadro is also free to use.
If there is a more tech-savvy researcher in the research team, the advantages of Quadro go even further:
git.In qualitative data analysis, "coding" is a form of fine-grained tagging of text segments, and "extraction" denotes the transforming of prose text into structured data.
Coding is implemented in Quadro via "bidirectional" links between Data Files and Code Files by inserting wikilinks in both files. (Obsidian itself does have backlinks, but those are unidirectional links, since the implicit backlink is only inferred and not stored anywhere in the Markdown file.).
It makes use of Obsidian's note-embedding functionality to keep track of coded text segments.
[[wikilinks]] instead of #tags, as the former
allows for more flexibility, such as having separate file per code.Extraction is implemented by creating separate Extract Files for each extraction, using YAML frontmatter to store the data in a structured form. Quadro uses a simplistic templating mechanism to support the creation of those Extraction Files.
Advantages
Disadvantages
**bold text** for
bold text.There is a pre-configured example vault to be used with Quadro. Apart from some preinstalled plugins for QDA, it includes some mock data with exemplary codes and extractions, and showcases of extraction capabilities, to demonstrate the capabilities of Quadro.
quadro-example-vault as an Obsidian vault.
(If you are new to Obsidian, see the Obsidian Documentation on how to do that.)If you are experienced with Obsidian, you can also directly install the plugin, though checking out the example vault is nonetheless helpful to get a grasp on the capabilities of Quadro.
It is recommended to create a separate vault for data analysis and install the plugin there, for several reasons:
Unfortunately, this is not supported. The main reason is that commercial QDA software uses proprietary formats, the exact reason why researchers should use research software utilizing open formats to begin with.
If your research data is saved in Markdown, Obsidian is able to import them though. Importing from various other note-taking apps like Notion, Evernote, OneNote, Google Keep, Apple Notes, Bear, or Roam is supported as well.
It is, however, possible to export the results done with Quadro, to collaborate with other researchers. You can either export individual files as PDF, or export aggregated results as CSV.
To work correctly, Quadro modifies some behavior of Obsidian core:
As mentioned before it is recommended to use a separate vault for data analysis with Quadro.
There are two basic types of files for the analysis, Data Files and Code Files, which are both stored as Markdown files.
Data Files
The empirical material as text files. They can be stored anywhere in the vault
as .md files. (A separate subfolder named Data is recommended though.) As
Quadro assigns codes to whole paragraphs, these data files should
be split up into smaller segments.
When a code is assigned, a link to the corresponding Code File and a unique ID are appended to the paragraph:
Filename: ./Data/Interview 1.md
Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint
consectetur cupidatat. [[MyCode]] ^id-240302-124012
Code Files
All Markdown files in the folder {vault-root}/Codes are considered code
files. (The folder is configurable.)
When a code is assigned, a link back to the original location in the Data File
is appended to the code file. The link has the format
[[{filename-datafile}#^{id-of-paragraph}]], with the id being a timestamp.
[^1]
Filepath: ./Codes/MyCode.md
![[Interview 1#^id-240302-124012]]
As the link is a so-called embedded link, Obsidian renders the respective paragraph of the Data File inside the Code File:

The underlying folder structure for coding looks like this:
.
├── 📂 Data
│ ├── 📄 Interview 1.md
│ ├── 📄 Field Notes 1.md
│ └── …
└── 📂 Coding
├── 📄 code 1.md
├── 📄 code 2.md
└── 📂 Group 1
├── 📄 code 3.md
├── 📄 code 4.md
└── …
[!NOTE] The main caveat of this approach is that the assignment of codes is mostly restricted to the paragraph level. Assigning codes to only segments of a paragraph is limited to adding highlights to the respective section. Assignment of codes to individual words and coded segments with overlap is not supported.
| Action | Description | Sidebar button | Default hotkey | Capability provider |
|---|---|---|---|---|
| Assign code | Assign a code to the current paragraph, any selected text is highlighted. (overlapping highlights not supported though). Select Create new code or press shift ⏎ to create a new code file and assign it to the paragraph. |
mod+shift+a |
Quadro | |
| Rename code | All references to the Code File are automatically updated. (You can also rename by right-clicking a file or link and selecting "Rename.") | Obsidian Built-in | ||
| Delete code from paragraph | Removes a code from the current paragraph of a Data File or Code File. The reference is also removed from the corresponding other file. | mod+shift+d |
Quadro | |
| Delete Code File and all references to it | Moves the Code File to the trash, and deletes all references to it. | — | Quadro | |
| Bulk-create new codes | Create multiple new codes at once (without assigning them to a paragraph). | — | Quadro | |
| Merge codes | Merge the current Code File into another Code File. All references from data files are updated to point to the merged file. | — | Quadro | |
| Code grouping | Codes can be arranged in subfolders via drag-and-drop in the File Explorer. | — | — | Obsidian Built-in |
| Show code overview | Creates an auto-updating overview of all codes in a nested list with code assignment counts. | — | Quadro | |
| Axial coding | Using the Canvas plugins, you can freely arrange entities on a board, and connect them via lines and arrows, suitable for Axial Coding. Further Documentation |
— | Obsidian Core Plugin: Canvas Obsidian Community Plugin: Semantic Canvas |
|
| Investigation of code co-occurrences | In the Obsidian Search, use a query such as line:([[MyCodeOne]] [[MyCodeTwo]]). Further Documentation |
— | mod+shift+f |
Obsidian Core Plugin: Search |
| Visualization of code relationships | In the Graph View, use a query like path:Codes OR path:Data, and assign Data and Codes to different groups. Further Documentation |
mod+g |
Obsidian Core Plugin: Graph View |
mod refers the ctrl on Windows and to cmd on macOS.Codes/Template.md, its frontmatter is used as template
for any newly created code.Quadro implements extraction following the principles of Qualitative Content Analysis as outlined by Gläser and Laudel.
Extraction is implemented similarly to coding, using two basic filetypes, Data Files and Extraction Files.
Data Files
The empirical material as text files. They can be stored anywhere in the vault
as .md files.
When making an extraction, a link to the corresponding Extraction File and a unique ID are appended to the paragraph, just like with coding:
Filename: ./Data/Interview 2.md
Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint
consectetur cupidatat. [[Career Visions/1]] ^id-240302-124012
Extraction Files Extraction is implemented via Markdown metadata (YAML frontmatter), which is supported via Obsidian Properties.
When making an extraction, you are presented with a choice of your extraction
types. Upon selection, a new file is created in the folder that groups
extractions, that is {vault-root}/Extractions/{Extraction Group}/. As
such, each file corresponds to a single extraction, with its parent folder
indicating what type of extraction it is.
You can then fill out the fields of newly created file. The
extraction-source key contains a link back to the paragraph in the Data File
where you initiated the extraction. In the rendered view, the file contains a
Properties header which can conveniently be filled out:

The underlying plaintext view of the file looks like this:
Filepath: ./Extractions/Career Visions/Career Visions 001.md
---
occupation: "painter"
career stage: "novice"
year of experience: 4
extraction-date: 2024-03-02T12:40:12
Extraction-source: "[[Field notes 3#^id-240302-124012]]"
---
**Paragraph extracted from:** ![[Field Notes 3#^id-240302-124012]]
Extraction Templates (Extraction Types)
The available extraction types are determined by the subfolders of
{vault-root}/Extractions/. The fields that are created for filling in
information are determined by the Template.md file located in that subfolder.
For the example above, the Extraction Template looks like this:
The corresponding template for the extraction type is located in the same
folder, but has the filename Template.md.
Filepath: ./Extractions/Career Visions/Template.md
---
occupation:
career stage:
Year of experience
---
All in all, the underlying folder structure for extractions looks like this:
.
├── 📂 Data
│ ├── 📄 Interview 1.md
│ ├── 📄 Field Notes 1.md
│ └── …
└── 📂 Extractions
├── 📂 Career Obstacles
│ ├── 📄 Template.md
│ ├── 📄 Career Obstacles 001.md
│ ├── 📄 Career Obstacles 002.md
│ └── …
└── 📂 Career Visions
├── 📄 Template.md
├── 📄 Career Visions 001.md
└── …
There are various Obsidian plugins that allow you to get a spreadsheet-like overview of all extractions.
The recommended one is the Obsidian Bases Plugin, due to its first-party support and extensive filtering, sorting, and aggregation features.
Please refer to the Obsidian Bases documentation for details.
| Action | Description | Sidebar button | Default hotkey | Capability provider |
|---|---|---|---|---|
| Extract from paragraph | Creates an Extraction File from Extraction Template. | mod+shift+e |
Quadro | |
| Add paragraph to last Extraction File | Adds a reference to the last modified Extraction file to the current paragraph. Useful when information is spread across to paragraphs. | mod+shift+l |
Quadro | |
| Merge extractions | Merge the current Extraction File into another Extraction File. All references from data files are updated to point to the merged file. | — | Quadro | |
| Create new extraction type | Creates a new Extraction Type (= a new subfolder in "Extractions," alongside a new Extraction Template). | — | Quadro | |
| Show Extraction type overview | Creates an auto-updating overview of an Extraction Type and their values. | — | Quadro | |
| Co-occurrent extraction dimensions | Find extractions where two dimensions have a specific value, by using a query such as ["cause of the issue": fragmentation] ["type of compatibility":backward] in the Obsidian Search. Further Documentation |
— | mod+shift+f |
Obsidian Core Plugin: Search |
| Rename dimension globally | Renaming a property field within a file only affects the property for that file. To rename a property globally, use the Command Palette (mod+p), and search for Properties View: Show all Properties. A list of properties pops up in the sidebar, where you can rename properties via right-click. |
— | — | Obsidian Core Plugin: Properties View |
Export all extractions as .csv |
All extractions for all extraction types are exported as .csv. |
— | Quadro | |
| Show theoretical saturation | Percentage of new extractions to all extraction activities. | — | Quadro (using Chart.js) |
mod refers the ctrl on Windows and to cmd on macOS..csv exports, the included properties are
determined by the properties of the template files (Template.md).Depending on methodological considerations, it can make sense to analyze Data files in random order.
| Action | Description | Sidebar button | Default hotkey |
|---|---|---|---|
| Open random unread Data File | Open a random file in the vault that has the property read set to false |
mod+shift+n |
Quadro also offers some basic progress tracking capabilities. Most coding and
extraction actions are counted in a JSON file progress.json. Furthermore, the
command Mark current Data File as read also increments the count of read Data
Files in the progress.json file.
| Action | Description | Sidebar button | Default hotkey |
|---|---|---|---|
| Mark current Data File as read | Sets a property read for the current file to true and increments the progress.json. |
mod+shift+r |
|
| Show data analysis progress file | Reveals the progress.json file in the system explorer. |
The progress tracking is not only useful for accountability and planning, but also has methodological value. For instance, you could operationalize theoretical saturation for a coding-based investigation by examining the ratio of newly created codes to paragraphs being assigned to existing codes. Or you could investigate the theoretical saturation of an extraction-based project by looking at the ratio of newly created extractions to paragraphs only being assigned to existing extractions.
To remove or rearrange buttons, go to the Obsidian settings: Appearance →
Ribbon Menu → Manage.
Every hotkey can be customized by searching for the name of the respective
action in the Obsidian settings under Hotkeys.
The plugin behavior can be customized in the Quadro tab of the Obsidian
settings. Aside from folder locations, there are a few settings which change the
way codes and extractions are presented. Note that these are not technical or
personal decisions, but methodological decisions as they may change your
choice of codes and extraction values.
Settings → Community plugins → Check for updates → Update all.git clone "[email protected]:chrisgrieser/obsidian-quadro.git"
just init
just format # run all formatters
just build # builds the plugin
just check-all # runs the pre-commit hook (without committing)
[!NOTE] This repo uses a pre-commit hook, which prevents commits that do not pass all the checks.
Every single modal, prompt, settings-tab, or button added by this plugin has
the class .quadro, so theme designers can easily change the appearance of this
plugin.
If you have completed a research project with Quadro, feel free to reach out and let me know about it to include it here.
Thanks to Ryan Murphy who gave me the idea for this project with a blog post of his.
Please cite this software project as (APA):
Grieser, C. (2024). Quadro – Qualitative Data Analysis Realized in Obsidian [Computer software].
https://github.com/chrisgrieser/obsidian-qualitative-data-analysis
I am a sociologist studying the social mechanisms underlying the digital economy. For my PhD project, I investigate the governance of the app economy and how software ecosystems manage the tension between innovation and compatibility. If you are interested in this subject, feel free to get in touch.
For bug reports and features requests, please use the GitHub issue tracker.
If you find this project helpful, you can support me via 🩷 GitHub Sponsors.
[^1]: Note that the timestamp is assigned the first time the paragraph is assigned a code. The timestamp is not updated when the paragraph you remove the code or assign another code, since the paragraph ID needs to be immutable to ensure reliable references to it. Think of the timestamp as "first time the paragraph a code has been assigned".