Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to specify a directory in which to save an image using plotly py.image.save_as

I would like to save the plot images I generate into a specific directory, but save_as only has a filename argument. I'm using the following code to save the plots

py.image.save_as(fig,filename='T_avg_'+lst_QoST_prop[i]+'.pdf')

Is there a way to specify a directory?

like image 605
Khalil Mebarkia Avatar asked Jun 27 '18 14:06

Khalil Mebarkia


1 Answers

In order to save your file in a specific file path you need to use filename parameter.

import plotly.plotly as py
help(py.image)
 |  Helper functions wrapped around plotly's static image generation api.
 |
 |  Class methods defined here:
 |  save_as(figure_or_data, filename, format=None, width=None, height=None, scale=None) from builtins.type
 |      Save a image of the plot described by `figure_or_data` locally as
 |      `filename`.
 |
 |      Valid image formats are 'png', 'svg', 'jpeg', and 'pdf'.
 |      The format is taken as the extension of the filename or as the
 |      supplied format.
 |
 |      positional arguments:
 |      - figure_or_data: The figure dict-like or data list-like object that
 |                        describes a plotly figure.
 |                        Same argument used in `py.plot`, `py.iplot`,
 |                        see https://plot.ly/python for examples
 |      - filename: The filepath to save the image to
 |      - format: 'png', 'svg', 'jpeg', 'pdf'
 |      - width: output width
 |      - height: output height
 |      - scale: Increase the resolution of the image by `scale` amount
 |             Only valid for PNG and JPEG images.


Using filename with path (offline):

However, this results in a HTML file that's opened in a new tab of the browser. The image is saved to the 'Downloads' folder, and it's not possible to specify the path at which the image should be saved.

from plotly.offline import py
from plotly.graph_objs import Scatter

plot([Scatter(x=[14, 19, 24, 29, 34, 39, 89],
              y=[30, 15, 18, 30, 24, 27, 50])], filename='2/billympoufo.html')

So you'll have the html file in the specified folder (image in download folder) in order to bypass browser behavior you can: (1) import copyfile from shutil and move the image.

import os
import plotly
import plotly.graph_objs as go
import time
from shutil import copyfile

img_name = 'billympoufo'
dload = os.path.expanduser('~/Downloads')
save_dir = '/tmp'

data = [go.Scatter(x=[14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64, 69, 74, 79, 84, 89, 1], y=[30, 15, 18, 30, 24, 27, 50, 36, 39, 42, 50, 48, 51, 54])]

plotly.offline.plot(data, image_filename=img_name, image='svg')

### might need to wait for plot to download before copying
time.sleep(1)

copyfile('{}/{}.svg'.format(dload, img_name),
     '{}/{}.svg'.format(save_dir, img_name))

for more offline options: (2) check chromium or (3) Firefox download behavior.

By using the parameter auto_open=False it should save the image in the folder without opening a tab in your browser but this was an an issue,
check here: Directly save image (without opening in browser) #880
and plotly didn't plan to add this feature at that time.
Also you can (4) use selenium to screenshot the page

In Jupiter, for offline saving you can do the following:

import os
import pandas as pd
import plotly
import plotly.graph_objs as go
import time    
from selenium import webdriver
from PIL import Image
from pyvirtualdisplay import Display 

### from bokeh/io, slightly modified to avoid their import_required util
### didn't ultimately use, but leaving in case I figure out how to stick wtih phentomjs
### - https://github.com/bokeh/bokeh/blob/master/bokeh/io/export.py
def create_default_webdriver():
    '''Return phantomjs enabled webdriver'''
    phantomjs_path = detect_phantomjs()
    return webdriver.PhantomJS(executable_path=phantomjs_path, service_log_path=devnull)    

### based on last SO answer above
### - https://stackoverflow.com/questions/38615811/how-to-download-a-file-with-python-selenium-and-phantomjs
def create_chromedriver_webdriver(dload_path):
    display = Display(visible=0)
    display.start()
    chrome_options = webdriver.ChromeOptions()
    prefs = {"download.default_directory": dload_path}
    chrome_options.add_experimental_option("prefs", prefs)
    driver = webdriver.Chrome(chrome_options=chrome_options)
    return driver, display
df = pd.DataFrame(
    {'fruits': ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries'],
     'counts': [5, 3, 4, 2, 4, 6] })    
data = [go.Bar(x=df['fruits'],y=df['counts'])]    
dload = os.path.expanduser('~/Downloads')
html_file = 'plotly-fruit-plot.html'
fname = 'plotly-fruit-plot'

### original code contained height/width for the display and chromium webdriver
### I found they didn't matter; specifying the image size to generate will 
### produce a plot of that size no matter the webdriver
plotly.offline.plot(data, filename=html_file, auto_open=False,
                    image_width=1280, image_height=800,image_filename=fname, image='png')

### create webdrive, open file, maximize, and sleep
driver, display = create_chromedriver_webdriver(dload)    
driver.get('file:///{}'.format(os.path.abspath(html_file)))

# make sure we give the file time to download
time.sleep(1)

### was in the SO post and could be a more robust way to wait vs. just sleeping 1sec
# while not(glob.glob(os.path.join(dl_location, filename))):
#     time.sleep(1)    
driver.close()
display.stop()    
image = Image.open('{}.png'.format(os.path.join(dload, fname)))
image

(source: jupiter)


or online folder:

import plotly.plotly as py
import plotly.graph_objs as go
# sign in
data = [
    go.Scatter(
        x=[14, 19, 24, 29, 5, 10, 22],
        y=[15, 18, 30, 24, 27, 30, 40]
    )
]

plot_out = py.plot(data, filename='all_my_graphs/my_new_plot')
like image 178
Panos Kal. Avatar answered Nov 14 '22 23:11

Panos Kal.