Currently, the SHAP module uses a mix of matplotlib and IML to visualize the prediction explanations. It would be great if there was an easy way to save these to a file. For the matplotlib charts, that is easy enough to just call savefig, but saving the IML output is almost impossible.
Is there any way we can achieve this without having to make changes deep within the IML code?
That's tricky, but might not be too bad. The right way to do it is to save an SVG file with SVG tags that get displayed by React. Perhaps there is a way in iPython to get the html contents of the output cell?
When I needed to do it myself I either took a screen capture or for paper-quality figures manually snipped out the SVG tags from the document tree in the browser.
I guess I should have been a bit more specific. I'm looking to use these visualizations at a much larger scale than would be supported in a Jupyter notebook -- something that requires running a script through thousands of samples at the command line.
That pretty much eliminates anything that uses iPython's rendering engine.
Ah. Well the visualizations are a mixture of React and D3, which run
Javascript that needs to access to a DOM of some sort. The output of these
frameworks is an SVG document inside the HTML page.
I know people have done server side rendering with both those frameworks,
but it would be an involved process unless you are very familiar with doing
that already.
On Tue, Oct 24, 2017 at 4:44 PM Scott Coull notifications@github.com
wrote:
I guess I should have been a bit more specific. I'm looking to use these
visualizations at a much larger scale than would be supported in a Jupyter
notebook -- something that requires running a script through thousands of
samples at the command line.That pretty much eliminates anything that uses iPython's rendering engine.
—
You are receiving this because you commented.Reply to this email directly, view it on GitHub
https://github.com/slundberg/shap/issues/3#issuecomment-339169225, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ADkTxfLzrJduAlKjIW9oyMKzj7nfWvKUks5svnZCgaJpZM4QFAtz
.
That is what I figured after looking through the code. The best I could expect without a huge amount of effort is to essentially make a custom fork of IML that saves the HTML to a file instead of using the iPython display. Thanks for the note!
@coulls any luck with outputting to a file? This is an excellent package and I am running into the same issue as you i.e. how to use it in a context where ipython cannot be used
Hi @coulls ,
I was wondering if you managed to find the way to generate outputs from command line.
Ivan
Hey everyone!
When I first asked this question, I did some digging into the interpretable ML package (https://github.com/interpretable-ml/iml) that these visualizations are based on. Unfortunately, when I looked at it, there was some pretty heavy reliance on Javascript output directly into the Jupyter notebook, so there was no easy way to move it to another graphics backend.
If anyone happens to have a solution, please feel free to chime in!
Hi all!
I found a similar application to shap. In this package, the images can be exported to html (including a notebook):
https://marcotcr.github.io/lime/tutorials/Lime%20-%20basic%20usage%2C%20two%20class%20case.html
May be this can help us?
Ivan
Indeed, LIME was around even before SHAP. However, the approach is slightly different (parameterizations are different in some key ways). In my experience, SHAP has been more 'accurate' or in-line with human interpretation than LIME.
I should note that that dependence_plot and summary_plot are already in matplotlib and so can be saved to a file. force_plot is by default drawn using javascript, but someone has contributed a matplotlib version that can obtained by using the matplotlib=True option. Hope that helps clarify the current state of things :)
Thanks @coulls for your comments. but do you think that the approach used by LIME to generate an HTML file could be applied to SHAP?
Thaks @slundberg for letting me know that it is possible to save dependence_plot() and summary_plot() to a file. Please let me know if I got this right. After the command dependence_plot(), can I use plt.savefig() to generate a graphic output?
Regarding LIME capability to generate an HTML file. From a DOS terminal, I can use the command "explainer.save_to_file(path + filename)" - I attached an example for your reference.
Many thanks,
Ivan
@ivan-marroquin That's right. You can also pass show=False if you want to keep manipulating the matplotlib plot. I also just added a shap.save_html(file, output_of_force_plot) function since it does seem useful.
Hi @slundberg thanks a lot for adding this functionality!
Hi @slundberg ,
Following your advice, I used these commands:
s_plot= plt.figure()
shap.summary_plot(shap_values_1[0], features= X_test, title= "Toy")
s_plot.savefig('C:\Users\IMarroquin\Documents\SHAP_Model_1_55_summary.png')
The file got created. But the title is missing - and also in the displayed image. Do you have suggestions?
Then, I decided to do the following (since I have a multi-class classifier):
s_plot= plt.figure()
plt.subplot(311)
shap.summary_plot(shap_values_1[0], features= X_test, title= "Toy")
plt.title("Toy")
plt.subplot(312)
shap.summary_plot(shap_values_1[1], features= X_test, title= "Bike")
plt.title("Bike")
plt.subplot(313)
shap.summary_plot(shap_values_1[2], features= X_test, title= "Shoes")
plt.title("Shoes")
s_plot.savefig('C:\Users\IMarroquin\Documents\SHAP_Model_1_55_summary.png')
Failed with these messages:
raise ValueError("'box_aspect' and 'fig_aspect' must be positive")
ValueError: 'box_aspect' and 'fig_aspect' must be positive
Any ideas?
Many thanks,
Ivan
Try using show=False in summary_plot to prevent it from displaying the figure before you save it :)
Hi @slundberg ,
Thanks for the suggestion. Unfortunately, I still have the same issue. So, I decided to create individual plots.
Kind regards,
Ivan
Ah. Well if you happen to find a solution at some point please share it back here!
@slundberg
First off, great library and I very much appreciate the continually improving functionality.
I was able to get the output from the forceplots - both the initjs() and matplotlib variations, but got and error when I tried to use save_html() for both formats. Any idea as to what's going on here?

@michael1albq I had the same problem, had to make the following change to force.py (just added encoding="utf-8" to the open command for the out_file). I thought maybe it was just a problem with my install, so I didn't open an issue, but maybe it's worth seeing if it's a general problem?@slundberg
I included a large part of the save_html command below for context.
def save_html(out_file, plot_html):
""" Save html plots to an output file.
"""
internal_open = False
if type(out_file) == str:
out_file = open(out_file, "w", encoding="utf-8") # <--- change here
# out_file = open(out_file, "w")
internal_open = True
out_file.write("<html><head><script>\n")
# dump the js code
bundle_path = os.path.join(os.path.split(__file__)[0], "resources", "bundle.js")
with io.open(bundle_path, encoding="utf-8") as f:
bundle_data = f.read()
out_file.write(bundle_data)
out_file.write("</script></head><body>\n")
out_file.write(plot_html.data)
out_file.write("</body></html>\n")
This worked!
@slundberg is there a release on PyPi with the fix available?
@kjanko I'm planning to get a new release out this week that will have this
I wonder how to export to csv the values used for the dot plot (default) and bar plot (global).
For the moment I can get the raw data for the SHAP values.
df_shap_values = pd.DataFrame(shap_values, index=X.index, columns=X.columns)
df_shap_values.to_csv('df_shap_values.csv')
But this of course lacks any transformation, normalization or cleaning that these plots are doing.
Is there any way to export these?
Is all the code behind here https://github.com/slundberg/shap/blob/master/shap/plots/_summary.py?
Most helpful comment
@ivan-marroquin That's right. You can also pass show=False if you want to keep manipulating the matplotlib plot. I also just added a
shap.save_html(file, output_of_force_plot)function since it does seem useful.