blacksmithgu / obsidian-dataview

A data index and query language over Markdown files, for https://obsidian.md/.
https://blacksmithgu.github.io/obsidian-dataview/
MIT License
7.02k stars 412 forks source link

Links from dataview rendered in the graph view #63

Open EhuddR opened 3 years ago

EhuddR commented 3 years ago

Hi!

It is possible to make the list of elements displayed by the plugin to be recognized by Obsidian as output links? In other words, that they can be understood as links that are displayed in the note in which the query is executed [[Note A]] --> [[Element 1]]; [[Note A]] --> [[Element 2]].

I don't know, if it makes sense.

What I am looking for is that in the Graph View you can notice the links that the plugin organizes and generates.

Thanks in advance.

image

blacksmithgu commented 3 years ago

I have a potential hack for this, though doing it is somewhat annoying in general (I don't think I can add links directly to the Obsidian indices easily). Will investigate for next major release.

EhuddR commented 3 years ago

Thank you! It will be amazing if you can add that feature

thorlucas commented 3 years ago

Duplicate of #224

ngraham20 commented 3 years ago

While I realize this doesn't fit every use case, it fits nearly all of mine, so it might help some people.

Until this exciting feature is added, I've got a work around using the Templater plugin to auto-generate my links. I've tested it on Windows 10, Linux, and mobile, and it only works on the first two. Since it works on Linux, I would guess it works on MacOS too, though I can't say for sure.

https://gist.github.com/ngraham20/bb1528357bb692baacffc5fb3943c0a0

Essentially it just scrapes the file's current folder and generates links to all files in said folder. Hope it helps!

robertofgama commented 3 years ago

This will be a excelent adiction

veradrawer commented 3 years ago

Is there an ETA for this?

RazgrizSix commented 3 years ago

Just showing my support for this issue. Thanks for your hard work. This tool is incredibly useful.

blacksmithgu commented 3 years ago

To give some context on why this has not been implemented: it's difficult. I need two things for this to work:

  1. I have to pre-compute every query in the vault for links that it produces, and cache these somewhere.
  2. I have to have a way to inform the graph plugin of all of these extra relationships so it can render them.

The first one is a little scary performance wise, though it is probably doable; the second one I have no route forward on. The only remediation I can offer is work I am doing on "materializing" views, where it converts a query into plain markdown results, which WILL show up in the graph (since Obsidian will parse it). This should work as a stopgap for MOCs / other tables in the short term.

dleeftink commented 2 years ago

Re: materialising views, something akin to freezing MIDI tracks in Ableton Live might be worthwhile, e.g. bouncing the results in place and freezing the initial query/settings. This way, users could run a "refreeze" command that executes the query once more while updating the frozen results. This may prevent extensive recalculation, and would suit my use case where I would only need to update the graph once in a while (and might actually be preferable, as this also paves the way for modular writing approaches where frozen query results can be reviewed and edited in place as pure markdown, while the initial query still exists somewhere in a frozen codeblock, YAML field or elsewhere).

veradrawer commented 2 years ago

If graph rendering is to be have by default, I would like an approach that offers the non-indexation and vice versa. I suggest something in the lines of the existing WITHOUT ID. I.E: "WITHOUT INDEX".

blacksmithgu commented 2 years ago

Graph rendering would be default-off and opt-in on queries (since it would be super noisy otherwise); it would likely be WITH INDEX or INDEXED or be a different query type all-together.

rzfzr commented 2 years ago

@blacksmithgu

  1. I have to pre-compute every query in the vault for links that it produces, and cache these somewhere.

One of my needs of this feature is somewhat static, so what I'm currently doing is the following:

  1. I make the query
  2. copy the computed list and paste it on the same file
  3. manually add the brackets using multiple cursors (because the pasted links are external)
  4. then I hide the query in a folded h1.
  5. profit

Maybe there is no need for external caching, this process could be done programmatically, the end user don't even have to notice that when he finishes editing the query, that the rendered result is the just computed or just a copy of the computed. So the extension would run the query and copy it results to its place.

By having the computed result with the links right in the .md file, there is no need for adaptations to work with the graph view.

There could be a routine that goes though every single file and updates the query, this could be called manually, periodically, each time the vault is opened... in the future there could even be some clever watchers and triggers to not check all the files or something like it.

I don't know if I made myself clear, I'll gladly converse about it if needed.

Edit. reading the comments it seems that this is in line with what @dleeftink had in mind as well.

blacksmithgu commented 2 years ago

@rzfzr - this is the same option I would consider myself as well; the only annoying part is where to put the generated links and output in the general case if the plugin automatically does the generation. Do I just append them in a "## Generated Links" section at the bottom of the page?

rzfzr commented 2 years ago

That would work for me, but it could be inline as well. Either way I'm sure that this would have to be a togglable feature, as many people must have tons of queries that would make the graph view un-renderable... But instead of being global in the settings it could be an opt-in inside the code block, for instance, default as is now: image Lets say we add another triple-` descriptor like livelinks, that would inject the result of the query right below it while making its own block code not rendered, or rendered in one line just indicating that is a dataview: image I believe it would be an elegant solution as in the reader's view there wouldn't be any difference to notice.

The only possible problem I see when re-rendering the query as the user will be able to edit the 'live' results... So even with complex caching, it would be hard to know what was generated, in order to know what must be replaced.

There could be a second closing block/inline code to limit the generated space: image Let's say the user deletes the second block, we could warn him, not re-rendering until the block is placed, and once it's placed every line between these two is far game for replacing. image

I haven't messed with plugin development but I'm willing to get started, let's discuss some more though, there must be a better solution, the second block is not that elegant, what do you think?

rzfzr commented 2 years ago

@blacksmithgu or anybody else has any suggestions on the topic so that I could start implementing it?

yulqen commented 2 years ago

Keeping an eye on this as interested in any solution.

Olyve commented 2 years ago

Very interested in this, has there been any progress on this so far, beyond discussion?

blacksmithgu commented 2 years ago

Very interested in this, has there been any progress on this so far, beyond discussion?

See #42; the backup mechanism (which converts dataview queries into plain markdown isnide the page) will also provide graph discoverability.

MAWSpitau commented 2 years ago

I am just here to show support for this feature! That would be great to have!

tomasforsman commented 2 years ago

Adding my support as well.

One way of doing this would be to have query files that you can schedule that generates the result outside of the codeblock.

Example: queryexample.md

---
type: dataviewquery
---
TABLE WITHOUT ID
    file.link AS Note,
    filter(file.etags, (x) => !contains(x, "#idea")) AS "Tags"
    FROM #idea
    SORT file.mtime DESC

MyIdeas.md

---
type: MOC
---

´´´dataviewschedule
USE queryexample EVERY hour %% Executes every hour, on the hour %%
´´´
Variant:

´´´dataviewschedule
USE queryexample EVERY (day + (hour * 2)) %% Executes 2 AM every day %% 
´´´

´´´dataviewschedule
USE queryexample EVERY day * 2 %% Executes every other day from STARTING or from start of year %%
STARTING 2022-10-13
´´´

Result would be in the form of: %% scheduled-dataview-start: queryexample %% Generated code %% scheduled-dataview-end: queryexample %%

That way you can find the generated part and remove or update it.

USE queryexample AS "Example Query"

Would generate: %% scheduled-dataview-start: Example Query %%

Advantages of doing it this way would be: You can do any query you normally do without changing them. You can reuse the query as templates. You don't have to save any duplicate query. You can expand how you schedule without having to change the query. Would not produce noise.

Finally I want to say thanks for a wonderful and impressive plugin that has changed how we use Obsidian profoundly. <3

AB1908 commented 2 years ago

If anyone has seen the discussion on 42, this is halfway there since there are new markdown rendering methods. You could write your own plugin/templater script to already achieve this.

imevul commented 1 year ago

I've ended up in the same rabbit hole as everyone else it seems, trying to get the dataview results into the graph.

Here's a crude Templater javascript that I use to solve this for any dataview block. (Inspired from the stuff in 42)

Materialize Dataview.md

<% tp.user.materializeDataview(tp) %>

materializeDataview.js

/**
 * Take selected dataview and insert a comment with materialized data
 * @param tp
 */
async function materializeDataview(tp) {
    const editor = app.workspace.activeLeaf.view.editor;
    var delim = "%%\n";

    // Get current selection. Either entire dataview block, or just the dataview query (TABLE FROM ...)
    const selection = editor.getSelection();
    var query = selection;

    if (selection.startsWith('```dataview')) {
        query = selection.replace('```dataview', '').replace('```', '');
    } else {
        delim = '';
    }

    const dv = app.plugins.plugins["dataview"].api;
    const data = await dv.tryQueryMarkdown(query);

    // Replace selection with: selection + materialized data comment
    return selection + "\n" + delim + "materialized-dataview\n" + data + delim;
}

module.exports = materializeDataview;

Basically, just select an entire dataview block or just a dataview query and insert the template. The original selection will be left intact, but after it a comment block will be inserted containing the current markdown result. Feel free to use it if it helps. 😃

Was originally planning on making it easily refreshable using a button or something, but this is the point where my patience ran out. If you want to refresh the data, just manually delete the comment block and run it again.

darkwater4213 commented 1 year ago

Perhaps add an INDEX or MOC query type that actually generates links?

For instance, most physical folders in my vault have a MoC in them (with the same name as the folder they're in) and I usually have some dataview query in them for Easy Navigation™ but that means that the links don't show up in the Graph. I'm pretty glad to see that it's not just my use case that makes this a Good Thing™.

My contribution is that the INDEX query functions much like a LIST, but the linked notes are actually shown as links in the Graph View. Furthermore, notes with the metadata field index: true (or moc: true) are treated specially. Namely, each file should have a parent field (needn't contain only one parent); if a file's single parent is pointed at a file with index: true, that (child) file will be displayed under (as a child of) the index. Multiple parents and and non-index parents are ignored. The most important thing is that either parentage acts as a link to the index in the Graph view or INDEX queries produce actual links that show up in the graph view. Either one works, but I would imagine that the first is easier to implement.

obvionaoe commented 1 year ago

Hi, this would still be an extremely useful feature to have in Dataview, but since development for Datacore is already underway, is this something that could be implemented in Datacore from the get go? @blacksmithgu

Thanks for all your work in this amazing plugin

darkwater4213 commented 10 months ago

Re: materialising views, something akin to freezing MIDI tracks in Ableton Live might be worthwhile, e.g. bouncing the results in place and freezing the initial query/settings. This way, users could run a "refreeze" command that executes the query once more while updating the frozen results. This may prevent extensive recalculation, and would suit my use case where I would only need to update the graph once in a while (and might actually be preferable, as this also paves the way for modular writing approaches where frozen query results can be reviewed and edited in place as pure markdown, while the initial query still exists somewhere in a frozen codeblock, YAML field or elsewhere).

Perhaps some syntax like:

%% \```dataview
LIST WITHOUT ID "[[" + file.name + "|" + name + "]]"
    FROM "philo" OR #philo
    WHERE name != [[]].name
\``` BEGIN DATAVIEW RESULTS %%
- [[philo-edu|Philosophy of Education]]
- [[epistem|Epistemology]]
- [[Utilitarianism|Utilitarianism]]
%% END DATAVIEW RESULTS %%

Those are some actual results from my vault btw

Anything between the BEGIN and END would updated each time the vault's queries are re-ran. The most obvious issue is visually delineating the dataview results from the rest of the contents.

Any thoughts?

natefrisch01 commented 9 months ago

I didn't notice this FR till now. Perhaps this plugin will help some people: https://github.com/natefrisch01/Graph-Link-Types.

"Add metadata with internal links to your notes using Dataview's syntax. Graph Link Types will render these links as text in the graph view."

Let me know what you think!

dsebastien commented 2 months ago

I've created a plugin to serialize Dataview queries: https://github.com/dsebastien/obsidian-dataview-serializer

Here's an example from one of my Maps of Content:

<!-- QueryToSerialize: LIST FROM #luck WHERE public_note = true SORT file.name ASC -->
<!-- SerializedQuery: LIST FROM #luck WHERE public_note = true SORT file.name ASC -->
- [[30 Areas/32 Literature notes/32.04 Expressions/Audaces fortuna juvat.md|Audaces fortuna juvat]]
- [[30 Areas/32 Literature notes/32.05 Quotes/Choice, not chance, determines your destiny.md|Choice, not chance, determines your destiny]]
- [[30 Areas/33 Permanent notes/33.02 Content/Engineer serendipity.md|Engineer serendipity]]
- [[30 Areas/32 Literature notes/32.05 Quotes/Give yourself a lot of shots to get lucky.md|Give yourself a lot of shots to get lucky]]
- [[30 Areas/32 Literature notes/32.02 Content/Glücksshuld.md|Glücksshuld]]
- [[30 Areas/33 Permanent notes/33.02 Content/Invest in your relationship capital.md|Invest in your relationship capital]]
- [[30 Areas/32 Literature notes/32.05 Quotes/It’s a lot easier to say all successful people got lucky than it is to admit you have no ability to delay gratification, handle rejection, or think for yourself.md|It’s a lot easier to say all successful people got lucky than it is to admit you have no ability to delay gratification, handle rejection, or think for yourself]]
- [[30 Areas/32 Literature notes/32.05 Quotes/La fortune sourit aux audacieux.md|La fortune sourit aux audacieux]]
- [[30 Areas/32 Literature notes/32.05 Quotes/Life, I've found, works the following way. Daily, you're presented with many small and surprising opportunities. Sometimes you seize one that takes you to the top. Most, though, if valuable at all, take you only a little way.md|Life, I've found, works the following way. Daily, you're presented with many small and surprising opportunities. Sometimes you seize one that takes you to the top. Most, though, if valuable at all, take you only a little way]]
- [[30 Areas/32 Literature notes/32.05 Quotes/Luck is what happens when preparation meets opportunity.md|Luck is what happens when preparation meets opportunity]]
- [[30 Areas/32 Literature notes/32.05 Quotes/Luck isn’t an independent variable but increases super-linearly with more surface area—you meet more people, make more connections between new ideas, learn patterns, etc.md|Luck isn’t an independent variable but increases super-linearly with more surface area—you meet more people, make more connections between new ideas, learn patterns, etc]]
- [[30 Areas/33 Permanent notes/33.02 Content/Luck surface area.md|Luck surface area]]
- [[30 Areas/32 Literature notes/32.05 Quotes/Persistence beats timing. Execution beats luck. Not immediately, but eventually.md|Persistence beats timing. Execution beats luck. Not immediately, but eventually]]
<!-- SerializedQuery END -->

As you can see, the query in comment gets executed and the output is added to the note as Markdown.

Result online: https://notes.dsebastien.net/30+Areas/34+MOCs/Luck+(MoC)

The documentation is here: https://developassion.gitbook.io/obsidian-dataview-serializer

Note that you must be careful with Dataview queries that output tags, since those will be actual tags in the notes where the queries are located, which could lead to unexpected results.