I have a vertical line plot of Lithology data (x=Lithology, y=Depth) and a dictionary with colors and patterns. I need to fill my line plot using plotly and patterns:colors from my dictionary, like one in this picture on the right side. In matplotlib this achieved with ax.fill_betweenx().
ax.fill_betweenx(well['DEPTH_MD'], 0, well['LITHOLOGY'],
where=(well['LITHOLOGY']==key),
facecolor=color, hatch=hatch)
How can it be done in plotly?
Well Logs
A workaround:
import numpy as np
import plotly.graph_objects as go
depth = list(range(2900, 3100, 5))
density1 = np.random.random_sample((len(depth), )) * 2
density2 = np.random.random_sample((len(depth), )) * 2 + 1
fig = go.Figure()
fig.add_trace(go.Scatter(
x=density1,
y=depth,
mode='lines',
name='left'
))
fig.add_trace(go.Scatter(
x=density2,
y=depth,
mode='lines',
name='right'
))
fig.for_each_trace(
lambda trace: trace.update(fill='tonextx') if trace.name == "right" else (),
)
fig.show()
My solution requires you to give a name to each trace (ie. lines). Only after the two traces are updated, do fig.for_each_trace() to update either one of the traces with argument fill='tonextx'.
Related
I'm trying to create a bar graph using two plots but the Y axis doesn't fit with the y values I have assigned to it (Percent Change). I don't see what I have done wrong when creating the bar graph because when I created a scatter graph with the same approach and assigned values it seemed to be working fine. The y axis should be showing 'percent change' that is 10 or higher. While it does so when a scatter graph is created, it doesn't show these values when creating the bar graph. Instead the bar graph shows the random percent change between 0 and 100 which is not in the assigned values table. Is there any way that I can fix this?
I've copied the code below.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
trace1 = go.Bar(
x=df["Date"],
y=TopTesla["Percent Change"],
name='With Tesla',
text=TopTesla['text'],
marker=dict(
color='rgb(30,160,190)'
)
)
trace2 = go.Bar(
x=df["Date"],
y=TopNotTesla["Percent Change"],
name='Without Tesla',
text=TopNotTesla["text"],
marker=dict(
color='rgb(255,200,35)'
),
yaxis='y2',
offset=100,
showlegend=True
)
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(trace1)
fig.add_trace(trace2,secondary_y=True)
fig['layout'].update(height = 1100, width = 1500,xaxis=dict(
tickangle=-90
))
plt.figure(figsize=[20,25])
iplot(fig)
Here is CDF visualization I have:
fig_cdf = px.ecdf(df['Timespan'], color_discrete_sequence=['blue'],ecdfnorm='probability', orientation='h')
fig_cdf.add_hline(y=90, line_width=2, line_color="red", name='90%', visible=True)
fig_cdf.add_hline(y=30, line_width=2, line_color="red", name='75%', visible=True)
fig_cdf.update_layout(width=500, height=500)
The problem here is that i want horizontal lines' names to be visible and appear as 2nd and 3rd legends. For this, I tried to add visible=True. However, it seems not to work. What's wrong?
This is one way of doing it...
Add the two lines to the dataframe as new columns
Use color_discrete_sequence to identify the colors you want
I am using some random dummy data, which you can replace with your data
import plotly.express as px
df = pd.DataFrame({'firstline': random.sample(range(1, 500), 20),'myX' : range(20)}) #My dummy data
#Add the two lines to dataframe
df['90%'] = [90] * 20
df['75%'] = [75] * 20
fig = px.line(df,
y = ['firstline', '90%', '75%'], x= 'myX', color_discrete_sequence=["blue", "red", "red"])
fig.update_layout(legend_title_text='Legend Heading') #Update Legend header if you dont like 'variable'
fig.show()
Output graph
This is my first experience with this graph, but to add it to the legend, you can use the line mode of the scatter plot. So I took the maximum x-axis value used in the first graph and set the legend name Average using the appropriate y-axis value. This example is taken from the official reference.
import plotly.express as px
import plotly.graph_objects as go
df = px.data.tips()
fig = px.ecdf(df, x=["total_bill", "tip"])
xmax = max(fig.data[0]['x'])
#print(xmax)
fig.add_trace(go.Scatter(
x=[0,xmax],
y=[0.6,0.6],
mode='lines',
line_color='red',
name='mean',
showlegend=True
))
fig.show()
I want to create a lollipop plot with several horizontal line segments like this - https://python-graph-gallery.com/184-lollipop-plot-with-2-group. I'd like to use plotly since I prefer the graphics (and easy interactivity) but can't find a succint way.
There's both line graphs (https://plot.ly/python/line-charts/) and you can add lines in the layout (https://plot.ly/python/shapes/#vertical-and-horizontal-lines-positioned-relative-to-the-axes), but both of these solutions require each line segment to be added separately, with about 4-8 lines of code each. While I could just for-loop this, would appreciate if anyone can point me to anything with inbuilt vectorization, like the matplotlib solution (first link)!
Edit: Also tried the following code, to first make the plot ala matplotlib, then convert to plotly. The line segments disappear in the process. Starting to think it's just impossible.
mpl_fig = plt.figure()
# make matplotlib plot - WITH HLINES
plt.rcParams['figure.figsize'] = [5,5]
ax = mpl_fig.add_subplot(111)
ax.hlines(y=my_range, xmin=ordered_df['value1'], xmax=ordered_df['value2'],
color='grey', alpha=0.4)
ax.scatter(ordered_df['value1'], my_range, color='skyblue', alpha=1,
label='value1')
ax.scatter(ordered_df['value2'], my_range, color='green', alpha=0.4 ,
label='value2')
ax.legend()
# convert to plotly
plotly_fig = tls.mpl_to_plotly(mpl_fig)
plotly_fig['layout']['xaxis1']['showgrid'] = True
plotly_fig['layout']['xaxis1']['autorange'] = True
plotly_fig['layout']['yaxis1']['showgrid'] = True
plotly_fig['layout']['yaxis1']['autorange'] = True
# plot: hlines disappear :/
iplot(plotly_fig)
You can use None in the data like this:
import plotly.offline as pyo
import plotly.graph_objs as go
fig = go.Figure()
x = [1, 4, None, 2, 3, None, 3, 4]
y = [0, 0, None, 1, 1, None, 2, 2]
fig.add_trace(
go.Scatter(x=x, y=y))
pyo.plot(fig)
Plotly doesn't provide a built in vectorization for such chart, because it can be done easily by yourself, see my example based on your provided links:
import pandas as pd
import numpy as np
import plotly.offline as pyo
import plotly.graph_objs as go
# Create a dataframe
value1 = np.random.uniform(size = 20)
value2 = value1 + np.random.uniform(size = 20) / 4
df = pd.DataFrame({'group':list(map(chr, range(65, 85))), 'value1':value1 , 'value2':value2 })
my_range=range(1,len(df.index)+1)
# Add title and axis names
data1 = go.Scatter(
x=df['value1'],
y=np.array(my_range),
mode='markers',
marker=dict(color='blue')
)
data2 = go.Scatter(
x=df['value2'],
y=np.array(my_range),
mode='markers',
marker=dict(color='green')
)
# Horizontal line shape
shapes=[dict(
type='line',
x0 = df['value1'].loc[i],
y0 = i + 1,
x1 = df['value2'].loc[i],
y1 = i + 1,
line = dict(
color = 'grey',
width = 2
)
) for i in range(len(df['value1']))]
layout = go.Layout(
shapes = shapes,
title='Lollipop Chart'
)
# Plot the chart
fig = go.Figure([data1, data2], layout)
pyo.plot(fig)
With the result I got:
I use plotly package to show dynamic finance chart at python. However I didn't manage to put my all key points lines on one chart with for loop. Here is my code:
fig.update_layout(
for i in range(0,len(data)):
shapes=[
go.layout.Shape(
type="rect",
x0=data['Date'][i],
y0=data['Max_alt'][i],
x1='2019-12-31',
y1=data['Max_ust'][i],
fillcolor="LightSkyBlue",
opacity=0.5,
layer="below",
line_width=0)])
fig.show()
I have a data like below one. It is time series based EURUSD parity financial dataset. I calculated two constraits for both Local Min and Max. I wanted to draw rectangule shape to based on for each Min_alt / Min_ust and Max_alt / Max_range. I can draw for just one date like below image however I didn't manage to show all ranges in same plotly graph.
Here is the sample data set.
Here is the solution for added lines:
import datetime
colors = ["LightSkyBlue", "RoyalBlue", "forestgreen", "lightseagreen"]
ply_shapes = {}
for i in range(0, len(data1)):
ply_shapes['shape_' + str(i)]=go.layout.Shape(type="rect",
x0=data1['Date'][i].strftime('%Y-%m-%d'),
y0=data1['Max_alt'][i],
x1='2019-12-31',
y1=data1['Max_ust'][i],
fillcolor="LightSkyBlue",
opacity=0.5,
layer="below"
)
lst_shapes=list(ply_shapes.values())
fig1.update_layout(shapes=lst_shapes)
fig1.show()
However I have still problems to add traces to those lines. I mean text attribute.
Here is my code:
add_trace = {}
for i in range(0, len(data1)):
add_trace['scatter_' + str(i)] = go.Scatter(
x=['2019-12-31'],
y=[data1['Max_ust'][i]],
text=[str(data['Max_Label'][i])],
mode="text")
lst_trace = list(add_trace.values())
fig2=go.Figure(lst_trace)
fig2.show()
The answer:
For full control of each and every shape you insert, you could follow this logic:
fig = go.Figure()
#[...] data, traces and such
ply_shapes = {}
for i in range(1, len(df)):
ply_shapes['shape_' + str(i)]=go.layout.Shape()
lst_shapes=list(ply_shapes.values())
fig.update_layout(shapes=lst_shapes)
fig.show()
The details:
I'm not 100% sure what you're aimin to do here, but the following suggestion will answer your question quite literally regarding:
How to add more than one shape with loop in plotly?
Then you'll have to figure out the details regarding:
manage to put my all key points lines on one chart
Plot:
The plot itself is most likely not what you're looking for, but since you for some reason are adding a plot by the length of your data for i in range(0,len(data), I've made this:
Code:
This snippet will show how to handle all desired traces and shapes with for loops:
# Imports
import pandas as pd
#import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objects as go
#from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
# data, random sample to illustrate stocks
np.random.seed(12345)
rows = 20
x = pd.Series(np.random.randn(rows),index=pd.date_range('1/1/2020', periods=rows)).cumsum()
y = pd.Series(x-np.random.randn(rows)*5,index=pd.date_range('1/1/2020', periods=rows))
df = pd.concat([y,x], axis = 1)
df.columns = ['StockA', 'StockB']
# lines
df['keyPoints1']=np.random.randint(-5,5,len(df))
df['keyPoints2']=df['keyPoints1']*-1
# plotly traces
fig = go.Figure()
stocks = ['StockA', 'StockB']
df[stocks].tail()
traces = {}
for i in range(0, len(stocks)):
traces['trace_' + str(i)]=go.Scatter(x=df.index,
y=df[stocks[i]].values,
name=stocks[i])
data=list(traces.values())
fig=go.Figure(data)
# shapes update
colors = ["LightSkyBlue", "RoyalBlue", "forestgreen", "lightseagreen"]
ply_shapes = {}
for i in range(1, len(df)):
ply_shapes['shape_' + str(i)]=go.layout.Shape(type="line",
x0=df.index[i-1],
y0=df['keyPoints1'].iloc[i-1],
x1=df.index[i],
y1=df['keyPoints2'].iloc[i-1],
line=dict(
color=np.random.choice(colors,1)[0],
width=30),
opacity=0.5,
layer="below"
)
lst_shapes=list(ply_shapes.values())
fig.update_layout(shapes=lst_shapes)
fig.show()
Also you can use fig.add_{shape}:
fig = go.Figure()
fig.add_trace(
go.Scatter( ...)
for i in range( 1, len( vrect)):
fig.add_vrect(
x0=vrect.start.iloc[ i-1],
x1=vrect.finish.iloc[ i-1],
fillcolor=vrect.color.iloc[ i-1]],
opacity=0.25,
line_width=0)
fig.show()
How can I set the color of a line in plotly?
import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(rows=2, cols=1, subplot_titles=('Plot 1', 'Plot 2'))
# plot the first line of the first plot
fig.append_trace(go.Scatter(x=self.x_axis_pd, y=self.y_1, mode='lines+markers', name='line#1'), row=1, col=1) # this line should be #ffe476
I tried fillcolor but that I suspected doesn't work because this is a simple line.
You can add line=dict(color="#ffe476") inside your go.Scatter(...) call. Documentation here: https://plot.ly/python/reference/#scatter-line-color
#nicolaskruchten is of course right, but I'd like to throw in two other options:
line_color="#0000ff"
And:
fig['data'][0]['line']['color']="#00ff00"
Or:
fig.data[0].line.color = "#00ff00"
I particularly appreciate the flexibility of the latter option since it easily lets you set a new color for a desired line after you've built a figure using for example fig.append_trace(go.Scatter()) or fig = go.Figure(data=go.Scatter)). Below is an example using all three options.
Code 1:
import plotly.graph_objects as go
import numpy as np
t = np.linspace(0, 10, 100)
y = np.cos(t)
y2= np.sin(t)
fig = go.Figure(data=go.Scatter(x=t, y=y,mode='lines+markers', line_color='#ffe476'))
fig.add_trace(go.Scatter(x=t, y=y2,mode='lines+markers', line=dict(color="#0000ff")))
fig.show()
Plot 1:
Now you can change the colors directly if you insert the snippet below in a new cell and run it.
Code 2:
fig['data'][0]['line']['color']="#00ff00"
fig.show()
Plot 2:
fig.add_trace(
go.Scatter(
x=list(dict_val['yolo_timecost'].keys()),
y=signal.savgol_filter(list(dict_val['yolo_timecost'].values()),2653,3),
mode='lines',
name='YOLOv3实时耗时',
line=dict(
color='rgb(204, 204, 204)',
width=5
),
),
)
fig.data[0].line.color = 'rgb(204, 20, 204)'
You can use color_discrete_sequence like that
import plotly.express as px
df = px.data.gapminder().query("country=='Canada'")
fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada',color_discrete_sequence=["#ff97ff"])
fig.show()