Skip to content

Commit

Permalink
Provide a way to render plots in DataViewJS blocks.
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmytro-Shulha committed Nov 13, 2021
1 parent 0bc05e0 commit 8ccbc8e
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 19 deletions.
62 changes: 57 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
# obsidian-plotly
Obsidian plugin, which allow user to embed Plotly charts into markdown notes.

## Usage
Use double-click to add basic plotly template:
# Usage
## Basic (using plotly block)
Use Command Palette (`Ctrl-P`) to add basic plotly template:
![Command example](./media/plotly-command-demo.gif)

## Examples
Plugin supports both JSON and YAML formats.
Those plots are identical:
This approach allows you to create JSON or YAML inside `plotly` block
with payload for data, layout and config objects.
It does NOT support JavaScript examples from plotly.com site - it only support static payload forvarding to `Plotly.newPlot` function.
For JavaScript support use Advanced approach with DataViewJS.

Basic example (those YAML and JSON result in identical plots):
```yaml
```plotly
data:
Expand All @@ -27,4 +30,53 @@ Those plots are identical:
}
```
```

## Advanced (using dataviewjs block)
Use Command Palette (`Ctrl-P`) to add plotly template:
![Command example](./media/plotly-dataviewjs-command-demo.gif)

This approach DOES support any example from plotly.com.
(I haven't checked them all, feel free to create issue if some aren't working).
However, this approach require DataView plugin to process JavaScript.
As a benefit, you can create plots based on data from you notes which you retrieve via DataView API!
(By the way, this sounds similar to what [obsidian-tracker](https://github.com/pyrochlore/obsidian-tracker) plugin does).

To use it, just add DataviewJS block with Plotly command, copy desired example and paste it.
NOTE: All examples use `Plotly.newPlot(component, data, layout, config)` to draw, and it takes some extra code to work in Obsidian.
There is a wrapper function available as `window.renderPlotly(this.component, data, layout, config)`, which will draw plot inside DataViewJS block.
(Wrapper parameters should be same as in example).

A lot of examples are on [Plotly](https://plotly.com/javascript/) official site.

![How to copy examples from plotly.com](./media/plotly-copy-from-examples-demo.gif)

NOTE: Some examples also require d3 library. This is large library and rarely needed. That's why I do not want to have it in plugin.
If you need this library, there is a workaround: you can download d3 library from official [site](https://d3js.org/d3.v7.min.js) (Open link->Right click->Save as...), place it in your vault and import using `require`;

```js
```dataviewjs
//Some plotly examples require d3 library to work.
//Since it's large and used by few examples,
//I propose a workaround to import d3;
//You need to download dependency from https://d3js.org/d3.v7.min.js
//and place it in your vault.
let path = app.vault.adapter.basePath;//absolute path to your vault
var d3 = require(path+"\\utils\\d3.v7.min.js");
//Replace this block with any example from plotly.com
//NOTE: `Plotly.newPlot` won't work here, use `window.renderPlotly` instead
var data = [
{x:[0,1,2,3,4,5,6,7,8,9],y:[4,4,2,2,3,3,2,2,4,4]},
{x:[0,1,2,3,4,5,6,7,8,9],y:[3,3,1,1,2,2,1,1,3,3]}
];
var layout = {title:"Example in DataViewJS"};
var config = {displaylogo:false};
window.renderPlotly(this.container, data, layout, config)
```
```

# Examples
TODO: create vault to test this plugin with examples.

More examples on [Plotly](https://plotly.com/javascript/) official site.
Binary file added media/plotly-copy-from-examples-demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/plotly-dataviewjs-command-demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 44 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Editor, MarkdownView, Plugin } from 'obsidian';
import * as Plotly from 'plotly.js-dist-min';

import { preprocessor } from './preprocessor';
import { Editor, MarkdownView, Plugin } from 'obsidian';
import { preprocessor, renderPlotly } from './preprocessor';

const basicPlotlyChart = [
'```plotly',
Expand All @@ -9,18 +10,52 @@ const basicPlotlyChart = [
'\t y: [0,1,0]',
'```\n'
].join('\n')

const NEW_PLOTLY_CHART_NAME = "New Plotly Chart";
const newPlotlyChart = (editor: Editor)=>{
let doc = editor.getDoc();
let cursor = doc.getCursor();
doc.replaceRange(basicPlotlyChart, cursor);
}

const dataviewjsPlotlyChart = [
'```dataviewjs',
'//Some plotly examples require d3 library to work.',
'//Since it\'s large and used by few examples,',
'//I propose a workaround to import d3;',
'//You need to download dependency from https://d3js.org/d3.v7.min.js',
'//and place it in your vault.',
'let path = app.vault.adapter.basePath;//absolute path to your vault',
'var d3 = require(path+"\\\\utils\\\\d3.v7.min.js");',
'',
'//Replace this block with any example from plotly.com',
'//NOTE: `Plotly.newPlot` won\'t work here, use `window.renderPlotly` instead',
'var data = [',
'{x:[0,1,2,3,4,5,6,7,8,9],y:[4,4,2,2,3,3,2,2,4,4]},',
'{x:[0,1,2,3,4,5,6,7,8,9],y:[3,3,1,1,2,2,1,1,3,3]}',
'];',
'var layout = {};',
'var config = {};',
'',
'window.renderPlotly(this.container, data, layout, config)',
'```'
].join('\n')
const NEW_PLOTLY_CHART_BY_DATAVIEWJS_NAME = "New Plotly Chart generated by Dataviewjs";
const newPlotlyChartByDataviewjs = (editor: Editor)=>{
let doc = editor.getDoc();
let cursor = doc.getCursor();
doc.replaceRange(dataviewjsPlotlyChart, cursor);
}


export default class PlotlyPlugin extends Plugin {
Plotly: object

async onload() {
//@ts-ignore
window.renderPlotly = renderPlotly;

console.log('loading Plotly plugin');
this.Plotly = Plotly;

this.registerMarkdownCodeBlockProcessor('plotly', preprocessor);

Expand All @@ -29,6 +64,12 @@ export default class PlotlyPlugin extends Plugin {
name: NEW_PLOTLY_CHART_NAME,
editorCallback: (editor: Editor, view: MarkdownView)=>newPlotlyChart(editor)
});

this.addCommand({
id: "add-plotly-dataviewjs-example",
name: NEW_PLOTLY_CHART_BY_DATAVIEWJS_NAME,
editorCallback: (editor: Editor, view: MarkdownView)=>newPlotlyChartByDataviewjs(editor)
});
}

onunload() {
Expand Down
28 changes: 17 additions & 11 deletions src/preprocessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,8 @@ export const preprocessor = (content: string, el: HTMLElement, ctx: MarkdownPost
let json;
try{
json = parseYaml(content);

validate(json, el)

const destination = document.createElement('div');

if(el.firstElementChild!=null){
Plotly.update(destination, json.data, json.layout, json.config);
el.replaceChild(destination, el.firstElementChild);
} else {
Plotly.newPlot(destination, json.data, json.layout, json.config);
el.appendChild(destination);
}
render(json, el)
} catch (error) {
let errorDiv = document.createElement('div');
errorDiv.textContent = "Couldn't render plot:" + error;
Expand All @@ -38,3 +28,19 @@ const validate = (json: any, el: HTMLElement) => {
}
})
}

const render = (json: any, el: HTMLElement) => {
renderPlotly(el, json.data, json.layout, json.config)
}

export const renderPlotly = (el: HTMLElement, data: Object[], layout: Object, config: Object) => {
const destination = document.createElement('div');

if(el.firstElementChild!=null){
Plotly.update(destination, data as any, layout, config as any);
el.replaceChild(destination, el.firstElementChild);
} else {
Plotly.newPlot(destination, data, layout, config);
el.appendChild(destination);
}
}

0 comments on commit 8ccbc8e

Please sign in to comment.