twibiral / obsidian-execute-code

Obsidian Plugin to execute code in a note.
MIT License
1.11k stars 66 forks source link

Failure on pyplot with `numpy.sin` #34

Closed SoundsSerious closed 2 years ago

SoundsSerious commented 2 years ago

Hey! Amazing work with this library! Overall everything has worked but had some issues with plotting.

I'm running a fairly simple example and have had some limited success plotting, however I've had a number of suprises.

Using numpy.sin causes a very weird error:

import seaborn as sns
import matplotlib.pyplot as plt
sns.set_style("darkgrid")
import matplotlib.pyplot as plt
import numpy

x = numpy.array(list(range(10)))
y = numpy.sin( x )

plt.plot( x , y )
plt.show()

And the error:

Traceback (most recent call last):
  File "C:\Users\Sup\AppData\Local\Temp\temp_1659324923767.py", line 11, in <module>
    import io; __obsidian_execute_code_temp_pyplot_var__=io.StringIO(); plt.plot(); plt.savefig(__obsidian_execute_code_temp_pyplot_var__, format='svg'); plt.close(); print(f"<div align=\"center\">{__obsidian_execute_code_temp_pyplot_var__.getvalue()}</div>")
  File "C:\Users\Sup\Anaconda3\envs\triton\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u2212' in position 7994: character maps to <undefined>
twibiral commented 2 years ago

Hey, thanks for the feedback!

This is really weird. When plt.show() is called I generate the plot as svg and load it as html element afterwards. It looks like this error happens when embedding this svg into the note. I will look into this and try to fix it.

If you stumble upon more errors please post them here or in a new issue.

SoundsSerious commented 2 years ago

Absolutely I will definitely post any updates I find here. Graphics integrations can be tough.

I've been pondering the best way to create reports with python plots, and im guessing you've given it some thought too :)

I definitely like the ability to run code in browser but I think something like a pweave extension might work well since you choose your markdown files and it will render the output in the same file or different ones with templates.

I wonder if it might be an easier approach to leverage that tool since it seems there's a special emphasis on python here?

SoundsSerious commented 2 years ago

@twibiral

Hey got some more info on this, looks like this might be an issue with the file format: https://github.com/kupiqu/fig2svg/issues/27

on persons conclusion: I believe that any "extended" characters in tick labels will cause this issue

SoundsSerious commented 2 years ago

Modifying my example so that the plot has nothing in the negative quadrangs (\u2212 is minus sign)

import seaborn as sns
import matplotlib.pyplot as plt
sns.set_style("darkgrid")
import matplotlib.pyplot as plt
import numpy

x = numpy.array(list(range(10)))
y = numpy.sin( x ) + 2

p = plt.plot( x , y )
plt.show()
SoundsSerious commented 2 years ago

This works OK!

weivdev commented 2 years ago

Hi @SoundsSerious did your numpy work?

if so, how did you set up the python path in obsidian? and where was your numpy site-packages in? I just raised this https://github.com/twibiral/obsidian-execute-code/issues/39 and then saw here thus am seeking advice to make numpy works. Thank you!

SoundsSerious commented 2 years ago

Yes numpy works for me, i saw your issue too.. looks more like a dependency issue, so i dont think its an issue with the library itself

Thylane commented 2 years ago

Same problem here. I may find a solution.

Find this line in main.js, function addInlinePlotsToPython:

const showPlot = 'import io; __obsidian_execute_code_temp_pyplot_var__=io.StringIO(); plt.plot(); plt.savefig(__obsidian_execute_code_temp_pyplot_var__, format=\'svg\'); plt.close(); print(f"<div align=\\"center\\">{__obsidian_execute_code_temp_pyplot_var__.getvalue()}</div>")';

Replace it with:

const showPlot = `import io;import sys;__obsidian_execute_code_temp_pyplot_var__=io.BytesIO();plt.plot();` + 
  `plt.savefig(__obsidian_execute_code_temp_pyplot_var__, format='svg');plt.close();` +
  `sys.stdout.buffer.write(__obsidian_execute_code_temp_pyplot_var__.getvalue());`;

No encode problem now, so plot with negative quadrants will render properly, like this:

SoundsSerious commented 2 years ago

Ayyy awesome @Thylane! Nice work.

So just to recap on this, the change is replacing StringIO with BytesIO? as well as replacing print with stdout.write?

twibiral commented 2 years ago

@Thylane thank you! This seems to work. I will release this in about a week.

I would appreciate if you could create a pull request with the fix to develop in the meantime. Otherwise I can change it by myself.

twibiral commented 2 years ago

Solved by #44 and published in Release 0.9.2