I am using Plotly offline on Jupyter.
I am plotting curves:
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
from plotly.graph_objs import *
import datetime as dt
list_date = [dt.datetime(2016,1,1).date(), dt.datetime(2016,1,2).date(), dt.datetime(2016,1,3).date(), dt.datetime(2016,1,4).date()]
data = []
for i in range(3) :
list = [i/2+1, i/2+2, i/2+3, i/2+4]
data.append(Scatter(x=list_date, y=list, name='y'+str(i)))
figure = Figure(data=data)
iplot(figure)
And I get a very nice graph!
In the latter case, the user wants to add a bar graph on it (in addition to the two lines already there).
list_bar = [0.5, 1.5, 2.5, 3.5]
data = [Bar(x=list_date, y=list_bar, name='bar')]
figure.update(data=data)
iplot(figure)
But I have only the bar chart, not the previous 2 lines. How to have offline the equivalent of the online function fileopt='append'?
py.plot(data, filename='append plot', fileopt='append')
In the latest plotly version 3, a FigureWidget has been added specifically to handle your problem of wanting to update an existing offline figure.
For me, running pip install plotly --upgrade got me the latest version within my Anaconda environment.
I've modified your example code below to use the new FigureWidget, and left in your old code that needed changing with comments. The new FigureWidget is meant to be compatible with the ordinary Figure that you were using.
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
from plotly.graph_objs import *
import datetime as dt
# list_date = [dt.datetime(2016,1,1).date(), dt.datetime(2016,1,2).date(), dt.datetime(2016,1,3).date(), dt.datetime(2016,1,4).date()]
list_date = [dt.datetime(2016,1,1), dt.datetime(2016,1,2), dt.datetime(2016,1,3), dt.datetime(2016,1,4)]
data = []
for i in range(3) :
list = [i/2+1, i/2+2, i/2+3, i/2+4]
data.append(Scatter(x=list_date, y=list, name='y'+str(i)))
# figure = Figure(data=data)
# iplot(figure)
figure = FigureWidget(data=data)
figure
I've commented out the portions that were changed so you can see them for reference.
One other thing to note, due to a problem within ipykernel.json_util, the json_clean function that serializes Plotly JSON objects to show on your Jupyter screen doesn't know what to do with a datetime.date object -- only datetime objects. If you don't remove the .date you will get an exception and no graph. I'm guessing this would happen for datetime.time objects as well because it seems it is also unhandled in the current ipykernel code.
When you're ready to run your updated code, you simple create your data and use the add_trace function:
list_bar = [0.5, 1.5, 2.5, 3.5]
figure.add_trace(Bar(x=list_date, y=list_bar, name='bar'))
And your plot automatically updates in the previous cell with the added trace.
Lastly, there's a good guide about the new FigureWidget for those interested.
Related
I want to show specific data (not the columns I used in plotting my scatter plot but other columns in the dataframe) whenever I hover my mouse on each data point using matpotlib. I don't want to use plotly because I need to implement another part of matplotlib.
I wrote the following script but it is not implementing the hovering part when I run it in my jupyter notebook.
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib widget
# Load sample data
diamonds = sns.load_dataset('diamonds')
# Create a scatter plot with hue and use matplotlib to display the specific column values when hovering over a datapoint
sns.scatterplot(x="carat", y="price", hue="cut", data=diamonds)
def hover(event):
# Get the current mouse position
ax = event.inaxes
x, y = event.xdata, event.ydata
# Find the nearest datapoint
distances = ((diamonds['carat'] - x)**2 + (diamonds['price'] - y)**2)
idx = distances.idxmin()
# Display the specific column values in a pop-up window
text = f"Cut: {diamonds.loc[idx, 'cut']}\n" \
f"Clarity: {diamonds.loc[idx, 'clarity']}\n" \
f"Color: {diamonds.loc[idx, 'color']}"
plt.gcf().text(x, y, text, ha='left', va='bottom', fontsize=10, backgroundcolor='white', alpha=0.7)
# Connect the hover function to the figure
fig = plt.gcf()
fig.canvas.mpl_connect("motion_notify_event", hover)
# Show the plot
plt.show()
This is easier with mplcursors. There's a similar example of extracting the data and labels for the annotation from a dataframe to plug into. Implemented with your example it is:
%matplotlib ipympl
# based on https://mplcursors.readthedocs.io/en/stable/examples/dataframe.html
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.patheffects import withSimplePatchShadow
import mplcursors
df = sns.load_dataset('diamonds')[:10]
sbsp = sns.scatterplot(x="carat", y="price", hue="cut", data=df)
def show_hover_panel(get_text_func=None):
cursor = mplcursors.cursor(
hover=2, # Transient
annotation_kwargs=dict(
bbox=dict(
boxstyle="square,pad=0.5",
facecolor="wheat",
edgecolor="#ddd",
linewidth=0.5,
path_effects=[withSimplePatchShadow(offset=(1.5, -1.5))],
),
linespacing=1.5,
arrowprops=None,
),
highlight=True,
highlight_kwargs=dict(linewidth=2),
)
if get_text_func:
cursor.connect(
event="add",
func=lambda sel: sel.annotation.set_text(get_text_func(sel.index)),
)
return cursor
def on_add(index):
item = df.iloc[index]
parts = [
f"Cut: {item.cut}", # f"Cut: {diamonds.loc[idx, 'cut']}\n"
f"Clarity: {item.clarity}", # f"Clarity: {diamonds.loc[idx, 'clarity']}\n"
f"Color: {item.color}", #f"Color: {diamonds.loc[idx, 'color']}"
]
return "\n".join(parts)
sbsp.figure.canvas.header_visible = False # Hide the Figure name at the top of the figure;based on https://matplotlib.org/ipympl/examples/full-example.html
show_hover_panel(on_add)
plt.show();
That's for running it in JupyterLab where ipympl has been installed.
For running it in Jupyter Notebook at present, change the first line to %matplotlib notebook.
I saw it be smoother in JupyterLab.
I'll point to ways to try the code in both interfaces without installing anything on your system below.
(Your approach may be able to work with more incorporation of things here. However, there's already a very similar answer with mplcursors)
(The places and steps to run the code outlined below were worked out primarily for the Matplotlib option here yesterday. Noting that here as there were some quirks to the ipympl offering launching and I worry that I may miss updating each place if something changes.)
Try it in JupyterLab in conjunction with ipympl without touching your system
This will allow you to try the code in JupyterLab without installing anything on your own system.
Go to here. Sadly the link currently goes to a dead end and doesn't seem to build a new image right now. Fortunately, right now this offering works for launching.
When that session opens, run in a notebook %pip install mplcursors seaborn. Let that installation command run to install both mplcursors and seaborn and then restart the kernel.
Make a new cell and paste in the code from above and run it.
Try it Jupyter Notebook classic interface without touching your system
This will allow you to try the code in the present classic Jupyter Notebook interface (soon-to-be more-often-referenced as 'the document-centric interface' as the underlying machinery for Jupyter Notebook 7 will use JupyterLab components) without installing anything on your own system.
Go here and press 'launch binder'. A temporary, remote session will spin up served via MyBinder.
Make a new cell and simply add %matplotlib notebook at the top of the cell. Then add the code above to the cell, leaving off the first line of the suggested code, so that you effectively substitute %matplotlib notebook in place of %matplotlib ipympl.
Run the cell.
I'm using Spyder v5 within Anaconda and having issues with any styles being applied on charts. Basic chart below (deliberately commented out the sns import to see if it makes any difference -it doesn't)
Basic code below - gives a normal plot as expected
import matplotlib.pyplot as plt
#import seaborn as sns
x_values = [0,1,2,3,4,5,6,7,8,9,10]
x_squared = [x ** 2 for x in x_values]
plt.plot(x_values,x_squared, label = "X-Squared")
plt.plot(x_values,x_cubed, label = "X-Cubed")
plt.show()
If i then try
plt.style.use("seaborn-deep")
plt.plot(x_values,x_squared, label = "X-Squared")
plt.plot(x_values,x_cubed, label = "X-Cubed")
plt.show()
Nothing changes? The style is avaialble (from plt.styles.available) and there is no error when applying the style so something is amiss here.
If i import seaborn then nothing changes
If i try any or all of the following from other solutions in various places in my plt code then nothing much changes (all of the below lines of code work with no errors
%matplotlib inline
plt.rcParams.update(plt.rcParamsDefault)
sns.set()
One time somehow this did seem to force it to change to a seaborn-paper style but that's then the only one i can use and i can't use any other seaborn or other styles at all?? Not sure what forced it to change, think it was sns.set() so I suspect the one it then shows is the default seaborn style, but then why won't it let me use any other styles?
As i'm using SPyder in anaconda the packages are installed to do this plot
I do have Python installed on my base desktop as well... but documentation insists this won't cause a problem and i've not had this problem on any other code ever of having another installation
any tips?
This question already has an answer here:
How to save candlestick chart in matplotlib finance
(1 answer)
Closed 1 year ago.
I'm new to matplotlib. I'm struggling to customise elements of my plot within the first .plot call. For example, ylabel works but xlabel doesn't. I was hoping I could separate the savefig command so that I could add/modify elements of the plot between the first .plot call and the savefig call (because all the examples I see online seem to create the plot and then modify elements separately, i.e. the line fplt.xlabel("Blah")
I notice that a lot of plot examples I found online (for line graphs and such) provide all x and y values separately, but I like the plot technique I've used as it automatically uses high, low, etc. to create candles.
So why does this code work:
fplt.plot(
dft,
type="candle",
style='charles',
addplot=extraPlot2,
ylabel=stock,
# xlabel="Blah", <= removed as doesn't work
figratio=(10, 6), volume=True,
savefig=dict(
fname=folder2,
bbox_inches="tight"
)
)
But this code doesn't (even with the hashes added):
fplt.plot(
dft,
type="candle",
style='charles',
addplot=extraPlot2,
ylabel=stock,
# xlabel="Blah", <= removed as doesn't work
figratio=(10, 6), volume=True,
)
# fplt.xlabel("Blah") <= would like to do this if I can get savefig to work
# fplt.xticks(rotation=45) <= i'd also like to do stuff like this
fplt.savefig(folder2)
I've tried making fplt.plot a variable and targeting that but with no luck.
Apologies for any poor terminology, I am very new to this.
EDIT: Imports added below for reference. And I realise why xlabel wasn't working now, as I see I was importing it.
import datetime as dt
from matplotlib.pyplot import bar, xlabel
from numpy import False_, NaN
import pandas as pd
from pandas_datareader import data as pdr
import yfinance as yf
from tkinter import EXCEPTION, Tk
from tkinter.filedialog import askopenfilename
import os
from pandas import ExcelWriter
import mplfinance as fplt
from pathlib import Path
You can import the Matplotlib pyplot module and use the gcf() ("get current figure") function to return a Figure object. It is the Figure object that has the savefig() method. E.g.,
from matplotlib import pyplot as plot
# your code here
fig = plt.gcf() # gcf is "get current figure"
fig.savefig(folder2)
Looking at this mplfinance issue it also looks like you can return the figure object with:
fig, axlist = fplt.plot(..., returnfig=True)
# save figure
fig.savefig(folder2)
I have a plotly object that should be showing up properly but for some reason it only shows up blank in DataBricks. The object type is:
plotly.graph_objs._figure.Figure
I have tried the following to display the figure:
fig.show()
display(fig)
displayHTML(fig.to_html())
All possible solutions I can think of result in the same thing. Thanks!
Btw... Using Plotly Version 4.9
Try using the plot method from plotly.offline. This following is from DataBricks documentation, but Jupyter notebooks have a similar issue where a Plotly graph_object Figure won't render unless you use plotly.offline.
from plotly.offline import plot
import plotly.graph_objects as go
# Instead of simply calling plot(...), store your plot as a variable and pass it to displayHTML().
# Make sure to specify output_type='div' as a keyword argument.
# (Note that if you call displayHTML() multiple times in the same cell, only the last will take effect.)
p = plot(
[ ## define your go.Figure here ##
],
output_type='div'
)
displayHTML(p)
Worth noting that you can similarly use the plot method from plotly.offline to display plotly.express plots.
This saves a lot of code for simple plots where graph_objects are overkill!
from plotly.offline import plot
import plotly.express as px
p = plot(
px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16]),
output_type='div'
)
displayHTML(p)
I am using the waterfall_chart package in Python to create a waterfall figure. The package mainly uses matplotlib in the backend, so I was trying to use the tls.mpl_to_plotly(mpl_fig) function to covert the matplotlib figure into plotly. But when converting, an error pops up. Is there a way to convert waterfall_chart into plotly or is there an easy way to create the chart directly in plotly? I saw some previous discussion on similar chart in plotly, but it involved pretty manual coding of the chart number.
You could use the following code to recreate the chart.
import waterfall_chart
import matplotlib.pyplot as plt
import plotly.tools as tls
a = ['sales','returns','credit fees','rebates','late charges','shipping']
b = [10,-30,-7.5,-25,95,-7]
mpl_fig = plt.figure()
waterfall_chart.plot(a, b)
plt.show()
waterfall chart
But when I try to convert to plotly using mpl_to_plotly(), there is an error:
plotly_fig = tls.mpl_to_plotly(mpl_fig)
ValueError: min() arg is an empty sequence
The detail of the waterfall_chart package could be found here: https://github.com/chrispaulca/waterfall/blob/master/waterfall_chart.py
My answer addresses
[...] or is there an easy way to create the chart directly in plotly?
With newer versions of plotly you can use plotly.graph_objs.Waterfall.
Below is a basic example with your data sample with a setup that uses iplot in an off-line Jupyter Notebook:
Plot:
Code:
# imports
import plotly
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
from IPython.core.display import display, HTML
import plotly.figure_factory as ff
import plotly.graph_objs as go
import pandas as pd
import numpy as np
# setup
display(HTML("<style>.container { width:35% !important; } .widget-select > select {background-color: gainsboro;}</style>"))
init_notebook_mode(connected=True)
np.random.seed(1)
import plotly.offline as py
import plotly.graph_objs as go
py.init_notebook_mode(connected = False)
# your values
a = ['sales','returns','credit fees','rebates','late charges','shipping']
b = [10,-30,-7.5,-25,95,-7]
# waterfall trace
trace = go.Waterfall(
x = a,
textposition = "outside",
text = [str(elem) for elem in b],
y = b,
connector = {"line":{"color":"rgb(63, 63, 63)"}},
)
layout = go.Layout(
title = "Waterfall chart, plotly version 3.9.0",
showlegend = True
)
iplot(go.Figure([trace], layout))
Check your version with:
import plotly
plotly.__version__
Update your version in a cmd console using:
pip install plotly --upgrade
List a has a length of 6, list b has a length of 5.
Matplotlib refuses to display an empty array, list or whatever.
Solve it to add a number or 0 to b or add an if to your code, to avoid matplotlib gets an empty sequence.