I ran into the same issue and my solution so far has been the following:
The example here does not include datetime for ticks but it hopefully is obvious how this would work with a matplotlib figure generated with datetime ticks.
I generated the graph I wanted using matplotlib and then used plotly tools to convert it into a plotly graph:
import matplotlib.pyplot as plt
import plotly.tools as tls
mpl_fig = plt.figure()
x = np.linspace(np.pi, 3*np.pi, 1000)
sinx = np.sin(x)
ax = mpl_fig.add_subplot(111)
ax.plot(x, sinx)
ax.set_title('A Sine Curve')
ax.set_ylabel('test')
plt.tight_layout()
plotly_fig = tls.mpl_to_plotly(mpl_fig)
The only issue with this is that the mpl_to_plotly() will set layout defaults which results in the plot pane not fitting the graph dimensions.

To overcome this I checked the layout that is send by a viz.line() plot and overwrote the standard "layout" generated by mpl_to_plotly by a custom version.
plotly_fig["layout"] = {u'showlegend': ['simulation'],
u'yaxis': {u'title': 'sin(x)'},
u'margin': {u'r': 60, u'b': 60, u'l': 60, u't': 60},
u'xaxis': {u'title': 'Time'},
u'title': "%s for %s" % (name, operator_name[op])}
This results in better treatment of image scaling in the plot panes of visdom.

For all of this to work I also just added a custom function into __init__.py to allow me sending a plot to the server which I realise needs to be improved but I share it for the sake of the example here.
def mpl_converted(self, converted, win=None, env=None, opts=None, update=None):
return self._send({
'data': converted["data"],
'win': win,
'eid': env,
'layout': converted["layout"]
})
Any suggestions welcome, happy to contribute to the project with a PR (after comments and improvements) if that is wanted.
Interesting @Florian-Roessler, thanks for sharing!
I think it may be useful to add a function viz.matplot(mplfig) to the Python client that takes as input Matplotlib figure mplfig, converts it to a Plotly figure (hacking the margins if necessary), and sends it to the server as you describe.
(Note that power users can directly use _send() if they want to hack their own visualizations.)
Note also that as @lvdmaaten mentioned, you can use _send directly with the usual Plotly API.
Specifically, for date/time xaxis, see https://plot.ly/python/time-series/ ('Time Series Plot with Custom Date Range'):
import datetime
def to_unix_time(dt):
epoch = datetime.datetime.utcfromtimestamp(0)
return (dt - epoch).total_seconds() * 1000
x = [datetime.datetime(year=2013, month=10, day=04),
datetime.datetime(year=2013, month=11, day=05),
datetime.datetime(year=2013, month=12, day=06)]
data = [dict(
x=x,
y=[1, 3, 6])]
layout = dict(xaxis = dict(
range = [to_unix_time(datetime.datetime(2013, 10, 17)),
to_unix_time(datetime.datetime(2013, 11, 20))]
))
Note that you don't need to use go.Scatter and go.Layout (you can use dicts instead).
Once you have your Plotly data and layout, you can just do:
self._send({
'data': data,
'win': win,
'eid': env,
'layout': layout
})
@ajabri, can you rewrite the code above as a self-contained example? I get that "datetime is not JSON serializable". If I simplify the data to get past that, I get u'' as the retuned window and nothing is being plot. I presume that self should be a visdom.Visdom(), right?
I think it may be useful to add a function viz.matplot(mplfig) to the Python client that takes as input Matplotlib figure mplfig, converts it to a Plotly figure (hacking the margins if necessary), and sends it to the server as you describe.
I second that, it would be extremely useful, especially for already existing visualizations in Matplotlib that I would like to port to Visdom.
Hi @psmaragdis
Sorry for replying so late! Here's a self-contained, bug-free example:
import datetime
import visdom
def to_unix_time(dt):
epoch = datetime.datetime.utcfromtimestamp(0)
return (dt - epoch).total_seconds() * 1000
x = [datetime.datetime(year=2013, month=10, day=04),
datetime.datetime(year=2013, month=11, day=05),
datetime.datetime(year=2013, month=12, day=06)]
data = [dict(
x=[str(xx) for xx in x],
y=[1, 3, 6],
type='plot')]
layout = dict(xaxis = dict(
range = [to_unix_time(datetime.datetime(2013, 10, 17)),
to_unix_time(datetime.datetime(2013, 11, 20))]
))
visdom.Visdom()._send({
'data': data,
'opts': {},
'layout': layout
})
Most helpful comment
Interesting @Florian-Roessler, thanks for sharing!
I think it may be useful to add a function
viz.matplot(mplfig)to the Python client that takes as input Matplotlib figuremplfig, converts it to a Plotly figure (hacking the margins if necessary), and sends it to the server as you describe.(Note that power users can directly use
_send()if they want to hack their own visualizations.)